[DEV] correct IOs and MacOs audio interface (tested on MacOs but not on IOs)

This commit is contained in:
Edouard DUPIN 2015-02-12 23:19:48 +01:00
parent 4fc9a3e05f
commit 650f24c288
5 changed files with 65 additions and 87 deletions

View File

@ -55,6 +55,7 @@ airtaudio::Api::~Api() {
} }
enum airtaudio::error airtaudio::Api::startStream() { enum airtaudio::error airtaudio::Api::startStream() {
ATA_VERBOSE("Start Stream");
m_startTime = std::chrono::system_clock::now(); m_startTime = std::chrono::system_clock::now();
m_duration = std::chrono::duration<int64_t, std::micro>(0); m_duration = std::chrono::duration<int64_t, std::micro>(0);
return airtaudio::error_none; return airtaudio::error_none;
@ -156,6 +157,7 @@ uint32_t airtaudio::Api::getDefaultOutputDevice() {
} }
enum airtaudio::error airtaudio::Api::closeStream() { enum airtaudio::error airtaudio::Api::closeStream() {
ATA_VERBOSE("Close Stream");
// MUST be implemented in subclasses! // MUST be implemented in subclasses!
return airtaudio::error_none; return airtaudio::error_none;
} }

View File

@ -346,9 +346,10 @@ airtaudio::DeviceInfo airtaudio::api::Core::getDeviceInfo(uint32_t _device) {
} }
} }
info.sampleRates.clear(); info.sampleRates.clear();
for (uint32_t k=0; k<MAX_SAMPLE_RATES; k++) { for (auto &it : airtaudio::genericSampleRate()) {
if (SAMPLE_RATES[k] >= (uint32_t) minimumRate && SAMPLE_RATES[k] <= (uint32_t) maximumRate) { if ( it >= minimumRate
info.sampleRates.push_back(SAMPLE_RATES[k]); && it <= maximumRate) {
info.sampleRates.push_back(it);
} }
} }
if (info.sampleRates.size() == 0) { if (info.sampleRates.size() == 0) {
@ -388,7 +389,7 @@ OSStatus airtaudio::api::Core::callbackEvent(AudioDeviceID _inDevice,
} }
} }
static OSStatus xrunListener(AudioObjectID _inDevice, OSStatus airtaudio::api::Core::xrunListener(AudioObjectID _inDevice,
uint32_t _nAddresses, uint32_t _nAddresses,
const AudioObjectPropertyAddress _properties[], const AudioObjectPropertyAddress _properties[],
void* _userData) { void* _userData) {
@ -406,7 +407,7 @@ static OSStatus xrunListener(AudioObjectID _inDevice,
} }
static OSStatus rateListener(AudioObjectID _inDevice, static OSStatus rateListener(AudioObjectID _inDevice,
uint32_t _nAddresses, UInt32 _nAddresses,
const AudioObjectPropertyAddress _properties[], const AudioObjectPropertyAddress _properties[],
void* _ratePointer) { void* _ratePointer) {
double *rate = (double*)_ratePointer; double *rate = (double*)_ratePointer;
@ -593,26 +594,6 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
} }
m_bufferSize = *_bufferSize; m_bufferSize = *_bufferSize;
m_nBuffers = 1; m_nBuffers = 1;
// Try to set "hog" mode ... it's not clear to me this is working.
if ( _options != nullptr
&& _options->flags & HOG_DEVICE) {
pid_t hog_pid;
dataSize = sizeof(hog_pid);
property.mSelector = kAudioDevicePropertyHogMode;
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &hog_pid);
if (result != noErr) {
ATA_ERROR("system error (" << getErrorCode(result) << ") getting 'hog' state!");
return false;
}
if (hog_pid != getpid()) {
hog_pid = getpid();
result = AudioObjectSetPropertyData(id, &property, 0, nullptr, dataSize, &hog_pid);
if (result != noErr) {
ATA_ERROR("system error (" << getErrorCode(result) << ") setting 'hog' state!");
return false;
}
}
}
// Check and if necessary, change the sample rate for the device. // Check and if necessary, change the sample rate for the device.
double nominalRate; double nominalRate;
dataSize = sizeof(double); dataSize = sizeof(double);
@ -627,7 +608,7 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
// Set a property listener for the sample rate change // Set a property listener for the sample rate change
double reportedRate = 0.0; double reportedRate = 0.0;
AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
result = AudioObjectAddPropertyListener(id, &tmp, rateListener, (void *) &reportedRate); result = AudioObjectAddPropertyListener(id, &tmp, &rateListener, (void *) &reportedRate);
if (result != noErr) { if (result != noErr) {
ATA_ERROR("system error (" << getErrorCode(result) << ") setting sample rate property listener for device (" << _device << ")."); ATA_ERROR("system error (" << getErrorCode(result) << ") setting sample rate property listener for device (" << _device << ").");
return false; return false;
@ -648,7 +629,7 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
usleep(5000); usleep(5000);
} }
// Remove the property listener. // Remove the property listener.
AudioObjectRemovePropertyListener(id, &tmp, rateListener, (void *) &reportedRate); AudioObjectRemovePropertyListener(id, &tmp, &rateListener, (void *) &reportedRate);
if (microCounter > 5000000) { if (microCounter > 5000000) {
ATA_ERROR("timeout waiting for sample rate update for device (" << _device << ")."); ATA_ERROR("timeout waiting for sample rate update for device (" << _device << ").");
return false; return false;
@ -763,7 +744,7 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
// From the CoreAudio documentation, PCM data must be supplied as // From the CoreAudio documentation, PCM data must be supplied as
// 32-bit floats. // 32-bit floats.
m_userFormat = _format; m_userFormat = _format;
m_deviceFormat[modeToIdTable(_mode)] = FLOAT32; m_deviceFormat[modeToIdTable(_mode)] = audio::format_float;
if (streamCount == 1) { if (streamCount == 1) {
m_nDeviceChannels[modeToIdTable(_mode)] = description.mChannelsPerFrame; m_nDeviceChannels[modeToIdTable(_mode)] = description.mChannelsPerFrame;
} else { } else {
@ -799,9 +780,8 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
uint64_t bufferBytes; uint64_t bufferBytes;
bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_userFormat); bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_userFormat);
// m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1); // m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1);
m_userBuffer[modeToIdTable(_mode)] = (char *) malloc(bufferBytes * sizeof(char)); m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes, 0);
memset(m_userBuffer[modeToIdTable(_mode)], 0, bufferBytes * sizeof(char)); if (m_userBuffer[modeToIdTable(_mode)].size() == 0) {
if (m_userBuffer[modeToIdTable(_mode)] == nullptr) {
ATA_ERROR("error allocating user buffer memory."); ATA_ERROR("error allocating user buffer memory.");
goto error; goto error;
} }
@ -837,7 +817,7 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
m_sampleRate = _sampleRate; m_sampleRate = _sampleRate;
m_device[modeToIdTable(_mode)] = _device; m_device[modeToIdTable(_mode)] = _device;
m_state = airtaudio::state_stopped; m_state = airtaudio::state_stopped;
m_callbackInfo.object = (void *) this; ATA_VERBOSE("Set state as stopped");
// Setup the buffer conversion information structure. // Setup the buffer conversion information structure.
if (m_doConvertBuffer[modeToIdTable(_mode)]) { if (m_doConvertBuffer[modeToIdTable(_mode)]) {
if (streamCount > 1) { if (streamCount > 1) {
@ -853,10 +833,10 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
m_mode = airtaudio::mode_duplex; m_mode = airtaudio::mode_duplex;
} else { } else {
#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
result = AudioDeviceCreateIOProcID(id, &airtaudio::api::Core::callbackEvent, (void *) &m_callbackInfo, &m_private->procId[modeToIdTable(_mode)]); result = AudioDeviceCreateIOProcID(id, &airtaudio::api::Core::callbackEvent, this, &m_private->procId[modeToIdTable(_mode)]);
#else #else
// deprecated in favor of AudioDeviceCreateIOProcID() // deprecated in favor of AudioDeviceCreateIOProcID()
result = AudioDeviceAddIOProc(id, &airtaudio::api::Core::callbackEvent, (void *) &m_callbackInfo); result = AudioDeviceAddIOProc(id, &airtaudio::api::Core::callbackEvent, this);
#endif #endif
if (result != noErr) { if (result != noErr) {
ATA_ERROR("system error setting callback for device (" << _device << ")."); ATA_ERROR("system error setting callback for device (" << _device << ").");
@ -871,20 +851,17 @@ bool airtaudio::api::Core::probeDeviceOpen(uint32_t _device,
} }
// Setup the device property listener for over/underload. // Setup the device property listener for over/underload.
property.mSelector = kAudioDeviceProcessorOverload; property.mSelector = kAudioDeviceProcessorOverload;
result = AudioObjectAddPropertyListener(id, &property, xrunListener, this); result = AudioObjectAddPropertyListener(id, &property, &airtaudio::api::Core::xrunListener, this);
return true; return true;
error: error:
for (int32_t i=0; i<2; i++) { m_userBuffer[0].clear();
if (m_userBuffer[i]) { m_userBuffer[1].clear();
free(m_userBuffer[i]);
m_userBuffer[i] = 0;
}
}
if (m_deviceBuffer) { if (m_deviceBuffer) {
free(m_deviceBuffer); free(m_deviceBuffer);
m_deviceBuffer = 0; m_deviceBuffer = 0;
} }
m_state = airtaudio::state_closed; m_state = airtaudio::state_closed;
ATA_VERBOSE("Set state as closed");
return false; return false;
} }
@ -918,18 +895,15 @@ enum airtaudio::error airtaudio::api::Core::closeStream() {
AudioDeviceRemoveIOProc(m_private->id[1], &airtaudio::api::Core::callbackEvent); AudioDeviceRemoveIOProc(m_private->id[1], &airtaudio::api::Core::callbackEvent);
#endif #endif
} }
for (int32_t i=0; i<2; i++) { m_userBuffer[0].clear();
if (m_userBuffer[i]) { m_userBuffer[1].clear();
free(m_userBuffer[i]);
m_userBuffer[i] = nullptr;
}
}
if (m_deviceBuffer) { if (m_deviceBuffer) {
free(m_deviceBuffer); free(m_deviceBuffer);
m_deviceBuffer = nullptr; m_deviceBuffer = nullptr;
} }
m_mode = airtaudio::mode_unknow; m_mode = airtaudio::mode_unknow;
m_state = airtaudio::state_closed; m_state = airtaudio::state_closed;
ATA_VERBOSE("Set state as closed");
return airtaudio::error_none; return airtaudio::error_none;
} }
@ -964,6 +938,7 @@ enum airtaudio::error airtaudio::api::Core::startStream() {
m_private->drainCounter = 0; m_private->drainCounter = 0;
m_private->internalDrain = false; m_private->internalDrain = false;
m_state = airtaudio::state_running; m_state = airtaudio::state_running;
ATA_VERBOSE("Set state as running");
unlock: unlock:
if (result == noErr) { if (result == noErr) {
return airtaudio::error_none; return airtaudio::error_none;
@ -1003,6 +978,7 @@ enum airtaudio::error airtaudio::api::Core::stopStream() {
} }
} }
m_state = airtaudio::state_stopped; m_state = airtaudio::state_stopped;
ATA_VERBOSE("Set state as stopped");
unlock: unlock:
if (result == noErr) { if (result == noErr) {
return airtaudio::error_none; return airtaudio::error_none;
@ -1047,6 +1023,7 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
// Check if we were draining the stream and signal is finished. // Check if we were draining the stream and signal is finished.
if (m_private->drainCounter > 3) { if (m_private->drainCounter > 3) {
m_state = airtaudio::state_stopping; m_state = airtaudio::state_stopping;
ATA_VERBOSE("Set state as stopping");
if (m_private->internalDrain == true) { if (m_private->internalDrain == true) {
new std::thread(&airtaudio::api::Core::coreStopStream, this); new std::thread(&airtaudio::api::Core::coreStopStream, this);
} else { } else {
@ -1064,21 +1041,22 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
enum airtaudio::status status = airtaudio::status_ok; enum airtaudio::status status = airtaudio::status_ok;
if ( m_mode != airtaudio::mode_input if ( m_mode != airtaudio::mode_input
&& m_private->xrun[0] == true) { && m_private->xrun[0] == true) {
status |= airtaudio::status_underflow; status = airtaudio::status_underflow;
m_private->xrun[0] = false; m_private->xrun[0] = false;
} }
if ( m_mode != airtaudio::mode_output if ( m_mode != airtaudio::mode_output
&& m_private->xrun[1] == true) { && m_private->xrun[1] == true) {
status |= airtaudio::mode_input_OVERFLOW; status = airtaudio::status_overflow;
m_private->xrun[1] = false; m_private->xrun[1] = false;
} }
int32_t cbReturnValue = info->callback(m_userBuffer[0], int32_t cbReturnValue = info->callback(&m_userBuffer[0][0],
m_userBuffer[1], &m_userBuffer[1][0],
m_bufferSize, m_bufferSize,
streamTime, streamTime,
status); status);
if (cbReturnValue == 2) { if (cbReturnValue == 2) {
m_state = airtaudio::state_stopping; m_state = airtaudio::state_stopping;
ATA_VERBOSE("Set state as stopping");
m_private->drainCounter = 2; m_private->drainCounter = 2;
abortStream(); abortStream();
return true; return true;
@ -1108,19 +1086,19 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
if (m_doConvertBuffer[0]) { if (m_doConvertBuffer[0]) {
// convert directly to CoreAudio stream buffer // convert directly to CoreAudio stream buffer
convertBuffer((char*)_outBufferList->mBuffers[m_private->iStream[0]].mData, convertBuffer((char*)_outBufferList->mBuffers[m_private->iStream[0]].mData,
m_userBuffer[0], &m_userBuffer[0][0],
m_convertInfo[0]); m_convertInfo[0]);
} else { } else {
// copy from user buffer // copy from user buffer
memcpy(_outBufferList->mBuffers[m_private->iStream[0]].mData, memcpy(_outBufferList->mBuffers[m_private->iStream[0]].mData,
m_userBuffer[0], &m_userBuffer[0][0],
_outBufferList->mBuffers[m_private->iStream[0]].mDataByteSize); _outBufferList->mBuffers[m_private->iStream[0]].mDataByteSize);
} }
} else { } else {
// fill multiple streams // fill multiple streams
float *inBuffer = (float *) m_userBuffer[0]; float *inBuffer = (float *) &m_userBuffer[0][0];
if (m_doConvertBuffer[0]) { if (m_doConvertBuffer[0]) {
convertBuffer(m_deviceBuffer, m_userBuffer[0], m_convertInfo[0]); convertBuffer(m_deviceBuffer, &m_userBuffer[0][0], m_convertInfo[0]);
inBuffer = (float *) m_deviceBuffer; inBuffer = (float *) m_deviceBuffer;
} }
if (m_deviceInterleaved[0] == false) { // mono mode if (m_deviceInterleaved[0] == false) { // mono mode
@ -1194,16 +1172,16 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
if (m_private->nStreams[1] == 1) { if (m_private->nStreams[1] == 1) {
if (m_doConvertBuffer[1]) { if (m_doConvertBuffer[1]) {
// convert directly from CoreAudio stream buffer // convert directly from CoreAudio stream buffer
convertBuffer(m_userBuffer[1], convertBuffer(&m_userBuffer[1][0],
(char *) _inBufferList->mBuffers[m_private->iStream[1]].mData, (char *) _inBufferList->mBuffers[m_private->iStream[1]].mData,
m_convertInfo[1]); m_convertInfo[1]);
} else { // copy to user buffer } else { // copy to user buffer
memcpy(m_userBuffer[1], memcpy(&m_userBuffer[1][0],
_inBufferList->mBuffers[m_private->iStream[1]].mData, _inBufferList->mBuffers[m_private->iStream[1]].mData,
_inBufferList->mBuffers[m_private->iStream[1]].mDataByteSize); _inBufferList->mBuffers[m_private->iStream[1]].mDataByteSize);
} }
} else { // read from multiple streams } else { // read from multiple streams
float *outBuffer = (float *) m_userBuffer[1]; float *outBuffer = (float *) &m_userBuffer[1][0];
if (m_doConvertBuffer[1]) { if (m_doConvertBuffer[1]) {
outBuffer = (float *) m_deviceBuffer; outBuffer = (float *) m_deviceBuffer;
} }
@ -1266,7 +1244,7 @@ bool airtaudio::api::Core::callbackEvent(AudioDeviceID _deviceId,
} }
} }
if (m_doConvertBuffer[1]) { // convert from our internal "device" buffer if (m_doConvertBuffer[1]) { // convert from our internal "device" buffer
convertBuffer(m_userBuffer[1], convertBuffer(&m_userBuffer[1][0],
m_deviceBuffer, m_deviceBuffer,
m_convertInfo[1]); m_convertInfo[1]);
} }

View File

@ -45,7 +45,7 @@ namespace airtaudio {
AudioBufferList* _outOutputData, AudioBufferList* _outOutputData,
const AudioTimeStamp* _inOutputTime, const AudioTimeStamp* _inOutputTime,
void* _infoPointer); void* _infoPointer);
void coreStopStream(void *_userData); static void coreStopStream(void *_userData);
private: private:
std::unique_ptr<CorePrivate> m_private; std::unique_ptr<CorePrivate> m_private;
bool probeDeviceOpen(uint32_t _device, bool probeDeviceOpen(uint32_t _device,
@ -57,6 +57,11 @@ namespace airtaudio {
uint32_t *_bufferSize, uint32_t *_bufferSize,
airtaudio::StreamOptions *_options); airtaudio::StreamOptions *_options);
static const char* getErrorCode(OSStatus _code); static const char* getErrorCode(OSStatus _code);
static OSStatus xrunListener(AudioObjectID _inDevice,
uint32_t _nAddresses,
const AudioObjectPropertyAddress _properties[],
void* _userData);
}; };
}; };
}; };

View File

@ -45,14 +45,8 @@ namespace airtaudio {
public: public:
void callBackEvent(void* _data, void callBackEvent(void* _data,
int32_t _frameRate); int32_t _frameRate);
private: public:
std::unique_ptr<CoreIosPrivate> m_private; std::unique_ptr<CoreIosPrivate> m_private;
static OSStatus playbackCallback(void *_userData,
AudioUnitRenderActionFlags* _ioActionFlags,
const AudioTimeStamp* _inTimeStamp,
uint32_t _inBusNumber,
uint32_t _inNumberFrames,
AudioBufferList* _ioData);
}; };
}; };
}; };

