mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 15:54:57 +01:00
more ongoing work on the coreaudio backend
* audio port names * latency compensation * xrun reporting * various fixes and cleanup
This commit is contained in:
parent
3b941fc0fa
commit
13bad670fa
4 changed files with 173 additions and 67 deletions
|
|
@ -42,12 +42,32 @@ std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_audio_device_status;
|
||||||
std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_midi_device_status;
|
std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_midi_device_status;
|
||||||
|
|
||||||
|
|
||||||
|
/* static class instance access */
|
||||||
static void hw_changed_callback_ptr (void *arg)
|
static void hw_changed_callback_ptr (void *arg)
|
||||||
{
|
{
|
||||||
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
|
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
|
||||||
d->hw_changed_callback();
|
d->hw_changed_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void error_callback_ptr (void *arg)
|
||||||
|
{
|
||||||
|
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
|
||||||
|
d->error_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xrun_callback_ptr (void *arg)
|
||||||
|
{
|
||||||
|
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
|
||||||
|
d->xrun_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void midi_port_change (void *arg)
|
||||||
|
{
|
||||||
|
CoreAudioBackend *d = static_cast<CoreAudioBackend *>(arg);
|
||||||
|
d->coremidi_rediscover ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
||||||
: AudioBackend (e, info)
|
: AudioBackend (e, info)
|
||||||
, _run (false)
|
, _run (false)
|
||||||
|
|
@ -386,18 +406,6 @@ static int process_callback_ptr (void *arg)
|
||||||
return d->process_callback();
|
return d->process_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void error_callback_ptr (void *arg)
|
|
||||||
{
|
|
||||||
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
|
|
||||||
d->error_callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void midi_port_change (void *arg)
|
|
||||||
{
|
|
||||||
CoreAudioBackend *d = static_cast<CoreAudioBackend *>(arg);
|
|
||||||
d->coremidi_rediscover ();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
CoreAudioBackend::_start (bool for_latency_measurement)
|
CoreAudioBackend::_start (bool for_latency_measurement)
|
||||||
{
|
{
|
||||||
|
|
@ -463,13 +471,13 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||||
_samples_per_period = _pcmio->sample_per_period();
|
_samples_per_period = _pcmio->sample_per_period();
|
||||||
PBD::warning << _("CoreAudioBackend: samples per period does not match.") << endmsg;
|
PBD::warning << _("CoreAudioBackend: samples per period does not match.") << endmsg;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_pcmio->samplerate() != _samplerate) {
|
if (_pcmio->current_sample_rate(name_to_id(_audio_device)) != _samplerate) {
|
||||||
_samplerate = _pcmio->samplerate();
|
_samplerate = _pcmio->current_sample_rate(name_to_id(_audio_device));
|
||||||
engine.sample_rate_change (_samplerate);
|
engine.sample_rate_change (_samplerate);
|
||||||
PBD::warning << _("CoreAudioBackend: sample rate does not match.") << endmsg;
|
PBD::warning << _("CoreAudioBackend: sample rate does not match.") << endmsg;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
_measure_latency = for_latency_measurement;
|
_measure_latency = for_latency_measurement;
|
||||||
|
|
||||||
|
|
@ -531,6 +539,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
_preinit = false;
|
_preinit = false;
|
||||||
|
_pcmio->set_xrun_callback (xrun_callback_ptr, this);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -856,31 +865,34 @@ int
|
||||||
CoreAudioBackend::register_system_audio_ports()
|
CoreAudioBackend::register_system_audio_ports()
|
||||||
{
|
{
|
||||||
LatencyRange lr;
|
LatencyRange lr;
|
||||||
printf("COREAUDIO LATENCY: i:%d, o:%d\n",
|
|
||||||
_pcmio->get_latency(name_to_id(_audio_device), true),
|
|
||||||
_pcmio->get_latency(name_to_id(_audio_device), false));
|
|
||||||
|
|
||||||
//TODO set latencies
|
|
||||||
//TODO query port names
|
|
||||||
|
|
||||||
const int a_ins = _n_inputs > 0 ? _n_inputs : 2;
|
const int a_ins = _n_inputs > 0 ? _n_inputs : 2;
|
||||||
const int a_out = _n_outputs > 0 ? _n_outputs : 2;
|
const int a_out = _n_outputs > 0 ? _n_outputs : 2;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("COREAUDIO LATENCY: i:%d, o:%d\n",
|
||||||
|
coreaudio_reported_input_latency,
|
||||||
|
coreaudio_reported_output_latency);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* audio ports */
|
/* audio ports */
|
||||||
lr.min = lr.max = _samples_per_period + (_measure_latency ? 0 : _systemic_audio_input_latency);
|
lr.min = lr.max = _samples_per_period + coreaudio_reported_input_latency + (_measure_latency ? 0 : _systemic_audio_input_latency);
|
||||||
for (int i = 1; i <= a_ins; ++i) {
|
for (int i = 0; i < a_ins; ++i) {
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
|
snprintf(tmp, sizeof(tmp), "system:capture_%s", _pcmio->cached_port_name(i, true).c_str());
|
||||||
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
|
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
|
||||||
if (!p) return -1;
|
if (!p) return -1;
|
||||||
set_latency_range (p, false, lr);
|
set_latency_range (p, false, lr);
|
||||||
_system_inputs.push_back(static_cast<CoreBackendPort*>(p));
|
_system_inputs.push_back(static_cast<CoreBackendPort*>(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
lr.min = lr.max = _samples_per_period + (_measure_latency ? 0 : _systemic_audio_output_latency);
|
lr.min = lr.max = _samples_per_period + coreaudio_reported_output_latency + (_measure_latency ? 0 : _systemic_audio_output_latency);
|
||||||
for (int i = 1; i <= a_out; ++i) {
|
for (int i = 0; i < a_out; ++i) {
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
|
snprintf(tmp, sizeof(tmp), "system:playback_%s", _pcmio->cached_port_name(i, false).c_str());
|
||||||
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
|
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
|
||||||
if (!p) return -1;
|
if (!p) return -1;
|
||||||
set_latency_range (p, true, lr);
|
set_latency_range (p, true, lr);
|
||||||
|
|
@ -1434,7 +1446,7 @@ CoreAudioBackend::process_callback ()
|
||||||
|
|
||||||
/* get audio */
|
/* get audio */
|
||||||
i = 0;
|
i = 0;
|
||||||
for (std::vector<CoreBackendPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
|
for (std::vector<CoreBackendPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) {
|
||||||
_pcmio->get_capture_channel (i, (float*)((*it)->get_buffer(n_samples)), n_samples);
|
_pcmio->get_capture_channel (i, (float*)((*it)->get_buffer(n_samples)), n_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1480,8 +1492,6 @@ CoreAudioBackend::process_callback ()
|
||||||
const int64_t elapsed_time = clock2 - clock1;
|
const int64_t elapsed_time = clock2 - clock1;
|
||||||
_dsp_load = elapsed_time / (float) nominal_time;
|
_dsp_load = elapsed_time / (float) nominal_time;
|
||||||
|
|
||||||
//engine.Xrun (); // TODO, if any
|
|
||||||
|
|
||||||
/* port-connection change */
|
/* port-connection change */
|
||||||
post_process();
|
post_process();
|
||||||
pthread_mutex_unlock (&_process_callback_mutex);
|
pthread_mutex_unlock (&_process_callback_mutex);
|
||||||
|
|
@ -1495,6 +1505,12 @@ CoreAudioBackend::error_callback ()
|
||||||
engine.halted_callback("CoreAudio Process aborted.");
|
engine.halted_callback("CoreAudio Process aborted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CoreAudioBackend::xrun_callback ()
|
||||||
|
{
|
||||||
|
engine.Xrun ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CoreAudioBackend::hw_changed_callback ()
|
CoreAudioBackend::hw_changed_callback ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ class CoreAudioBackend : public AudioBackend {
|
||||||
// really private, but needing static access:
|
// really private, but needing static access:
|
||||||
int process_callback();
|
int process_callback();
|
||||||
void error_callback();
|
void error_callback();
|
||||||
|
void xrun_callback();
|
||||||
void hw_changed_callback();
|
void hw_changed_callback();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -20,25 +20,60 @@
|
||||||
#include "coreaudio_pcmio.h"
|
#include "coreaudio_pcmio.h"
|
||||||
|
|
||||||
#ifdef COREAUDIO_108
|
#ifdef COREAUDIO_108
|
||||||
static OSStatus hardwarePropertyChangeCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) {
|
static OSStatus hw_changed_callback_ptr(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) {
|
||||||
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
|
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
|
||||||
self->hwPropertyChange();
|
self->hw_changed_callback();
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static OSStatus hardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* arg) {
|
static OSStatus hw_changed_callback_ptr (AudioHardwarePropertyID inPropertyID, void* arg) {
|
||||||
if (inPropertyID == kAudioHardwarePropertyDevices) {
|
if (inPropertyID == kAudioHardwarePropertyDevices) {
|
||||||
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
|
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
|
||||||
self->hwPropertyChange();
|
self->hw_changed_callback();
|
||||||
}
|
}
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef COREAUDIO_108
|
||||||
|
static OSStatus xrun_callback_ptr(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) {
|
||||||
|
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
|
||||||
|
self->xrun_callback();
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static OSStatus xrun_callback_ptr(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
void* inClientData)
|
||||||
|
{
|
||||||
|
CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inClientData);
|
||||||
|
d->xrun_callback();
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static OSStatus render_callback_ptr (
|
||||||
|
void* inRefCon,
|
||||||
|
AudioUnitRenderActionFlags* ioActionFlags,
|
||||||
|
const AudioTimeStamp* inTimeStamp,
|
||||||
|
UInt32 inBusNumber,
|
||||||
|
UInt32 inNumberFrames,
|
||||||
|
AudioBufferList* ioData)
|
||||||
|
{
|
||||||
|
CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inRefCon);
|
||||||
|
return d->render_callback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CoreAudioPCM::CoreAudioPCM ()
|
CoreAudioPCM::CoreAudioPCM ()
|
||||||
: _auhal (0)
|
: _auhal (0)
|
||||||
, _device_ids (0)
|
, _device_ids (0)
|
||||||
, _input_audio_buffer_list (0)
|
, _input_audio_buffer_list (0)
|
||||||
|
, _active_input (0)
|
||||||
|
, _active_output (0)
|
||||||
, _state (-1)
|
, _state (-1)
|
||||||
, _capture_channels (0)
|
, _capture_channels (0)
|
||||||
, _playback_channels (0)
|
, _playback_channels (0)
|
||||||
|
|
@ -47,6 +82,7 @@ CoreAudioPCM::CoreAudioPCM ()
|
||||||
, _process_callback (0)
|
, _process_callback (0)
|
||||||
, _error_callback (0)
|
, _error_callback (0)
|
||||||
, _hw_changed_callback (0)
|
, _hw_changed_callback (0)
|
||||||
|
, _xrun_callback (0)
|
||||||
, _device_ins (0)
|
, _device_ins (0)
|
||||||
, _device_outs (0)
|
, _device_outs (0)
|
||||||
{
|
{
|
||||||
|
|
@ -61,9 +97,9 @@ CoreAudioPCM::CoreAudioPCM ()
|
||||||
prop.mSelector = kAudioHardwarePropertyDevices;
|
prop.mSelector = kAudioHardwarePropertyDevices;
|
||||||
prop.mScope = kAudioObjectPropertyScopeGlobal;
|
prop.mScope = kAudioObjectPropertyScopeGlobal;
|
||||||
prop.mElement = 0;
|
prop.mElement = 0;
|
||||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, hardwarePropertyChangeCallback, this);
|
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, hw_changed_callback_ptr, this);
|
||||||
#else
|
#else
|
||||||
AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback, this);
|
AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hw_changed_callback_ptr, this);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,9 +116,9 @@ CoreAudioPCM::~CoreAudioPCM ()
|
||||||
prop.mSelector = kAudioHardwarePropertyDevices;
|
prop.mSelector = kAudioHardwarePropertyDevices;
|
||||||
prop.mScope = kAudioObjectPropertyScopeGlobal;
|
prop.mScope = kAudioObjectPropertyScopeGlobal;
|
||||||
prop.mElement = 0;
|
prop.mElement = 0;
|
||||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &hardwarePropertyChangeCallback, this);
|
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &hw_changed_callback_ptr, this);
|
||||||
#else
|
#else
|
||||||
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback);
|
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hw_changed_callback_ptr);
|
||||||
#endif
|
#endif
|
||||||
free(_input_audio_buffer_list);
|
free(_input_audio_buffer_list);
|
||||||
pthread_mutex_destroy (&_discovery_lock);
|
pthread_mutex_destroy (&_discovery_lock);
|
||||||
|
|
@ -90,7 +126,8 @@ CoreAudioPCM::~CoreAudioPCM ()
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CoreAudioPCM::hwPropertyChange() {
|
CoreAudioPCM::hw_changed_callback() {
|
||||||
|
printf("CHANGE..\n");
|
||||||
discover();
|
discover();
|
||||||
// TODO Filter events..
|
// TODO Filter events..
|
||||||
if (_hw_changed_callback) {
|
if (_hw_changed_callback) {
|
||||||
|
|
@ -305,7 +342,7 @@ CoreAudioPCM::get_stream_latencies(uint32 device_id, bool input, std::vector<uin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
printf("Stream %d latency: %d\n", i, stream_latency);
|
printf(" ^ Stream %d latency: %d\n", i, stream_latency);
|
||||||
#endif
|
#endif
|
||||||
latencies.push_back(stream_latency);
|
latencies.push_back(stream_latency);
|
||||||
}
|
}
|
||||||
|
|
@ -349,7 +386,8 @@ CoreAudioPCM::get_latency(uint32 device_id, bool input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
printf("Base Latency systemic+safetyoffset = %d+%d\n", lat0, latS);
|
printf("%s Latency systemic+safetyoffset = %d + %d\n",
|
||||||
|
input ? "Input" : "Output", lat0, latS);
|
||||||
#endif
|
#endif
|
||||||
latency = lat0 + latS;
|
latency = lat0 + latS;
|
||||||
|
|
||||||
|
|
@ -542,12 +580,41 @@ CoreAudioPCM::discover()
|
||||||
pthread_mutex_unlock (&_discovery_lock);
|
pthread_mutex_unlock (&_discovery_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CoreAudioPCM::xrun_callback ()
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("Coreaudio XRUN\n");
|
||||||
|
#endif
|
||||||
|
if (_xrun_callback) {
|
||||||
|
_xrun_callback(_xrun_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CoreAudioPCM::pcm_stop ()
|
CoreAudioPCM::pcm_stop ()
|
||||||
{
|
{
|
||||||
if (!_auhal) return;
|
if (!_auhal) return;
|
||||||
|
|
||||||
AudioOutputUnitStop(_auhal);
|
AudioOutputUnitStop(_auhal);
|
||||||
|
if (_state == 0) {
|
||||||
|
#ifdef COREAUDIO_108
|
||||||
|
AudioObjectPropertyAddress prop;
|
||||||
|
prop.mSelector = kAudioDeviceProcessorOverload;
|
||||||
|
prop.mScope = kAudioObjectPropertyScopeGlobal;
|
||||||
|
prop.mElement = 0;
|
||||||
|
if (_active_output > 0) {
|
||||||
|
AudioObjectRemovePropertyListener(_active_input, &prop, &xrun_callback_ptr, this);
|
||||||
|
}
|
||||||
|
if (_active_input > 0 && _active_output != _active_input) {
|
||||||
|
AudioObjectRemovePropertyListener(_active_output, &prop, &xrun_callback_ptr, this);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
AudioDeviceRemovePropertyListener(_active_input, 0 , true, kAudioDeviceProcessorOverload, xrun_callback_ptr);
|
||||||
|
AudioDeviceRemovePropertyListener(_active_output, 0 , false, kAudioDeviceProcessorOverload, xrun_callback_ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
AudioUnitUninitialize(_auhal);
|
AudioUnitUninitialize(_auhal);
|
||||||
#ifdef COREAUDIO_108
|
#ifdef COREAUDIO_108
|
||||||
AudioComponentInstanceDispose(_auhal);
|
AudioComponentInstanceDispose(_auhal);
|
||||||
|
|
@ -567,6 +634,7 @@ CoreAudioPCM::pcm_stop ()
|
||||||
|
|
||||||
_error_callback = 0;
|
_error_callback = 0;
|
||||||
_process_callback = 0;
|
_process_callback = 0;
|
||||||
|
_xrun_callback = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
@ -585,20 +653,6 @@ static void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static OSStatus render_callback_ptr (
|
|
||||||
void* inRefCon,
|
|
||||||
AudioUnitRenderActionFlags* ioActionFlags,
|
|
||||||
const AudioTimeStamp* inTimeStamp,
|
|
||||||
UInt32 inBusNumber,
|
|
||||||
UInt32 inNumberFrames,
|
|
||||||
AudioBufferList* ioData)
|
|
||||||
{
|
|
||||||
CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inRefCon);
|
|
||||||
return d->render_callback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
CoreAudioPCM::pcm_start (
|
CoreAudioPCM::pcm_start (
|
||||||
uint32_t device_id_in, uint32_t device_id_out,
|
uint32_t device_id_in, uint32_t device_id_out,
|
||||||
|
|
@ -618,6 +672,7 @@ CoreAudioPCM::pcm_start (
|
||||||
_process_arg = process_arg;
|
_process_arg = process_arg;
|
||||||
_max_samples_per_period = samples_per_period;
|
_max_samples_per_period = samples_per_period;
|
||||||
_cur_samples_per_period = 0;
|
_cur_samples_per_period = 0;
|
||||||
|
_active_input = _active_output = 0;
|
||||||
|
|
||||||
ComponentResult err;
|
ComponentResult err;
|
||||||
UInt32 uint32val;
|
UInt32 uint32val;
|
||||||
|
|
@ -715,6 +770,7 @@ CoreAudioPCM::pcm_start (
|
||||||
#endif
|
#endif
|
||||||
if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat Input"; goto error; }
|
if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat Input"; goto error; }
|
||||||
|
|
||||||
|
/* read back stream descriptions */
|
||||||
UInt32 size;
|
UInt32 size;
|
||||||
size = sizeof(AudioStreamBasicDescription);
|
size = sizeof(AudioStreamBasicDescription);
|
||||||
err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, &size);
|
err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, &size);
|
||||||
|
|
@ -733,10 +789,32 @@ CoreAudioPCM::pcm_start (
|
||||||
PrintStreamDesc(&dstFormat);
|
PrintStreamDesc(&dstFormat);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* prepare buffers for input */
|
||||||
_input_audio_buffer_list = (AudioBufferList*)malloc(sizeof(UInt32) + _capture_channels * sizeof(AudioBuffer));
|
_input_audio_buffer_list = (AudioBufferList*)malloc(sizeof(UInt32) + _capture_channels * sizeof(AudioBuffer));
|
||||||
assert(_input_audio_buffer_list);
|
assert(_input_audio_buffer_list);
|
||||||
if (!_input_audio_buffer_list) { errorMsg="Out of Memory."; goto error; }
|
if (!_input_audio_buffer_list) { errorMsg="Out of Memory."; goto error; }
|
||||||
|
|
||||||
|
_active_input = _device_ids[device_id_in];
|
||||||
|
_active_output = _device_ids[device_id_out];
|
||||||
|
|
||||||
|
#ifdef COREAUDIO_108
|
||||||
|
AudioObjectPropertyAddress prop;
|
||||||
|
prop.mSelector = kAudioDeviceProcessorOverload;
|
||||||
|
prop.mScope = kAudioObjectPropertyScopeGlobal;
|
||||||
|
prop.mElement = 0;
|
||||||
|
AudioObjectAddPropertyListener(_active_output, &prop, xrun_callback_ptr, this);
|
||||||
|
if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Output"; goto error; }
|
||||||
|
if (_active_input != _active_output) {
|
||||||
|
AudioObjectAddPropertyListener(_active_input, &prop, xrun_callback_ptr, this);
|
||||||
|
if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Input"; goto error; }
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
err = AudioDeviceAddPropertyListener(_device_ids[device_id_out], 0 , false, kAudioDeviceProcessorOverload, xrun_callback_ptr, this);
|
||||||
|
if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Output"; goto error; }
|
||||||
|
err = AudioDeviceAddPropertyListener(_device_ids[device_id_in], 0 , true, kAudioDeviceProcessorOverload, xrun_callback_ptr, this);
|
||||||
|
if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Input"; goto error; }
|
||||||
|
#endif
|
||||||
|
|
||||||
// Setup callbacks
|
// Setup callbacks
|
||||||
AURenderCallbackStruct renderCallback;
|
AURenderCallbackStruct renderCallback;
|
||||||
memset (&renderCallback, 0, sizeof (renderCallback));
|
memset (&renderCallback, 0, sizeof (renderCallback));
|
||||||
|
|
@ -748,6 +826,7 @@ CoreAudioPCM::pcm_start (
|
||||||
&renderCallback, sizeof (renderCallback));
|
&renderCallback, sizeof (renderCallback));
|
||||||
if (err != noErr) { errorMsg="kAudioUnitProperty_SetRenderCallback"; goto error; }
|
if (err != noErr) { errorMsg="kAudioUnitProperty_SetRenderCallback"; goto error; }
|
||||||
|
|
||||||
|
/* setup complete, now get going.. */
|
||||||
if (AudioOutputUnitStart(_auhal) == noErr) {
|
if (AudioOutputUnitStart(_auhal) == noErr) {
|
||||||
_input_names.clear();
|
_input_names.clear();
|
||||||
_output_names.clear();
|
_output_names.clear();
|
||||||
|
|
@ -762,6 +841,7 @@ error:
|
||||||
fprintf(stderr, "CoreaudioPCM Error: %c%c%c%c %s\n", rv[0], rv[1], rv[2], rv[3], errorMsg.c_str());
|
fprintf(stderr, "CoreaudioPCM Error: %c%c%c%c %s\n", rv[0], rv[1], rv[2], rv[3], errorMsg.c_str());
|
||||||
pcm_stop();
|
pcm_stop();
|
||||||
_state = -3;
|
_state = -3;
|
||||||
|
_active_input = _active_output = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -820,19 +900,14 @@ CoreAudioPCM::cache_port_names(uint32 device_id, bool input)
|
||||||
decoded = CFStringGetCString(name, cstr_name, maxSize, kCFStringEncodingUTF8);
|
decoded = CFStringGetCString(name, cstr_name, maxSize, kCFStringEncodingUTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << (c + 1) << " - ";
|
ss << (c + 1);
|
||||||
|
|
||||||
if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) {
|
if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) {
|
||||||
ss << cstr_name;
|
ss << " - " << cstr_name;
|
||||||
} else {
|
|
||||||
if (input) {
|
|
||||||
ss << "Input " << (c + 1);
|
|
||||||
} else {
|
|
||||||
ss << "Output " << (c + 1);
|
|
||||||
}
|
}
|
||||||
}
|
#if 0
|
||||||
|
|
||||||
printf("%s %d Name: %s\n", input ? "Input" : "Output", c+1, ss.str().c_str());
|
printf("%s %d Name: %s\n", input ? "Input" : "Output", c+1, ss.str().c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
_input_names.push_back (ss.str());
|
_input_names.push_back (ss.str());
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ public:
|
||||||
void * process_arg
|
void * process_arg
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: combine callbacks below, add a enum type
|
|
||||||
void set_error_callback (
|
void set_error_callback (
|
||||||
void ( error_callback (void*)),
|
void ( error_callback (void*)),
|
||||||
void * error_arg
|
void * error_arg
|
||||||
|
|
@ -80,6 +79,13 @@ public:
|
||||||
_hw_changed_callback = callback;
|
_hw_changed_callback = callback;
|
||||||
_hw_changed_arg = arg;
|
_hw_changed_arg = arg;
|
||||||
}
|
}
|
||||||
|
void set_xrun_callback (
|
||||||
|
void ( callback (void*)),
|
||||||
|
void * arg
|
||||||
|
) {
|
||||||
|
_xrun_callback = callback;
|
||||||
|
_xrun_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
// must be called from process_callback;
|
// must be called from process_callback;
|
||||||
int get_capture_channel (uint32_t chn, float *input, uint32_t n_samples);
|
int get_capture_channel (uint32_t chn, float *input, uint32_t n_samples);
|
||||||
|
|
@ -94,7 +100,8 @@ public:
|
||||||
UInt32 inNumberFrames,
|
UInt32 inNumberFrames,
|
||||||
AudioBufferList* ioData);
|
AudioBufferList* ioData);
|
||||||
|
|
||||||
void hwPropertyChange();
|
void xrun_callback ();
|
||||||
|
void hw_changed_callback ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int set_device_sample_rate (uint32 device_id, float rate, bool input);
|
int set_device_sample_rate (uint32 device_id, float rate, bool input);
|
||||||
|
|
@ -106,6 +113,9 @@ private:
|
||||||
AudioBufferList* _input_audio_buffer_list;
|
AudioBufferList* _input_audio_buffer_list;
|
||||||
AudioBufferList* _output_audio_buffer_list;
|
AudioBufferList* _output_audio_buffer_list;
|
||||||
|
|
||||||
|
AudioDeviceID _active_input;
|
||||||
|
AudioDeviceID _active_output;
|
||||||
|
|
||||||
int _state;
|
int _state;
|
||||||
|
|
||||||
uint32_t _max_samples_per_period;
|
uint32_t _max_samples_per_period;
|
||||||
|
|
@ -124,6 +134,10 @@ private:
|
||||||
void (* _hw_changed_callback) (void*);
|
void (* _hw_changed_callback) (void*);
|
||||||
void * _hw_changed_arg;
|
void * _hw_changed_arg;
|
||||||
|
|
||||||
|
void (* _xrun_callback) (void*);
|
||||||
|
void * _xrun_arg;
|
||||||
|
|
||||||
|
|
||||||
// TODO proper device info struct
|
// TODO proper device info struct
|
||||||
std::map<size_t, std::string> _devices;
|
std::map<size_t, std::string> _devices;
|
||||||
uint32_t * _device_ins;
|
uint32_t * _device_ins;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue