use new error-messages
[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 std::vector<std::string> AlsaAudioBackend::_midi_options;
42 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_input_audio_device_status;
43 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_output_audio_device_status;
44 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_duplex_audio_device_status;
45 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_midi_device_status;
46
47 ALSADeviceInfo AlsaAudioBackend::_input_audio_device_info;
48 ALSADeviceInfo AlsaAudioBackend::_output_audio_device_info;
49
50 AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
51         : AudioBackend (e, info)
52         , _pcmi (0)
53         , _run (false)
54         , _active (false)
55         , _freewheel (false)
56         , _freewheeling (false)
57         , _measure_latency (false)
58         , _last_process_start (0)
59         , _input_audio_device("")
60         , _output_audio_device("")
61         , _midi_driver_option(get_standard_device_name(DeviceNone))
62         , _device_reservation(0)
63         , _samplerate (48000)
64         , _samples_per_period (1024)
65         , _periods_per_cycle (2)
66         , _n_inputs (0)
67         , _n_outputs (0)
68         , _systemic_audio_input_latency (0)
69         , _systemic_audio_output_latency (0)
70         , _dsp_load (0)
71         , _processed_samples (0)
72         , _port_change_flag (false)
73 {
74         _instance_name = s_instance_name;
75         pthread_mutex_init (&_port_callback_mutex, 0);
76         _input_audio_device_info.valid = false;
77         _output_audio_device_info.valid = false;
78 }
79
80 AlsaAudioBackend::~AlsaAudioBackend ()
81 {
82         pthread_mutex_destroy (&_port_callback_mutex);
83 }
84
85 /* AUDIOBACKEND API */
86
87 std::string
88 AlsaAudioBackend::name () const
89 {
90         return X_("ALSA");
91 }
92
93 bool
94 AlsaAudioBackend::is_realtime () const
95 {
96         return true;
97 }
98
99 std::vector<AudioBackend::DeviceStatus>
100 AlsaAudioBackend::enumerate_devices () const
101 {
102         _duplex_audio_device_status.clear();
103         std::map<std::string, std::string> devices;
104         get_alsa_audio_device_names(devices);
105         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
106                 if (_input_audio_device == "") _input_audio_device = i->first;
107                 if (_output_audio_device == "") _output_audio_device = i->first;
108                 _duplex_audio_device_status.push_back (DeviceStatus (i->first, true));
109         }
110         return _duplex_audio_device_status;
111 }
112
113 std::vector<AudioBackend::DeviceStatus>
114 AlsaAudioBackend::enumerate_input_devices () const
115 {
116         _input_audio_device_status.clear();
117         std::map<std::string, std::string> devices;
118         get_alsa_audio_device_names(devices, HalfDuplexIn);
119         _input_audio_device_status.push_back (DeviceStatus (get_standard_device_name(DeviceNone), true));
120         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
121                 if (_input_audio_device == "") _input_audio_device = i->first;
122                 _input_audio_device_status.push_back (DeviceStatus (i->first, true));
123         }
124         return _input_audio_device_status;
125 }
126
127 std::vector<AudioBackend::DeviceStatus>
128 AlsaAudioBackend::enumerate_output_devices () const
129 {
130         _output_audio_device_status.clear();
131         std::map<std::string, std::string> devices;
132         get_alsa_audio_device_names(devices, HalfDuplexOut);
133         _output_audio_device_status.push_back (DeviceStatus (get_standard_device_name(DeviceNone), true));
134         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
135                 if (_output_audio_device == "") _output_audio_device = i->first;
136                 _output_audio_device_status.push_back (DeviceStatus (i->first, true));
137         }
138         return _output_audio_device_status;
139 }
140
141 void
142 AlsaAudioBackend::reservation_stdout (std::string d, size_t /* s */)
143 {
144   if (d.substr(0, 19) == "Acquired audio-card") {
145                 _reservation_succeeded = true;
146         }
147 }
148
149 void
150 AlsaAudioBackend::release_device()
151 {
152         _reservation_connection.drop_connections();
153         ARDOUR::SystemExec * tmp = _device_reservation;
154         _device_reservation = 0;
155         delete tmp;
156 }
157
158 bool
159 AlsaAudioBackend::acquire_device(const char* device_name)
160 {
161         /* This is  quick hack, ideally we'll link against libdbus and implement a dbus-listener
162          * that owns the device. here we try to get away by just requesting it and then block it...
163          * (pulseaudio periodically checks anyway)
164          *
165          * dbus-send --session --print-reply --type=method_call --dest=org.freedesktop.ReserveDevice1.Audio2 /org/freedesktop/ReserveDevice1/Audio2 org.freedesktop.ReserveDevice1.RequestRelease int32:4
166          * -> should not return  'boolean false'
167          */
168         int device_number = card_to_num(device_name);
169         if (device_number < 0) return false;
170
171         assert(_device_reservation == 0);
172         _reservation_succeeded = false;
173
174         std::string request_device_exe;
175         if (!PBD::find_file (
176                                 PBD::Searchpath(Glib::build_filename(ARDOUR::ardour_dll_directory(), "ardouralsautil")
177                                         + G_SEARCHPATH_SEPARATOR_S + ARDOUR::ardour_dll_directory()),
178                                 "ardour-request-device", request_device_exe))
179         {
180                 PBD::warning << "ardour-request-device binary was not found..'" << endmsg;
181                 return false;
182         }
183         else
184         {
185                 char **argp;
186                 char tmp[128];
187                 argp=(char**) calloc(5,sizeof(char*));
188                 argp[0] = strdup(request_device_exe.c_str());
189                 argp[1] = strdup("-P");
190                 snprintf(tmp, sizeof(tmp), "%d", getpid());
191                 argp[2] = strdup(tmp);
192                 snprintf(tmp, sizeof(tmp), "Audio%d", device_number);
193                 argp[3] = strdup(tmp);
194                 argp[4] = 0;
195
196                 _device_reservation = new ARDOUR::SystemExec(request_device_exe, argp);
197                 _device_reservation->ReadStdout.connect_same_thread (_reservation_connection, boost::bind (&AlsaAudioBackend::reservation_stdout, this, _1 ,_2));
198                 _device_reservation->Terminated.connect_same_thread (_reservation_connection, boost::bind (&AlsaAudioBackend::release_device, this));
199                 if (_device_reservation->start(0)) {
200                         PBD::warning << _("AlsaAudioBackend: Device Request failed.") << endmsg;
201                         release_device();
202                         return false;
203                 }
204         }
205         // wait to check if reservation suceeded.
206         int timeout = 500; // 5 sec
207         while (_device_reservation && !_reservation_succeeded && --timeout > 0) {
208                 Glib::usleep(10000);
209         }
210         if (timeout == 0 || !_reservation_succeeded) {
211                 PBD::warning << _("AlsaAudioBackend: Device Reservation failed.") << endmsg;
212                 release_device();
213                 return false;
214         }
215         return true;
216 }
217
218 std::vector<float>
219 AlsaAudioBackend::available_sample_rates2 (const std::string& input_device, const std::string& output_device) const
220 {
221         std::vector<float> sr;
222         if (input_device == get_standard_device_name(DeviceNone) && output_device == get_standard_device_name(DeviceNone)) {
223                 return sr;
224         }
225         else if (input_device == get_standard_device_name(DeviceNone)) {
226                 sr = available_sample_rates (output_device);
227         }
228         else if (output_device == get_standard_device_name(DeviceNone)) {
229                 sr = available_sample_rates (input_device);
230         } else {
231                 std::vector<float> sr_in =  available_sample_rates (input_device);
232                 std::vector<float> sr_out = available_sample_rates (output_device);
233                 std::set_intersection (sr_in.begin(), sr_in.end(), sr_out.begin(), sr_out.end(), std::back_inserter(sr));
234         }
235         return sr;
236 }
237
238 std::vector<float>
239 AlsaAudioBackend::available_sample_rates (const std::string& device) const
240 {
241         ALSADeviceInfo *nfo = NULL;
242         std::vector<float> sr;
243         if (device == get_standard_device_name(DeviceNone)) {
244                 return sr;
245         }
246         if (device == _input_audio_device && _input_audio_device_info.valid) {
247                 nfo = &_input_audio_device_info;
248         }
249         else if (device == _output_audio_device && _output_audio_device_info.valid) {
250                 nfo = &_output_audio_device_info;
251         }
252
253         static const float avail_rates [] = { 8000, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
254
255         for (size_t i = 0 ; i < sizeof(avail_rates) / sizeof(float); ++i) {
256                 if (!nfo || (avail_rates[i] >= nfo->min_rate && avail_rates[i] <= nfo->max_rate)) {
257                         sr.push_back (avail_rates[i]);
258                 }
259         }
260
261         return sr;
262 }
263
264 std::vector<uint32_t>
265 AlsaAudioBackend::available_buffer_sizes2 (const std::string& input_device, const std::string& output_device) const
266 {
267         std::vector<uint32_t> bs;
268         if (input_device == get_standard_device_name(DeviceNone) && output_device == get_standard_device_name(DeviceNone)) {
269                 return bs;
270         }
271         else if (input_device == get_standard_device_name(DeviceNone)) {
272                 bs = available_buffer_sizes (output_device);
273         }
274         else if (output_device == get_standard_device_name(DeviceNone)) {
275                 bs = available_buffer_sizes (input_device);
276         } else {
277                 std::vector<uint32_t> bs_in =  available_buffer_sizes (input_device);
278                 std::vector<uint32_t> bs_out = available_buffer_sizes (output_device);
279                 std::set_intersection (bs_in.begin(), bs_in.end(), bs_out.begin(), bs_out.end(), std::back_inserter(bs));
280         }
281         return bs;
282 }
283
284 std::vector<uint32_t>
285 AlsaAudioBackend::available_buffer_sizes (const std::string& device) const
286 {
287         ALSADeviceInfo *nfo = NULL;
288         std::vector<uint32_t> bs;
289         if (device == get_standard_device_name(DeviceNone)) {
290                 return bs;
291         }
292         if (device == _input_audio_device && _input_audio_device_info.valid) {
293                 nfo = &_input_audio_device_info;
294         }
295         else if (device == _output_audio_device && _output_audio_device_info.valid) {
296                 nfo = &_output_audio_device_info;
297         }
298
299         static const unsigned long avail_sizes [] = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
300
301         for (size_t i = 0 ; i < sizeof(avail_sizes) / sizeof(unsigned long); ++i) {
302                 if (!nfo || (avail_sizes[i] >= nfo->min_size && avail_sizes[i] <= nfo->max_size)) {
303                         bs.push_back (avail_sizes[i]);
304                 }
305         }
306         return bs;
307 }
308
309 uint32_t
310 AlsaAudioBackend::available_input_channel_count (const std::string& device) const
311 {
312         if (device == get_standard_device_name(DeviceNone)) {
313                 return 0;
314         }
315         if (device == _input_audio_device && _input_audio_device_info.valid) {
316                 return _input_audio_device_info.max_channels;
317         }
318         return 128;
319 }
320
321 uint32_t
322 AlsaAudioBackend::available_output_channel_count (const std::string& device) const
323 {
324         if (device == get_standard_device_name(DeviceNone)) {
325                 return 0;
326         }
327         if (device == _output_audio_device && _output_audio_device_info.valid) {
328                 return _output_audio_device_info.max_channels;
329         }
330         return 128;
331 }
332
333 bool
334 AlsaAudioBackend::can_change_sample_rate_when_running () const
335 {
336         return false;
337 }
338
339 bool
340 AlsaAudioBackend::can_change_buffer_size_when_running () const
341 {
342         return false; // why not? :)
343 }
344
345 int
346 AlsaAudioBackend::set_input_device_name (const std::string& d)
347 {
348         if (_input_audio_device == d) {
349                 return 0;
350         }
351         _input_audio_device = d;
352
353         if (d == get_standard_device_name(DeviceNone)) {
354                 _input_audio_device_info.valid = false;
355                 return 0;
356         }
357         std::string alsa_device;
358         std::map<std::string, std::string> devices;
359
360         get_alsa_audio_device_names(devices, HalfDuplexIn);
361         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
362                 if (i->first == d) {
363                         alsa_device = i->second;
364                         break;
365                 }
366         }
367         if (alsa_device == "") {
368                 _input_audio_device_info.valid = false;
369                 return 1;
370         }
371         /* device will be busy once used, hence cache the parameters */
372         /* return */ get_alsa_device_parameters (alsa_device.c_str(), true, &_input_audio_device_info);
373         return 0;
374 }
375
376 int
377 AlsaAudioBackend::set_output_device_name (const std::string& d)
378 {
379         if (_output_audio_device == d) {
380                 return 0;
381         }
382
383         _output_audio_device = d;
384
385         if (d == get_standard_device_name(DeviceNone)) {
386                 _output_audio_device_info.valid = false;
387                 return 0;
388         }
389         std::string alsa_device;
390         std::map<std::string, std::string> devices;
391
392         get_alsa_audio_device_names(devices, HalfDuplexOut);
393         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
394                 if (i->first == d) {
395                         alsa_device = i->second;
396                         break;
397                 }
398         }
399         if (alsa_device == "") {
400                 _output_audio_device_info.valid = false;
401                 return 1;
402         }
403         /* return */ get_alsa_device_parameters (alsa_device.c_str(), true, &_output_audio_device_info);
404         return 0;
405 }
406
407 int
408 AlsaAudioBackend::set_device_name (const std::string& d)
409 {
410         int rv = 0;
411         rv |= set_input_device_name (d);
412         rv |= set_output_device_name (d);
413         return rv;
414 }
415
416 int
417 AlsaAudioBackend::set_sample_rate (float sr)
418 {
419         if (sr <= 0) { return -1; }
420         _samplerate = sr;
421         engine.sample_rate_change (sr);
422         return 0;
423 }
424
425 int
426 AlsaAudioBackend::set_buffer_size (uint32_t bs)
427 {
428         if (bs <= 0 || bs >= _max_buffer_size) {
429                 return -1;
430         }
431         if (_run) {
432                 return -1;
433         }
434         _samples_per_period = bs;
435         engine.buffer_size_change (bs);
436         return 0;
437 }
438
439 int
440 AlsaAudioBackend::set_interleaved (bool yn)
441 {
442         if (!yn) { return 0; }
443         return -1;
444 }
445
446 int
447 AlsaAudioBackend::set_input_channels (uint32_t cc)
448 {
449         _n_inputs = cc;
450         return 0;
451 }
452
453 int
454 AlsaAudioBackend::set_output_channels (uint32_t cc)
455 {
456         _n_outputs = cc;
457         return 0;
458 }
459
460 int
461 AlsaAudioBackend::set_systemic_input_latency (uint32_t sl)
462 {
463         _systemic_audio_input_latency = sl;
464         return 0;
465 }
466
467 int
468 AlsaAudioBackend::set_systemic_output_latency (uint32_t sl)
469 {
470         _systemic_audio_output_latency = sl;
471         return 0;
472 }
473
474 int
475 AlsaAudioBackend::set_systemic_midi_input_latency (std::string const device, uint32_t sl)
476 {
477         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
478         if (!nfo) return -1;
479         nfo->systemic_input_latency = sl;
480         return 0;
481 }
482
483 int
484 AlsaAudioBackend::set_systemic_midi_output_latency (std::string const device, uint32_t sl)
485 {
486         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
487         if (!nfo) return -1;
488         nfo->systemic_output_latency = sl;
489         return 0;
490 }
491
492 /* Retrieving parameters */
493 std::string
494 AlsaAudioBackend::device_name () const
495 {
496         if (_input_audio_device != get_standard_device_name(DeviceNone)) {
497                 return _input_audio_device;
498         }
499         if (_output_audio_device != get_standard_device_name(DeviceNone)) {
500                 return _output_audio_device;
501         }
502         return "";
503 }
504
505 std::string
506 AlsaAudioBackend::input_device_name () const
507 {
508         return _input_audio_device;
509 }
510
511 std::string
512 AlsaAudioBackend::output_device_name () const
513 {
514         return _output_audio_device;
515 }
516
517 float
518 AlsaAudioBackend::sample_rate () const
519 {
520         return _samplerate;
521 }
522
523 uint32_t
524 AlsaAudioBackend::buffer_size () const
525 {
526         return _samples_per_period;
527 }
528
529 bool
530 AlsaAudioBackend::interleaved () const
531 {
532         return false;
533 }
534
535 uint32_t
536 AlsaAudioBackend::input_channels () const
537 {
538         return _n_inputs;
539 }
540
541 uint32_t
542 AlsaAudioBackend::output_channels () const
543 {
544         return _n_outputs;
545 }
546
547 uint32_t
548 AlsaAudioBackend::systemic_input_latency () const
549 {
550         return _systemic_audio_input_latency;
551 }
552
553 uint32_t
554 AlsaAudioBackend::systemic_output_latency () const
555 {
556         return _systemic_audio_output_latency;
557 }
558
559 uint32_t
560 AlsaAudioBackend::systemic_midi_input_latency (std::string const device) const
561 {
562         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
563         if (!nfo) return 0;
564         return nfo->systemic_input_latency;
565 }
566
567 uint32_t
568 AlsaAudioBackend::systemic_midi_output_latency (std::string const device) const
569 {
570         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
571         if (!nfo) return 0;
572         return nfo->systemic_output_latency;
573 }
574
575 /* MIDI */
576 struct AlsaAudioBackend::AlsaMidiDeviceInfo *
577 AlsaAudioBackend::midi_device_info(std::string const name) const {
578         for (std::map<std::string, struct AlsaMidiDeviceInfo*>::const_iterator i = _midi_devices.begin (); i != _midi_devices.end(); ++i) {
579                 if (i->first == name) {
580                         return (i->second);
581                 }
582         }
583
584         assert(_midi_driver_option != get_standard_device_name(DeviceNone));
585
586         std::map<std::string, std::string> devices;
587         if (_midi_driver_option == _("ALSA raw devices")) {
588                 get_alsa_rawmidi_device_names(devices);
589         } else {
590                 get_alsa_sequencer_names (devices);
591         }
592
593         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
594                 if (i->first == name) {
595                         _midi_devices[name] = new AlsaMidiDeviceInfo();
596                         return _midi_devices[name];
597                 }
598         }
599         return 0;
600 }
601
602 std::vector<std::string>
603 AlsaAudioBackend::enumerate_midi_options () const
604 {
605         if (_midi_options.empty()) {
606                 _midi_options.push_back (_("ALSA raw devices"));
607                 _midi_options.push_back (_("ALSA sequencer"));
608                 _midi_options.push_back (get_standard_device_name(DeviceNone));
609         }
610         return _midi_options;
611 }
612
613 std::vector<AudioBackend::DeviceStatus>
614 AlsaAudioBackend::enumerate_midi_devices () const
615 {
616         _midi_device_status.clear();
617         std::map<std::string, std::string> devices;
618
619         if (_midi_driver_option == _("ALSA raw devices")) {
620                 get_alsa_rawmidi_device_names (devices);
621         }
622         else if (_midi_driver_option == _("ALSA sequencer")) {
623                 get_alsa_sequencer_names (devices);
624         }
625
626         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
627                 _midi_device_status.push_back (DeviceStatus (i->first, true));
628         }
629         return _midi_device_status;
630 }
631
632 int
633 AlsaAudioBackend::set_midi_option (const std::string& opt)
634 {
635         if (opt != get_standard_device_name(DeviceNone) && opt != _("ALSA raw devices") && opt != _("ALSA sequencer")) {
636                 return -1;
637         }
638         _midi_driver_option = opt;
639         return 0;
640 }
641
642 std::string
643 AlsaAudioBackend::midi_option () const
644 {
645         return _midi_driver_option;
646 }
647
648 int
649 AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable)
650 {
651         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
652         if (!nfo) return -1;
653         nfo->enabled = enable;
654         return 0;
655 }
656
657 bool
658 AlsaAudioBackend::midi_device_enabled (std::string const device) const
659 {
660         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
661         if (!nfo) return false;
662         return nfo->enabled;
663 }
664
665 /* State Control */
666
667 static void * pthread_process (void *arg)
668 {
669         AlsaAudioBackend *d = static_cast<AlsaAudioBackend *>(arg);
670         d->main_process_thread ();
671         pthread_exit (0);
672         return 0;
673 }
674
675 int
676 AlsaAudioBackend::_start (bool for_latency_measurement)
677 {
678         if (!_active && _run) {
679                 // recover from 'halted', reap threads
680                 stop();
681         }
682
683         if (_active || _run) {
684                 PBD::error << _("AlsaAudioBackend: already active.") << endmsg;
685                 return BackendReinitializationError;
686         }
687
688         if (_ports.size()) {
689                 PBD::warning << _("AlsaAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
690                 _system_inputs.clear();
691                 _system_outputs.clear();
692                 _system_midi_in.clear();
693                 _system_midi_out.clear();
694                 _ports.clear();
695         }
696
697         /* reset internal state */
698         _dsp_load = 0;
699         _freewheeling = false;
700         _freewheel = false;
701         _last_process_start = 0;
702
703         release_device();
704
705         assert(_rmidi_in.size() == 0);
706         assert(_rmidi_out.size() == 0);
707         assert(_pcmi == 0);
708
709         int duplex = 0;
710         std::string audio_device;
711         std::string alsa_device;
712         std::map<std::string, std::string> devices;
713
714         if (_input_audio_device == get_standard_device_name(DeviceNone) && _output_audio_device == get_standard_device_name(DeviceNone)) {
715                 PBD::error << _("AlsaAudioBackend: At least one of input or output device needs to be set.");
716                 return AudioDeviceInvalidError;
717         }
718
719         if (_input_audio_device != _output_audio_device) {
720                 if (_input_audio_device != get_standard_device_name(DeviceNone) && _output_audio_device != get_standard_device_name(DeviceNone)) {
721                         PBD::error << _("AlsaAudioBackend: Cannot use two different devices.");
722                         return AudioDeviceInvalidError;
723                 }
724                 if (_input_audio_device != get_standard_device_name(DeviceNone)) {
725                         get_alsa_audio_device_names(devices, HalfDuplexIn);
726                         audio_device = _input_audio_device;
727                         duplex = 1;
728                 } else {
729                         get_alsa_audio_device_names(devices, HalfDuplexOut);
730                         audio_device = _output_audio_device;
731                         duplex = 2;
732                 }
733         } else {
734                 get_alsa_audio_device_names(devices);
735                 audio_device = _input_audio_device;
736                 duplex = 3;
737         }
738
739         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
740                 if (i->first == audio_device) {
741                         alsa_device = i->second;
742                         break;
743                 }
744         }
745         if (alsa_device == "") {
746                 PBD::error << _("AlsaAudioBackend: Cannot find configured device. Is it still connected?");
747                 return AudioDeviceNotAvailableError;
748         }
749
750         acquire_device(alsa_device.c_str());
751         _pcmi = new Alsa_pcmi (
752                         (duplex & 2) ? alsa_device.c_str() : NULL,
753                         (duplex & 1) ? alsa_device.c_str() : NULL,
754                         0, _samplerate, _samples_per_period, _periods_per_cycle, 0);
755
756         AudioBackend::ErrorCode error_code = NoError;
757         switch (_pcmi->state()) {
758         case 0: /* OK */
759                 break;
760         case -1:
761                 PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg;
762                 error_code = AudioDeviceOpenError;
763                 break;
764         case -2:
765                 PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg;
766                 error_code = AudioDeviceOpenError;
767                 break;
768         case -3:
769                 PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.")
770                            << endmsg;
771                 error_code = SampleRateNotSupportedError;
772                 break;
773         case -4:
774                 PBD::error << _("AlsaAudioBackend: cannot set requested period size.")
775                            << endmsg;
776                 error_code = PeriodSizeNotSupportedError;
777                 break;
778         case -5:
779                 PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.")
780                            << endmsg;
781                 error_code = PeriodCountNotSupportedError;
782                 break;
783         case -6:
784                 PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg;
785                 error_code = SampleFormatNotSupportedError;
786                 break;
787         default:
788                 PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg;
789                 error_code = AudioDeviceOpenError;
790                 break;
791         }
792
793         if (_pcmi->state ()) {
794                 delete _pcmi; _pcmi = 0;
795                 release_device();
796                 return error_code;
797         }
798
799 #ifndef NDEBUG
800         _pcmi->printinfo ();
801 #endif
802
803         if (_n_outputs != _pcmi->nplay ()) {
804                 if (_n_outputs == 0) {
805                  _n_outputs = _pcmi->nplay ();
806                 } else {
807                  _n_outputs = std::min (_n_outputs, _pcmi->nplay ());
808                 }
809                 PBD::warning << _("AlsaAudioBackend: adjusted output channel count to match device.") << endmsg;
810         }
811
812         if (_n_inputs != _pcmi->ncapt ()) {
813                 if (_n_inputs == 0) {
814                  _n_inputs = _pcmi->ncapt ();
815                 } else {
816                  _n_inputs = std::min (_n_inputs, _pcmi->ncapt ());
817                 }
818                 PBD::warning << _("AlsaAudioBackend: adjusted input channel count to match device.") << endmsg;
819         }
820
821         if (_pcmi->fsize() != _samples_per_period) {
822                 _samples_per_period = _pcmi->fsize();
823                 PBD::warning << _("AlsaAudioBackend: samples per period does not match.") << endmsg;
824         }
825
826         if (_pcmi->fsamp() != _samplerate) {
827                 _samplerate = _pcmi->fsamp();
828                 engine.sample_rate_change (_samplerate);
829                 PBD::warning << _("AlsaAudioBackend: sample rate does not match.") << endmsg;
830         }
831
832         _measure_latency = for_latency_measurement;
833
834         register_system_midi_ports();
835
836         if (register_system_audio_ports()) {
837                 PBD::error << _("AlsaAudioBackend: failed to register system ports.") << endmsg;
838                 delete _pcmi; _pcmi = 0;
839                 release_device();
840                 return PortRegistrationError;
841         }
842
843         engine.sample_rate_change (_samplerate);
844         engine.buffer_size_change (_samples_per_period);
845
846         if (engine.reestablish_ports ()) {
847                 PBD::error << _("AlsaAudioBackend: Could not re-establish ports.") << endmsg;
848                 delete _pcmi; _pcmi = 0;
849                 release_device();
850                 return PortReconnectError;
851         }
852
853         engine.reconnect_ports ();
854         _run = true;
855         _port_change_flag = false;
856
857         if (_realtime_pthread_create (SCHED_FIFO, -20, 100000,
858                                 &_main_thread, pthread_process, this))
859         {
860                 if (pthread_create (&_main_thread, NULL, pthread_process, this))
861                 {
862                         PBD::error << _("AlsaAudioBackend: failed to create process thread.") << endmsg;
863                         delete _pcmi; _pcmi = 0;
864                         release_device();
865                         _run = false;
866                         return ProcessThreadStartError;
867                 } else {
868                         PBD::warning << _("AlsaAudioBackend: cannot acquire realtime permissions.") << endmsg;
869                 }
870         }
871
872         int timeout = 5000;
873         while (!_active && --timeout > 0) { Glib::usleep (1000); }
874
875         if (timeout == 0 || !_active) {
876                 PBD::error << _("AlsaAudioBackend: failed to start process thread.") << endmsg;
877                 delete _pcmi; _pcmi = 0;
878                 release_device();
879                 _run = false;
880                 return ProcessThreadStartError;
881         }
882
883         return NoError;
884 }
885
886 int
887 AlsaAudioBackend::stop ()
888 {
889         void *status;
890         if (!_run) {
891                 return 0;
892         }
893
894         _run = false;
895         if (pthread_join (_main_thread, &status)) {
896                 PBD::error << _("AlsaAudioBackend: failed to terminate.") << endmsg;
897                 return -1;
898         }
899
900         while (!_rmidi_out.empty ()) {
901                 AlsaMidiIO *m = _rmidi_out.back ();
902                 m->stop();
903                 _rmidi_out.pop_back ();
904                 delete m;
905         }
906         while (!_rmidi_in.empty ()) {
907                 AlsaMidiIO *m = _rmidi_in.back ();
908                 m->stop();
909                 _rmidi_in.pop_back ();
910                 delete m;
911         }
912
913         unregister_ports();
914         delete _pcmi; _pcmi = 0;
915         release_device();
916
917         return (_active == false) ? 0 : -1;
918 }
919
920 int
921 AlsaAudioBackend::freewheel (bool onoff)
922 {
923         _freewheeling = onoff;
924         return 0;
925 }
926
927 float
928 AlsaAudioBackend::dsp_load () const
929 {
930         return 100.f * _dsp_load;
931 }
932
933 size_t
934 AlsaAudioBackend::raw_buffer_size (DataType t)
935 {
936         switch (t) {
937                 case DataType::AUDIO:
938                         return _samples_per_period * sizeof(Sample);
939                 case DataType::MIDI:
940                         return _max_buffer_size; // XXX not really limited
941         }
942         return 0;
943 }
944
945 /* Process time */
946 framepos_t
947 AlsaAudioBackend::sample_time ()
948 {
949         return _processed_samples;
950 }
951
952 framepos_t
953 AlsaAudioBackend::sample_time_at_cycle_start ()
954 {
955         return _processed_samples;
956 }
957
958 pframes_t
959 AlsaAudioBackend::samples_since_cycle_start ()
960 {
961         if (!_active || !_run || _freewheeling || _freewheel) {
962                 return 0;
963         }
964         if (_last_process_start == 0) {
965                 return 0;
966         }
967
968         const int64_t elapsed_time_us = g_get_monotonic_time() - _last_process_start;
969         return std::max((pframes_t)0, (pframes_t)rint(1e-6 * elapsed_time_us * _samplerate));
970 }
971
972
973 void *
974 AlsaAudioBackend::alsa_process_thread (void *arg)
975 {
976         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
977         boost::function<void ()> f = td->f;
978         delete td;
979         f ();
980         return 0;
981 }
982
983 int
984 AlsaAudioBackend::create_process_thread (boost::function<void()> func)
985 {
986         pthread_t thread_id;
987         pthread_attr_t attr;
988         size_t stacksize = 100000;
989
990         ThreadData* td = new ThreadData (this, func, stacksize);
991
992         if (_realtime_pthread_create (SCHED_FIFO, -21, stacksize,
993                                 &thread_id, alsa_process_thread, td)) {
994                 pthread_attr_init (&attr);
995                 pthread_attr_setstacksize (&attr, stacksize);
996                 if (pthread_create (&thread_id, &attr, alsa_process_thread, td)) {
997                         PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
998                         pthread_attr_destroy (&attr);
999                         return -1;
1000                 }
1001                 pthread_attr_destroy (&attr);
1002         }
1003
1004         _threads.push_back (thread_id);
1005         return 0;
1006 }
1007
1008 int
1009 AlsaAudioBackend::join_process_threads ()
1010 {
1011         int rv = 0;
1012
1013         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
1014         {
1015                 void *status;
1016                 if (pthread_join (*i, &status)) {
1017                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
1018                         rv -= 1;
1019                 }
1020         }
1021         _threads.clear ();
1022         return rv;
1023 }
1024
1025 bool
1026 AlsaAudioBackend::in_process_thread ()
1027 {
1028         if (pthread_equal (_main_thread, pthread_self()) != 0) {
1029                 return true;
1030         }
1031
1032         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
1033         {
1034                 if (pthread_equal (*i, pthread_self ()) != 0) {
1035                         return true;
1036                 }
1037         }
1038         return false;
1039 }
1040
1041 uint32_t
1042 AlsaAudioBackend::process_thread_count ()
1043 {
1044         return _threads.size ();
1045 }
1046
1047 void
1048 AlsaAudioBackend::update_latencies ()
1049 {
1050         // trigger latency callback in RT thread (locked graph)
1051         port_connect_add_remove_callback();
1052 }
1053
1054 /* PORTENGINE API */
1055
1056 void*
1057 AlsaAudioBackend::private_handle () const
1058 {
1059         return NULL;
1060 }
1061
1062 const std::string&
1063 AlsaAudioBackend::my_name () const
1064 {
1065         return _instance_name;
1066 }
1067
1068 bool
1069 AlsaAudioBackend::available () const
1070 {
1071         return _run && _active;
1072 }
1073
1074 uint32_t
1075 AlsaAudioBackend::port_name_size () const
1076 {
1077         return 256;
1078 }
1079
1080 int
1081 AlsaAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
1082 {
1083         if (!valid_port (port)) {
1084                 PBD::error << _("AlsaBackend::set_port_name: Invalid Port(s)") << endmsg;
1085                 return -1;
1086         }
1087         return static_cast<AlsaPort*>(port)->set_name (_instance_name + ":" + name);
1088 }
1089
1090 std::string
1091 AlsaAudioBackend::get_port_name (PortEngine::PortHandle port) const
1092 {
1093         if (!valid_port (port)) {
1094                 PBD::error << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
1095                 return std::string ();
1096         }
1097         return static_cast<AlsaPort*>(port)->name ();
1098 }
1099
1100 PortEngine::PortHandle
1101 AlsaAudioBackend::get_port_by_name (const std::string& name) const
1102 {
1103         PortHandle port = (PortHandle) find_port (name);
1104         return port;
1105 }
1106
1107 int
1108 AlsaAudioBackend::get_ports (
1109                 const std::string& port_name_pattern,
1110                 DataType type, PortFlags flags,
1111                 std::vector<std::string>& port_names) const
1112 {
1113         int rv = 0;
1114         regex_t port_regex;
1115         bool use_regexp = false;
1116         if (port_name_pattern.size () > 0) {
1117                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
1118                         use_regexp = true;
1119                 }
1120         }
1121         for (size_t i = 0; i < _ports.size (); ++i) {
1122                 AlsaPort* port = _ports[i];
1123                 if ((port->type () == type) && flags == (port->flags () & flags)) {
1124                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
1125                                 port_names.push_back (port->name ());
1126                                 ++rv;
1127                         }
1128                 }
1129         }
1130         if (use_regexp) {
1131                 regfree (&port_regex);
1132         }
1133         return rv;
1134 }
1135
1136 DataType
1137 AlsaAudioBackend::port_data_type (PortEngine::PortHandle port) const
1138 {
1139         if (!valid_port (port)) {
1140                 return DataType::NIL;
1141         }
1142         return static_cast<AlsaPort*>(port)->type ();
1143 }
1144
1145 PortEngine::PortHandle
1146 AlsaAudioBackend::register_port (
1147                 const std::string& name,
1148                 ARDOUR::DataType type,
1149                 ARDOUR::PortFlags flags)
1150 {
1151         if (name.size () == 0) { return 0; }
1152         if (flags & IsPhysical) { return 0; }
1153         return add_port (_instance_name + ":" + name, type, flags);
1154 }
1155
1156 PortEngine::PortHandle
1157 AlsaAudioBackend::add_port (
1158                 const std::string& name,
1159                 ARDOUR::DataType type,
1160                 ARDOUR::PortFlags flags)
1161 {
1162         assert(name.size ());
1163         if (find_port (name)) {
1164                 PBD::error << _("AlsaBackend::register_port: Port already exists:")
1165                                 << " (" << name << ")" << endmsg;
1166                 return 0;
1167         }
1168         AlsaPort* port = NULL;
1169         switch (type) {
1170                 case DataType::AUDIO:
1171                         port = new AlsaAudioPort (*this, name, flags);
1172                         break;
1173                 case DataType::MIDI:
1174                         port = new AlsaMidiPort (*this, name, flags);
1175                         break;
1176                 default:
1177                         PBD::error << _("AlsaBackend::register_port: Invalid Data Type.") << endmsg;
1178                         return 0;
1179         }
1180
1181         _ports.push_back (port);
1182
1183         return port;
1184 }
1185
1186 void
1187 AlsaAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
1188 {
1189         if (!_run) {
1190                 return;
1191         }
1192         AlsaPort* port = static_cast<AlsaPort*>(port_handle);
1193         std::vector<AlsaPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<AlsaPort*>(port_handle));
1194         if (i == _ports.end ()) {
1195                 PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
1196                 return;
1197         }
1198         disconnect_all(port_handle);
1199         _ports.erase (i);
1200         delete port;
1201 }
1202
1203 int
1204 AlsaAudioBackend::register_system_audio_ports()
1205 {
1206         LatencyRange lr;
1207
1208         const int a_ins = _n_inputs;
1209         const int a_out = _n_outputs;
1210
1211         /* audio ports */
1212         lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_input_latency);
1213         for (int i = 1; i <= a_ins; ++i) {
1214                 char tmp[64];
1215                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
1216                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1217                 if (!p) return -1;
1218                 set_latency_range (p, false, lr);
1219                 _system_inputs.push_back(static_cast<AlsaPort*>(p));
1220         }
1221
1222         lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency);
1223         for (int i = 1; i <= a_out; ++i) {
1224                 char tmp[64];
1225                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
1226                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1227                 if (!p) return -1;
1228                 set_latency_range (p, true, lr);
1229                 _system_outputs.push_back(static_cast<AlsaPort*>(p));
1230         }
1231         return 0;
1232 }
1233
1234 int
1235 AlsaAudioBackend::register_system_midi_ports()
1236 {
1237         std::map<std::string, std::string> devices;
1238         int midi_ins = 0;
1239         int midi_outs = 0;
1240
1241         if (_midi_driver_option == get_standard_device_name(DeviceNone)) {
1242                 return 0;
1243         } else if (_midi_driver_option == _("ALSA raw devices")) {
1244                 get_alsa_rawmidi_device_names(devices);
1245         } else {
1246                 get_alsa_sequencer_names (devices);
1247         }
1248
1249         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
1250                 struct AlsaMidiDeviceInfo * nfo = midi_device_info(i->first);
1251                 if (!nfo) continue;
1252                 if (!nfo->enabled) continue;
1253
1254                 AlsaMidiOut *mout;
1255                 if (_midi_driver_option == _("ALSA raw devices")) {
1256                         mout = new AlsaRawMidiOut (i->second.c_str());
1257                 } else {
1258                         mout = new AlsaSeqMidiOut (i->second.c_str());
1259                 }
1260
1261                 if (mout->state ()) {
1262                         PBD::warning << string_compose (
1263                                         _("AlsaMidiOut: failed to open midi device '%1'."), i->second)
1264                                 << endmsg;
1265                         delete mout;
1266                 } else {
1267                         mout->setup_timing(_samples_per_period, _samplerate);
1268                         mout->sync_time (g_get_monotonic_time());
1269                         if (mout->start ()) {
1270                                 PBD::warning << string_compose (
1271                                                 _("AlsaMidiOut: failed to start midi device '%1'."), i->second)
1272                                         << endmsg;
1273                                 delete mout;
1274                         } else {
1275                                 char tmp[64];
1276                                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++midi_ins);
1277                                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1278                                 if (!p) {
1279                                         mout->stop();
1280                                         delete mout;
1281                                 }
1282                                 LatencyRange lr;
1283                                 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency);
1284                                 set_latency_range (p, false, lr);
1285                                 static_cast<AlsaMidiPort*>(p)->set_n_periods(2);
1286                                 _system_midi_out.push_back(static_cast<AlsaPort*>(p));
1287                                 _rmidi_out.push_back (mout);
1288                         }
1289                 }
1290
1291                 AlsaMidiIn *midin;
1292                 if (_midi_driver_option == _("ALSA raw devices")) {
1293                         midin = new AlsaRawMidiIn (i->second.c_str());
1294                 } else {
1295                         midin = new AlsaSeqMidiIn (i->second.c_str());
1296                 }
1297
1298                 if (midin->state ()) {
1299                         PBD::warning << string_compose (
1300                                         _("AlsaMidiIn: failed to open midi device '%1'."), i->second)
1301                                 << endmsg;
1302                         delete midin;
1303                 } else {
1304                         midin->setup_timing(_samples_per_period, _samplerate);
1305                         midin->sync_time (g_get_monotonic_time());
1306                         if (midin->start ()) {
1307                                 PBD::warning << string_compose (
1308                                                 _("AlsaMidiIn: failed to start midi device '%1'."), i->second)
1309                                         << endmsg;
1310                                 delete midin;
1311                         } else {
1312                                 char tmp[64];
1313                                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++midi_outs);
1314                                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1315                                 if (!p) {
1316                                         midin->stop();
1317                                         delete midin;
1318                                         continue;
1319                                 }
1320                                 LatencyRange lr;
1321                                 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
1322                                 set_latency_range (p, false, lr);
1323                                 _system_midi_in.push_back(static_cast<AlsaPort*>(p));
1324                                 _rmidi_in.push_back (midin);
1325                         }
1326                 }
1327         }
1328         return 0;
1329 }
1330
1331 void
1332 AlsaAudioBackend::unregister_ports (bool system_only)
1333 {
1334         size_t i = 0;
1335         _system_inputs.clear();
1336         _system_outputs.clear();
1337         _system_midi_in.clear();
1338         _system_midi_out.clear();
1339         while (i <  _ports.size ()) {
1340                 AlsaPort* port = _ports[i];
1341                 if (! system_only || (port->is_physical () && port->is_terminal ())) {
1342                         port->disconnect_all ();
1343                         delete port;
1344                         _ports.erase (_ports.begin() + i);
1345                 } else {
1346                         ++i;
1347                 }
1348         }
1349 }
1350
1351 int
1352 AlsaAudioBackend::connect (const std::string& src, const std::string& dst)
1353 {
1354         AlsaPort* src_port = find_port (src);
1355         AlsaPort* dst_port = find_port (dst);
1356
1357         if (!src_port) {
1358                 PBD::error << _("AlsaBackend::connect: Invalid Source port:")
1359                                 << " (" << src <<")" << endmsg;
1360                 return -1;
1361         }
1362         if (!dst_port) {
1363                 PBD::error << _("AlsaBackend::connect: Invalid Destination port:")
1364                         << " (" << dst <<")" << endmsg;
1365                 return -1;
1366         }
1367         return src_port->connect (dst_port);
1368 }
1369
1370 int
1371 AlsaAudioBackend::disconnect (const std::string& src, const std::string& dst)
1372 {
1373         AlsaPort* src_port = find_port (src);
1374         AlsaPort* dst_port = find_port (dst);
1375
1376         if (!src_port || !dst_port) {
1377                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1378                 return -1;
1379         }
1380         return src_port->disconnect (dst_port);
1381 }
1382
1383 int
1384 AlsaAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
1385 {
1386         AlsaPort* dst_port = find_port (dst);
1387         if (!valid_port (src)) {
1388                 PBD::error << _("AlsaBackend::connect: Invalid Source Port Handle") << endmsg;
1389                 return -1;
1390         }
1391         if (!dst_port) {
1392                 PBD::error << _("AlsaBackend::connect: Invalid Destination Port")
1393                         << " (" << dst << ")" << endmsg;
1394                 return -1;
1395         }
1396         return static_cast<AlsaPort*>(src)->connect (dst_port);
1397 }
1398
1399 int
1400 AlsaAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
1401 {
1402         AlsaPort* dst_port = find_port (dst);
1403         if (!valid_port (src) || !dst_port) {
1404                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1405                 return -1;
1406         }
1407         return static_cast<AlsaPort*>(src)->disconnect (dst_port);
1408 }
1409
1410 int
1411 AlsaAudioBackend::disconnect_all (PortEngine::PortHandle port)
1412 {
1413         if (!valid_port (port)) {
1414                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1415                 return -1;
1416         }
1417         static_cast<AlsaPort*>(port)->disconnect_all ();
1418         return 0;
1419 }
1420
1421 bool
1422 AlsaAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
1423 {
1424         if (!valid_port (port)) {
1425                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1426                 return false;
1427         }
1428         return static_cast<AlsaPort*>(port)->is_connected ();
1429 }
1430
1431 bool
1432 AlsaAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
1433 {
1434         AlsaPort* dst_port = find_port (dst);
1435         if (!valid_port (src) || !dst_port) {
1436                 PBD::error << _("AlsaBackend::connected_to: Invalid Port") << endmsg;
1437                 return false;
1438         }
1439         return static_cast<AlsaPort*>(src)->is_connected (dst_port);
1440 }
1441
1442 bool
1443 AlsaAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
1444 {
1445         if (!valid_port (port)) {
1446                 PBD::error << _("AlsaBackend::physically_connected: Invalid Port") << endmsg;
1447                 return false;
1448         }
1449         return static_cast<AlsaPort*>(port)->is_physically_connected ();
1450 }
1451
1452 int
1453 AlsaAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
1454 {
1455         if (!valid_port (port)) {
1456                 PBD::error << _("AlsaBackend::get_connections: Invalid Port") << endmsg;
1457                 return -1;
1458         }
1459
1460         assert (0 == names.size ());
1461
1462         const std::vector<AlsaPort*>& connected_ports = static_cast<AlsaPort*>(port)->get_connections ();
1463
1464         for (std::vector<AlsaPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
1465                 names.push_back ((*i)->name ());
1466         }
1467
1468         return (int)names.size ();
1469 }
1470
1471 /* MIDI */
1472 int
1473 AlsaAudioBackend::midi_event_get (
1474                 pframes_t& timestamp,
1475                 size_t& size, uint8_t** buf, void* port_buffer,
1476                 uint32_t event_index)
1477 {
1478         assert (buf && port_buffer);
1479         AlsaMidiBuffer& source = * static_cast<AlsaMidiBuffer*>(port_buffer);
1480         if (event_index >= source.size ()) {
1481                 return -1;
1482         }
1483         AlsaMidiEvent * const event = source[event_index].get ();
1484
1485         timestamp = event->timestamp ();
1486         size = event->size ();
1487         *buf = event->data ();
1488         return 0;
1489 }
1490
1491 int
1492 AlsaAudioBackend::midi_event_put (
1493                 void* port_buffer,
1494                 pframes_t timestamp,
1495                 const uint8_t* buffer, size_t size)
1496 {
1497         assert (buffer && port_buffer);
1498         AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
1499         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
1500 #ifndef NDEBUG
1501                 // nevermind, ::get_buffer() sorts events
1502                 fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
1503                                 (pframes_t)dst.back ()->timestamp (), timestamp);
1504 #endif
1505         }
1506         dst.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (timestamp, buffer, size)));
1507         return 0;
1508 }
1509
1510 uint32_t
1511 AlsaAudioBackend::get_midi_event_count (void* port_buffer)
1512 {
1513         assert (port_buffer);
1514         return static_cast<AlsaMidiBuffer*>(port_buffer)->size ();
1515 }
1516
1517 void
1518 AlsaAudioBackend::midi_clear (void* port_buffer)
1519 {
1520         assert (port_buffer);
1521         AlsaMidiBuffer * buf = static_cast<AlsaMidiBuffer*>(port_buffer);
1522         assert (buf);
1523         buf->clear ();
1524 }
1525
1526 /* Monitoring */
1527
1528 bool
1529 AlsaAudioBackend::can_monitor_input () const
1530 {
1531         return false;
1532 }
1533
1534 int
1535 AlsaAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
1536 {
1537         return -1;
1538 }
1539
1540 int
1541 AlsaAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
1542 {
1543         return -1;
1544 }
1545
1546 bool
1547 AlsaAudioBackend::monitoring_input (PortEngine::PortHandle)
1548 {
1549         return false;
1550 }
1551
1552 /* Latency management */
1553
1554 void
1555 AlsaAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
1556 {
1557         if (!valid_port (port)) {
1558                 PBD::error << _("AlsaPort::set_latency_range (): invalid port.") << endmsg;
1559         }
1560         static_cast<AlsaPort*>(port)->set_latency_range (latency_range, for_playback);
1561 }
1562
1563 LatencyRange
1564 AlsaAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
1565 {
1566         LatencyRange r;
1567         if (!valid_port (port)) {
1568                 PBD::error << _("AlsaPort::get_latency_range (): invalid port.") << endmsg;
1569                 r.min = 0;
1570                 r.max = 0;
1571                 return r;
1572         }
1573         AlsaPort *p = static_cast<AlsaPort*>(port);
1574         assert(p);
1575
1576         r = p->latency_range (for_playback);
1577         if (p->is_physical() && p->is_terminal()) {
1578                 if (p->is_input() && for_playback) {
1579                         r.min += _samples_per_period;
1580                         r.max += _samples_per_period;
1581                 }
1582                 if (p->is_output() && !for_playback) {
1583                         r.min += _samples_per_period;
1584                         r.max += _samples_per_period;
1585                 }
1586         }
1587         return r;
1588 }
1589
1590 /* Discovering physical ports */
1591
1592 bool
1593 AlsaAudioBackend::port_is_physical (PortEngine::PortHandle port) const
1594 {
1595         if (!valid_port (port)) {
1596                 PBD::error << _("AlsaPort::port_is_physical (): invalid port.") << endmsg;
1597                 return false;
1598         }
1599         return static_cast<AlsaPort*>(port)->is_physical ();
1600 }
1601
1602 void
1603 AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
1604 {
1605         for (size_t i = 0; i < _ports.size (); ++i) {
1606                 AlsaPort* port = _ports[i];
1607                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
1608                         port_names.push_back (port->name ());
1609                 }
1610         }
1611 }
1612
1613 void
1614 AlsaAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
1615 {
1616         for (size_t i = 0; i < _ports.size (); ++i) {
1617                 AlsaPort* port = _ports[i];
1618                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
1619                         port_names.push_back (port->name ());
1620                 }
1621         }
1622 }
1623
1624 ChanCount
1625 AlsaAudioBackend::n_physical_outputs () const
1626 {
1627         int n_midi = 0;
1628         int n_audio = 0;
1629         for (size_t i = 0; i < _ports.size (); ++i) {
1630                 AlsaPort* port = _ports[i];
1631                 if (port->is_output () && port->is_physical ()) {
1632                         switch (port->type ()) {
1633                                 case DataType::AUDIO: ++n_audio; break;
1634                                 case DataType::MIDI: ++n_midi; break;
1635                                 default: break;
1636                         }
1637                 }
1638         }
1639         ChanCount cc;
1640         cc.set (DataType::AUDIO, n_audio);
1641         cc.set (DataType::MIDI, n_midi);
1642         return cc;
1643 }
1644
1645 ChanCount
1646 AlsaAudioBackend::n_physical_inputs () const
1647 {
1648         int n_midi = 0;
1649         int n_audio = 0;
1650         for (size_t i = 0; i < _ports.size (); ++i) {
1651                 AlsaPort* port = _ports[i];
1652                 if (port->is_input () && port->is_physical ()) {
1653                         switch (port->type ()) {
1654                                 case DataType::AUDIO: ++n_audio; break;
1655                                 case DataType::MIDI: ++n_midi; break;
1656                                 default: break;
1657                         }
1658                 }
1659         }
1660         ChanCount cc;
1661         cc.set (DataType::AUDIO, n_audio);
1662         cc.set (DataType::MIDI, n_midi);
1663         return cc;
1664 }
1665
1666 /* Getting access to the data buffer for a port */
1667
1668 void*
1669 AlsaAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
1670 {
1671         assert (port);
1672         assert (valid_port (port));
1673         return static_cast<AlsaPort*>(port)->get_buffer (nframes);
1674 }
1675
1676 /* Engine Process */
1677 void *
1678 AlsaAudioBackend::main_process_thread ()
1679 {
1680         AudioEngine::thread_init_callback (this);
1681         _active = true;
1682         _processed_samples = 0;
1683
1684         uint64_t clock1;
1685         _pcmi->pcm_start ();
1686         int no_proc_errors = 0;
1687         const int bailout = 2 * _samplerate / _samples_per_period;
1688
1689         manager.registration_callback();
1690         manager.graph_order_callback();
1691
1692         while (_run) {
1693                 long nr;
1694                 bool xrun = false;
1695
1696                 if (_freewheeling != _freewheel) {
1697                         _freewheel = _freewheeling;
1698                         engine.freewheel_callback (_freewheel);
1699                 }
1700
1701                 if (!_freewheel) {
1702                         nr = _pcmi->pcm_wait ();
1703
1704                         if (_pcmi->state () > 0) {
1705                                 ++no_proc_errors;
1706                                 xrun = true;
1707                         }
1708                         if (_pcmi->state () < 0) {
1709                                 PBD::error << _("AlsaAudioBackend: I/O error. Audio Process Terminated.") << endmsg;
1710                                 break;
1711                         }
1712                         if (no_proc_errors > bailout) {
1713                                 PBD::error
1714                                         << string_compose (
1715                                                         _("AlsaAudioBackend: Audio Process Terminated after %1 consecutive x-runs."),
1716                                                         no_proc_errors)
1717                                         << endmsg;
1718                                 break;
1719                         }
1720
1721                         while (nr >= (long)_samples_per_period && _freewheeling == _freewheel) {
1722                                 uint32_t i = 0;
1723                                 clock1 = g_get_monotonic_time();
1724                                 no_proc_errors = 0;
1725
1726                                 _pcmi->capt_init (_samples_per_period);
1727                                 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) {
1728                                         _pcmi->capt_chan (i, (float*)((*it)->get_buffer(_samples_per_period)), _samples_per_period);
1729                                 }
1730                                 _pcmi->capt_done (_samples_per_period);
1731
1732                                 /* de-queue incoming midi*/
1733                                 i = 0;
1734                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1735                                         assert (_rmidi_in.size() > i);
1736                                         AlsaMidiIn *rm = _rmidi_in.at(i);
1737                                         void *bptr = (*it)->get_buffer(0);
1738                                         pframes_t time;
1739                                         uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
1740                                         size_t size = sizeof(data);
1741                                         midi_clear(bptr);
1742                                         while (rm->recv_event (time, data, size)) {
1743                                                 midi_event_put(bptr, time, data, size);
1744                                                 size = sizeof(data);
1745                                         }
1746                                         rm->sync_time (clock1);
1747                                 }
1748
1749                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
1750                                         memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1751                                 }
1752
1753                                 /* call engine process callback */
1754                                 _last_process_start = g_get_monotonic_time();
1755                                 if (engine.process_callback (_samples_per_period)) {
1756                                         _pcmi->pcm_stop ();
1757                                         _active = false;
1758                                         return 0;
1759                                 }
1760
1761                                 for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1762                                         static_cast<AlsaMidiPort*>(*it)->next_period();
1763                                 }
1764
1765                                 /* queue outgoing midi */
1766                                 i = 0;
1767                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
1768                                         assert (_rmidi_out.size() > i);
1769                                         const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*it)->const_buffer();
1770                                         AlsaMidiOut *rm = _rmidi_out.at(i);
1771                                         rm->sync_time (clock1);
1772                                         for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
1773                                                 rm->send_event ((*mit)->timestamp(), (*mit)->data(), (*mit)->size());
1774                                         }
1775                                 }
1776
1777                                 /* write back audio */
1778                                 i = 0;
1779                                 _pcmi->play_init (_samples_per_period);
1780                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it, ++i) {
1781                                         _pcmi->play_chan (i, (const float*)(*it)->get_buffer (_samples_per_period), _samples_per_period);
1782                                 }
1783                                 for (; i < _pcmi->nplay (); ++i) {
1784                                         _pcmi->clear_chan (i, _samples_per_period);
1785                                 }
1786                                 _pcmi->play_done (_samples_per_period);
1787                                 nr -= _samples_per_period;
1788                                 _processed_samples += _samples_per_period;
1789
1790                                 _dsp_load_calc.set_max_time(_samplerate, _samples_per_period);
1791                                 _dsp_load_calc.set_start_timestamp_us (clock1);
1792                                 _dsp_load_calc.set_stop_timestamp_us (g_get_monotonic_time());
1793                                 _dsp_load = _dsp_load_calc.get_dsp_load ();
1794                         }
1795
1796                         if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) {
1797                                 engine.Xrun ();
1798 #if 0
1799                                 fprintf(stderr, "ALSA x-run read: %.2f ms, write: %.2f ms\n",
1800                                                 _pcmi->capt_xrun() * 1000.0, _pcmi->play_xrun() * 1000.0);
1801 #endif
1802                         }
1803                 } else {
1804                         // Freewheelin'
1805
1806                         // zero audio input buffers
1807                         for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
1808                                 memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1809                         }
1810
1811                         clock1 = g_get_monotonic_time();
1812                         uint32_t i = 0;
1813                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1814                                 static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
1815                                 AlsaMidiIn *rm = _rmidi_in.at(i);
1816                                 void *bptr = (*it)->get_buffer(0);
1817                                 midi_clear(bptr); // zero midi buffer
1818
1819                                 // TODO add an API call for this.
1820                                 pframes_t time;
1821                                 uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
1822                                 size_t size = sizeof(data);
1823                                 while (rm->recv_event (time, data, size)) {
1824                                         ; // discard midi-data from HW.
1825                                 }
1826                                 rm->sync_time (clock1);
1827                         }
1828
1829                         _last_process_start = 0;
1830                         if (engine.process_callback (_samples_per_period)) {
1831                                 _pcmi->pcm_stop ();
1832                                 _active = false;
1833                                 return 0;
1834                         }
1835
1836                         // drop all outgoing MIDI messages
1837                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1838                                         void *bptr = (*it)->get_buffer(0);
1839                                         midi_clear(bptr);
1840                         }
1841
1842                         _dsp_load = 1.0;
1843                         Glib::usleep (100); // don't hog cpu
1844                 }
1845
1846                 bool connections_changed = false;
1847                 bool ports_changed = false;
1848                 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
1849                         if (_port_change_flag) {
1850                                 ports_changed = true;
1851                                 _port_change_flag = false;
1852                         }
1853                         if (!_port_connection_queue.empty ()) {
1854                                 connections_changed = true;
1855                         }
1856                         while (!_port_connection_queue.empty ()) {
1857                                 PortConnectData *c = _port_connection_queue.back ();
1858                                 manager.connect_callback (c->a, c->b, c->c);
1859                                 _port_connection_queue.pop_back ();
1860                                 delete c;
1861                         }
1862                         pthread_mutex_unlock (&_port_callback_mutex);
1863                 }
1864                 if (ports_changed) {
1865                         manager.registration_callback();
1866                 }
1867                 if (connections_changed) {
1868                         manager.graph_order_callback();
1869                 }
1870                 if (connections_changed || ports_changed) {
1871                         engine.latency_callback(false);
1872                         engine.latency_callback(true);
1873                 }
1874
1875         }
1876         _pcmi->pcm_stop ();
1877         _active = false;
1878         if (_run) {
1879                 engine.halted_callback("ALSA I/O error.");
1880         }
1881         return 0;
1882 }
1883
1884
1885 /******************************************************************************/
1886
1887 static boost::shared_ptr<AlsaAudioBackend> _instance;
1888
1889 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1890 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1891 static int deinstantiate ();
1892 static bool already_configured ();
1893 static bool available ();
1894
1895 static ARDOUR::AudioBackendInfo _descriptor = {
1896         "ALSA",
1897         instantiate,
1898         deinstantiate,
1899         backend_factory,
1900         already_configured,
1901         available
1902 };
1903
1904 static boost::shared_ptr<AudioBackend>
1905 backend_factory (AudioEngine& e)
1906 {
1907         if (!_instance) {
1908                 _instance.reset (new AlsaAudioBackend (e, _descriptor));
1909         }
1910         return _instance;
1911 }
1912
1913 static int
1914 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1915 {
1916         s_instance_name = arg1;
1917         return 0;
1918 }
1919
1920 static int
1921 deinstantiate ()
1922 {
1923         _instance.reset ();
1924         return 0;
1925 }
1926
1927 static bool
1928 already_configured ()
1929 {
1930         return false;
1931 }
1932
1933 static bool
1934 available ()
1935 {
1936         return true;
1937 }
1938
1939 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1940 {
1941         return &_descriptor;
1942 }
1943
1944
1945 /******************************************************************************/
1946 AlsaPort::AlsaPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
1947         : _alsa_backend (b)
1948         , _name  (name)
1949         , _flags (flags)
1950 {
1951         _capture_latency_range.min = 0;
1952         _capture_latency_range.max = 0;
1953         _playback_latency_range.min = 0;
1954         _playback_latency_range.max = 0;
1955 }
1956
1957 AlsaPort::~AlsaPort () {
1958         disconnect_all ();
1959 }
1960
1961
1962 int AlsaPort::connect (AlsaPort *port)
1963 {
1964         if (!port) {
1965                 PBD::error << _("AlsaPort::connect (): invalid (null) port") << endmsg;
1966                 return -1;
1967         }
1968
1969         if (type () != port->type ()) {
1970                 PBD::error << _("AlsaPort::connect (): wrong port-type") << endmsg;
1971                 return -1;
1972         }
1973
1974         if (is_output () && port->is_output ()) {
1975                 PBD::error << _("AlsaPort::connect (): cannot inter-connect output ports.") << endmsg;
1976                 return -1;
1977         }
1978
1979         if (is_input () && port->is_input ()) {
1980                 PBD::error << _("AlsaPort::connect (): cannot inter-connect input ports.") << endmsg;
1981                 return -1;
1982         }
1983
1984         if (this == port) {
1985                 PBD::error << _("AlsaPort::connect (): cannot self-connect ports.") << endmsg;
1986                 return -1;
1987         }
1988
1989         if (is_connected (port)) {
1990 #if 0 // don't bother to warn about this for now. just ignore it
1991                 PBD::error << _("AlsaPort::connect (): ports are already connected:")
1992                         << " (" << name () << ") -> (" << port->name () << ")"
1993                         << endmsg;
1994 #endif
1995                 return -1;
1996         }
1997
1998         _connect (port, true);
1999         return 0;
2000 }
2001
2002
2003 void AlsaPort::_connect (AlsaPort *port, bool callback)
2004 {
2005         _connections.push_back (port);
2006         if (callback) {
2007                 port->_connect (this, false);
2008                 _alsa_backend.port_connect_callback (name(),  port->name(), true);
2009         }
2010 }
2011
2012 int AlsaPort::disconnect (AlsaPort *port)
2013 {
2014         if (!port) {
2015                 PBD::error << _("AlsaPort::disconnect (): invalid (null) port") << endmsg;
2016                 return -1;
2017         }
2018
2019         if (!is_connected (port)) {
2020                 PBD::error << _("AlsaPort::disconnect (): ports are not connected:")
2021                         << " (" << name () << ") -> (" << port->name () << ")"
2022                         << endmsg;
2023                 return -1;
2024         }
2025         _disconnect (port, true);
2026         return 0;
2027 }
2028
2029 void AlsaPort::_disconnect (AlsaPort *port, bool callback)
2030 {
2031         std::vector<AlsaPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
2032
2033         assert (it != _connections.end ());
2034
2035         _connections.erase (it);
2036
2037         if (callback) {
2038                 port->_disconnect (this, false);
2039                 _alsa_backend.port_connect_callback (name(),  port->name(), false);
2040         }
2041 }
2042
2043
2044 void AlsaPort::disconnect_all ()
2045 {
2046         while (!_connections.empty ()) {
2047                 _connections.back ()->_disconnect (this, false);
2048                 _alsa_backend.port_connect_callback (name(),  _connections.back ()->name(), false);
2049                 _connections.pop_back ();
2050         }
2051 }
2052
2053 bool
2054 AlsaPort::is_connected (const AlsaPort *port) const
2055 {
2056         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
2057 }
2058
2059 bool AlsaPort::is_physically_connected () const
2060 {
2061         for (std::vector<AlsaPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
2062                 if ((*it)->is_physical ()) {
2063                         return true;
2064                 }
2065         }
2066         return false;
2067 }
2068
2069 /******************************************************************************/
2070
2071 AlsaAudioPort::AlsaAudioPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2072         : AlsaPort (b, name, flags)
2073 {
2074         memset (_buffer, 0, sizeof (_buffer));
2075         mlock(_buffer, sizeof (_buffer));
2076 }
2077
2078 AlsaAudioPort::~AlsaAudioPort () { }
2079
2080 void* AlsaAudioPort::get_buffer (pframes_t n_samples)
2081 {
2082         if (is_input ()) {
2083                 std::vector<AlsaPort*>::const_iterator it = get_connections ().begin ();
2084                 if (it == get_connections ().end ()) {
2085                         memset (_buffer, 0, n_samples * sizeof (Sample));
2086                 } else {
2087                         AlsaAudioPort const * source = static_cast<const AlsaAudioPort*>(*it);
2088                         assert (source && source->is_output ());
2089                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
2090                         while (++it != get_connections ().end ()) {
2091                                 source = static_cast<const AlsaAudioPort*>(*it);
2092                                 assert (source && source->is_output ());
2093                                 Sample* dst = buffer ();
2094                                 const Sample* src = source->const_buffer ();
2095                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
2096                                         *dst += *src;
2097                                 }
2098                         }
2099                 }
2100         }
2101         return _buffer;
2102 }
2103
2104
2105 AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2106         : AlsaPort (b, name, flags)
2107         , _n_periods (1)
2108         , _bufperiod (0)
2109 {
2110         _buffer[0].clear ();
2111         _buffer[1].clear ();
2112 }
2113
2114 AlsaMidiPort::~AlsaMidiPort () { }
2115
2116 struct MidiEventSorter {
2117         bool operator() (const boost::shared_ptr<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& b) {
2118                 return *a < *b;
2119         }
2120 };
2121
2122 void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
2123 {
2124         if (is_input ()) {
2125                 (_buffer[_bufperiod]).clear ();
2126                 for (std::vector<AlsaPort*>::const_iterator i = get_connections ().begin ();
2127                                 i != get_connections ().end ();
2128                                 ++i) {
2129                         const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
2130                         for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
2131                                 (_buffer[_bufperiod]).push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (**it)));
2132                         }
2133                 }
2134                 std::sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
2135         }
2136         return &(_buffer[_bufperiod]);
2137 }
2138
2139 AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
2140         : _size (size)
2141         , _timestamp (timestamp)
2142         , _data (0)
2143 {
2144         if (size > 0) {
2145                 _data = (uint8_t*) malloc (size);
2146                 memcpy (_data, data, size);
2147         }
2148 }
2149
2150 AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
2151         : _size (other.size ())
2152         , _timestamp (other.timestamp ())
2153         , _data (0)
2154 {
2155         if (other.size () && other.const_data ()) {
2156                 _data = (uint8_t*) malloc (other.size ());
2157                 memcpy (_data, other.const_data (), other.size ());
2158         }
2159 };
2160
2161 AlsaMidiEvent::~AlsaMidiEvent () {
2162         free (_data);
2163 };