2 * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
3 * Copyright (C) 2013 Paul Davis
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.
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.
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.
26 #include "alsa_audiobackend.h"
28 #include "pbd/compose.h"
29 #include "pbd/error.h"
30 #include "pbd/file_utils.h"
31 #include "pbd/pthread_utils.h"
32 #include "ardour/filesystem_paths.h"
33 #include "ardour/port_manager.h"
34 #include "ardouralsautil/devicelist.h"
37 using namespace ARDOUR;
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;
47 ALSADeviceInfo AlsaAudioBackend::_input_audio_device_info;
48 ALSADeviceInfo AlsaAudioBackend::_output_audio_device_info;
50 AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
51 : AudioBackend (e, info)
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)
64 , _samples_per_period (1024)
65 , _periods_per_cycle (2)
68 , _systemic_audio_input_latency (0)
69 , _systemic_audio_output_latency (0)
71 , _processed_samples (0)
74 , _port_change_flag (false)
76 _instance_name = s_instance_name;
77 pthread_mutex_init (&_port_callback_mutex, 0);
78 _input_audio_device_info.valid = false;
79 _output_audio_device_info.valid = false;
81 _port_connection_queue.reserve (128);
84 AlsaAudioBackend::~AlsaAudioBackend ()
86 pthread_mutex_destroy (&_port_callback_mutex);
89 /* AUDIOBACKEND API */
92 AlsaAudioBackend::name () const
98 AlsaAudioBackend::is_realtime () const
103 std::vector<AudioBackend::DeviceStatus>
104 AlsaAudioBackend::enumerate_devices () const
106 _duplex_audio_device_status.clear();
107 std::map<std::string, std::string> devices;
108 get_alsa_audio_device_names(devices);
109 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
110 if (_input_audio_device == "") _input_audio_device = i->first;
111 if (_output_audio_device == "") _output_audio_device = i->first;
112 _duplex_audio_device_status.push_back (DeviceStatus (i->first, true));
114 return _duplex_audio_device_status;
117 std::vector<AudioBackend::DeviceStatus>
118 AlsaAudioBackend::enumerate_input_devices () const
120 _input_audio_device_status.clear();
121 std::map<std::string, std::string> devices;
122 get_alsa_audio_device_names(devices, HalfDuplexIn);
123 _input_audio_device_status.push_back (DeviceStatus (get_standard_device_name(DeviceNone), true));
124 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
125 if (_input_audio_device == "") _input_audio_device = i->first;
126 _input_audio_device_status.push_back (DeviceStatus (i->first, true));
128 return _input_audio_device_status;
131 std::vector<AudioBackend::DeviceStatus>
132 AlsaAudioBackend::enumerate_output_devices () const
134 _output_audio_device_status.clear();
135 std::map<std::string, std::string> devices;
136 get_alsa_audio_device_names(devices, HalfDuplexOut);
137 _output_audio_device_status.push_back (DeviceStatus (get_standard_device_name(DeviceNone), true));
138 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
139 if (_output_audio_device == "") _output_audio_device = i->first;
140 _output_audio_device_status.push_back (DeviceStatus (i->first, true));
142 return _output_audio_device_status;
146 AlsaAudioBackend::reservation_stdout (std::string d, size_t /* s */)
148 if (d.substr(0, 19) == "Acquired audio-card") {
149 _reservation_succeeded = true;
154 AlsaAudioBackend::release_device()
156 _reservation_connection.drop_connections();
157 ARDOUR::SystemExec * tmp = _device_reservation;
158 _device_reservation = 0;
163 AlsaAudioBackend::acquire_device(const char* device_name)
165 /* This is quick hack, ideally we'll link against libdbus and implement a dbus-listener
166 * that owns the device. here we try to get away by just requesting it and then block it...
167 * (pulseaudio periodically checks anyway)
169 * dbus-send --session --print-reply --type=method_call --dest=org.freedesktop.ReserveDevice1.Audio2 /org/freedesktop/ReserveDevice1/Audio2 org.freedesktop.ReserveDevice1.RequestRelease int32:4
170 * -> should not return 'boolean false'
172 int device_number = card_to_num(device_name);
173 if (device_number < 0) return false;
175 assert(_device_reservation == 0);
176 _reservation_succeeded = false;
178 std::string request_device_exe;
179 if (!PBD::find_file (
180 PBD::Searchpath(Glib::build_filename(ARDOUR::ardour_dll_directory(), "ardouralsautil")
181 + G_SEARCHPATH_SEPARATOR_S + ARDOUR::ardour_dll_directory()),
182 "ardour-request-device", request_device_exe))
184 PBD::warning << "ardour-request-device binary was not found..'" << endmsg;
191 argp=(char**) calloc(5,sizeof(char*));
192 argp[0] = strdup(request_device_exe.c_str());
193 argp[1] = strdup("-P");
194 snprintf(tmp, sizeof(tmp), "%d", getpid());
195 argp[2] = strdup(tmp);
196 snprintf(tmp, sizeof(tmp), "Audio%d", device_number);
197 argp[3] = strdup(tmp);
200 _device_reservation = new ARDOUR::SystemExec(request_device_exe, argp);
201 _device_reservation->ReadStdout.connect_same_thread (_reservation_connection, boost::bind (&AlsaAudioBackend::reservation_stdout, this, _1 ,_2));
202 _device_reservation->Terminated.connect_same_thread (_reservation_connection, boost::bind (&AlsaAudioBackend::release_device, this));
203 if (_device_reservation->start(0)) {
204 PBD::warning << _("AlsaAudioBackend: Device Request failed.") << endmsg;
209 // wait to check if reservation suceeded.
210 int timeout = 500; // 5 sec
211 while (_device_reservation && !_reservation_succeeded && --timeout > 0) {
214 if (timeout == 0 || !_reservation_succeeded) {
215 PBD::warning << _("AlsaAudioBackend: Device Reservation failed.") << endmsg;
223 AlsaAudioBackend::available_sample_rates2 (const std::string& input_device, const std::string& output_device) const
225 std::vector<float> sr;
226 if (input_device == get_standard_device_name(DeviceNone) && output_device == get_standard_device_name(DeviceNone)) {
229 else if (input_device == get_standard_device_name(DeviceNone)) {
230 sr = available_sample_rates (output_device);
232 else if (output_device == get_standard_device_name(DeviceNone)) {
233 sr = available_sample_rates (input_device);
235 std::vector<float> sr_in = available_sample_rates (input_device);
236 std::vector<float> sr_out = available_sample_rates (output_device);
237 std::set_intersection (sr_in.begin(), sr_in.end(), sr_out.begin(), sr_out.end(), std::back_inserter(sr));
243 AlsaAudioBackend::available_sample_rates (const std::string& device) const
245 ALSADeviceInfo *nfo = NULL;
246 std::vector<float> sr;
247 if (device == get_standard_device_name(DeviceNone)) {
250 if (device == _input_audio_device && _input_audio_device_info.valid) {
251 nfo = &_input_audio_device_info;
253 else if (device == _output_audio_device && _output_audio_device_info.valid) {
254 nfo = &_output_audio_device_info;
257 static const float avail_rates [] = { 8000, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
259 for (size_t i = 0 ; i < sizeof(avail_rates) / sizeof(float); ++i) {
260 if (!nfo || (avail_rates[i] >= nfo->min_rate && avail_rates[i] <= nfo->max_rate)) {
261 sr.push_back (avail_rates[i]);
268 std::vector<uint32_t>
269 AlsaAudioBackend::available_buffer_sizes2 (const std::string& input_device, const std::string& output_device) const
271 std::vector<uint32_t> bs;
272 if (input_device == get_standard_device_name(DeviceNone) && output_device == get_standard_device_name(DeviceNone)) {
275 else if (input_device == get_standard_device_name(DeviceNone)) {
276 bs = available_buffer_sizes (output_device);
278 else if (output_device == get_standard_device_name(DeviceNone)) {
279 bs = available_buffer_sizes (input_device);
281 std::vector<uint32_t> bs_in = available_buffer_sizes (input_device);
282 std::vector<uint32_t> bs_out = available_buffer_sizes (output_device);
283 std::set_intersection (bs_in.begin(), bs_in.end(), bs_out.begin(), bs_out.end(), std::back_inserter(bs));
288 std::vector<uint32_t>
289 AlsaAudioBackend::available_buffer_sizes (const std::string& device) const
291 ALSADeviceInfo *nfo = NULL;
292 std::vector<uint32_t> bs;
293 if (device == get_standard_device_name(DeviceNone)) {
296 if (device == _input_audio_device && _input_audio_device_info.valid) {
297 nfo = &_input_audio_device_info;
299 else if (device == _output_audio_device && _output_audio_device_info.valid) {
300 nfo = &_output_audio_device_info;
303 static const unsigned long avail_sizes [] = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
305 for (size_t i = 0 ; i < sizeof(avail_sizes) / sizeof(unsigned long); ++i) {
306 if (!nfo || (avail_sizes[i] >= nfo->min_size && avail_sizes[i] <= nfo->max_size)) {
307 bs.push_back (avail_sizes[i]);
314 AlsaAudioBackend::available_input_channel_count (const std::string& device) const
316 if (device == get_standard_device_name(DeviceNone)) {
319 if (device == _input_audio_device && _input_audio_device_info.valid) {
320 return _input_audio_device_info.max_channels;
326 AlsaAudioBackend::available_output_channel_count (const std::string& device) const
328 if (device == get_standard_device_name(DeviceNone)) {
331 if (device == _output_audio_device && _output_audio_device_info.valid) {
332 return _output_audio_device_info.max_channels;
337 std::vector<uint32_t>
338 AlsaAudioBackend::available_period_sizes (const std::string& driver) const
340 std::vector<uint32_t> ps;
347 AlsaAudioBackend::can_change_sample_rate_when_running () const
353 AlsaAudioBackend::can_change_buffer_size_when_running () const
355 return false; // why not? :)
359 AlsaAudioBackend::set_input_device_name (const std::string& d)
361 if (_input_audio_device == d) {
364 _input_audio_device = d;
366 if (d == get_standard_device_name(DeviceNone)) {
367 _input_audio_device_info.valid = false;
370 std::string alsa_device;
371 std::map<std::string, std::string> devices;
373 get_alsa_audio_device_names(devices, HalfDuplexIn);
374 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
376 alsa_device = i->second;
380 if (alsa_device == "") {
381 _input_audio_device_info.valid = false;
384 /* device will be busy once used, hence cache the parameters */
385 /* return */ get_alsa_device_parameters (alsa_device.c_str(), true, &_input_audio_device_info);
390 AlsaAudioBackend::set_output_device_name (const std::string& d)
392 if (_output_audio_device == d) {
396 _output_audio_device = d;
398 if (d == get_standard_device_name(DeviceNone)) {
399 _output_audio_device_info.valid = false;
402 std::string alsa_device;
403 std::map<std::string, std::string> devices;
405 get_alsa_audio_device_names(devices, HalfDuplexOut);
406 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
408 alsa_device = i->second;
412 if (alsa_device == "") {
413 _output_audio_device_info.valid = false;
416 /* return */ get_alsa_device_parameters (alsa_device.c_str(), true, &_output_audio_device_info);
421 AlsaAudioBackend::set_device_name (const std::string& d)
424 rv |= set_input_device_name (d);
425 rv |= set_output_device_name (d);
430 AlsaAudioBackend::set_sample_rate (float sr)
432 if (sr <= 0) { return -1; }
434 engine.sample_rate_change (sr);
439 AlsaAudioBackend::set_peridod_size (uint32_t n)
441 if (n == 0 || n > 3) {
447 _periods_per_cycle = n;
452 AlsaAudioBackend::set_buffer_size (uint32_t bs)
454 if (bs <= 0 || bs >= _max_buffer_size) {
460 _samples_per_period = bs;
461 engine.buffer_size_change (bs);
466 AlsaAudioBackend::set_interleaved (bool yn)
468 if (!yn) { return 0; }
473 AlsaAudioBackend::set_input_channels (uint32_t cc)
480 AlsaAudioBackend::set_output_channels (uint32_t cc)
487 AlsaAudioBackend::set_systemic_input_latency (uint32_t sl)
489 _systemic_audio_input_latency = sl;
491 update_systemic_audio_latencies();
497 AlsaAudioBackend::set_systemic_output_latency (uint32_t sl)
499 _systemic_audio_output_latency = sl;
501 update_systemic_audio_latencies();
507 AlsaAudioBackend::set_systemic_midi_input_latency (std::string const device, uint32_t sl)
509 struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
511 nfo->systemic_input_latency = sl;
512 if (_run && nfo->enabled) {
513 update_systemic_midi_latencies ();
519 AlsaAudioBackend::set_systemic_midi_output_latency (std::string const device, uint32_t sl)
521 struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
523 nfo->systemic_output_latency = sl;
524 if (_run && nfo->enabled) {
525 update_systemic_midi_latencies ();
531 AlsaAudioBackend::update_systemic_audio_latencies ()
533 const uint32_t lcpp = (_periods_per_cycle - 2) * _samples_per_period;
536 lr.min = lr.max = lcpp + (_measure_latency ? 0 : _systemic_audio_input_latency);
537 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
538 set_latency_range (*it, true, lr);
541 lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency);
542 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
543 set_latency_range (*it, false, lr);
549 AlsaAudioBackend::update_systemic_midi_latencies ()
552 for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
553 assert (_rmidi_out.size() > i);
554 AlsaMidiOut *rm = _rmidi_out.at(i);
555 struct AlsaMidiDeviceInfo * nfo = midi_device_info (rm->name());
558 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency);
559 set_latency_range (*it, false, lr);
563 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
564 assert (_rmidi_in.size() > i);
565 AlsaMidiIO *rm = _rmidi_in.at(i);
566 struct AlsaMidiDeviceInfo * nfo = midi_device_info (rm->name());
569 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
570 set_latency_range (*it, true, lr);
575 /* Retrieving parameters */
577 AlsaAudioBackend::device_name () const
579 if (_input_audio_device != get_standard_device_name(DeviceNone)) {
580 return _input_audio_device;
582 if (_output_audio_device != get_standard_device_name(DeviceNone)) {
583 return _output_audio_device;
589 AlsaAudioBackend::input_device_name () const
591 return _input_audio_device;
595 AlsaAudioBackend::output_device_name () const
597 return _output_audio_device;
601 AlsaAudioBackend::sample_rate () const
607 AlsaAudioBackend::buffer_size () const
609 return _samples_per_period;
613 AlsaAudioBackend::period_size () const
615 return _periods_per_cycle;
619 AlsaAudioBackend::interleaved () const
625 AlsaAudioBackend::input_channels () const
631 AlsaAudioBackend::output_channels () const
637 AlsaAudioBackend::systemic_input_latency () const
639 return _systemic_audio_input_latency;
643 AlsaAudioBackend::systemic_output_latency () const
645 return _systemic_audio_output_latency;
649 AlsaAudioBackend::systemic_midi_input_latency (std::string const device) const
651 struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
653 return nfo->systemic_input_latency;
657 AlsaAudioBackend::systemic_midi_output_latency (std::string const device) const
659 struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
661 return nfo->systemic_output_latency;
665 struct AlsaAudioBackend::AlsaMidiDeviceInfo *
666 AlsaAudioBackend::midi_device_info(std::string const name) const {
667 for (std::map<std::string, struct AlsaMidiDeviceInfo*>::const_iterator i = _midi_devices.begin (); i != _midi_devices.end(); ++i) {
668 if (i->first == name) {
673 assert(_midi_driver_option != get_standard_device_name(DeviceNone));
675 std::map<std::string, std::string> devices;
676 if (_midi_driver_option == _("ALSA raw devices")) {
677 get_alsa_rawmidi_device_names(devices);
679 get_alsa_sequencer_names (devices);
682 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
683 if (i->first == name) {
684 _midi_devices[name] = new AlsaMidiDeviceInfo();
685 return _midi_devices[name];
691 std::vector<std::string>
692 AlsaAudioBackend::enumerate_midi_options () const
694 if (_midi_options.empty()) {
695 _midi_options.push_back (_("ALSA raw devices"));
696 _midi_options.push_back (_("ALSA sequencer"));
697 _midi_options.push_back (get_standard_device_name(DeviceNone));
699 return _midi_options;
702 std::vector<AudioBackend::DeviceStatus>
703 AlsaAudioBackend::enumerate_midi_devices () const
705 _midi_device_status.clear();
706 std::map<std::string, std::string> devices;
708 if (_midi_driver_option == _("ALSA raw devices")) {
709 get_alsa_rawmidi_device_names (devices);
711 else if (_midi_driver_option == _("ALSA sequencer")) {
712 get_alsa_sequencer_names (devices);
715 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
716 _midi_device_status.push_back (DeviceStatus (i->first, true));
718 return _midi_device_status;
722 AlsaAudioBackend::set_midi_option (const std::string& opt)
724 if (opt != get_standard_device_name(DeviceNone) && opt != _("ALSA raw devices") && opt != _("ALSA sequencer")) {
727 if (_run && _midi_driver_option != opt) {
730 _midi_driver_option = opt;
735 AlsaAudioBackend::midi_option () const
737 return _midi_driver_option;
741 AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable)
743 struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
745 const bool prev_enabled = nfo->enabled;
746 nfo->enabled = enable;
748 if (_run && prev_enabled != enable) {
750 // add ports for the given device
751 register_system_midi_ports(device);
753 // remove all ports provided by the given device
755 for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end ();) {
756 assert (_rmidi_out.size() > i);
757 AlsaMidiOut *rm = _rmidi_out.at(i);
758 if (rm->name () != device) { ++it; ++i; continue; }
759 it = _system_midi_out.erase (it);
760 unregister_port (*it);
762 _rmidi_out.erase (_rmidi_out.begin() + i);
767 for (std::vector<AlsaPort*>::iterator it = _system_midi_in.begin (); it != _system_midi_in.end ();) {
768 assert (_rmidi_in.size() > i);
769 AlsaMidiIn *rm = _rmidi_in.at(i);
770 if (rm->name () != device) { ++it; ++i; continue; }
771 it = _system_midi_in.erase (it);
772 unregister_port (*it);
774 _rmidi_in.erase (_rmidi_in.begin() + i);
778 update_systemic_midi_latencies ();
784 AlsaAudioBackend::midi_device_enabled (std::string const device) const
786 struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
787 if (!nfo) return false;
793 static void * pthread_process (void *arg)
795 AlsaAudioBackend *d = static_cast<AlsaAudioBackend *>(arg);
796 d->main_process_thread ();
802 AlsaAudioBackend::_start (bool for_latency_measurement)
804 if (!_active && _run) {
805 // recover from 'halted', reap threads
809 if (_active || _run) {
810 if (for_latency_measurement != _measure_latency) {
811 _measure_latency = for_latency_measurement;
812 update_systemic_audio_latencies();
813 update_systemic_midi_latencies ();
814 PBD::info << _("AlsaAudioBackend: reload latencies.") << endmsg;
817 PBD::info << _("AlsaAudioBackend: already active.") << endmsg;
818 return BackendReinitializationError;
821 if (_ports.size () || _portmap.size ()) {
822 PBD::warning << _("AlsaAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
823 _system_inputs.clear();
824 _system_outputs.clear();
825 _system_midi_in.clear();
826 _system_midi_out.clear();
831 /* reset internal state */
833 _freewheeling = false;
835 _last_process_start = 0;
839 assert(_rmidi_in.size() == 0);
840 assert(_rmidi_out.size() == 0);
844 std::string audio_device;
845 std::string alsa_device;
846 std::map<std::string, std::string> devices;
848 if (_input_audio_device == get_standard_device_name(DeviceNone) && _output_audio_device == get_standard_device_name(DeviceNone)) {
849 PBD::error << _("AlsaAudioBackend: At least one of input or output device needs to be set.");
850 return AudioDeviceInvalidError;
853 if (_input_audio_device != _output_audio_device) {
854 if (_input_audio_device != get_standard_device_name(DeviceNone) && _output_audio_device != get_standard_device_name(DeviceNone)) {
855 PBD::error << _("AlsaAudioBackend: Cannot use two different devices.");
856 return AudioDeviceInvalidError;
858 if (_input_audio_device != get_standard_device_name(DeviceNone)) {
859 get_alsa_audio_device_names(devices, HalfDuplexIn);
860 audio_device = _input_audio_device;
863 get_alsa_audio_device_names(devices, HalfDuplexOut);
864 audio_device = _output_audio_device;
868 get_alsa_audio_device_names(devices);
869 audio_device = _input_audio_device;
873 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
874 if (i->first == audio_device) {
875 alsa_device = i->second;
879 if (alsa_device == "") {
880 PBD::error << _("AlsaAudioBackend: Cannot find configured device. Is it still connected?");
881 return AudioDeviceNotAvailableError;
884 acquire_device(alsa_device.c_str());
885 _pcmi = new Alsa_pcmi (
886 (duplex & 2) ? alsa_device.c_str() : NULL,
887 (duplex & 1) ? alsa_device.c_str() : NULL,
889 _samplerate, _samples_per_period,
890 _periods_per_cycle, /* _periods_per_cycle */ 2,
893 AudioBackend::ErrorCode error_code = NoError;
894 switch (_pcmi->state()) {
898 PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg;
899 error_code = AudioDeviceOpenError;
902 PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg;
903 error_code = AudioDeviceOpenError;
906 PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.")
908 error_code = SampleRateNotSupportedError;
911 PBD::error << _("AlsaAudioBackend: cannot set requested period size.")
913 error_code = PeriodSizeNotSupportedError;
916 PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.")
918 error_code = PeriodCountNotSupportedError;
921 PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg;
922 error_code = SampleFormatNotSupportedError;
925 PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg;
926 error_code = AudioDeviceOpenError;
930 if (_pcmi->state ()) {
931 delete _pcmi; _pcmi = 0;
940 if (_n_outputs != _pcmi->nplay ()) {
941 if (_n_outputs == 0) {
942 _n_outputs = _pcmi->nplay ();
944 _n_outputs = std::min (_n_outputs, _pcmi->nplay ());
946 PBD::warning << _("AlsaAudioBackend: adjusted output channel count to match device.") << endmsg;
949 if (_n_inputs != _pcmi->ncapt ()) {
950 if (_n_inputs == 0) {
951 _n_inputs = _pcmi->ncapt ();
953 _n_inputs = std::min (_n_inputs, _pcmi->ncapt ());
955 PBD::warning << _("AlsaAudioBackend: adjusted input channel count to match device.") << endmsg;
958 if (_pcmi->fsize() != _samples_per_period) {
959 _samples_per_period = _pcmi->fsize();
960 PBD::warning << _("AlsaAudioBackend: samples per period does not match.") << endmsg;
963 if (_pcmi->fsamp() != _samplerate) {
964 _samplerate = _pcmi->fsamp();
965 engine.sample_rate_change (_samplerate);
966 PBD::warning << _("AlsaAudioBackend: sample rate does not match.") << endmsg;
969 _measure_latency = for_latency_measurement;
971 _midi_ins = _midi_outs = 0;
972 register_system_midi_ports();
974 if (register_system_audio_ports()) {
975 PBD::error << _("AlsaAudioBackend: failed to register system ports.") << endmsg;
976 delete _pcmi; _pcmi = 0;
978 return PortRegistrationError;
981 engine.sample_rate_change (_samplerate);
982 engine.buffer_size_change (_samples_per_period);
984 if (engine.reestablish_ports ()) {
985 PBD::error << _("AlsaAudioBackend: Could not re-establish ports.") << endmsg;
986 delete _pcmi; _pcmi = 0;
988 return PortReconnectError;
991 engine.reconnect_ports ();
993 _port_change_flag = false;
995 if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, -20, 100000,
996 &_main_thread, pthread_process, this))
998 if (pthread_create (&_main_thread, NULL, pthread_process, this))
1000 PBD::error << _("AlsaAudioBackend: failed to create process thread.") << endmsg;
1001 delete _pcmi; _pcmi = 0;
1004 return ProcessThreadStartError;
1006 PBD::warning << _("AlsaAudioBackend: cannot acquire realtime permissions.") << endmsg;
1011 while (!_active && --timeout > 0) { Glib::usleep (1000); }
1013 if (timeout == 0 || !_active) {
1014 PBD::error << _("AlsaAudioBackend: failed to start process thread.") << endmsg;
1015 delete _pcmi; _pcmi = 0;
1018 return ProcessThreadStartError;
1025 AlsaAudioBackend::stop ()
1033 if (pthread_join (_main_thread, &status)) {
1034 PBD::error << _("AlsaAudioBackend: failed to terminate.") << endmsg;
1038 while (!_rmidi_out.empty ()) {
1039 AlsaMidiIO *m = _rmidi_out.back ();
1041 _rmidi_out.pop_back ();
1044 while (!_rmidi_in.empty ()) {
1045 AlsaMidiIO *m = _rmidi_in.back ();
1047 _rmidi_in.pop_back ();
1052 delete _pcmi; _pcmi = 0;
1053 _midi_ins = _midi_outs = 0;
1055 _measure_latency = false;
1057 return (_active == false) ? 0 : -1;
1061 AlsaAudioBackend::freewheel (bool onoff)
1063 _freewheeling = onoff;
1068 AlsaAudioBackend::dsp_load () const
1070 return 100.f * _dsp_load;
1074 AlsaAudioBackend::raw_buffer_size (DataType t)
1077 case DataType::AUDIO:
1078 return _samples_per_period * sizeof(Sample);
1079 case DataType::MIDI:
1080 return _max_buffer_size; // XXX not really limited
1087 AlsaAudioBackend::sample_time ()
1089 return _processed_samples;
1093 AlsaAudioBackend::sample_time_at_cycle_start ()
1095 return _processed_samples;
1099 AlsaAudioBackend::samples_since_cycle_start ()
1101 if (!_active || !_run || _freewheeling || _freewheel) {
1104 if (_last_process_start == 0) {
1108 const int64_t elapsed_time_us = g_get_monotonic_time() - _last_process_start;
1109 return std::max((pframes_t)0, (pframes_t)rint(1e-6 * elapsed_time_us * _samplerate));
1114 AlsaAudioBackend::alsa_process_thread (void *arg)
1116 ThreadData* td = reinterpret_cast<ThreadData*> (arg);
1117 boost::function<void ()> f = td->f;
1124 AlsaAudioBackend::create_process_thread (boost::function<void()> func)
1126 pthread_t thread_id;
1127 pthread_attr_t attr;
1128 size_t stacksize = 100000;
1130 ThreadData* td = new ThreadData (this, func, stacksize);
1132 if (pbd_realtime_pthread_create (PBD_SCHED_FIFO, -22, stacksize,
1133 &thread_id, alsa_process_thread, td)) {
1134 pthread_attr_init (&attr);
1135 pthread_attr_setstacksize (&attr, stacksize);
1136 if (pthread_create (&thread_id, &attr, alsa_process_thread, td)) {
1137 PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
1138 pthread_attr_destroy (&attr);
1141 pthread_attr_destroy (&attr);
1144 _threads.push_back (thread_id);
1149 AlsaAudioBackend::join_process_threads ()
1153 for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
1156 if (pthread_join (*i, &status)) {
1157 PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
1166 AlsaAudioBackend::in_process_thread ()
1168 if (pthread_equal (_main_thread, pthread_self()) != 0) {
1172 for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
1174 if (pthread_equal (*i, pthread_self ()) != 0) {
1182 AlsaAudioBackend::process_thread_count ()
1184 return _threads.size ();
1188 AlsaAudioBackend::update_latencies ()
1190 // trigger latency callback in RT thread (locked graph)
1191 port_connect_add_remove_callback();
1194 /* PORTENGINE API */
1197 AlsaAudioBackend::private_handle () const
1203 AlsaAudioBackend::my_name () const
1205 return _instance_name;
1209 AlsaAudioBackend::available () const
1211 return _run && _active;
1215 AlsaAudioBackend::port_name_size () const
1221 AlsaAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
1223 std::string newname (_instance_name + ":" + name);
1224 if (!valid_port (port)) {
1225 PBD::error << _("AlsaBackend::set_port_name: Invalid Port") << endmsg;
1228 if (find_port (newname)) {
1229 PBD::error << _("AlsaBackend::set_port_name: Port with given name already exists") << endmsg;
1233 AlsaPort* p = static_cast<AlsaPort*>(port);
1234 _portmap.erase (p->name());
1235 _portmap.insert (make_pair (newname, p));
1236 return p->set_name (newname);
1240 AlsaAudioBackend::get_port_name (PortEngine::PortHandle port) const
1242 if (!valid_port (port)) {
1243 PBD::warning << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
1244 return std::string ();
1246 return static_cast<AlsaPort*>(port)->name ();
1250 AlsaAudioBackend::get_port_property (PortHandle port, const std::string& key, std::string& value, std::string& type) const
1252 if (!valid_port (port)) {
1253 PBD::warning << _("AlsaBackend::get_port_property: Invalid Port(s)") << endmsg;
1256 if (key == "http://jackaudio.org/metadata/pretty-name") {
1258 value = static_cast<AlsaPort*>(port)->pretty_name ();
1259 if (!value.empty()) {
1267 AlsaAudioBackend::set_port_property (PortHandle port, const std::string& key, const std::string& value, const std::string& type)
1269 if (!valid_port (port)) {
1270 PBD::warning << _("AlsaBackend::set_port_property: Invalid Port(s)") << endmsg;
1273 if (key == "http://jackaudio.org/metadata/pretty-name" && type.empty ()) {
1274 static_cast<AlsaPort*>(port)->set_pretty_name (value);
1280 PortEngine::PortHandle
1281 AlsaAudioBackend::get_port_by_name (const std::string& name) const
1283 PortHandle port = (PortHandle) find_port (name);
1288 AlsaAudioBackend::get_ports (
1289 const std::string& port_name_pattern,
1290 DataType type, PortFlags flags,
1291 std::vector<std::string>& port_names) const
1295 bool use_regexp = false;
1296 if (port_name_pattern.size () > 0) {
1297 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
1302 for (PortIndex::const_iterator i = _ports.begin (); i != _ports.end (); ++i) {
1303 AlsaPort* port = *i;
1304 if ((port->type () == type) && flags == (port->flags () & flags)) {
1305 if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
1306 port_names.push_back (port->name ());
1312 regfree (&port_regex);
1318 AlsaAudioBackend::port_data_type (PortEngine::PortHandle port) const
1320 if (!valid_port (port)) {
1321 return DataType::NIL;
1323 return static_cast<AlsaPort*>(port)->type ();
1326 PortEngine::PortHandle
1327 AlsaAudioBackend::register_port (
1328 const std::string& name,
1329 ARDOUR::DataType type,
1330 ARDOUR::PortFlags flags)
1332 if (name.size () == 0) { return 0; }
1333 if (flags & IsPhysical) { return 0; }
1334 return add_port (_instance_name + ":" + name, type, flags);
1337 PortEngine::PortHandle
1338 AlsaAudioBackend::add_port (
1339 const std::string& name,
1340 ARDOUR::DataType type,
1341 ARDOUR::PortFlags flags)
1343 assert(name.size ());
1344 if (find_port (name)) {
1345 PBD::error << _("AlsaBackend::register_port: Port already exists:")
1346 << " (" << name << ")" << endmsg;
1349 AlsaPort* port = NULL;
1351 case DataType::AUDIO:
1352 port = new AlsaAudioPort (*this, name, flags);
1354 case DataType::MIDI:
1355 port = new AlsaMidiPort (*this, name, flags);
1358 PBD::error << _("AlsaBackend::register_port: Invalid Data Type.") << endmsg;
1362 _ports.insert (port);
1363 _portmap.insert (make_pair (name, port));
1369 AlsaAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
1374 AlsaPort* port = static_cast<AlsaPort*>(port_handle);
1375 PortIndex::iterator i = std::find (_ports.begin(), _ports.end(), static_cast<AlsaPort*>(port_handle));
1376 if (i == _ports.end ()) {
1377 PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
1380 disconnect_all(port_handle);
1381 _portmap.erase (port->name());
1387 AlsaAudioBackend::register_system_audio_ports()
1391 const int a_ins = _n_inputs;
1392 const int a_out = _n_outputs;
1394 const uint32_t lcpp = (_periods_per_cycle - 2) * _samples_per_period;
1397 lr.min = lr.max = (_systemic_audio_input_latency);
1398 for (int i = 1; i <= a_ins; ++i) {
1400 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
1401 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1403 set_latency_range (p, false, lr);
1404 AlsaPort *ap = static_cast<AlsaPort*>(p);
1405 //ap->set_pretty_name ("")
1406 _system_inputs.push_back (ap);
1409 lr.min = lr.max = lcpp + (_systemic_audio_output_latency);
1410 for (int i = 1; i <= a_out; ++i) {
1412 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
1413 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1415 set_latency_range (p, true, lr);
1416 AlsaPort *ap = static_cast<AlsaPort*>(p);
1417 //ap->set_pretty_name ("")
1418 _system_outputs.push_back (ap);
1423 /* libs/ardouralsautil/devicelist.cc appends either of
1424 * " (IO)", " (I)", or " (O)"
1425 * depending of the device is full-duples or half-duplex
1427 static std::string replace_name_io (std::string const& name, bool in)
1429 if (name.empty ()) {
1432 size_t pos = name.find_last_of ('(');
1433 if (pos == std::string::npos) {
1434 assert (0); // this should never happen.
1437 return name.substr (0, pos) + "(" + (in ? "In" : "Out") + ")";
1441 AlsaAudioBackend::register_system_midi_ports(const std::string device)
1443 std::map<std::string, std::string> devices;
1445 // TODO use consistent numbering when re-adding devices: _midi_ins, _midi_outs
1447 if (_midi_driver_option == get_standard_device_name(DeviceNone)) {
1449 } else if (_midi_driver_option == _("ALSA raw devices")) {
1450 get_alsa_rawmidi_device_names(devices);
1452 get_alsa_sequencer_names (devices);
1455 for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
1456 if (!device.empty() && device != i->first) {
1459 struct AlsaMidiDeviceInfo * nfo = midi_device_info(i->first);
1461 if (!nfo->enabled) continue;
1464 if (_midi_driver_option == _("ALSA raw devices")) {
1465 mout = new AlsaRawMidiOut (i->first, i->second.c_str());
1467 mout = new AlsaSeqMidiOut (i->first, i->second.c_str());
1470 if (mout->state ()) {
1471 PBD::warning << string_compose (
1472 _("AlsaMidiOut: failed to open midi device '%1'."), i->second)
1476 mout->setup_timing(_samples_per_period, _samplerate);
1477 mout->sync_time (g_get_monotonic_time());
1478 if (mout->start ()) {
1479 PBD::warning << string_compose (
1480 _("AlsaMidiOut: failed to start midi device '%1'."), i->second)
1485 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++_midi_ins);
1486 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1492 lr.min = lr.max = (nfo->systemic_output_latency);
1493 set_latency_range (p, true, lr);
1494 static_cast<AlsaMidiPort*>(p)->set_n_periods(_periods_per_cycle); // TODO check MIDI alignment
1495 AlsaPort *ap = static_cast<AlsaPort*>(p);
1496 ap->set_pretty_name (replace_name_io (i->first, false));
1497 _system_midi_out.push_back (ap);
1498 _rmidi_out.push_back (mout);
1503 if (_midi_driver_option == _("ALSA raw devices")) {
1504 midin = new AlsaRawMidiIn (i->first, i->second.c_str());
1506 midin = new AlsaSeqMidiIn (i->first, i->second.c_str());
1509 if (midin->state ()) {
1510 PBD::warning << string_compose (
1511 _("AlsaMidiIn: failed to open midi device '%1'."), i->second)
1515 midin->setup_timing(_samples_per_period, _samplerate);
1516 midin->sync_time (g_get_monotonic_time());
1517 if (midin->start ()) {
1518 PBD::warning << string_compose (
1519 _("AlsaMidiIn: failed to start midi device '%1'."), i->second)
1524 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++_midi_outs);
1525 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1532 lr.min = lr.max = (nfo->systemic_input_latency);
1533 set_latency_range (p, false, lr);
1534 AlsaPort *ap = static_cast<AlsaPort*>(p);
1535 ap->set_pretty_name (replace_name_io (i->first, true));
1536 _system_midi_in.push_back (ap);
1537 _rmidi_in.push_back (midin);
1545 AlsaAudioBackend::unregister_ports (bool system_only)
1547 _system_inputs.clear();
1548 _system_outputs.clear();
1549 _system_midi_in.clear();
1550 _system_midi_out.clear();
1552 for (PortIndex::iterator i = _ports.begin (); i != _ports.end ();) {
1553 PortIndex::iterator cur = i++;
1554 AlsaPort* port = *cur;
1555 if (! system_only || (port->is_physical () && port->is_terminal ())) {
1556 port->disconnect_all ();
1557 _portmap.erase (port->name());
1565 AlsaAudioBackend::connect (const std::string& src, const std::string& dst)
1567 AlsaPort* src_port = find_port (src);
1568 AlsaPort* dst_port = find_port (dst);
1571 PBD::error << _("AlsaBackend::connect: Invalid Source port:")
1572 << " (" << src <<")" << endmsg;
1576 PBD::error << _("AlsaBackend::connect: Invalid Destination port:")
1577 << " (" << dst <<")" << endmsg;
1580 return src_port->connect (dst_port);
1584 AlsaAudioBackend::disconnect (const std::string& src, const std::string& dst)
1586 AlsaPort* src_port = find_port (src);
1587 AlsaPort* dst_port = find_port (dst);
1589 if (!src_port || !dst_port) {
1590 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1593 return src_port->disconnect (dst_port);
1597 AlsaAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
1599 AlsaPort* dst_port = find_port (dst);
1600 if (!valid_port (src)) {
1601 PBD::error << _("AlsaBackend::connect: Invalid Source Port Handle") << endmsg;
1605 PBD::error << _("AlsaBackend::connect: Invalid Destination Port")
1606 << " (" << dst << ")" << endmsg;
1609 return static_cast<AlsaPort*>(src)->connect (dst_port);
1613 AlsaAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
1615 AlsaPort* dst_port = find_port (dst);
1616 if (!valid_port (src) || !dst_port) {
1617 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1620 return static_cast<AlsaPort*>(src)->disconnect (dst_port);
1624 AlsaAudioBackend::disconnect_all (PortEngine::PortHandle port)
1626 if (!valid_port (port)) {
1627 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1630 static_cast<AlsaPort*>(port)->disconnect_all ();
1635 AlsaAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
1637 if (!valid_port (port)) {
1638 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1641 return static_cast<AlsaPort*>(port)->is_connected ();
1645 AlsaAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
1647 AlsaPort* dst_port = find_port (dst);
1649 if (!valid_port (src) || !dst_port) {
1650 PBD::error << _("AlsaBackend::connected_to: Invalid Port") << endmsg;
1654 return static_cast<AlsaPort*>(src)->is_connected (dst_port);
1658 AlsaAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
1660 if (!valid_port (port)) {
1661 PBD::error << _("AlsaBackend::physically_connected: Invalid Port") << endmsg;
1664 return static_cast<AlsaPort*>(port)->is_physically_connected ();
1668 AlsaAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
1670 if (!valid_port (port)) {
1671 PBD::error << _("AlsaBackend::get_connections: Invalid Port") << endmsg;
1675 assert (0 == names.size ());
1677 const std::set<AlsaPort*>& connected_ports = static_cast<AlsaPort*>(port)->get_connections ();
1679 for (std::set<AlsaPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
1680 names.push_back ((*i)->name ());
1683 return (int)names.size ();
1688 AlsaAudioBackend::midi_event_get (
1689 pframes_t& timestamp,
1690 size_t& size, uint8_t const** buf, void* port_buffer,
1691 uint32_t event_index)
1693 assert (buf && port_buffer);
1694 AlsaMidiBuffer& source = * static_cast<AlsaMidiBuffer*>(port_buffer);
1695 if (event_index >= source.size ()) {
1698 AlsaMidiEvent const& event = source[event_index];
1700 timestamp = event.timestamp ();
1701 size = event.size ();
1702 *buf = event.data ();
1707 AlsaAudioBackend::midi_event_put (
1709 pframes_t timestamp,
1710 const uint8_t* buffer, size_t size)
1712 assert (buffer && port_buffer);
1713 if (size >= MaxAlsaMidiEventSize) {
1716 AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
1718 if (dst.size () && (pframes_t)dst.back ().timestamp () > timestamp) {
1719 // nevermind, ::get_buffer() sorts events
1720 fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
1721 (pframes_t)dst.back ().timestamp (), timestamp);
1724 dst.push_back (AlsaMidiEvent (timestamp, buffer, size));
1729 AlsaAudioBackend::get_midi_event_count (void* port_buffer)
1731 assert (port_buffer);
1732 return static_cast<AlsaMidiBuffer*>(port_buffer)->size ();
1736 AlsaAudioBackend::midi_clear (void* port_buffer)
1738 assert (port_buffer);
1739 AlsaMidiBuffer * buf = static_cast<AlsaMidiBuffer*>(port_buffer);
1747 AlsaAudioBackend::can_monitor_input () const
1753 AlsaAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
1759 AlsaAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
1765 AlsaAudioBackend::monitoring_input (PortEngine::PortHandle)
1770 /* Latency management */
1773 AlsaAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
1775 if (!valid_port (port)) {
1776 PBD::error << _("AlsaPort::set_latency_range (): invalid port.") << endmsg;
1778 static_cast<AlsaPort*>(port)->set_latency_range (latency_range, for_playback);
1782 AlsaAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
1785 if (!valid_port (port)) {
1786 PBD::error << _("AlsaPort::get_latency_range (): invalid port.") << endmsg;
1791 AlsaPort *p = static_cast<AlsaPort*>(port);
1794 r = p->latency_range (for_playback);
1795 if (p->is_physical() && p->is_terminal()) {
1796 if (p->is_input() && for_playback) {
1797 r.min += _samples_per_period;
1798 r.max += _samples_per_period;
1800 if (p->is_output() && !for_playback) {
1801 r.min += _samples_per_period;
1802 r.max += _samples_per_period;
1808 /* Discovering physical ports */
1811 AlsaAudioBackend::port_is_physical (PortEngine::PortHandle port) const
1813 if (!valid_port (port)) {
1814 PBD::error << _("AlsaPort::port_is_physical (): invalid port.") << endmsg;
1817 return static_cast<AlsaPort*>(port)->is_physical ();
1821 AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
1823 for (PortIndex::iterator i = _ports.begin (); i != _ports.end (); ++i) {
1824 AlsaPort* port = *i;
1825 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
1826 port_names.push_back (port->name ());
1832 AlsaAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
1834 for (PortIndex::iterator i = _ports.begin (); i != _ports.end (); ++i) {
1835 AlsaPort* port = *i;
1836 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
1837 port_names.push_back (port->name ());
1843 AlsaAudioBackend::n_physical_outputs () const
1847 for (PortIndex::const_iterator i = _ports.begin (); i != _ports.end (); ++i) {
1848 AlsaPort* port = *i;
1849 if (port->is_output () && port->is_physical ()) {
1850 switch (port->type ()) {
1851 case DataType::AUDIO: ++n_audio; break;
1852 case DataType::MIDI: ++n_midi; break;
1858 cc.set (DataType::AUDIO, n_audio);
1859 cc.set (DataType::MIDI, n_midi);
1864 AlsaAudioBackend::n_physical_inputs () const
1868 for (PortIndex::const_iterator i = _ports.begin (); i != _ports.end (); ++i) {
1869 AlsaPort* port = *i;
1870 if (port->is_input () && port->is_physical ()) {
1871 switch (port->type ()) {
1872 case DataType::AUDIO: ++n_audio; break;
1873 case DataType::MIDI: ++n_midi; break;
1879 cc.set (DataType::AUDIO, n_audio);
1880 cc.set (DataType::MIDI, n_midi);
1884 /* Getting access to the data buffer for a port */
1887 AlsaAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
1890 assert (valid_port (port));
1891 return static_cast<AlsaPort*>(port)->get_buffer (nframes);
1894 /* Engine Process */
1896 AlsaAudioBackend::main_process_thread ()
1898 AudioEngine::thread_init_callback (this);
1900 _processed_samples = 0;
1903 _pcmi->pcm_start ();
1904 int no_proc_errors = 0;
1905 const int bailout = 2 * _samplerate / _samples_per_period;
1907 manager.registration_callback();
1908 manager.graph_order_callback();
1914 if (_freewheeling != _freewheel) {
1915 _freewheel = _freewheeling;
1916 engine.freewheel_callback (_freewheel);
1920 nr = _pcmi->pcm_wait ();
1922 if (_pcmi->state () > 0) {
1926 if (_pcmi->state () < 0) {
1927 PBD::error << _("AlsaAudioBackend: I/O error. Audio Process Terminated.") << endmsg;
1930 if (no_proc_errors > bailout) {
1933 _("AlsaAudioBackend: Audio Process Terminated after %1 consecutive x-runs."),
1939 while (nr >= (long)_samples_per_period && _freewheeling == _freewheel) {
1941 clock1 = g_get_monotonic_time();
1944 _pcmi->capt_init (_samples_per_period);
1945 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) {
1946 _pcmi->capt_chan (i, (float*)((*it)->get_buffer(_samples_per_period)), _samples_per_period);
1948 _pcmi->capt_done (_samples_per_period);
1950 /* de-queue incoming midi*/
1952 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1953 assert (_rmidi_in.size() > i);
1954 AlsaMidiIn *rm = _rmidi_in.at(i);
1955 void *bptr = (*it)->get_buffer(0);
1957 uint8_t data[MaxAlsaMidiEventSize];
1958 size_t size = sizeof(data);
1960 while (rm->recv_event (time, data, size)) {
1961 midi_event_put(bptr, time, data, size);
1962 size = sizeof(data);
1964 rm->sync_time (clock1);
1967 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
1968 memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1971 /* call engine process callback */
1972 _last_process_start = g_get_monotonic_time();
1973 if (engine.process_callback (_samples_per_period)) {
1979 for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1980 static_cast<AlsaMidiPort*>(*it)->next_period();
1983 /* queue outgoing midi */
1985 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
1986 assert (_rmidi_out.size() > i);
1987 const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*it)->const_buffer();
1988 AlsaMidiOut *rm = _rmidi_out.at(i);
1989 rm->sync_time (clock1);
1990 for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
1991 rm->send_event (mit->timestamp (), mit->data (), mit->size ());
1995 /* write back audio */
1997 _pcmi->play_init (_samples_per_period);
1998 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it, ++i) {
1999 _pcmi->play_chan (i, (const float*)(*it)->get_buffer (_samples_per_period), _samples_per_period);
2001 for (; i < _pcmi->nplay (); ++i) {
2002 _pcmi->clear_chan (i, _samples_per_period);
2004 _pcmi->play_done (_samples_per_period);
2005 nr -= _samples_per_period;
2006 _processed_samples += _samples_per_period;
2008 _dsp_load_calc.set_max_time(_samplerate, _samples_per_period);
2009 _dsp_load_calc.set_start_timestamp_us (clock1);
2010 _dsp_load_calc.set_stop_timestamp_us (g_get_monotonic_time());
2011 _dsp_load = _dsp_load_calc.get_dsp_load ();
2014 if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) {
2017 fprintf(stderr, "ALSA x-run read: %.2f ms, write: %.2f ms\n",
2018 _pcmi->capt_xrun() * 1000.0, _pcmi->play_xrun() * 1000.0);
2024 // zero audio input buffers
2025 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
2026 memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
2029 clock1 = g_get_monotonic_time();
2031 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
2032 static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
2033 AlsaMidiIn *rm = _rmidi_in.at(i);
2034 void *bptr = (*it)->get_buffer(0);
2035 midi_clear(bptr); // zero midi buffer
2037 // TODO add an API call for this.
2039 uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
2040 size_t size = sizeof(data);
2041 while (rm->recv_event (time, data, size)) {
2042 ; // discard midi-data from HW.
2044 rm->sync_time (clock1);
2047 _last_process_start = 0;
2048 if (engine.process_callback (_samples_per_period)) {
2054 // drop all outgoing MIDI messages
2055 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
2056 void *bptr = (*it)->get_buffer(0);
2061 Glib::usleep (100); // don't hog cpu
2064 bool connections_changed = false;
2065 bool ports_changed = false;
2066 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
2067 if (_port_change_flag) {
2068 ports_changed = true;
2069 _port_change_flag = false;
2071 if (!_port_connection_queue.empty ()) {
2072 connections_changed = true;
2074 while (!_port_connection_queue.empty ()) {
2075 PortConnectData *c = _port_connection_queue.back ();
2076 manager.connect_callback (c->a, c->b, c->c);
2077 _port_connection_queue.pop_back ();
2080 pthread_mutex_unlock (&_port_callback_mutex);
2082 if (ports_changed) {
2083 manager.registration_callback();
2085 if (connections_changed) {
2086 manager.graph_order_callback();
2088 if (connections_changed || ports_changed) {
2089 engine.latency_callback(false);
2090 engine.latency_callback(true);
2097 engine.halted_callback("ALSA I/O error.");
2103 /******************************************************************************/
2105 static boost::shared_ptr<AlsaAudioBackend> _instance;
2107 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
2108 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
2109 static int deinstantiate ();
2110 static bool already_configured ();
2111 static bool available ();
2113 static ARDOUR::AudioBackendInfo _descriptor = {
2122 static boost::shared_ptr<AudioBackend>
2123 backend_factory (AudioEngine& e)
2126 _instance.reset (new AlsaAudioBackend (e, _descriptor));
2132 instantiate (const std::string& arg1, const std::string& /* arg2 */)
2134 s_instance_name = arg1;
2146 already_configured ()
2157 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
2159 return &_descriptor;
2163 /******************************************************************************/
2164 AlsaPort::AlsaPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2169 _capture_latency_range.min = 0;
2170 _capture_latency_range.max = 0;
2171 _playback_latency_range.min = 0;
2172 _playback_latency_range.max = 0;
2175 AlsaPort::~AlsaPort () {
2180 int AlsaPort::connect (AlsaPort *port)
2183 PBD::error << _("AlsaPort::connect (): invalid (null) port") << endmsg;
2187 if (type () != port->type ()) {
2188 PBD::error << _("AlsaPort::connect (): wrong port-type") << endmsg;
2192 if (is_output () && port->is_output ()) {
2193 PBD::error << _("AlsaPort::connect (): cannot inter-connect output ports.") << endmsg;
2197 if (is_input () && port->is_input ()) {
2198 PBD::error << _("AlsaPort::connect (): cannot inter-connect input ports.") << endmsg;
2203 PBD::error << _("AlsaPort::connect (): cannot self-connect ports.") << endmsg;
2207 if (is_connected (port)) {
2208 #if 0 // don't bother to warn about this for now. just ignore it
2209 PBD::error << _("AlsaPort::connect (): ports are already connected:")
2210 << " (" << name () << ") -> (" << port->name () << ")"
2216 _connect (port, true);
2221 void AlsaPort::_connect (AlsaPort *port, bool callback)
2223 _connections.insert (port);
2225 port->_connect (this, false);
2226 _alsa_backend.port_connect_callback (name(), port->name(), true);
2230 int AlsaPort::disconnect (AlsaPort *port)
2233 PBD::error << _("AlsaPort::disconnect (): invalid (null) port") << endmsg;
2237 if (!is_connected (port)) {
2238 PBD::error << _("AlsaPort::disconnect (): ports are not connected:")
2239 << " (" << name () << ") -> (" << port->name () << ")"
2243 _disconnect (port, true);
2247 void AlsaPort::_disconnect (AlsaPort *port, bool callback)
2249 std::set<AlsaPort*>::iterator it = _connections.find (port);
2250 assert (it != _connections.end ());
2251 _connections.erase (it);
2253 port->_disconnect (this, false);
2254 _alsa_backend.port_connect_callback (name(), port->name(), false);
2259 void AlsaPort::disconnect_all ()
2261 while (!_connections.empty ()) {
2262 std::set<AlsaPort*>::iterator it = _connections.begin ();
2263 (*it)->_disconnect (this, false);
2264 _alsa_backend.port_connect_callback (name(), (*it)->name(), false);
2265 _connections.erase (it);
2270 AlsaPort::is_connected (const AlsaPort *port) const
2272 return _connections.find (const_cast<AlsaPort *>(port)) != _connections.end ();
2275 bool AlsaPort::is_physically_connected () const
2277 for (std::set<AlsaPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
2278 if ((*it)->is_physical ()) {
2285 /******************************************************************************/
2287 AlsaAudioPort::AlsaAudioPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2288 : AlsaPort (b, name, flags)
2290 memset (_buffer, 0, sizeof (_buffer));
2291 mlock(_buffer, sizeof (_buffer));
2294 AlsaAudioPort::~AlsaAudioPort () { }
2296 void* AlsaAudioPort::get_buffer (pframes_t n_samples)
2299 const std::set<AlsaPort *>& connections = get_connections ();
2300 std::set<AlsaPort*>::const_iterator it = connections.begin ();
2301 if (it == connections.end ()) {
2302 memset (_buffer, 0, n_samples * sizeof (Sample));
2304 AlsaAudioPort const * source = static_cast<const AlsaAudioPort*>(*it);
2305 assert (source && source->is_output ());
2306 memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
2307 while (++it != connections.end ()) {
2308 source = static_cast<const AlsaAudioPort*>(*it);
2309 assert (source && source->is_output ());
2310 Sample* dst = buffer ();
2311 const Sample* src = source->const_buffer ();
2312 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
2322 AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2323 : AlsaPort (b, name, flags)
2327 _buffer[0].clear ();
2328 _buffer[1].clear ();
2329 _buffer[2].clear ();
2331 _buffer[0].reserve(256);
2332 _buffer[1].reserve(256);
2333 _buffer[2].reserve(256);
2336 AlsaMidiPort::~AlsaMidiPort () { }
2338 struct MidiEventSorter {
2339 bool operator() (AlsaMidiEvent const& a, AlsaMidiEvent const& b) {
2344 void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
2347 (_buffer[_bufperiod]).clear ();
2348 const std::set<AlsaPort*>& connections = get_connections ();
2349 for (std::set<AlsaPort*>::const_iterator i = connections.begin ();
2350 i != connections.end ();
2352 const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
2353 for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
2354 (_buffer[_bufperiod]).push_back (*it);
2357 std::stable_sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
2359 return &(_buffer[_bufperiod]);
2362 AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
2364 , _timestamp (timestamp)
2366 if (size > 0 && size < MaxAlsaMidiEventSize) {
2367 memcpy (_data, data, size);
2371 AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
2372 : _size (other.size ())
2373 , _timestamp (other.timestamp ())
2375 if (other._size > 0) {
2376 assert (other._size < MaxAlsaMidiEventSize);
2377 memcpy (_data, other._data, other._size);