mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-12 01:26:31 +01:00
coreaudio support for multiple devices
This commit is contained in:
parent
4d2bc612f2
commit
1fe738a36e
4 changed files with 134 additions and 23 deletions
|
|
@ -38,7 +38,9 @@ using namespace ARDOUR;
|
||||||
static std::string s_instance_name;
|
static std::string s_instance_name;
|
||||||
size_t CoreAudioBackend::_max_buffer_size = 8192;
|
size_t CoreAudioBackend::_max_buffer_size = 8192;
|
||||||
std::vector<std::string> CoreAudioBackend::_midi_options;
|
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 */
|
/* static class instance access */
|
||||||
|
|
@ -90,7 +92,8 @@ CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
||||||
, _reinit_thread_callback (false)
|
, _reinit_thread_callback (false)
|
||||||
, _measure_latency (false)
|
, _measure_latency (false)
|
||||||
, _last_process_start (0)
|
, _last_process_start (0)
|
||||||
, _audio_device("")
|
, _input_audio_device("")
|
||||||
|
, _output_audio_device("")
|
||||||
, _midi_driver_option(_("None"))
|
, _midi_driver_option(_("None"))
|
||||||
, _samplerate (48000)
|
, _samplerate (48000)
|
||||||
, _samples_per_period (1024)
|
, _samples_per_period (1024)
|
||||||
|
|
@ -142,30 +145,67 @@ CoreAudioBackend::is_realtime () const
|
||||||
std::vector<AudioBackend::DeviceStatus>
|
std::vector<AudioBackend::DeviceStatus>
|
||||||
CoreAudioBackend::enumerate_devices () const
|
CoreAudioBackend::enumerate_devices () const
|
||||||
{
|
{
|
||||||
_audio_device_status.clear();
|
_duplex_audio_device_status.clear();
|
||||||
std::map<size_t, std::string> devices;
|
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) {
|
for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
|
||||||
if (_audio_device == "") _audio_device = i->second;
|
if (_input_audio_device == "") _input_audio_device = i->second;
|
||||||
_audio_device_status.push_back (DeviceStatus (i->second, true));
|
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>
|
std::vector<float>
|
||||||
CoreAudioBackend::available_sample_rates (const std::string&) const
|
CoreAudioBackend::available_sample_rates (const std::string&) const
|
||||||
{
|
{
|
||||||
std::vector<float> sr;
|
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;
|
return sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint32_t>
|
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;
|
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;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,8 +236,27 @@ CoreAudioBackend::can_change_buffer_size_when_running () const
|
||||||
int
|
int
|
||||||
CoreAudioBackend::set_device_name (const std::string& d)
|
CoreAudioBackend::set_device_name (const std::string& d)
|
||||||
{
|
{
|
||||||
_audio_device = d;
|
int rv = 0;
|
||||||
const float sr = _pcmio->current_sample_rate(name_to_id(_audio_device));
|
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); }
|
if (sr > 0) { set_sample_rate(sr); }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -205,8 +264,10 @@ CoreAudioBackend::set_device_name (const std::string& d)
|
||||||
int
|
int
|
||||||
CoreAudioBackend::set_sample_rate (float sr)
|
CoreAudioBackend::set_sample_rate (float sr)
|
||||||
{
|
{
|
||||||
if (sr <= 0) { return -1; }
|
std::vector<float> srs = available_sample_rates (/* really ignored */_input_audio_device);
|
||||||
// TODO check if it's in the list of valid SR
|
if (std::find(srs.begin(), srs.end(), sr) == srs.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
_samplerate = sr;
|
_samplerate = sr;
|
||||||
engine.sample_rate_change (sr);
|
engine.sample_rate_change (sr);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -263,7 +324,19 @@ CoreAudioBackend::set_systemic_output_latency (uint32_t sl)
|
||||||
std::string
|
std::string
|
||||||
CoreAudioBackend::device_name () const
|
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
|
float
|
||||||
|
|
@ -339,7 +412,7 @@ CoreAudioBackend::midi_option () const
|
||||||
void
|
void
|
||||||
CoreAudioBackend::launch_control_app ()
|
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 */
|
/* State Control */
|
||||||
|
|
@ -380,8 +453,8 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||||
_ports.clear();
|
_ports.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t device1 = name_to_id(_audio_device); // usually input, but in an aggregate, 1st defines the clock
|
uint32_t device1 = name_to_id(_input_audio_device);
|
||||||
uint32_t device2 = name_to_id(_audio_device); // usually output
|
uint32_t device2 = name_to_id(_output_audio_device);
|
||||||
|
|
||||||
assert(_active_ca == false);
|
assert(_active_ca == false);
|
||||||
assert(_active_fw == 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->set_sample_rate_callback (sample_rate_callback_ptr, this);
|
||||||
|
|
||||||
_pcmio->pcm_start (device1, device2, _samplerate, _samples_per_period, process_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 ()) {
|
switch (_pcmio->state ()) {
|
||||||
case 0: /* OK */ break;
|
case 0: /* OK */ break;
|
||||||
|
|
@ -867,8 +941,8 @@ CoreAudioBackend::register_system_audio_ports()
|
||||||
const uint32_t a_ins = _n_inputs;
|
const uint32_t a_ins = _n_inputs;
|
||||||
const uint32_t a_out = _n_outputs;
|
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_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(_audio_device), false);
|
const uint32_t coreaudio_reported_output_latency = _pcmio->get_latency(name_to_id(_output_audio_device), false);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
printf("COREAUDIO LATENCY: i:%d, o:%d\n",
|
printf("COREAUDIO LATENCY: i:%d, o:%d\n",
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,11 @@ class CoreAudioBackend : public AudioBackend {
|
||||||
std::string name () const;
|
std::string name () const;
|
||||||
bool is_realtime () 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_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<float> available_sample_rates (const std::string& device) const;
|
||||||
std::vector<uint32_t> available_buffer_sizes (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;
|
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;
|
bool can_change_buffer_size_when_running () const;
|
||||||
|
|
||||||
int set_device_name (const std::string&);
|
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_sample_rate (float);
|
||||||
int set_buffer_size (uint32_t);
|
int set_buffer_size (uint32_t);
|
||||||
int set_interleaved (bool yn);
|
int set_interleaved (bool yn);
|
||||||
|
|
@ -189,6 +195,8 @@ class CoreAudioBackend : public AudioBackend {
|
||||||
|
|
||||||
/* Retrieving parameters */
|
/* Retrieving parameters */
|
||||||
std::string device_name () const;
|
std::string device_name () const;
|
||||||
|
std::string input_device_name () const;
|
||||||
|
std::string output_device_name () const;
|
||||||
float sample_rate () const;
|
float sample_rate () const;
|
||||||
uint32_t buffer_size () const;
|
uint32_t buffer_size () const;
|
||||||
bool interleaved () const;
|
bool interleaved () const;
|
||||||
|
|
@ -336,10 +344,13 @@ class CoreAudioBackend : public AudioBackend {
|
||||||
pthread_cond_t _freewheel_signal;
|
pthread_cond_t _freewheel_signal;
|
||||||
|
|
||||||
static std::vector<std::string> _midi_options;
|
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;
|
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;
|
std::string _midi_driver_option;
|
||||||
|
|
||||||
/* audio settings */
|
/* audio settings */
|
||||||
|
|
|
||||||
|
|
@ -479,6 +479,15 @@ CoreAudioPCM::get_latency(uint32_t device_id, bool input)
|
||||||
return latency;
|
return latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
CoreAudioPCM::get_latency(bool input)
|
||||||
|
{
|
||||||
|
if (_active_device_id == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return get_latency (_active_device_id, input);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
CoreAudioPCM::current_buffer_size_id(AudioDeviceID id) {
|
CoreAudioPCM::current_buffer_size_id(AudioDeviceID id) {
|
||||||
UInt32 buffer_size;
|
UInt32 buffer_size;
|
||||||
|
|
@ -629,6 +638,15 @@ CoreAudioPCM::discover()
|
||||||
if (outputChannelCount > 0 || inputChannelCount > 0) {
|
if (outputChannelCount > 0 || inputChannelCount > 0) {
|
||||||
_devices.insert (std::pair<size_t, std::string> (idx, dn));
|
_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);
|
pthread_mutex_unlock (&_discovery_lock);
|
||||||
|
|
@ -695,6 +713,7 @@ CoreAudioPCM::pcm_stop ()
|
||||||
}
|
}
|
||||||
if (_aggregate_plugin_id) {
|
if (_aggregate_plugin_id) {
|
||||||
destroy_aggregate_device();
|
destroy_aggregate_device();
|
||||||
|
discover();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioUnitUninitialize(_auhal);
|
AudioUnitUninitialize(_auhal);
|
||||||
|
|
@ -811,7 +830,7 @@ CoreAudioPCM::pcm_start (
|
||||||
err = AudioUnitInitialize(_auhal);
|
err = AudioUnitInitialize(_auhal);
|
||||||
if (err != noErr) { errorMsg="AudioUnitInitialize"; goto error; }
|
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)) {
|
if (set_device_sample_rate(device_id_in, sample_rate, true)) {
|
||||||
errorMsg="Failed to set SampleRate, Capture Device"; goto error;
|
errorMsg="Failed to set SampleRate, Capture Device"; goto error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,12 +48,16 @@ public:
|
||||||
|
|
||||||
void discover();
|
void discover();
|
||||||
void device_list (std::map<size_t, std::string> &devices) const { devices = _devices;}
|
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_sample_rates (uint32_t device_id, std::vector<float>& sampleRates);
|
||||||
int available_buffer_sizes (uint32_t device_id, std::vector<uint32_t>& sampleRates);
|
int available_buffer_sizes (uint32_t device_id, std::vector<uint32_t>& sampleRates);
|
||||||
uint32_t available_channels (uint32_t device_id, bool input);
|
uint32_t available_channels (uint32_t device_id, bool input);
|
||||||
float current_sample_rate (uint32_t device_id, bool input = false);
|
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 (uint32_t device_id, bool input);
|
||||||
|
uint32_t get_latency (bool input);
|
||||||
|
|
||||||
std::string cached_port_name (uint32_t portnum, bool input) const;
|
std::string cached_port_name (uint32_t portnum, bool input) const;
|
||||||
|
|
||||||
|
|
@ -186,6 +190,9 @@ private:
|
||||||
|
|
||||||
// TODO proper device info struct
|
// TODO proper device info struct
|
||||||
std::map<size_t, std::string> _devices;
|
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_ins;
|
||||||
uint32_t * _device_outs;
|
uint32_t * _device_outs;
|
||||||
std::vector<std::string> _input_names;
|
std::vector<std::string> _input_names;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue