Use ARDOUR::DSPLoadCalculator in ALSA Backend
[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 -1;
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 -1;
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 -1;
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 -1;
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         switch (_pcmi->state ()) {
756                 case 0: /* OK */ break;
757                 case -1: PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg; break;
758                 case -2: PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg; break;
759                 case -3: PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.") << endmsg; break;
760                 case -4: PBD::error << _("AlsaAudioBackend: cannot set requested period size.") << endmsg; break;
761                 case -5: PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.") << endmsg; break;
762                 case -6: PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg; break;
763                 default: PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg; break;
764         }
765         if (_pcmi->state ()) {
766                 delete _pcmi; _pcmi = 0;
767                 release_device();
768                 return -1;
769         }
770
771 #ifndef NDEBUG
772         _pcmi->printinfo ();
773 #endif
774
775         if (_n_outputs != _pcmi->nplay ()) {
776                 if (_n_outputs == 0) {
777                  _n_outputs = _pcmi->nplay ();
778                 } else {
779                  _n_outputs = std::min (_n_outputs, _pcmi->nplay ());
780                 }
781                 PBD::warning << _("AlsaAudioBackend: adjusted output channel count to match device.") << endmsg;
782         }
783
784         if (_n_inputs != _pcmi->ncapt ()) {
785                 if (_n_inputs == 0) {
786                  _n_inputs = _pcmi->ncapt ();
787                 } else {
788                  _n_inputs = std::min (_n_inputs, _pcmi->ncapt ());
789                 }
790                 PBD::warning << _("AlsaAudioBackend: adjusted input channel count to match device.") << endmsg;
791         }
792
793         if (_pcmi->fsize() != _samples_per_period) {
794                 _samples_per_period = _pcmi->fsize();
795                 PBD::warning << _("AlsaAudioBackend: samples per period does not match.") << endmsg;
796         }
797
798         if (_pcmi->fsamp() != _samplerate) {
799                 _samplerate = _pcmi->fsamp();
800                 engine.sample_rate_change (_samplerate);
801                 PBD::warning << _("AlsaAudioBackend: sample rate does not match.") << endmsg;
802         }
803
804         _measure_latency = for_latency_measurement;
805
806         register_system_midi_ports();
807
808         if (register_system_audio_ports()) {
809                 PBD::error << _("AlsaAudioBackend: failed to register system ports.") << endmsg;
810                 delete _pcmi; _pcmi = 0;
811                 release_device();
812                 return -1;
813         }
814
815         engine.sample_rate_change (_samplerate);
816         engine.buffer_size_change (_samples_per_period);
817
818         _dsp_load_calc.set_max_time(_samplerate, _samples_per_period);
819
820         if (engine.reestablish_ports ()) {
821                 PBD::error << _("AlsaAudioBackend: Could not re-establish ports.") << endmsg;
822                 delete _pcmi; _pcmi = 0;
823                 release_device();
824                 return -1;
825         }
826
827         engine.reconnect_ports ();
828         _run = true;
829         _port_change_flag = false;
830
831         if (_realtime_pthread_create (SCHED_FIFO, -20, 100000,
832                                 &_main_thread, pthread_process, this))
833         {
834                 if (pthread_create (&_main_thread, NULL, pthread_process, this))
835                 {
836                         PBD::error << _("AlsaAudioBackend: failed to create process thread.") << endmsg;
837                         delete _pcmi; _pcmi = 0;
838                         release_device();
839                         _run = false;
840                         return -1;
841                 } else {
842                         PBD::warning << _("AlsaAudioBackend: cannot acquire realtime permissions.") << endmsg;
843                 }
844         }
845
846         int timeout = 5000;
847         while (!_active && --timeout > 0) { Glib::usleep (1000); }
848
849         if (timeout == 0 || !_active) {
850                 PBD::error << _("AlsaAudioBackend: failed to start process thread.") << endmsg;
851                 delete _pcmi; _pcmi = 0;
852                 release_device();
853                 _run = false;
854                 return -1;
855         }
856
857         return 0;
858 }
859
860 int
861 AlsaAudioBackend::stop ()
862 {
863         void *status;
864         if (!_run) {
865                 return 0;
866         }
867
868         _run = false;
869         if (pthread_join (_main_thread, &status)) {
870                 PBD::error << _("AlsaAudioBackend: failed to terminate.") << endmsg;
871                 return -1;
872         }
873
874         while (!_rmidi_out.empty ()) {
875                 AlsaMidiIO *m = _rmidi_out.back ();
876                 m->stop();
877                 _rmidi_out.pop_back ();
878                 delete m;
879         }
880         while (!_rmidi_in.empty ()) {
881                 AlsaMidiIO *m = _rmidi_in.back ();
882                 m->stop();
883                 _rmidi_in.pop_back ();
884                 delete m;
885         }
886
887         unregister_ports();
888         delete _pcmi; _pcmi = 0;
889         release_device();
890
891         return (_active == false) ? 0 : -1;
892 }
893
894 int
895 AlsaAudioBackend::freewheel (bool onoff)
896 {
897         _freewheeling = onoff;
898         return 0;
899 }
900
901 float
902 AlsaAudioBackend::dsp_load () const
903 {
904         return std::min(100.f, 100.f * _dsp_load);
905 }
906
907 size_t
908 AlsaAudioBackend::raw_buffer_size (DataType t)
909 {
910         switch (t) {
911                 case DataType::AUDIO:
912                         return _samples_per_period * sizeof(Sample);
913                 case DataType::MIDI:
914                         return _max_buffer_size; // XXX not really limited
915         }
916         return 0;
917 }
918
919 /* Process time */
920 framepos_t
921 AlsaAudioBackend::sample_time ()
922 {
923         return _processed_samples;
924 }
925
926 framepos_t
927 AlsaAudioBackend::sample_time_at_cycle_start ()
928 {
929         return _processed_samples;
930 }
931
932 pframes_t
933 AlsaAudioBackend::samples_since_cycle_start ()
934 {
935         if (!_active || !_run || _freewheeling || _freewheel) {
936                 return 0;
937         }
938         if (_last_process_start == 0) {
939                 return 0;
940         }
941
942         const int64_t elapsed_time_us = g_get_monotonic_time() - _last_process_start;
943         return std::max((pframes_t)0, (pframes_t)rint(1e-6 * elapsed_time_us * _samplerate));
944 }
945
946
947 void *
948 AlsaAudioBackend::alsa_process_thread (void *arg)
949 {
950         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
951         boost::function<void ()> f = td->f;
952         delete td;
953         f ();
954         return 0;
955 }
956
957 int
958 AlsaAudioBackend::create_process_thread (boost::function<void()> func)
959 {
960         pthread_t thread_id;
961         pthread_attr_t attr;
962         size_t stacksize = 100000;
963
964         ThreadData* td = new ThreadData (this, func, stacksize);
965
966         if (_realtime_pthread_create (SCHED_FIFO, -21, stacksize,
967                                 &thread_id, alsa_process_thread, td)) {
968                 pthread_attr_init (&attr);
969                 pthread_attr_setstacksize (&attr, stacksize);
970                 if (pthread_create (&thread_id, &attr, alsa_process_thread, td)) {
971                         PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
972                         pthread_attr_destroy (&attr);
973                         return -1;
974                 }
975                 pthread_attr_destroy (&attr);
976         }
977
978         _threads.push_back (thread_id);
979         return 0;
980 }
981
982 int
983 AlsaAudioBackend::join_process_threads ()
984 {
985         int rv = 0;
986
987         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
988         {
989                 void *status;
990                 if (pthread_join (*i, &status)) {
991                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
992                         rv -= 1;
993                 }
994         }
995         _threads.clear ();
996         return rv;
997 }
998
999 bool
1000 AlsaAudioBackend::in_process_thread ()
1001 {
1002         if (pthread_equal (_main_thread, pthread_self()) != 0) {
1003                 return true;
1004         }
1005
1006         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
1007         {
1008                 if (pthread_equal (*i, pthread_self ()) != 0) {
1009                         return true;
1010                 }
1011         }
1012         return false;
1013 }
1014
1015 uint32_t
1016 AlsaAudioBackend::process_thread_count ()
1017 {
1018         return _threads.size ();
1019 }
1020
1021 void
1022 AlsaAudioBackend::update_latencies ()
1023 {
1024         // trigger latency callback in RT thread (locked graph)
1025         port_connect_add_remove_callback();
1026 }
1027
1028 /* PORTENGINE API */
1029
1030 void*
1031 AlsaAudioBackend::private_handle () const
1032 {
1033         return NULL;
1034 }
1035
1036 const std::string&
1037 AlsaAudioBackend::my_name () const
1038 {
1039         return _instance_name;
1040 }
1041
1042 bool
1043 AlsaAudioBackend::available () const
1044 {
1045         return _run && _active;
1046 }
1047
1048 uint32_t
1049 AlsaAudioBackend::port_name_size () const
1050 {
1051         return 256;
1052 }
1053
1054 int
1055 AlsaAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
1056 {
1057         if (!valid_port (port)) {
1058                 PBD::error << _("AlsaBackend::set_port_name: Invalid Port(s)") << endmsg;
1059                 return -1;
1060         }
1061         return static_cast<AlsaPort*>(port)->set_name (_instance_name + ":" + name);
1062 }
1063
1064 std::string
1065 AlsaAudioBackend::get_port_name (PortEngine::PortHandle port) const
1066 {
1067         if (!valid_port (port)) {
1068                 PBD::error << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
1069                 return std::string ();
1070         }
1071         return static_cast<AlsaPort*>(port)->name ();
1072 }
1073
1074 PortEngine::PortHandle
1075 AlsaAudioBackend::get_port_by_name (const std::string& name) const
1076 {
1077         PortHandle port = (PortHandle) find_port (name);
1078         return port;
1079 }
1080
1081 int
1082 AlsaAudioBackend::get_ports (
1083                 const std::string& port_name_pattern,
1084                 DataType type, PortFlags flags,
1085                 std::vector<std::string>& port_names) const
1086 {
1087         int rv = 0;
1088         regex_t port_regex;
1089         bool use_regexp = false;
1090         if (port_name_pattern.size () > 0) {
1091                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
1092                         use_regexp = true;
1093                 }
1094         }
1095         for (size_t i = 0; i < _ports.size (); ++i) {
1096                 AlsaPort* port = _ports[i];
1097                 if ((port->type () == type) && flags == (port->flags () & flags)) {
1098                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
1099                                 port_names.push_back (port->name ());
1100                                 ++rv;
1101                         }
1102                 }
1103         }
1104         if (use_regexp) {
1105                 regfree (&port_regex);
1106         }
1107         return rv;
1108 }
1109
1110 DataType
1111 AlsaAudioBackend::port_data_type (PortEngine::PortHandle port) const
1112 {
1113         if (!valid_port (port)) {
1114                 return DataType::NIL;
1115         }
1116         return static_cast<AlsaPort*>(port)->type ();
1117 }
1118
1119 PortEngine::PortHandle
1120 AlsaAudioBackend::register_port (
1121                 const std::string& name,
1122                 ARDOUR::DataType type,
1123                 ARDOUR::PortFlags flags)
1124 {
1125         if (name.size () == 0) { return 0; }
1126         if (flags & IsPhysical) { return 0; }
1127         return add_port (_instance_name + ":" + name, type, flags);
1128 }
1129
1130 PortEngine::PortHandle
1131 AlsaAudioBackend::add_port (
1132                 const std::string& name,
1133                 ARDOUR::DataType type,
1134                 ARDOUR::PortFlags flags)
1135 {
1136         assert(name.size ());
1137         if (find_port (name)) {
1138                 PBD::error << _("AlsaBackend::register_port: Port already exists:")
1139                                 << " (" << name << ")" << endmsg;
1140                 return 0;
1141         }
1142         AlsaPort* port = NULL;
1143         switch (type) {
1144                 case DataType::AUDIO:
1145                         port = new AlsaAudioPort (*this, name, flags);
1146                         break;
1147                 case DataType::MIDI:
1148                         port = new AlsaMidiPort (*this, name, flags);
1149                         break;
1150                 default:
1151                         PBD::error << _("AlsaBackend::register_port: Invalid Data Type.") << endmsg;
1152                         return 0;
1153         }
1154
1155         _ports.push_back (port);
1156
1157         return port;
1158 }
1159
1160 void
1161 AlsaAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
1162 {
1163         if (!_run) {
1164                 return;
1165         }
1166         AlsaPort* port = static_cast<AlsaPort*>(port_handle);
1167         std::vector<AlsaPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<AlsaPort*>(port_handle));
1168         if (i == _ports.end ()) {
1169                 PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
1170                 return;
1171         }
1172         disconnect_all(port_handle);
1173         _ports.erase (i);
1174         delete port;
1175 }
1176
1177 int
1178 AlsaAudioBackend::register_system_audio_ports()
1179 {
1180         LatencyRange lr;
1181
1182         const int a_ins = _n_inputs;
1183         const int a_out = _n_outputs;
1184
1185         /* audio ports */
1186         lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_input_latency);
1187         for (int i = 1; i <= a_ins; ++i) {
1188                 char tmp[64];
1189                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
1190                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1191                 if (!p) return -1;
1192                 set_latency_range (p, false, lr);
1193                 _system_inputs.push_back(static_cast<AlsaPort*>(p));
1194         }
1195
1196         lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency);
1197         for (int i = 1; i <= a_out; ++i) {
1198                 char tmp[64];
1199                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
1200                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1201                 if (!p) return -1;
1202                 set_latency_range (p, true, lr);
1203                 _system_outputs.push_back(static_cast<AlsaPort*>(p));
1204         }
1205         return 0;
1206 }
1207
1208 int
1209 AlsaAudioBackend::register_system_midi_ports()
1210 {
1211         std::map<std::string, std::string> devices;
1212         int midi_ins = 0;
1213         int midi_outs = 0;
1214
1215         if (_midi_driver_option == get_standard_device_name(DeviceNone)) {
1216                 return 0;
1217         } else if (_midi_driver_option == _("ALSA raw devices")) {
1218                 get_alsa_rawmidi_device_names(devices);
1219         } else {
1220                 get_alsa_sequencer_names (devices);
1221         }
1222
1223         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
1224                 struct AlsaMidiDeviceInfo * nfo = midi_device_info(i->first);
1225                 if (!nfo) continue;
1226                 if (!nfo->enabled) continue;
1227
1228                 AlsaMidiOut *mout;
1229                 if (_midi_driver_option == _("ALSA raw devices")) {
1230                         mout = new AlsaRawMidiOut (i->second.c_str());
1231                 } else {
1232                         mout = new AlsaSeqMidiOut (i->second.c_str());
1233                 }
1234
1235                 if (mout->state ()) {
1236                         PBD::warning << string_compose (
1237                                         _("AlsaMidiOut: failed to open midi device '%1'."), i->second)
1238                                 << endmsg;
1239                         delete mout;
1240                 } else {
1241                         mout->setup_timing(_samples_per_period, _samplerate);
1242                         mout->sync_time (g_get_monotonic_time());
1243                         if (mout->start ()) {
1244                                 PBD::warning << string_compose (
1245                                                 _("AlsaMidiOut: failed to start midi device '%1'."), i->second)
1246                                         << endmsg;
1247                                 delete mout;
1248                         } else {
1249                                 char tmp[64];
1250                                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++midi_ins);
1251                                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1252                                 if (!p) {
1253                                         mout->stop();
1254                                         delete mout;
1255                                 }
1256                                 LatencyRange lr;
1257                                 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency);
1258                                 set_latency_range (p, false, lr);
1259                                 static_cast<AlsaMidiPort*>(p)->set_n_periods(2);
1260                                 _system_midi_out.push_back(static_cast<AlsaPort*>(p));
1261                                 _rmidi_out.push_back (mout);
1262                         }
1263                 }
1264
1265                 AlsaMidiIn *midin;
1266                 if (_midi_driver_option == _("ALSA raw devices")) {
1267                         midin = new AlsaRawMidiIn (i->second.c_str());
1268                 } else {
1269                         midin = new AlsaSeqMidiIn (i->second.c_str());
1270                 }
1271
1272                 if (midin->state ()) {
1273                         PBD::warning << string_compose (
1274                                         _("AlsaMidiIn: failed to open midi device '%1'."), i->second)
1275                                 << endmsg;
1276                         delete midin;
1277                 } else {
1278                         midin->setup_timing(_samples_per_period, _samplerate);
1279                         midin->sync_time (g_get_monotonic_time());
1280                         if (midin->start ()) {
1281                                 PBD::warning << string_compose (
1282                                                 _("AlsaMidiIn: failed to start midi device '%1'."), i->second)
1283                                         << endmsg;
1284                                 delete midin;
1285                         } else {
1286                                 char tmp[64];
1287                                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++midi_outs);
1288                                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1289                                 if (!p) {
1290                                         midin->stop();
1291                                         delete midin;
1292                                         continue;
1293                                 }
1294                                 LatencyRange lr;
1295                                 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
1296                                 set_latency_range (p, false, lr);
1297                                 _system_midi_in.push_back(static_cast<AlsaPort*>(p));
1298                                 _rmidi_in.push_back (midin);
1299                         }
1300                 }
1301         }
1302         return 0;
1303 }
1304
1305 void
1306 AlsaAudioBackend::unregister_ports (bool system_only)
1307 {
1308         size_t i = 0;
1309         _system_inputs.clear();
1310         _system_outputs.clear();
1311         _system_midi_in.clear();
1312         _system_midi_out.clear();
1313         while (i <  _ports.size ()) {
1314                 AlsaPort* port = _ports[i];
1315                 if (! system_only || (port->is_physical () && port->is_terminal ())) {
1316                         port->disconnect_all ();
1317                         delete port;
1318                         _ports.erase (_ports.begin() + i);
1319                 } else {
1320                         ++i;
1321                 }
1322         }
1323 }
1324
1325 int
1326 AlsaAudioBackend::connect (const std::string& src, const std::string& dst)
1327 {
1328         AlsaPort* src_port = find_port (src);
1329         AlsaPort* dst_port = find_port (dst);
1330
1331         if (!src_port) {
1332                 PBD::error << _("AlsaBackend::connect: Invalid Source port:")
1333                                 << " (" << src <<")" << endmsg;
1334                 return -1;
1335         }
1336         if (!dst_port) {
1337                 PBD::error << _("AlsaBackend::connect: Invalid Destination port:")
1338                         << " (" << dst <<")" << endmsg;
1339                 return -1;
1340         }
1341         return src_port->connect (dst_port);
1342 }
1343
1344 int
1345 AlsaAudioBackend::disconnect (const std::string& src, const std::string& dst)
1346 {
1347         AlsaPort* src_port = find_port (src);
1348         AlsaPort* dst_port = find_port (dst);
1349
1350         if (!src_port || !dst_port) {
1351                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1352                 return -1;
1353         }
1354         return src_port->disconnect (dst_port);
1355 }
1356
1357 int
1358 AlsaAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
1359 {
1360         AlsaPort* dst_port = find_port (dst);
1361         if (!valid_port (src)) {
1362                 PBD::error << _("AlsaBackend::connect: Invalid Source Port Handle") << endmsg;
1363                 return -1;
1364         }
1365         if (!dst_port) {
1366                 PBD::error << _("AlsaBackend::connect: Invalid Destination Port")
1367                         << " (" << dst << ")" << endmsg;
1368                 return -1;
1369         }
1370         return static_cast<AlsaPort*>(src)->connect (dst_port);
1371 }
1372
1373 int
1374 AlsaAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
1375 {
1376         AlsaPort* dst_port = find_port (dst);
1377         if (!valid_port (src) || !dst_port) {
1378                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1379                 return -1;
1380         }
1381         return static_cast<AlsaPort*>(src)->disconnect (dst_port);
1382 }
1383
1384 int
1385 AlsaAudioBackend::disconnect_all (PortEngine::PortHandle port)
1386 {
1387         if (!valid_port (port)) {
1388                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1389                 return -1;
1390         }
1391         static_cast<AlsaPort*>(port)->disconnect_all ();
1392         return 0;
1393 }
1394
1395 bool
1396 AlsaAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
1397 {
1398         if (!valid_port (port)) {
1399                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1400                 return false;
1401         }
1402         return static_cast<AlsaPort*>(port)->is_connected ();
1403 }
1404
1405 bool
1406 AlsaAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
1407 {
1408         AlsaPort* dst_port = find_port (dst);
1409         if (!valid_port (src) || !dst_port) {
1410                 PBD::error << _("AlsaBackend::connected_to: Invalid Port") << endmsg;
1411                 return false;
1412         }
1413         return static_cast<AlsaPort*>(src)->is_connected (dst_port);
1414 }
1415
1416 bool
1417 AlsaAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
1418 {
1419         if (!valid_port (port)) {
1420                 PBD::error << _("AlsaBackend::physically_connected: Invalid Port") << endmsg;
1421                 return false;
1422         }
1423         return static_cast<AlsaPort*>(port)->is_physically_connected ();
1424 }
1425
1426 int
1427 AlsaAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
1428 {
1429         if (!valid_port (port)) {
1430                 PBD::error << _("AlsaBackend::get_connections: Invalid Port") << endmsg;
1431                 return -1;
1432         }
1433
1434         assert (0 == names.size ());
1435
1436         const std::vector<AlsaPort*>& connected_ports = static_cast<AlsaPort*>(port)->get_connections ();
1437
1438         for (std::vector<AlsaPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
1439                 names.push_back ((*i)->name ());
1440         }
1441
1442         return (int)names.size ();
1443 }
1444
1445 /* MIDI */
1446 int
1447 AlsaAudioBackend::midi_event_get (
1448                 pframes_t& timestamp,
1449                 size_t& size, uint8_t** buf, void* port_buffer,
1450                 uint32_t event_index)
1451 {
1452         assert (buf && port_buffer);
1453         AlsaMidiBuffer& source = * static_cast<AlsaMidiBuffer*>(port_buffer);
1454         if (event_index >= source.size ()) {
1455                 return -1;
1456         }
1457         AlsaMidiEvent * const event = source[event_index].get ();
1458
1459         timestamp = event->timestamp ();
1460         size = event->size ();
1461         *buf = event->data ();
1462         return 0;
1463 }
1464
1465 int
1466 AlsaAudioBackend::midi_event_put (
1467                 void* port_buffer,
1468                 pframes_t timestamp,
1469                 const uint8_t* buffer, size_t size)
1470 {
1471         assert (buffer && port_buffer);
1472         AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
1473         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
1474 #ifndef NDEBUG
1475                 // nevermind, ::get_buffer() sorts events
1476                 fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
1477                                 (pframes_t)dst.back ()->timestamp (), timestamp);
1478 #endif
1479         }
1480         dst.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (timestamp, buffer, size)));
1481         return 0;
1482 }
1483
1484 uint32_t
1485 AlsaAudioBackend::get_midi_event_count (void* port_buffer)
1486 {
1487         assert (port_buffer);
1488         return static_cast<AlsaMidiBuffer*>(port_buffer)->size ();
1489 }
1490
1491 void
1492 AlsaAudioBackend::midi_clear (void* port_buffer)
1493 {
1494         assert (port_buffer);
1495         AlsaMidiBuffer * buf = static_cast<AlsaMidiBuffer*>(port_buffer);
1496         assert (buf);
1497         buf->clear ();
1498 }
1499
1500 /* Monitoring */
1501
1502 bool
1503 AlsaAudioBackend::can_monitor_input () const
1504 {
1505         return false;
1506 }
1507
1508 int
1509 AlsaAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
1510 {
1511         return -1;
1512 }
1513
1514 int
1515 AlsaAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
1516 {
1517         return -1;
1518 }
1519
1520 bool
1521 AlsaAudioBackend::monitoring_input (PortEngine::PortHandle)
1522 {
1523         return false;
1524 }
1525
1526 /* Latency management */
1527
1528 void
1529 AlsaAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
1530 {
1531         if (!valid_port (port)) {
1532                 PBD::error << _("AlsaPort::set_latency_range (): invalid port.") << endmsg;
1533         }
1534         static_cast<AlsaPort*>(port)->set_latency_range (latency_range, for_playback);
1535 }
1536
1537 LatencyRange
1538 AlsaAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
1539 {
1540         LatencyRange r;
1541         if (!valid_port (port)) {
1542                 PBD::error << _("AlsaPort::get_latency_range (): invalid port.") << endmsg;
1543                 r.min = 0;
1544                 r.max = 0;
1545                 return r;
1546         }
1547         AlsaPort *p = static_cast<AlsaPort*>(port);
1548         assert(p);
1549
1550         r = p->latency_range (for_playback);
1551         if (p->is_physical() && p->is_terminal()) {
1552                 if (p->is_input() && for_playback) {
1553                         r.min += _samples_per_period;
1554                         r.max += _samples_per_period;
1555                 }
1556                 if (p->is_output() && !for_playback) {
1557                         r.min += _samples_per_period;
1558                         r.max += _samples_per_period;
1559                 }
1560         }
1561         return r;
1562 }
1563
1564 /* Discovering physical ports */
1565
1566 bool
1567 AlsaAudioBackend::port_is_physical (PortEngine::PortHandle port) const
1568 {
1569         if (!valid_port (port)) {
1570                 PBD::error << _("AlsaPort::port_is_physical (): invalid port.") << endmsg;
1571                 return false;
1572         }
1573         return static_cast<AlsaPort*>(port)->is_physical ();
1574 }
1575
1576 void
1577 AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
1578 {
1579         for (size_t i = 0; i < _ports.size (); ++i) {
1580                 AlsaPort* port = _ports[i];
1581                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
1582                         port_names.push_back (port->name ());
1583                 }
1584         }
1585 }
1586
1587 void
1588 AlsaAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
1589 {
1590         for (size_t i = 0; i < _ports.size (); ++i) {
1591                 AlsaPort* port = _ports[i];
1592                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
1593                         port_names.push_back (port->name ());
1594                 }
1595         }
1596 }
1597
1598 ChanCount
1599 AlsaAudioBackend::n_physical_outputs () const
1600 {
1601         int n_midi = 0;
1602         int n_audio = 0;
1603         for (size_t i = 0; i < _ports.size (); ++i) {
1604                 AlsaPort* port = _ports[i];
1605                 if (port->is_output () && port->is_physical ()) {
1606                         switch (port->type ()) {
1607                                 case DataType::AUDIO: ++n_audio; break;
1608                                 case DataType::MIDI: ++n_midi; break;
1609                                 default: break;
1610                         }
1611                 }
1612         }
1613         ChanCount cc;
1614         cc.set (DataType::AUDIO, n_audio);
1615         cc.set (DataType::MIDI, n_midi);
1616         return cc;
1617 }
1618
1619 ChanCount
1620 AlsaAudioBackend::n_physical_inputs () const
1621 {
1622         int n_midi = 0;
1623         int n_audio = 0;
1624         for (size_t i = 0; i < _ports.size (); ++i) {
1625                 AlsaPort* port = _ports[i];
1626                 if (port->is_input () && port->is_physical ()) {
1627                         switch (port->type ()) {
1628                                 case DataType::AUDIO: ++n_audio; break;
1629                                 case DataType::MIDI: ++n_midi; break;
1630                                 default: break;
1631                         }
1632                 }
1633         }
1634         ChanCount cc;
1635         cc.set (DataType::AUDIO, n_audio);
1636         cc.set (DataType::MIDI, n_midi);
1637         return cc;
1638 }
1639
1640 /* Getting access to the data buffer for a port */
1641
1642 void*
1643 AlsaAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
1644 {
1645         assert (port);
1646         assert (valid_port (port));
1647         return static_cast<AlsaPort*>(port)->get_buffer (nframes);
1648 }
1649
1650 /* Engine Process */
1651 void *
1652 AlsaAudioBackend::main_process_thread ()
1653 {
1654         AudioEngine::thread_init_callback (this);
1655         _active = true;
1656         _processed_samples = 0;
1657
1658         uint64_t clock1;
1659         _pcmi->pcm_start ();
1660         int no_proc_errors = 0;
1661         const int bailout = 2 * _samplerate / _samples_per_period;
1662
1663         manager.registration_callback();
1664         manager.graph_order_callback();
1665
1666         while (_run) {
1667                 long nr;
1668                 bool xrun = false;
1669
1670                 if (_freewheeling != _freewheel) {
1671                         _freewheel = _freewheeling;
1672                         engine.freewheel_callback (_freewheel);
1673                 }
1674
1675                 if (!_freewheel) {
1676                         nr = _pcmi->pcm_wait ();
1677
1678                         if (_pcmi->state () > 0) {
1679                                 ++no_proc_errors;
1680                                 xrun = true;
1681                         }
1682                         if (_pcmi->state () < 0) {
1683                                 PBD::error << _("AlsaAudioBackend: I/O error. Audio Process Terminated.") << endmsg;
1684                                 break;
1685                         }
1686                         if (no_proc_errors > bailout) {
1687                                 PBD::error
1688                                         << string_compose (
1689                                                         _("AlsaAudioBackend: Audio Process Terminated after %1 consecutive x-runs."),
1690                                                         no_proc_errors)
1691                                         << endmsg;
1692                                 break;
1693                         }
1694
1695                         while (nr >= (long)_samples_per_period && _freewheeling == _freewheel) {
1696                                 uint32_t i = 0;
1697                                 clock1 = g_get_monotonic_time();
1698                                 no_proc_errors = 0;
1699
1700                                 _pcmi->capt_init (_samples_per_period);
1701                                 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) {
1702                                         _pcmi->capt_chan (i, (float*)((*it)->get_buffer(_samples_per_period)), _samples_per_period);
1703                                 }
1704                                 _pcmi->capt_done (_samples_per_period);
1705
1706                                 /* de-queue incoming midi*/
1707                                 i = 0;
1708                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1709                                         assert (_rmidi_in.size() > i);
1710                                         AlsaMidiIn *rm = _rmidi_in.at(i);
1711                                         void *bptr = (*it)->get_buffer(0);
1712                                         pframes_t time;
1713                                         uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
1714                                         size_t size = sizeof(data);
1715                                         midi_clear(bptr);
1716                                         while (rm->recv_event (time, data, size)) {
1717                                                 midi_event_put(bptr, time, data, size);
1718                                                 size = sizeof(data);
1719                                         }
1720                                         rm->sync_time (clock1);
1721                                 }
1722
1723                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
1724                                         memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1725                                 }
1726
1727                                 /* call engine process callback */
1728                                 _last_process_start = g_get_monotonic_time();
1729                                 if (engine.process_callback (_samples_per_period)) {
1730                                         _pcmi->pcm_stop ();
1731                                         _active = false;
1732                                         return 0;
1733                                 }
1734
1735                                 for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1736                                         static_cast<AlsaMidiPort*>(*it)->next_period();
1737                                 }
1738
1739                                 /* queue outgoing midi */
1740                                 i = 0;
1741                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
1742                                         assert (_rmidi_out.size() > i);
1743                                         const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*it)->const_buffer();
1744                                         AlsaMidiOut *rm = _rmidi_out.at(i);
1745                                         rm->sync_time (clock1);
1746                                         for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
1747                                                 rm->send_event ((*mit)->timestamp(), (*mit)->data(), (*mit)->size());
1748                                         }
1749                                 }
1750
1751                                 /* write back audio */
1752                                 i = 0;
1753                                 _pcmi->play_init (_samples_per_period);
1754                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it, ++i) {
1755                                         _pcmi->play_chan (i, (const float*)(*it)->get_buffer (_samples_per_period), _samples_per_period);
1756                                 }
1757                                 for (; i < _pcmi->nplay (); ++i) {
1758                                         _pcmi->clear_chan (i, _samples_per_period);
1759                                 }
1760                                 _pcmi->play_done (_samples_per_period);
1761                                 nr -= _samples_per_period;
1762                                 _processed_samples += _samples_per_period;
1763
1764                                 _dsp_load_calc.set_start_timestamp_us (clock1);
1765                                 _dsp_load_calc.set_stop_timestamp_us (g_get_monotonic_time());
1766                                 _dsp_load = _dsp_load_calc.get_dsp_load ();
1767                         }
1768
1769                         if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) {
1770                                 engine.Xrun ();
1771 #if 0
1772                                 fprintf(stderr, "ALSA x-run read: %.2f ms, write: %.2f ms\n",
1773                                                 _pcmi->capt_xrun() * 1000.0, _pcmi->play_xrun() * 1000.0);
1774 #endif
1775                         }
1776                 } else {
1777                         // Freewheelin'
1778
1779                         // zero audio input buffers
1780                         for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
1781                                 memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1782                         }
1783
1784                         clock1 = g_get_monotonic_time();
1785                         uint32_t i = 0;
1786                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1787                                 static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
1788                                 AlsaMidiIn *rm = _rmidi_in.at(i);
1789                                 void *bptr = (*it)->get_buffer(0);
1790                                 midi_clear(bptr); // zero midi buffer
1791
1792                                 // TODO add an API call for this.
1793                                 pframes_t time;
1794                                 uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
1795                                 size_t size = sizeof(data);
1796                                 while (rm->recv_event (time, data, size)) {
1797                                         ; // discard midi-data from HW.
1798                                 }
1799                                 rm->sync_time (clock1);
1800                         }
1801
1802                         _last_process_start = 0;
1803                         if (engine.process_callback (_samples_per_period)) {
1804                                 _pcmi->pcm_stop ();
1805                                 _active = false;
1806                                 return 0;
1807                         }
1808
1809                         // drop all outgoing MIDI messages
1810                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1811                                         void *bptr = (*it)->get_buffer(0);
1812                                         midi_clear(bptr);
1813                         }
1814
1815                         _dsp_load = 1.0;
1816                         Glib::usleep (100); // don't hog cpu
1817                 }
1818
1819                 bool connections_changed = false;
1820                 bool ports_changed = false;
1821                 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
1822                         if (_port_change_flag) {
1823                                 ports_changed = true;
1824                                 _port_change_flag = false;
1825                         }
1826                         if (!_port_connection_queue.empty ()) {
1827                                 connections_changed = true;
1828                         }
1829                         while (!_port_connection_queue.empty ()) {
1830                                 PortConnectData *c = _port_connection_queue.back ();
1831                                 manager.connect_callback (c->a, c->b, c->c);
1832                                 _port_connection_queue.pop_back ();
1833                                 delete c;
1834                         }
1835                         pthread_mutex_unlock (&_port_callback_mutex);
1836                 }
1837                 if (ports_changed) {
1838                         manager.registration_callback();
1839                 }
1840                 if (connections_changed) {
1841                         manager.graph_order_callback();
1842                 }
1843                 if (connections_changed || ports_changed) {
1844                         engine.latency_callback(false);
1845                         engine.latency_callback(true);
1846                 }
1847
1848         }
1849         _pcmi->pcm_stop ();
1850         _active = false;
1851         if (_run) {
1852                 engine.halted_callback("ALSA I/O error.");
1853         }
1854         return 0;
1855 }
1856
1857
1858 /******************************************************************************/
1859
1860 static boost::shared_ptr<AlsaAudioBackend> _instance;
1861
1862 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1863 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1864 static int deinstantiate ();
1865 static bool already_configured ();
1866 static bool available ();
1867
1868 static ARDOUR::AudioBackendInfo _descriptor = {
1869         "ALSA",
1870         instantiate,
1871         deinstantiate,
1872         backend_factory,
1873         already_configured,
1874         available
1875 };
1876
1877 static boost::shared_ptr<AudioBackend>
1878 backend_factory (AudioEngine& e)
1879 {
1880         if (!_instance) {
1881                 _instance.reset (new AlsaAudioBackend (e, _descriptor));
1882         }
1883         return _instance;
1884 }
1885
1886 static int
1887 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1888 {
1889         s_instance_name = arg1;
1890         return 0;
1891 }
1892
1893 static int
1894 deinstantiate ()
1895 {
1896         _instance.reset ();
1897         return 0;
1898 }
1899
1900 static bool
1901 already_configured ()
1902 {
1903         return false;
1904 }
1905
1906 static bool
1907 available ()
1908 {
1909         return true;
1910 }
1911
1912 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1913 {
1914         return &_descriptor;
1915 }
1916
1917
1918 /******************************************************************************/
1919 AlsaPort::AlsaPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
1920         : _alsa_backend (b)
1921         , _name  (name)
1922         , _flags (flags)
1923 {
1924         _capture_latency_range.min = 0;
1925         _capture_latency_range.max = 0;
1926         _playback_latency_range.min = 0;
1927         _playback_latency_range.max = 0;
1928 }
1929
1930 AlsaPort::~AlsaPort () {
1931         disconnect_all ();
1932 }
1933
1934
1935 int AlsaPort::connect (AlsaPort *port)
1936 {
1937         if (!port) {
1938                 PBD::error << _("AlsaPort::connect (): invalid (null) port") << endmsg;
1939                 return -1;
1940         }
1941
1942         if (type () != port->type ()) {
1943                 PBD::error << _("AlsaPort::connect (): wrong port-type") << endmsg;
1944                 return -1;
1945         }
1946
1947         if (is_output () && port->is_output ()) {
1948                 PBD::error << _("AlsaPort::connect (): cannot inter-connect output ports.") << endmsg;
1949                 return -1;
1950         }
1951
1952         if (is_input () && port->is_input ()) {
1953                 PBD::error << _("AlsaPort::connect (): cannot inter-connect input ports.") << endmsg;
1954                 return -1;
1955         }
1956
1957         if (this == port) {
1958                 PBD::error << _("AlsaPort::connect (): cannot self-connect ports.") << endmsg;
1959                 return -1;
1960         }
1961
1962         if (is_connected (port)) {
1963 #if 0 // don't bother to warn about this for now. just ignore it
1964                 PBD::error << _("AlsaPort::connect (): ports are already connected:")
1965                         << " (" << name () << ") -> (" << port->name () << ")"
1966                         << endmsg;
1967 #endif
1968                 return -1;
1969         }
1970
1971         _connect (port, true);
1972         return 0;
1973 }
1974
1975
1976 void AlsaPort::_connect (AlsaPort *port, bool callback)
1977 {
1978         _connections.push_back (port);
1979         if (callback) {
1980                 port->_connect (this, false);
1981                 _alsa_backend.port_connect_callback (name(),  port->name(), true);
1982         }
1983 }
1984
1985 int AlsaPort::disconnect (AlsaPort *port)
1986 {
1987         if (!port) {
1988                 PBD::error << _("AlsaPort::disconnect (): invalid (null) port") << endmsg;
1989                 return -1;
1990         }
1991
1992         if (!is_connected (port)) {
1993                 PBD::error << _("AlsaPort::disconnect (): ports are not connected:")
1994                         << " (" << name () << ") -> (" << port->name () << ")"
1995                         << endmsg;
1996                 return -1;
1997         }
1998         _disconnect (port, true);
1999         return 0;
2000 }
2001
2002 void AlsaPort::_disconnect (AlsaPort *port, bool callback)
2003 {
2004         std::vector<AlsaPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
2005
2006         assert (it != _connections.end ());
2007
2008         _connections.erase (it);
2009
2010         if (callback) {
2011                 port->_disconnect (this, false);
2012                 _alsa_backend.port_connect_callback (name(),  port->name(), false);
2013         }
2014 }
2015
2016
2017 void AlsaPort::disconnect_all ()
2018 {
2019         while (!_connections.empty ()) {
2020                 _connections.back ()->_disconnect (this, false);
2021                 _alsa_backend.port_connect_callback (name(),  _connections.back ()->name(), false);
2022                 _connections.pop_back ();
2023         }
2024 }
2025
2026 bool
2027 AlsaPort::is_connected (const AlsaPort *port) const
2028 {
2029         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
2030 }
2031
2032 bool AlsaPort::is_physically_connected () const
2033 {
2034         for (std::vector<AlsaPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
2035                 if ((*it)->is_physical ()) {
2036                         return true;
2037                 }
2038         }
2039         return false;
2040 }
2041
2042 /******************************************************************************/
2043
2044 AlsaAudioPort::AlsaAudioPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2045         : AlsaPort (b, name, flags)
2046 {
2047         memset (_buffer, 0, sizeof (_buffer));
2048         mlock(_buffer, sizeof (_buffer));
2049 }
2050
2051 AlsaAudioPort::~AlsaAudioPort () { }
2052
2053 void* AlsaAudioPort::get_buffer (pframes_t n_samples)
2054 {
2055         if (is_input ()) {
2056                 std::vector<AlsaPort*>::const_iterator it = get_connections ().begin ();
2057                 if (it == get_connections ().end ()) {
2058                         memset (_buffer, 0, n_samples * sizeof (Sample));
2059                 } else {
2060                         AlsaAudioPort const * source = static_cast<const AlsaAudioPort*>(*it);
2061                         assert (source && source->is_output ());
2062                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
2063                         while (++it != get_connections ().end ()) {
2064                                 source = static_cast<const AlsaAudioPort*>(*it);
2065                                 assert (source && source->is_output ());
2066                                 Sample* dst = buffer ();
2067                                 const Sample* src = source->const_buffer ();
2068                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
2069                                         *dst += *src;
2070                                 }
2071                         }
2072                 }
2073         }
2074         return _buffer;
2075 }
2076
2077
2078 AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2079         : AlsaPort (b, name, flags)
2080         , _n_periods (1)
2081         , _bufperiod (0)
2082 {
2083         _buffer[0].clear ();
2084         _buffer[1].clear ();
2085 }
2086
2087 AlsaMidiPort::~AlsaMidiPort () { }
2088
2089 struct MidiEventSorter {
2090         bool operator() (const boost::shared_ptr<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& b) {
2091                 return *a < *b;
2092         }
2093 };
2094
2095 void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
2096 {
2097         if (is_input ()) {
2098                 (_buffer[_bufperiod]).clear ();
2099                 for (std::vector<AlsaPort*>::const_iterator i = get_connections ().begin ();
2100                                 i != get_connections ().end ();
2101                                 ++i) {
2102                         const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
2103                         for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
2104                                 (_buffer[_bufperiod]).push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (**it)));
2105                         }
2106                 }
2107                 std::sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
2108         }
2109         return &(_buffer[_bufperiod]);
2110 }
2111
2112 AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
2113         : _size (size)
2114         , _timestamp (timestamp)
2115         , _data (0)
2116 {
2117         if (size > 0) {
2118                 _data = (uint8_t*) malloc (size);
2119                 memcpy (_data, data, size);
2120         }
2121 }
2122
2123 AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
2124         : _size (other.size ())
2125         , _timestamp (other.timestamp ())
2126         , _data (0)
2127 {
2128         if (other.size () && other.const_data ()) {
2129                 _data = (uint8_t*) malloc (other.size ());
2130                 memcpy (_data, other.const_data (), other.size ());
2131         }
2132 };
2133
2134 AlsaMidiEvent::~AlsaMidiEvent () {
2135         free (_data);
2136 };