View File

@ -69,8 +69,6 @@ airtaudio::api::CoreIos::CoreIos(void) :
airtaudio::api::CoreIos::~CoreIos(void) { airtaudio::api::CoreIos::~CoreIos(void) {
ATA_INFO("Destroy CoreIOs interface"); ATA_INFO("Destroy CoreIOs interface");
AudioUnitUninitialize(m_private->audioUnit); AudioUnitUninitialize(m_private->audioUnit);
delete m_private;
m_private = nullptr;
} }
uint32_t airtaudio::api::CoreIos::getDeviceCount(void) { uint32_t airtaudio::api::CoreIos::getDeviceCount(void) {
@ -131,13 +129,13 @@ void airtaudio::api::CoreIos::callBackEvent(void* _data,
int32_t doStopStream = 0; int32_t doStopStream = 0;
std::chrono::system_clock::time_point streamTime = getStreamTime(); std::chrono::system_clock::time_point streamTime = getStreamTime();
enum airtaudio::status status = airtaudio::status_ok; enum airtaudio::status status = airtaudio::status_ok;
if (m_doConvertBuffer[airtaudio::mode_output] == true) { if (m_doConvertBuffer[modeToIdTable(airtaudio::mode_output)] == true) {
doStopStream = m_callbackInfo.callback(m_userBuffer[airtaudio::mode_output], doStopStream = m_callbackInfo.callback(&m_userBuffer[modeToIdTable(airtaudio::mode_output)][0],
nullptr, nullptr,
_frameRate, _frameRate,
streamTime, streamTime,
status); status);
convertBuffer((char*)_data, (char*)m_userBuffer[airtaudio::mode_output], m_convertInfo[airtaudio::mode_output]); convertBuffer((char*)_data, &m_userBuffer[modeToIdTable(airtaudio::mode_output)][0], m_convertInfo[modeToIdTable(airtaudio::mode_output)]);
} else { } else {
doStopStream = m_callbackInfo.callback(_data, doStopStream = m_callbackInfo.callback(_data,
nullptr, nullptr,
@ -152,7 +150,8 @@ void airtaudio::api::CoreIos::callBackEvent(void* _data,
airtaudio::Api::tickStreamTime(); airtaudio::Api::tickStreamTime();
} }
OSStatus airtaudio::api::CoreIos::playbackCallback(void *_userData,
static OSStatus playbackCallback(void *_userData,
AudioUnitRenderActionFlags* _ioActionFlags, AudioUnitRenderActionFlags* _ioActionFlags,
const AudioTimeStamp* _inTimeStamp, const AudioTimeStamp* _inTimeStamp,
uint32_t _inBusNumber, uint32_t _inBusNumber,
@ -197,7 +196,7 @@ bool airtaudio::api::CoreIos::probeDeviceOpen(uint32_t _device,
m_doByteSwap[modeToIdTable(_mode)] = false; // for endienness ... m_doByteSwap[modeToIdTable(_mode)] = false; // for endienness ...
// TODO : For now, we write it in hard ==> to be update later ... // TODO : For now, we write it in hard ==> to be update later ...
m_deviceFormat[modeToIdTable(_mode)] = SINT16; m_deviceFormat[modeToIdTable(_mode)] = audio::format_int16;
m_nDeviceChannels[modeToIdTable(_mode)] = 2; m_nDeviceChannels[modeToIdTable(_mode)] = 2;
m_deviceInterleaved[modeToIdTable(_mode)] = true; m_deviceInterleaved[modeToIdTable(_mode)] = true;
@ -215,8 +214,8 @@ bool airtaudio::api::CoreIos::probeDeviceOpen(uint32_t _device,
if (m_doConvertBuffer[modeToIdTable(_mode)] == true) { if (m_doConvertBuffer[modeToIdTable(_mode)] == true) {
// Allocate necessary internal buffers. // Allocate necessary internal buffers.
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat); uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1); m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes, 0);
if (m_userBuffer[modeToIdTable(_mode)] == nullptr) { if (m_userBuffer[modeToIdTable(_mode)].size() == 0) {
ATA_ERROR("error allocating user buffer memory."); ATA_ERROR("error allocating user buffer memory.");
} }
setConvertInfo(_mode, _firstChannel); setConvertInfo(_mode, _firstChannel);
@ -285,7 +284,7 @@ bool airtaudio::api::CoreIos::probeDeviceOpen(uint32_t _device,
// Set output callback // Set output callback
AURenderCallbackStruct callbackStruct; AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = &airtaudio::api::CoreIos::playbackCallback; callbackStruct.inputProc = &playbackCallback;
callbackStruct.inputProcRefCon = this; callbackStruct.inputProcRefCon = this;
status = AudioUnitSetProperty(m_private->audioUnit, status = AudioUnitSetProperty(m_private->audioUnit,
kAudioUnitProperty_SetRenderCallback, kAudioUnitProperty_SetRenderCallback,