diff options
author | Robin Gareus <robin@gareus.org> | 2015-05-05 17:28:31 +0200 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2015-06-01 01:02:38 +0200 |
commit | 1fe738a36eb826594194498ab88dcfa9891030d2 (patch) | |
tree | b5a639f2a69db404356849d8d75f0be26e59cb9c /libs | |
parent | 4d2bc612f236e51473d75c9dbc50b5968b27e1bc (diff) |
coreaudio support for multiple devices
Diffstat (limited to 'libs')
-rw-r--r-- | libs/backends/coreaudio/coreaudio_backend.cc | 114 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_backend.h | 15 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_pcmio.cc | 21 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_pcmio.h | 7 |
4 files changed, 134 insertions, 23 deletions
diff --git a/libs/backends/coreaudio/coreaudio_backend.cc b/libs/backends/coreaudio/coreaudio_backend.cc index d22d067e38..6cc2adf833 100644 --- a/libs/backends/coreaudio/coreaudio_backend.cc +++ b/libs/backends/coreaudio/coreaudio_backend.cc @@ -38,7 +38,9 @@ using namespace ARDOUR; static std::string s_instance_name; size_t CoreAudioBackend::_max_buffer_size = 8192; std::vector<std::string> CoreAudioBackend::_midi_options; -std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_audio_device_status; +std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_duplex_audio_device_status; +std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_input_audio_device_status; +std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_output_audio_device_status; /* static class instance access */ @@ -90,7 +92,8 @@ CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info) , _reinit_thread_callback (false) , _measure_latency (false) , _last_process_start (0) - , _audio_device("") + , _input_audio_device("") + , _output_audio_device("") , _midi_driver_option(_("None")) , _samplerate (48000) , _samples_per_period (1024) @@ -142,30 +145,67 @@ CoreAudioBackend::is_realtime () const std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::enumerate_devices () const { - _audio_device_status.clear(); + _duplex_audio_device_status.clear(); std::map<size_t, std::string> devices; - _pcmio->device_list(devices); + _pcmio->duplex_device_list(devices); for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) { - if (_audio_device == "") _audio_device = i->second; - _audio_device_status.push_back (DeviceStatus (i->second, true)); + if (_input_audio_device == "") _input_audio_device = i->second; + if (_output_audio_device == "") _output_audio_device = i->second; + _duplex_audio_device_status.push_back (DeviceStatus (i->second, true)); } - return _audio_device_status; + return _duplex_audio_device_status; +} + +std::vector<AudioBackend::DeviceStatus> +CoreAudioBackend::enumerate_input_devices () const +{ + _input_audio_device_status.clear(); + std::map<size_t, std::string> devices; + _pcmio->input_device_list(devices); + + for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) { + if (_input_audio_device == "") _input_audio_device = i->second; + _input_audio_device_status.push_back (DeviceStatus (i->second, true)); + } + return _input_audio_device_status; +} + + +std::vector<AudioBackend::DeviceStatus> +CoreAudioBackend::enumerate_output_devices () const +{ + _output_audio_device_status.clear(); + std::map<size_t, std::string> devices; + _pcmio->output_device_list(devices); + + for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) { + if (_output_audio_device == "") _output_audio_device = i->second; + _output_audio_device_status.push_back (DeviceStatus (i->second, true)); + } + return _output_audio_device_status; } std::vector<float> CoreAudioBackend::available_sample_rates (const std::string&) const { std::vector<float> sr; - _pcmio->available_sample_rates(name_to_id(_audio_device), sr); + std::vector<float> sr_in; + std::vector<float> sr_out; + + _pcmio->available_sample_rates(name_to_id(_input_audio_device), sr_in); + _pcmio->available_sample_rates(name_to_id(_output_audio_device), sr_out); + + // TODO allow to use different SR per device, tweak aggregate + std::set_intersection(sr_in.begin(), sr_in.end(), sr_out.begin(), sr_out.end(), std::back_inserter(sr)); return sr; } std::vector<uint32_t> -CoreAudioBackend::available_buffer_sizes (const std::string&) const +CoreAudioBackend::available_buffer_sizes (const std::string& device) const { std::vector<uint32_t> bs; - _pcmio->available_buffer_sizes(name_to_id(_audio_device), bs); + _pcmio->available_buffer_sizes(name_to_id(device), bs); return bs; } @@ -196,8 +236,27 @@ CoreAudioBackend::can_change_buffer_size_when_running () const int CoreAudioBackend::set_device_name (const std::string& d) { - _audio_device = d; - const float sr = _pcmio->current_sample_rate(name_to_id(_audio_device)); + int rv = 0; + rv |= set_input_device_name (d); + rv |= set_output_device_name (d); + return rv; +} + +int +CoreAudioBackend::set_input_device_name (const std::string& d) +{ + _input_audio_device = d; + const float sr = _pcmio->current_sample_rate(name_to_id(_input_audio_device)); + if (sr > 0) { set_sample_rate(sr); } + return 0; +} + +int +CoreAudioBackend::set_output_device_name (const std::string& d) +{ + _output_audio_device = d; + // TODO check SR. + const float sr = _pcmio->current_sample_rate(name_to_id(_output_audio_device)); if (sr > 0) { set_sample_rate(sr); } return 0; } @@ -205,8 +264,10 @@ CoreAudioBackend::set_device_name (const std::string& d) int CoreAudioBackend::set_sample_rate (float sr) { - if (sr <= 0) { return -1; } - // TODO check if it's in the list of valid SR + std::vector<float> srs = available_sample_rates (/* really ignored */_input_audio_device); + if (std::find(srs.begin(), srs.end(), sr) == srs.end()) { + return -1; + } _samplerate = sr; engine.sample_rate_change (sr); return 0; @@ -263,7 +324,19 @@ CoreAudioBackend::set_systemic_output_latency (uint32_t sl) std::string CoreAudioBackend::device_name () const { - return _audio_device; + return ""; +} + +std::string +CoreAudioBackend::input_device_name () const +{ + return _input_audio_device; +} + +std::string +CoreAudioBackend::output_device_name () const +{ + return _output_audio_device; } float @@ -339,7 +412,7 @@ CoreAudioBackend::midi_option () const void CoreAudioBackend::launch_control_app () { - _pcmio->launch_control_app(name_to_id(_audio_device)); + _pcmio->launch_control_app(name_to_id(_input_audio_device)); } /* State Control */ @@ -380,8 +453,8 @@ CoreAudioBackend::_start (bool for_latency_measurement) _ports.clear(); } - uint32_t device1 = name_to_id(_audio_device); // usually input, but in an aggregate, 1st defines the clock - uint32_t device2 = name_to_id(_audio_device); // usually output + uint32_t device1 = name_to_id(_input_audio_device); + uint32_t device2 = name_to_id(_output_audio_device); assert(_active_ca == false); assert(_active_fw == false); @@ -395,6 +468,7 @@ CoreAudioBackend::_start (bool for_latency_measurement) _pcmio->set_sample_rate_callback (sample_rate_callback_ptr, this); _pcmio->pcm_start (device1, device2, _samplerate, _samples_per_period, process_callback_ptr, this); + printf("STATE: %d\n", _pcmio->state ()); switch (_pcmio->state ()) { case 0: /* OK */ break; @@ -867,8 +941,8 @@ CoreAudioBackend::register_system_audio_ports() const uint32_t a_ins = _n_inputs; const uint32_t a_out = _n_outputs; - const uint32_t coreaudio_reported_input_latency = _pcmio->get_latency(name_to_id(_audio_device), true); - const uint32_t coreaudio_reported_output_latency = _pcmio->get_latency(name_to_id(_audio_device), false); + const uint32_t coreaudio_reported_input_latency = _pcmio->get_latency(name_to_id(_input_audio_device), true); + const uint32_t coreaudio_reported_output_latency = _pcmio->get_latency(name_to_id(_output_audio_device), false); #ifndef NDEBUG printf("COREAUDIO LATENCY: i:%d, o:%d\n", diff --git a/libs/backends/coreaudio/coreaudio_backend.h b/libs/backends/coreaudio/coreaudio_backend.h index 7ac8e1c6e1..3300fc4216 100644 --- a/libs/backends/coreaudio/coreaudio_backend.h +++ b/libs/backends/coreaudio/coreaudio_backend.h @@ -165,7 +165,11 @@ class CoreAudioBackend : public AudioBackend { std::string name () const; bool is_realtime () const; + bool use_separate_input_and_output_devices () const { return true; } std::vector<DeviceStatus> enumerate_devices () const; + std::vector<DeviceStatus> enumerate_input_devices () const; + std::vector<DeviceStatus> enumerate_output_devices () const; + std::vector<float> available_sample_rates (const std::string& device) const; std::vector<uint32_t> available_buffer_sizes (const std::string& device) const; uint32_t available_input_channel_count (const std::string& device) const; @@ -175,6 +179,8 @@ class CoreAudioBackend : public AudioBackend { bool can_change_buffer_size_when_running () const; int set_device_name (const std::string&); + int set_input_device_name (const std::string&); + int set_output_device_name (const std::string&); int set_sample_rate (float); int set_buffer_size (uint32_t); int set_interleaved (bool yn); @@ -189,6 +195,8 @@ class CoreAudioBackend : public AudioBackend { /* Retrieving parameters */ std::string device_name () const; + std::string input_device_name () const; + std::string output_device_name () const; float sample_rate () const; uint32_t buffer_size () const; bool interleaved () const; @@ -336,10 +344,13 @@ class CoreAudioBackend : public AudioBackend { pthread_cond_t _freewheel_signal; static std::vector<std::string> _midi_options; - static std::vector<AudioBackend::DeviceStatus> _audio_device_status; + static std::vector<AudioBackend::DeviceStatus> _input_audio_device_status; + static std::vector<AudioBackend::DeviceStatus> _output_audio_device_status; + static std::vector<AudioBackend::DeviceStatus> _duplex_audio_device_status; static std::vector<AudioBackend::DeviceStatus> _midi_device_status; - mutable std::string _audio_device; + mutable std::string _input_audio_device; + mutable std::string _output_audio_device; std::string _midi_driver_option; /* audio settings */ diff --git a/libs/backends/coreaudio/coreaudio_pcmio.cc b/libs/backends/coreaudio/coreaudio_pcmio.cc index 0b31a9a3ff..fb1d8caeff 100644 --- a/libs/backends/coreaudio/coreaudio_pcmio.cc +++ b/libs/backends/coreaudio/coreaudio_pcmio.cc @@ -480,6 +480,15 @@ CoreAudioPCM::get_latency(uint32_t device_id, bool input) } uint32_t +CoreAudioPCM::get_latency(bool input) +{ + if (_active_device_id == 0) { + return 0; + } + return get_latency (_active_device_id, input); +} + +uint32_t CoreAudioPCM::current_buffer_size_id(AudioDeviceID id) { UInt32 buffer_size; UInt32 size = sizeof(UInt32); @@ -629,6 +638,15 @@ CoreAudioPCM::discover() if (outputChannelCount > 0 || inputChannelCount > 0) { _devices.insert (std::pair<size_t, std::string> (idx, dn)); } + if (inputChannelCount > 0) { + _input_devices.insert (std::pair<size_t, std::string> (idx, dn)); + } + if (outputChannelCount > 0) { + _output_devices.insert (std::pair<size_t, std::string> (idx, dn)); + } + if (outputChannelCount > 0 && inputChannelCount > 0) { + _duplex_devices.insert (std::pair<size_t, std::string> (idx, dn)); + } } } pthread_mutex_unlock (&_discovery_lock); @@ -695,6 +713,7 @@ CoreAudioPCM::pcm_stop () } if (_aggregate_plugin_id) { destroy_aggregate_device(); + discover(); } AudioUnitUninitialize(_auhal); @@ -811,7 +830,7 @@ CoreAudioPCM::pcm_start ( err = AudioUnitInitialize(_auhal); if (err != noErr) { errorMsg="AudioUnitInitialize"; goto error; } - // explicitly change samplerate of the device + // explicitly change samplerate of the devices, TODO allow separate rates with aggregates if (set_device_sample_rate(device_id_in, sample_rate, true)) { errorMsg="Failed to set SampleRate, Capture Device"; goto error; } diff --git a/libs/backends/coreaudio/coreaudio_pcmio.h b/libs/backends/coreaudio/coreaudio_pcmio.h index 76b5e76e1b..5f9778e845 100644 --- a/libs/backends/coreaudio/coreaudio_pcmio.h +++ b/libs/backends/coreaudio/coreaudio_pcmio.h @@ -48,12 +48,16 @@ public: void discover(); void device_list (std::map<size_t, std::string> &devices) const { devices = _devices;} + void input_device_list (std::map<size_t, std::string> &devices) const { devices = _input_devices;} + void output_device_list (std::map<size_t, std::string> &devices) const { devices = _output_devices;} + void duplex_device_list (std::map<size_t, std::string> &devices) const { devices = _duplex_devices;} int available_sample_rates (uint32_t device_id, std::vector<float>& sampleRates); int available_buffer_sizes (uint32_t device_id, std::vector<uint32_t>& sampleRates); uint32_t available_channels (uint32_t device_id, bool input); float current_sample_rate (uint32_t device_id, bool input = false); uint32_t get_latency (uint32_t device_id, bool input); + uint32_t get_latency (bool input); std::string cached_port_name (uint32_t portnum, bool input) const; @@ -186,6 +190,9 @@ private: // TODO proper device info struct std::map<size_t, std::string> _devices; + std::map<size_t, std::string> _input_devices; + std::map<size_t, std::string> _output_devices; + std::map<size_t, std::string> _duplex_devices; uint32_t * _device_ins; uint32_t * _device_outs; std::vector<std::string> _input_names; |