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