Revert "Revert "ALSA backend: separate flags for is-running and should-be-running""
[ardour.git] / libs / backends / alsa / alsa_audiobackend.cc
1 /*
2  * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2013 Paul Davis
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <regex.h>
21 #include <sys/mman.h>
22 #include <sys/time.h>
23
24 #include <glibmm.h>
25
26 #include "alsa_audiobackend.h"
27 #include "rt_thread.h"
28
29 #include "pbd/compose.h"
30 #include "pbd/error.h"
31 #include "ardour/port_manager.h"
32 #include "i18n.h"
33
34 using namespace ARDOUR;
35
36 static std::string s_instance_name;
37 size_t AlsaAudioBackend::_max_buffer_size = 8192;
38
39 AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
40         : AudioBackend (e, info)
41         , _pcmi (0)
42         , _run (false)
43         , _active (false)
44         , _freewheeling (false)
45         , _capture_device("")
46         , _playback_device("")
47         , _samplerate (48000)
48         , _samples_per_period (1024)
49         , _periods_per_cycle (2)
50         , _dsp_load (0)
51         , _n_inputs (0)
52         , _n_outputs (0)
53         , _systemic_input_latency (0)
54         , _systemic_output_latency (0)
55         , _processed_samples (0)
56 {
57         _instance_name = s_instance_name;
58         pthread_mutex_init (&_port_callback_mutex, 0);
59 }
60
61 AlsaAudioBackend::~AlsaAudioBackend ()
62 {
63         pthread_mutex_destroy (&_port_callback_mutex);
64 }
65
66 /* AUDIOBACKEND API */
67
68 std::string
69 AlsaAudioBackend::name () const
70 {
71         return X_("ALSA");
72 }
73
74 bool
75 AlsaAudioBackend::is_realtime () const
76 {
77         return true;
78 }
79
80 std::vector<AudioBackend::DeviceStatus>
81 AlsaAudioBackend::enumerate_devices () const
82 {
83         std::vector<AudioBackend::DeviceStatus> s;
84         int cardnum = -1;
85         int device = -1;
86         snd_ctl_card_info_t *info;
87         snd_ctl_card_info_alloca (&info);
88         snd_pcm_info_t *pcminfo;
89         snd_pcm_info_alloca (&pcminfo);
90
91         while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
92                 snd_ctl_t *handle;
93
94                 std::string devname = "hw:";
95                 devname += PBD::to_string (cardnum, std::dec);
96
97                 if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) {
98                         if (snd_ctl_card_info (handle, info) < 0) {
99                                 continue;
100                         }
101
102                         std::string card_name = snd_ctl_card_info_get_name (info);
103                         devname = "hw:";
104                         devname += snd_ctl_card_info_get_id (info);
105
106                         while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) {
107                                 snd_pcm_info_set_device (pcminfo, device);
108                                 snd_pcm_info_set_subdevice (pcminfo, 0);
109                                 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE);
110                                 if (snd_ctl_pcm_info (handle, pcminfo) < 0) {
111                                         continue;
112                                 }
113                                 snd_pcm_info_set_device (pcminfo, device);
114                                 snd_pcm_info_set_subdevice (pcminfo, 0);
115                                 snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK);
116                                 if (snd_ctl_pcm_info (handle, pcminfo) < 0) {
117                                         continue;
118                                 }
119                                 devname += ',';
120                                 devname += PBD::to_string (device, std::dec);
121                                 s.push_back (DeviceStatus (devname + " " + card_name, true));
122                         }
123                         snd_ctl_close (handle);
124                 }
125         }
126         return s;
127 }
128
129 std::vector<float>
130 AlsaAudioBackend::available_sample_rates (const std::string&) const
131 {
132         std::vector<float> sr;
133         sr.push_back (8000.0);
134         sr.push_back (22050.0);
135         sr.push_back (24000.0);
136         sr.push_back (44100.0);
137         sr.push_back (48000.0);
138         sr.push_back (88200.0);
139         sr.push_back (96000.0);
140         sr.push_back (176400.0);
141         sr.push_back (192000.0);
142         return sr;
143 }
144
145 std::vector<uint32_t>
146 AlsaAudioBackend::available_buffer_sizes (const std::string&) const
147 {
148         std::vector<uint32_t> bs;
149         bs.push_back (32);
150         bs.push_back (64);
151         bs.push_back (128);
152         bs.push_back (256);
153         bs.push_back (512);
154         bs.push_back (1024);
155         bs.push_back (2048);
156         bs.push_back (4096);
157         bs.push_back (8192);
158         return bs;
159 }
160
161 uint32_t
162 AlsaAudioBackend::available_input_channel_count (const std::string&) const
163 {
164         return 128; // TODO query current device
165 }
166
167 uint32_t
168 AlsaAudioBackend::available_output_channel_count (const std::string&) const
169 {
170         return 128; // TODO query current device
171 }
172
173 bool
174 AlsaAudioBackend::can_change_sample_rate_when_running () const
175 {
176         return false;
177 }
178
179 bool
180 AlsaAudioBackend::can_change_buffer_size_when_running () const
181 {
182         return false;
183 }
184
185 int
186 AlsaAudioBackend::set_device_name (const std::string& d)
187 {
188         _capture_device = d;
189         _playback_device = d;
190         return 0;
191 }
192
193 int
194 AlsaAudioBackend::set_sample_rate (float sr)
195 {
196         if (sr <= 0) { return -1; }
197         _samplerate = sr;
198         engine.sample_rate_change (sr);
199         return 0;
200 }
201
202 int
203 AlsaAudioBackend::set_buffer_size (uint32_t bs)
204 {
205         if (bs <= 0 || bs >= _max_buffer_size) {
206                 return -1;
207         }
208         _samples_per_period = bs;
209         engine.buffer_size_change (bs);
210         return 0;
211 }
212
213 int
214 AlsaAudioBackend::set_interleaved (bool yn)
215 {
216         if (!yn) { return 0; }
217         return -1;
218 }
219
220 int
221 AlsaAudioBackend::set_input_channels (uint32_t cc)
222 {
223         _n_inputs = cc;
224         return 0;
225 }
226
227 int
228 AlsaAudioBackend::set_output_channels (uint32_t cc)
229 {
230         _n_outputs = cc;
231         return 0;
232 }
233
234 int
235 AlsaAudioBackend::set_systemic_input_latency (uint32_t sl)
236 {
237         _systemic_input_latency = sl;
238         return 0;
239 }
240
241 int
242 AlsaAudioBackend::set_systemic_output_latency (uint32_t sl)
243 {
244         _systemic_output_latency = sl;
245         return 0;
246 }
247
248 /* Retrieving parameters */
249 std::string
250 AlsaAudioBackend::device_name () const
251 {
252         return _capture_device;
253 }
254
255 float
256 AlsaAudioBackend::sample_rate () const
257 {
258         return _samplerate;
259 }
260
261 uint32_t
262 AlsaAudioBackend::buffer_size () const
263 {
264         return _samples_per_period;
265 }
266
267 bool
268 AlsaAudioBackend::interleaved () const
269 {
270         return false;
271 }
272
273 uint32_t
274 AlsaAudioBackend::input_channels () const
275 {
276         return _n_inputs;
277 }
278
279 uint32_t
280 AlsaAudioBackend::output_channels () const
281 {
282         return _n_outputs;
283 }
284
285 uint32_t
286 AlsaAudioBackend::systemic_input_latency () const
287 {
288         return _systemic_input_latency;
289 }
290
291 uint32_t
292 AlsaAudioBackend::systemic_output_latency () const
293 {
294         return _systemic_output_latency;
295 }
296
297 /* MIDI */
298 void
299 AlsaAudioBackend::enumerate_midi_devices (std::vector<std::string> &m) const
300 {
301         int cardnum = -1;
302         snd_ctl_card_info_t *cinfo;
303         snd_ctl_card_info_alloca (&cinfo);
304         while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) {
305                 snd_ctl_t *handle;
306                 std::string devname = "hw:";
307                 devname += PBD::to_string (cardnum, std::dec);
308                 if (snd_ctl_open (&handle, devname.c_str (), 0) >= 0 && snd_ctl_card_info (handle, cinfo) >= 0) {
309                         int device = -1;
310                         while (snd_ctl_rawmidi_next_device (handle, &device) >= 0 && device >= 0) {
311                                 snd_rawmidi_info_t *info;
312                                 snd_rawmidi_info_alloca (&info);
313                                 snd_rawmidi_info_set_device (info, device);
314
315                                 int subs_in, subs_out;
316
317                                 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_INPUT);
318                                 if (snd_ctl_rawmidi_info (handle, info) >= 0) {
319                                         subs_in = snd_rawmidi_info_get_subdevices_count (info);
320                                 } else {
321                                         subs_in = 0;
322                                 }
323
324                                 snd_rawmidi_info_set_stream (info, SND_RAWMIDI_STREAM_OUTPUT);
325                                 if (snd_ctl_rawmidi_info (handle, info) >= 0) {
326                                         subs_out = snd_rawmidi_info_get_subdevices_count (info);
327                                 } else {
328                                         subs_out = 0;
329                                 }
330
331                                 const int subs = subs_in > subs_out ? subs_in : subs_out;
332                                 if (!subs) {
333                                         continue;
334                                 }
335
336                                 for (int sub = 0; sub < subs; ++sub) {
337                                         snd_rawmidi_info_set_stream (info, sub < subs_in ?
338                                                         SND_RAWMIDI_STREAM_INPUT :
339                                                         SND_RAWMIDI_STREAM_OUTPUT);
340
341                                         snd_rawmidi_info_set_subdevice (info, sub);
342                                         if (snd_ctl_rawmidi_info (handle, info) < 0) {
343                                                 continue;
344                                         }
345
346                                         const char *sub_name = snd_rawmidi_info_get_subdevice_name (info);
347                                         if (sub == 0 && sub_name[0] == '\0') {
348                                                 devname = "hw:";
349                                                 devname += snd_ctl_card_info_get_id (cinfo);
350                                                 devname += ",";
351                                                 devname += PBD::to_string (device, std::dec);
352                                                 devname += " ";
353                                                 devname += snd_rawmidi_info_get_name (info);
354                                                 devname += " (";
355                                                 if (sub < subs_in) devname += "I";
356                                                 if (sub < subs_out) devname += "O";
357                                                 devname += ")";
358                                                 m.push_back (devname);
359                                                 break;
360                                         } else {
361                                                 devname = "hw:";
362                                                 devname += snd_ctl_card_info_get_id (cinfo);
363                                                 devname += ",";
364                                                 devname += PBD::to_string (device, std::dec);
365                                                 devname += ",";
366                                                 devname += PBD::to_string (sub, std::dec);
367                                                 devname += " ";
368                                                 devname += sub_name;
369                                                 devname += " (";
370                                                 if (sub < subs_in) devname += "I";
371                                                 if (sub < subs_out) devname += "O";
372                                                 devname += ")";
373                                                 m.push_back (devname);
374                                         }
375                                 }
376                         }
377                         snd_ctl_close (handle);
378                 }
379         }
380 }
381
382 std::vector<std::string>
383 AlsaAudioBackend::enumerate_midi_options () const
384 {
385         std::vector<std::string> m;
386         m.push_back (_("-None-"));
387         enumerate_midi_devices(m);
388         if (m.size() > 2) {
389                 m.push_back (_("-All-"));
390         }
391         return m;
392 }
393
394 int
395 AlsaAudioBackend::set_midi_option (const std::string& opt)
396 {
397         _midi_device = opt;
398         return 0;
399 }
400
401 std::string
402 AlsaAudioBackend::midi_option () const
403 {
404         return _midi_device;
405 }
406
407 /* State Control */
408
409 static void * pthread_process (void *arg)
410 {
411         AlsaAudioBackend *d = static_cast<AlsaAudioBackend *>(arg);
412         d->main_process_thread ();
413         pthread_exit (0);
414         return 0;
415 }
416
417 int
418 AlsaAudioBackend::_start (bool for_latency_measurement)
419 {
420         if (_active || _run) {
421                 PBD::error << _("AlsaAudioBackend: already active.") << endmsg;
422                 return -1;
423         }
424
425         if (_ports.size()) {
426                 PBD::warning << _("AlsaAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
427                 _system_inputs.clear();
428                 _system_outputs.clear();
429                 _system_midi_in.clear();
430                 _system_midi_out.clear();
431                 _ports.clear();
432         }
433
434         assert(_rmidi_in.size() == 0);
435         assert(_rmidi_out.size() == 0);
436         assert(_pcmi == 0);
437
438         unsigned int pos = _capture_device.find(" ");
439         _pcmi = new Alsa_pcmi (_capture_device.substr(0, pos).c_str(), _playback_device.substr(0, pos).c_str(), 0, _samplerate, _samples_per_period, _periods_per_cycle, 0);
440         switch (_pcmi->state ()) {
441                 case 0: /* OK */ break;
442                 case -1: PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg; break;
443                 case -2: PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg; break;
444                 case -3: PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.") << endmsg; break;
445                 case -4: PBD::error << _("AlsaAudioBackend: cannot set requested period size.") << endmsg; break;
446                 case -5: PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.") << endmsg; break;
447                 case -6: PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg; break;
448                 default: PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg; break;
449         }
450         if (_pcmi->state ()) {
451                 delete _pcmi; _pcmi = 0;
452                 return -1;
453         }
454
455 #ifndef NDEBUG
456         _pcmi->printinfo ();
457 #endif
458
459         if (_n_outputs != _pcmi->nplay ()) {
460                 if (_n_outputs == 0) {
461                  _n_outputs = _pcmi->nplay ();
462                 } else {
463                  _n_outputs = std::min (_n_outputs, _pcmi->nplay ());
464                 }
465                 PBD::warning << _("AlsaAudioBackend: adjusted output channel count to match device.") << endmsg;
466         }
467
468         if (_n_inputs != _pcmi->ncapt ()) {
469                 if (_n_inputs == 0) {
470                  _n_inputs = _pcmi->ncapt ();
471                 } else {
472                  _n_inputs = std::min (_n_inputs, _pcmi->ncapt ());
473                 }
474                 PBD::warning << _("AlsaAudioBackend: adjusted input channel count to match device.") << endmsg;
475         }
476
477         if (_pcmi->fsize() != _samples_per_period) {
478                 _samples_per_period = _pcmi->fsize();
479                 PBD::warning << _("AlsaAudioBackend: samples per period does not match.") << endmsg;
480         }
481
482         if (_pcmi->fsamp() != _samplerate) {
483                 _samplerate = _pcmi->fsamp();
484                 engine.sample_rate_change (_samplerate);
485                 PBD::warning << _("AlsaAudioBackend: sample rate does not match.") << endmsg;
486         }
487
488         if (for_latency_measurement) {
489                 _systemic_input_latency = 0;
490                 _systemic_output_latency = 0;
491         }
492
493         register_system_midi_ports();
494
495         if (register_system_audio_ports()) {
496                 PBD::error << _("AlsaAudioBackend: failed to register system ports.") << endmsg;
497                 delete _pcmi; _pcmi = 0;
498                 return -1;
499         }
500
501         if (engine.reestablish_ports ()) {
502                 PBD::error << _("AlsaAudioBackend: Could not re-establish ports.") << endmsg;
503                 delete _pcmi; _pcmi = 0;
504                 return -1;
505         }
506
507         engine.buffer_size_change (_samples_per_period);
508         engine.reconnect_ports ();
509         _run = true;
510
511         if (_realtime_pthread_create (SCHED_FIFO, -20,
512                                 &_main_thread, pthread_process, this))
513         {
514                 if (pthread_create (&_main_thread, NULL, pthread_process, this))
515                 {
516                         PBD::error << _("AlsaAudioBackend: failed to create process thread.") << endmsg;
517                         delete _pcmi; _pcmi = 0;
518                         _run = false;
519                         return -1;
520                 } else {
521                         PBD::warning << _("AlsaAudioBackend: cannot acquire realtime permissions.") << endmsg;
522                 }
523         }
524
525         int timeout = 5000;
526         while (!_active && --timeout > 0) { Glib::usleep (1000); }
527
528         if (timeout == 0 || !_active) {
529                 PBD::error << _("AlsaAudioBackend: failed to start process thread.") << endmsg;
530                 delete _pcmi; _pcmi = 0;
531                 _run = false;
532                 return -1;
533         }
534
535         return 0;
536 }
537
538 int
539 AlsaAudioBackend::stop ()
540 {
541         void *status;
542         if (!_active) {
543                 return 0;
544         }
545
546         _run = false;
547         if (pthread_join (_main_thread, &status)) {
548                 PBD::error << _("AlsaAudioBackend: failed to terminate.") << endmsg;
549                 return -1;
550         }
551
552         while (!_rmidi_out.empty ()) {
553                 AlsaRawMidiIO *m = _rmidi_out.back ();
554                 m->stop();
555                 _rmidi_out.pop_back ();
556                 delete m;
557         }
558         while (!_rmidi_in.empty ()) {
559                 AlsaRawMidiIO *m = _rmidi_in.back ();
560                 m->stop();
561                 _rmidi_in.pop_back ();
562                 delete m;
563         }
564
565         unregister_system_ports();
566         delete _pcmi; _pcmi = 0;
567         return (_active == false) ? 0 : -1;
568 }
569
570 int
571 AlsaAudioBackend::freewheel (bool onoff)
572 {
573         if (onoff == _freewheeling) {
574                 return 0;
575         }
576         _freewheeling = onoff;
577         engine.freewheel_callback (onoff);
578         return 0;
579 }
580
581 float
582 AlsaAudioBackend::dsp_load () const
583 {
584         return 100.f * _dsp_load;
585 }
586
587 size_t
588 AlsaAudioBackend::raw_buffer_size (DataType t)
589 {
590         switch (t) {
591                 case DataType::AUDIO:
592                         return _samples_per_period * sizeof(Sample);
593                 case DataType::MIDI:
594                         return _max_buffer_size; // XXX not really limited
595         }
596         return 0;
597 }
598
599 /* Process time */
600 pframes_t
601 AlsaAudioBackend::sample_time ()
602 {
603         return _processed_samples;
604 }
605
606 pframes_t
607 AlsaAudioBackend::sample_time_at_cycle_start ()
608 {
609         return _processed_samples;
610 }
611
612 pframes_t
613 AlsaAudioBackend::samples_since_cycle_start ()
614 {
615         return 0;
616 }
617
618
619 void *
620 AlsaAudioBackend::alsa_process_thread (void *arg)
621 {
622         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
623         boost::function<void ()> f = td->f;
624         delete td;
625         f ();
626         return 0;
627 }
628
629 int
630 AlsaAudioBackend::create_process_thread (boost::function<void()> func)
631 {
632         pthread_t thread_id;
633         pthread_attr_t attr;
634         size_t stacksize = 100000;
635
636         pthread_attr_init (&attr);
637         pthread_attr_setstacksize (&attr, stacksize);
638         ThreadData* td = new ThreadData (this, func, stacksize);
639
640         if (pthread_create (&thread_id, &attr, alsa_process_thread, td)) {
641                 PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
642                 pthread_attr_destroy (&attr);
643                 return -1;
644         }
645         pthread_attr_destroy (&attr);
646
647         _threads.push_back (thread_id);
648         return 0;
649 }
650
651 int
652 AlsaAudioBackend::join_process_threads ()
653 {
654         int rv = 0;
655
656         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
657         {
658                 void *status;
659                 if (pthread_join (*i, &status)) {
660                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
661                         rv -= 1;
662                 }
663         }
664         _threads.clear ();
665         return rv;
666 }
667
668 bool
669 AlsaAudioBackend::in_process_thread ()
670 {
671         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
672         {
673                 if (pthread_equal (*i, pthread_self ()) != 0) {
674                         return true;
675                 }
676         }
677         return false;
678 }
679
680 uint32_t
681 AlsaAudioBackend::process_thread_count ()
682 {
683         return _threads.size ();
684 }
685
686 void
687 AlsaAudioBackend::update_latencies ()
688 {
689 }
690
691 /* PORTENGINE API */
692
693 void*
694 AlsaAudioBackend::private_handle () const
695 {
696         return NULL;
697 }
698
699 const std::string&
700 AlsaAudioBackend::my_name () const
701 {
702         return _instance_name;
703 }
704
705 bool
706 AlsaAudioBackend::available () const
707 {
708         return _run && _active;
709 }
710
711 uint32_t
712 AlsaAudioBackend::port_name_size () const
713 {
714         return 256;
715 }
716
717 int
718 AlsaAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
719 {
720         if (!valid_port (port)) {
721                 PBD::error << _("AlsaBackend::set_port_name: Invalid Port(s)") << endmsg;
722                 return -1;
723         }
724         return static_cast<AlsaPort*>(port)->set_name (_instance_name + ":" + name);
725 }
726
727 std::string
728 AlsaAudioBackend::get_port_name (PortEngine::PortHandle port) const
729 {
730         if (!valid_port (port)) {
731                 PBD::error << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
732                 return std::string ();
733         }
734         return static_cast<AlsaPort*>(port)->name ();
735 }
736
737 PortEngine::PortHandle
738 AlsaAudioBackend::get_port_by_name (const std::string& name) const
739 {
740         PortHandle port = (PortHandle) find_port (name);
741         return port;
742 }
743
744 int
745 AlsaAudioBackend::get_ports (
746                 const std::string& port_name_pattern,
747                 DataType type, PortFlags flags,
748                 std::vector<std::string>& port_names) const
749 {
750         int rv = 0;
751         regex_t port_regex;
752         bool use_regexp = false;
753         if (port_name_pattern.size () > 0) {
754                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
755                         use_regexp = true;
756                 }
757         }
758         for (size_t i = 0; i < _ports.size (); ++i) {
759                 AlsaPort* port = _ports[i];
760                 if ((port->type () == type) && (port->flags () & flags)) {
761                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
762                                 port_names.push_back (port->name ());
763                                 ++rv;
764                         }
765                 }
766         }
767         if (use_regexp) {
768                 regfree (&port_regex);
769         }
770         return rv;
771 }
772
773 DataType
774 AlsaAudioBackend::port_data_type (PortEngine::PortHandle port) const
775 {
776         if (!valid_port (port)) {
777                 return DataType::NIL;
778         }
779         return static_cast<AlsaPort*>(port)->type ();
780 }
781
782 PortEngine::PortHandle
783 AlsaAudioBackend::register_port (
784                 const std::string& name,
785                 ARDOUR::DataType type,
786                 ARDOUR::PortFlags flags)
787 {
788         if (name.size () == 0) { return 0; }
789         if (flags & IsPhysical) { return 0; }
790         return add_port (_instance_name + ":" + name, type, flags);
791 }
792
793 PortEngine::PortHandle
794 AlsaAudioBackend::add_port (
795                 const std::string& name,
796                 ARDOUR::DataType type,
797                 ARDOUR::PortFlags flags)
798 {
799         assert(name.size ());
800         if (find_port (name)) {
801                 PBD::error << _("AlsaBackend::register_port: Port already exists:")
802                                 << " (" << name << ")" << endmsg;
803                 return 0;
804         }
805         AlsaPort* port = NULL;
806         switch (type) {
807                 case DataType::AUDIO:
808                         port = new AlsaAudioPort (*this, name, flags);
809                         break;
810                 case DataType::MIDI:
811                         port = new AlsaMidiPort (*this, name, flags);
812                         break;
813                 default:
814                         PBD::error << _("AlsaBackend::register_port: Invalid Data Type.") << endmsg;
815                         return 0;
816         }
817
818         _ports.push_back (port);
819
820         return port;
821 }
822
823 void
824 AlsaAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
825 {
826         if (!valid_port (port_handle)) {
827                 PBD::error << _("AlsaBackend::unregister_port: Invalid Port.") << endmsg;
828         }
829         AlsaPort* port = static_cast<AlsaPort*>(port_handle);
830         std::vector<AlsaPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<AlsaPort*>(port_handle));
831         if (i == _ports.end ()) {
832                 PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
833                 return;
834         }
835         disconnect_all(port_handle);
836         _ports.erase (i);
837         delete port;
838 }
839
840 int
841 AlsaAudioBackend::register_system_audio_ports()
842 {
843         LatencyRange lr;
844
845         const int a_ins = _n_inputs > 0 ? _n_inputs : 2;
846         const int a_out = _n_outputs > 0 ? _n_outputs : 2;
847
848         /* audio ports */
849         lr.min = lr.max = _samples_per_period * _periods_per_cycle + _systemic_input_latency;
850         for (int i = 1; i <= a_ins; ++i) {
851                 char tmp[64];
852                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
853                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
854                 if (!p) return -1;
855                 set_latency_range (p, false, lr);
856                 _system_inputs.push_back(static_cast<AlsaPort*>(p));
857         }
858
859         lr.min = lr.max = _samples_per_period * _periods_per_cycle + _systemic_output_latency;
860         for (int i = 1; i <= a_out; ++i) {
861                 char tmp[64];
862                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
863                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
864                 if (!p) return -1;
865                 set_latency_range (p, false, lr);
866                 _system_outputs.push_back(static_cast<AlsaPort*>(p));
867         }
868         return 0;
869 }
870
871 int
872 AlsaAudioBackend::register_system_midi_ports()
873 {
874         LatencyRange lr;
875         std::vector<std::string> devices;
876
877         if (_midi_device == _("-None-")) {
878                 return 0;
879         }
880         else if (_midi_device == _("-All-")) {
881                 enumerate_midi_devices(devices);
882         } else {
883                 unsigned int pos = _midi_device.find(" ");
884                 devices.push_back(_midi_device.substr(0, pos));
885         }
886
887         for (std::vector<std::string>::const_iterator i = devices.begin (); i != devices.end (); ++i) {
888
889                 AlsaRawMidiOut *mout = new AlsaRawMidiOut (i->c_str());
890                 if (mout->state ()) {
891                         PBD::warning << string_compose (
892                                         _("AlsaRawMidiOut: failed to open midi device '%1'."), *i)
893                                 << endmsg;
894                         delete mout;
895                 } else {
896                         mout->setup_timing(_samples_per_period, _samplerate);
897                         mout->sync_time (g_get_monotonic_time());
898                         if (mout->start ()) {
899                                 PBD::warning << string_compose (
900                                                 _("AlsaRawMidiOut: failed to start midi device '%1'."), *i)
901                                         << endmsg;
902                                 delete mout;
903                         } else {
904                                 _rmidi_out.push_back (mout);
905                         }
906                 }
907
908                 AlsaRawMidiIn *midin = new AlsaRawMidiIn (i->c_str());
909                 if (midin->state ()) {
910                         PBD::warning << string_compose (
911                                         _("AlsaRawMidiIn: failed to open midi device '%1'."), *i)
912                                 << endmsg;
913                         delete midin;
914                 } else {
915                         midin->setup_timing(_samples_per_period, _samplerate);
916                         midin->sync_time (g_get_monotonic_time());
917                         if (midin->start ()) {
918                                 PBD::warning << string_compose (
919                                                 _("AlsaRawMidiIn: failed to start midi device '%1'."), *i)
920                                         << endmsg;
921                                 delete midin;
922                         } else {
923                                 _rmidi_in.push_back (midin);
924                         }
925                 }
926         }
927
928         const int m_ins = _rmidi_in.size();
929         const int m_out = _rmidi_out.size();
930
931         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
932         for (int i = 1; i <= m_ins; ++i) {
933                 char tmp[64];
934                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", i);
935                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
936                 if (!p) return -1;
937                 set_latency_range (p, false, lr);
938                 _system_midi_in.push_back(static_cast<AlsaPort*>(p));
939         }
940
941         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
942         for (int i = 1; i <= m_out; ++i) {
943                 char tmp[64];
944                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", i);
945                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
946                 if (!p) return -1;
947                 set_latency_range (p, false, lr);
948                 _system_midi_out.push_back(static_cast<AlsaPort*>(p));
949         }
950
951         return 0;
952 }
953
954 void
955 AlsaAudioBackend::unregister_system_ports()
956 {
957         size_t i = 0;
958         _system_inputs.clear();
959         _system_outputs.clear();
960         _system_midi_in.clear();
961         _system_midi_out.clear();
962         while (i <  _ports.size ()) {
963                 AlsaPort* port = _ports[i];
964                 if (port->is_physical () && port->is_terminal ()) {
965                         port->disconnect_all ();
966                         _ports.erase (_ports.begin() + i);
967                 } else {
968                         ++i;
969                 }
970         }
971 }
972
973 int
974 AlsaAudioBackend::connect (const std::string& src, const std::string& dst)
975 {
976         AlsaPort* src_port = find_port (src);
977         AlsaPort* dst_port = find_port (dst);
978
979         if (!src_port) {
980                 PBD::error << _("AlsaBackend::connect: Invalid Source port:")
981                                 << " (" << src <<")" << endmsg;
982                 return -1;
983         }
984         if (!dst_port) {
985                 PBD::error << _("AlsaBackend::connect: Invalid Destination port:")
986                         << " (" << dst <<")" << endmsg;
987                 return -1;
988         }
989         return src_port->connect (dst_port);
990 }
991
992 int
993 AlsaAudioBackend::disconnect (const std::string& src, const std::string& dst)
994 {
995         AlsaPort* src_port = find_port (src);
996         AlsaPort* dst_port = find_port (dst);
997
998         if (!src_port || !dst_port) {
999                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1000                 return -1;
1001         }
1002         return src_port->disconnect (dst_port);
1003 }
1004
1005 int
1006 AlsaAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
1007 {
1008         AlsaPort* dst_port = find_port (dst);
1009         if (!valid_port (src)) {
1010                 PBD::error << _("AlsaBackend::connect: Invalid Source Port Handle") << endmsg;
1011                 return -1;
1012         }
1013         if (!dst_port) {
1014                 PBD::error << _("AlsaBackend::connect: Invalid Destination Port")
1015                         << " (" << dst << ")" << endmsg;
1016                 return -1;
1017         }
1018         return static_cast<AlsaPort*>(src)->connect (dst_port);
1019 }
1020
1021 int
1022 AlsaAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
1023 {
1024         AlsaPort* dst_port = find_port (dst);
1025         if (!valid_port (src) || !dst_port) {
1026                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1027                 return -1;
1028         }
1029         return static_cast<AlsaPort*>(src)->disconnect (dst_port);
1030 }
1031
1032 int
1033 AlsaAudioBackend::disconnect_all (PortEngine::PortHandle port)
1034 {
1035         if (!valid_port (port)) {
1036                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1037                 return -1;
1038         }
1039         static_cast<AlsaPort*>(port)->disconnect_all ();
1040         return 0;
1041 }
1042
1043 bool
1044 AlsaAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
1045 {
1046         if (!valid_port (port)) {
1047                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1048                 return false;
1049         }
1050         return static_cast<AlsaPort*>(port)->is_connected ();
1051 }
1052
1053 bool
1054 AlsaAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
1055 {
1056         AlsaPort* dst_port = find_port (dst);
1057         if (!valid_port (src) || !dst_port) {
1058                 PBD::error << _("AlsaBackend::connected_to: Invalid Port") << endmsg;
1059                 return false;
1060         }
1061         return static_cast<AlsaPort*>(src)->is_connected (dst_port);
1062 }
1063
1064 bool
1065 AlsaAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
1066 {
1067         if (!valid_port (port)) {
1068                 PBD::error << _("AlsaBackend::physically_connected: Invalid Port") << endmsg;
1069                 return false;
1070         }
1071         return static_cast<AlsaPort*>(port)->is_physically_connected ();
1072 }
1073
1074 int
1075 AlsaAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
1076 {
1077         if (!valid_port (port)) {
1078                 PBD::error << _("AlsaBackend::get_connections: Invalid Port") << endmsg;
1079                 return -1;
1080         }
1081
1082         assert (0 == names.size ());
1083
1084         const std::vector<AlsaPort*>& connected_ports = static_cast<AlsaPort*>(port)->get_connections ();
1085
1086         for (std::vector<AlsaPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
1087                 names.push_back ((*i)->name ());
1088         }
1089
1090         return (int)names.size ();
1091 }
1092
1093 /* MIDI */
1094 int
1095 AlsaAudioBackend::midi_event_get (
1096                 pframes_t& timestamp,
1097                 size_t& size, uint8_t** buf, void* port_buffer,
1098                 uint32_t event_index)
1099 {
1100         assert (buf && port_buffer);
1101         AlsaMidiBuffer& source = * static_cast<AlsaMidiBuffer*>(port_buffer);
1102         if (event_index >= source.size ()) {
1103                 return -1;
1104         }
1105         AlsaMidiEvent * const event = source[event_index].get ();
1106
1107         timestamp = event->timestamp ();
1108         size = event->size ();
1109         *buf = event->data ();
1110         return 0;
1111 }
1112
1113 int
1114 AlsaAudioBackend::midi_event_put (
1115                 void* port_buffer,
1116                 pframes_t timestamp,
1117                 const uint8_t* buffer, size_t size)
1118 {
1119         assert (buffer && port_buffer);
1120         AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
1121         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
1122                 fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
1123                                 (pframes_t)dst.back ()->timestamp (), timestamp);
1124                 return -1;
1125         }
1126         dst.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (timestamp, buffer, size)));
1127         return 0;
1128 }
1129
1130 uint32_t
1131 AlsaAudioBackend::get_midi_event_count (void* port_buffer)
1132 {
1133         assert (port_buffer);
1134         return static_cast<AlsaMidiBuffer*>(port_buffer)->size ();
1135 }
1136
1137 void
1138 AlsaAudioBackend::midi_clear (void* port_buffer)
1139 {
1140         assert (port_buffer);
1141         AlsaMidiBuffer * buf = static_cast<AlsaMidiBuffer*>(port_buffer);
1142         assert (buf);
1143         buf->clear ();
1144 }
1145
1146 /* Monitoring */
1147
1148 bool
1149 AlsaAudioBackend::can_monitor_input () const
1150 {
1151         return false;
1152 }
1153
1154 int
1155 AlsaAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
1156 {
1157         return -1;
1158 }
1159
1160 int
1161 AlsaAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
1162 {
1163         return -1;
1164 }
1165
1166 bool
1167 AlsaAudioBackend::monitoring_input (PortEngine::PortHandle)
1168 {
1169         return false;
1170 }
1171
1172 /* Latency management */
1173
1174 void
1175 AlsaAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
1176 {
1177         if (!valid_port (port)) {
1178                 PBD::error << _("AlsaPort::set_latency_range (): invalid port.") << endmsg;
1179         }
1180         static_cast<AlsaPort*>(port)->set_latency_range (latency_range, for_playback);
1181 }
1182
1183 LatencyRange
1184 AlsaAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
1185 {
1186         if (!valid_port (port)) {
1187                 PBD::error << _("AlsaPort::get_latency_range (): invalid port.") << endmsg;
1188                 LatencyRange r;
1189                 r.min = 0;
1190                 r.max = 0;
1191                 return r;
1192         }
1193         return static_cast<AlsaPort*>(port)->latency_range (for_playback);
1194 }
1195
1196 /* Discovering physical ports */
1197
1198 bool
1199 AlsaAudioBackend::port_is_physical (PortEngine::PortHandle port) const
1200 {
1201         if (!valid_port (port)) {
1202                 PBD::error << _("AlsaPort::port_is_physical (): invalid port.") << endmsg;
1203                 return false;
1204         }
1205         return static_cast<AlsaPort*>(port)->is_physical ();
1206 }
1207
1208 void
1209 AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
1210 {
1211         for (size_t i = 0; i < _ports.size (); ++i) {
1212                 AlsaPort* port = _ports[i];
1213                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
1214                         port_names.push_back (port->name ());
1215                 }
1216         }
1217 }
1218
1219 void
1220 AlsaAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
1221 {
1222         for (size_t i = 0; i < _ports.size (); ++i) {
1223                 AlsaPort* port = _ports[i];
1224                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
1225                         port_names.push_back (port->name ());
1226                 }
1227         }
1228 }
1229
1230 ChanCount
1231 AlsaAudioBackend::n_physical_outputs () const
1232 {
1233         int n_midi = 0;
1234         int n_audio = 0;
1235         for (size_t i = 0; i < _ports.size (); ++i) {
1236                 AlsaPort* port = _ports[i];
1237                 if (port->is_output () && port->is_physical ()) {
1238                         switch (port->type ()) {
1239                                 case DataType::AUDIO: ++n_audio; break;
1240                                 case DataType::MIDI: ++n_midi; break;
1241                                 default: break;
1242                         }
1243                 }
1244         }
1245         ChanCount cc;
1246         cc.set (DataType::AUDIO, n_audio);
1247         cc.set (DataType::MIDI, n_midi);
1248         return cc;
1249 }
1250
1251 ChanCount
1252 AlsaAudioBackend::n_physical_inputs () const
1253 {
1254         int n_midi = 0;
1255         int n_audio = 0;
1256         for (size_t i = 0; i < _ports.size (); ++i) {
1257                 AlsaPort* port = _ports[i];
1258                 if (port->is_input () && port->is_physical ()) {
1259                         switch (port->type ()) {
1260                                 case DataType::AUDIO: ++n_audio; break;
1261                                 case DataType::MIDI: ++n_midi; break;
1262                                 default: break;
1263                         }
1264                 }
1265         }
1266         ChanCount cc;
1267         cc.set (DataType::AUDIO, n_audio);
1268         cc.set (DataType::MIDI, n_midi);
1269         return cc;
1270 }
1271
1272 /* Getting access to the data buffer for a port */
1273
1274 void*
1275 AlsaAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
1276 {
1277         assert (port);
1278         assert (valid_port (port));
1279         return static_cast<AlsaPort*>(port)->get_buffer (nframes);
1280 }
1281
1282 /* Engine Process */
1283 void *
1284 AlsaAudioBackend::main_process_thread ()
1285 {
1286         AudioEngine::thread_init_callback (this);
1287         _active = true;
1288         _processed_samples = 0;
1289
1290         uint64_t clock1, clock2;
1291         clock1 = g_get_monotonic_time();
1292         _pcmi->pcm_start ();
1293         int no_proc_errors = 0;
1294
1295         while (_run) {
1296                 long nr;
1297                 bool xrun = false;
1298                 if (!_freewheeling) {
1299                         nr = _pcmi->pcm_wait ();
1300
1301                         if (_pcmi->state () > 0) {
1302                                 ++no_proc_errors;
1303                                 xrun = true;
1304                         }
1305                         if (_pcmi->state () < 0 || no_proc_errors > 50) {
1306                                 PBD::error << _("AlsaAudioBackend: I/O error. Audio Process Terminated.") << endmsg;
1307                                 break;
1308                         }
1309                         while (nr >= (long)_samples_per_period) {
1310                                 uint32_t i = 0;
1311                                 clock1 = g_get_monotonic_time();
1312                                 no_proc_errors = 0;
1313
1314                                 _pcmi->capt_init (_samples_per_period);
1315                                 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) {
1316                                         _pcmi->capt_chan (i, (float*)((*it)->get_buffer(_samples_per_period)), _samples_per_period);
1317                                 }
1318                                 _pcmi->capt_done (_samples_per_period);
1319
1320                                 /* de-queue midi*/
1321                                 i = 0;
1322                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1323                                         assert (_rmidi_in.size() > i);
1324                                         AlsaRawMidiIn *rm = static_cast<AlsaRawMidiIn*>(_rmidi_in.at(i));
1325                                         void *bptr = (*it)->get_buffer(0);
1326                                         pframes_t time;
1327                                         uint8_t data[64]; // match MaxAlsaRawEventSize in alsa_rawmidi.cc
1328                                         size_t size = sizeof(data);
1329                                         midi_clear(bptr);
1330                                         while (rm->recv_event (time, data, size)) {
1331                                                 midi_event_put(bptr, time, data, size);
1332                                                 size = sizeof(data);
1333                                         }
1334                                         rm->sync_time (clock1);
1335                                 }
1336
1337                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
1338                                         memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1339                                 }
1340
1341                                 if (engine.process_callback (_samples_per_period)) {
1342                                         _pcmi->pcm_stop ();
1343                                         return 0;
1344                                 }
1345
1346                                 /* queue midi*/
1347                                 i = 0;
1348                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
1349                                         assert (_rmidi_out.size() > i);
1350                                         AlsaRawMidiOut *rm = static_cast<AlsaRawMidiOut*>(_rmidi_out.at(i));
1351                                         const AlsaMidiBuffer *src = static_cast<const AlsaMidiBuffer*>((*it)->get_buffer(0));
1352                                         rm->sync_time (clock1); // ?? use clock pre DSP load?
1353                                         for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
1354                                                 rm->send_event ((*mit)->timestamp(), (*mit)->data(), (*mit)->size());
1355                                         }
1356                                 }
1357
1358                                 /* write back audio */
1359                                 i = 0;
1360                                 _pcmi->play_init (_samples_per_period);
1361                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it, ++i) {
1362                                         _pcmi->play_chan (i, (const float*)(*it)->get_buffer (_samples_per_period), _samples_per_period);
1363                                 }
1364                                 for (; i < _pcmi->nplay (); ++i) {
1365                                         _pcmi->clear_chan (i, _samples_per_period);
1366                                 }
1367                                 _pcmi->play_done (_samples_per_period);
1368                                 nr -= _samples_per_period;
1369                                 _processed_samples += _samples_per_period;
1370
1371                                 /* calculate DSP load */
1372                                 clock2 = g_get_monotonic_time();
1373                                 const int64_t elapsed_time = clock2 - clock1;
1374                                 const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
1375                                 _dsp_load = elapsed_time / (float) nomial_time;
1376                         }
1377
1378                         if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) {
1379                                 engine.Xrun ();
1380 #if 0
1381                                 fprintf(stderr, "ALSA x-run read: %.1f ms, write: %.1f ms\n",
1382                                                 _pcmi->capt_xrun() * 1000.0, _pcmi->play_xrun() * 1000.0);
1383 #endif
1384                         }
1385                 } else {
1386                         // Freewheelin'
1387                         for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
1388                                 memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1389                         }
1390                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) {
1391                                 static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
1392                         }
1393
1394                         if (engine.process_callback (_samples_per_period)) {
1395                                 _pcmi->pcm_stop ();
1396                                 return 0;
1397                         }
1398                         _dsp_load = 1.0;
1399                         Glib::usleep (100); // don't hog cpu
1400                 }
1401
1402                 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
1403                         while (!_port_connection_queue.empty ()) {
1404                                 PortConnectData *c = _port_connection_queue.back ();
1405                                 manager.connect_callback (c->a, c->b, c->c);
1406                                 _port_connection_queue.pop_back ();
1407                                 delete c;
1408                         }
1409                         pthread_mutex_unlock (&_port_callback_mutex);
1410                 }
1411
1412         }
1413         _pcmi->pcm_stop ();
1414         _active = false;
1415         return 0;
1416 }
1417
1418
1419 /******************************************************************************/
1420
1421 static boost::shared_ptr<AlsaAudioBackend> _instance;
1422
1423 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1424 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1425 static int deinstantiate ();
1426 static bool already_configured ();
1427
1428 static ARDOUR::AudioBackendInfo _descriptor = {
1429         "Alsa",
1430         instantiate,
1431         deinstantiate,
1432         backend_factory,
1433         already_configured,
1434 };
1435
1436 static boost::shared_ptr<AudioBackend>
1437 backend_factory (AudioEngine& e)
1438 {
1439         if (!_instance) {
1440                 _instance.reset (new AlsaAudioBackend (e, _descriptor));
1441         }
1442         return _instance;
1443 }
1444
1445 static int
1446 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1447 {
1448         s_instance_name = arg1;
1449         return 0;
1450 }
1451
1452 static int
1453 deinstantiate ()
1454 {
1455         _instance.reset ();
1456         return 0;
1457 }
1458
1459 static bool
1460 already_configured ()
1461 {
1462         return false;
1463 }
1464
1465 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1466 {
1467         return &_descriptor;
1468 }
1469
1470
1471 /******************************************************************************/
1472 AlsaPort::AlsaPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
1473         : _alsa_backend (b)
1474         , _name  (name)
1475         , _flags (flags)
1476 {
1477         _capture_latency_range.min = 0;
1478         _capture_latency_range.max = 0;
1479         _playback_latency_range.min = 0;
1480         _playback_latency_range.max = 0;
1481 }
1482
1483 AlsaPort::~AlsaPort () {
1484         disconnect_all ();
1485 }
1486
1487
1488 int AlsaPort::connect (AlsaPort *port)
1489 {
1490         if (!port) {
1491                 PBD::error << _("AlsaPort::connect (): invalid (null) port") << endmsg;
1492                 return -1;
1493         }
1494
1495         if (type () != port->type ()) {
1496                 PBD::error << _("AlsaPort::connect (): wrong port-type") << endmsg;
1497                 return -1;
1498         }
1499
1500         if (is_output () && port->is_output ()) {
1501                 PBD::error << _("AlsaPort::connect (): cannot inter-connect output ports.") << endmsg;
1502                 return -1;
1503         }
1504
1505         if (is_input () && port->is_input ()) {
1506                 PBD::error << _("AlsaPort::connect (): cannot inter-connect input ports.") << endmsg;
1507                 return -1;
1508         }
1509
1510         if (this == port) {
1511                 PBD::error << _("AlsaPort::connect (): cannot self-connect ports.") << endmsg;
1512                 return -1;
1513         }
1514
1515         if (is_connected (port)) {
1516 #if 0 // don't bother to warn about this for now. just ignore it
1517                 PBD::error << _("AlsaPort::connect (): ports are already connected:")
1518                         << " (" << name () << ") -> (" << port->name () << ")"
1519                         << endmsg;
1520 #endif
1521                 return -1;
1522         }
1523
1524         _connect (port, true);
1525         return 0;
1526 }
1527
1528
1529 void AlsaPort::_connect (AlsaPort *port, bool callback)
1530 {
1531         _connections.push_back (port);
1532         if (callback) {
1533                 port->_connect (this, false);
1534                 _alsa_backend.port_connect_callback (name(),  port->name(), true);
1535         }
1536 }
1537
1538 int AlsaPort::disconnect (AlsaPort *port)
1539 {
1540         if (!port) {
1541                 PBD::error << _("AlsaPort::disconnect (): invalid (null) port") << endmsg;
1542                 return -1;
1543         }
1544
1545         if (!is_connected (port)) {
1546                 PBD::error << _("AlsaPort::disconnect (): ports are not connected:")
1547                         << " (" << name () << ") -> (" << port->name () << ")"
1548                         << endmsg;
1549                 return -1;
1550         }
1551         _disconnect (port, true);
1552         return 0;
1553 }
1554
1555 void AlsaPort::_disconnect (AlsaPort *port, bool callback)
1556 {
1557         std::vector<AlsaPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
1558
1559         assert (it != _connections.end ());
1560
1561         _connections.erase (it);
1562
1563         if (callback) {
1564                 port->_disconnect (this, false);
1565                 _alsa_backend.port_connect_callback (name(),  port->name(), false);
1566         }
1567 }
1568
1569
1570 void AlsaPort::disconnect_all ()
1571 {
1572         while (!_connections.empty ()) {
1573                 _connections.back ()->_disconnect (this, false);
1574                 _alsa_backend.port_connect_callback (name(),  _connections.back ()->name(), false);
1575                 _connections.pop_back ();
1576         }
1577 }
1578
1579 bool
1580 AlsaPort::is_connected (const AlsaPort *port) const
1581 {
1582         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
1583 }
1584
1585 bool AlsaPort::is_physically_connected () const
1586 {
1587         for (std::vector<AlsaPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
1588                 if ((*it)->is_physical ()) {
1589                         return true;
1590                 }
1591         }
1592         return false;
1593 }
1594
1595 /******************************************************************************/
1596
1597 AlsaAudioPort::AlsaAudioPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
1598         : AlsaPort (b, name, flags)
1599 {
1600         memset (_buffer, 0, sizeof (_buffer));
1601         mlock(_buffer, sizeof (_buffer));
1602 }
1603
1604 AlsaAudioPort::~AlsaAudioPort () { }
1605
1606 void* AlsaAudioPort::get_buffer (pframes_t n_samples)
1607 {
1608         if (is_input ()) {
1609                 std::vector<AlsaPort*>::const_iterator it = get_connections ().begin ();
1610                 if (it == get_connections ().end ()) {
1611                         memset (_buffer, 0, n_samples * sizeof (Sample));
1612                 } else {
1613                         AlsaAudioPort const * source = static_cast<const AlsaAudioPort*>(*it);
1614                         assert (source && source->is_output ());
1615                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
1616                         while (++it != get_connections ().end ()) {
1617                                 source = static_cast<const AlsaAudioPort*>(*it);
1618                                 assert (source && source->is_output ());
1619                                 Sample* dst = buffer ();
1620                                 const Sample* src = source->const_buffer ();
1621                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
1622                                         *dst += *src;
1623                                 }
1624                         }
1625                 }
1626         }
1627         return _buffer;
1628 }
1629
1630
1631 AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
1632         : AlsaPort (b, name, flags)
1633 {
1634         _buffer.clear ();
1635 }
1636
1637 AlsaMidiPort::~AlsaMidiPort () { }
1638
1639 struct MidiEventSorter {
1640         bool operator() (const boost::shared_ptr<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& b) {
1641                 return *a < *b;
1642         }
1643 };
1644
1645 void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
1646 {
1647         if (is_input ()) {
1648                 _buffer.clear ();
1649                 for (std::vector<AlsaPort*>::const_iterator i = get_connections ().begin ();
1650                                 i != get_connections ().end ();
1651                                 ++i) {
1652                         const AlsaMidiBuffer src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
1653                         for (AlsaMidiBuffer::const_iterator it = src.begin (); it != src.end (); ++it) {
1654                                 _buffer.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (**it)));
1655                         }
1656                 }
1657                 std::sort (_buffer.begin (), _buffer.end (), MidiEventSorter());
1658         }
1659         return &_buffer;
1660 }
1661
1662 AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
1663         : _size (size)
1664         , _timestamp (timestamp)
1665         , _data (0)
1666 {
1667         if (size > 0) {
1668                 _data = (uint8_t*) malloc (size);
1669                 memcpy (_data, data, size);
1670         }
1671 }
1672
1673 AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
1674         : _size (other.size ())
1675         , _timestamp (other.timestamp ())
1676         , _data (0)
1677 {
1678         if (other.size () && other.const_data ()) {
1679                 _data = (uint8_t*) malloc (other.size ());
1680                 memcpy (_data, other.const_data (), other.size ());
1681         }
1682 };
1683
1684 AlsaMidiEvent::~AlsaMidiEvent () {
1685         free (_data);
1686 };