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