From 22dd01978a2d10fcd8e6504abbc427701f1fa9e1 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Tue, 7 Jul 2015 21:37:03 +0200 Subject: [PATCH] [DEBUG] correct the Mac audio interface --- audio/orchestra/Api.cpp | 1 + audio/orchestra/DeviceInfo.cpp | 36 ++++++-- audio/orchestra/DeviceInfo.h | 9 ++ audio/orchestra/api/Core.cpp | 152 ++++++++++++++++----------------- audio/orchestra/api/CoreIos.mm | 22 ++--- 5 files changed, 124 insertions(+), 96 deletions(-) diff --git a/audio/orchestra/Api.cpp b/audio/orchestra/Api.cpp index 8174c18..740644a 100644 --- a/audio/orchestra/Api.cpp +++ b/audio/orchestra/Api.cpp @@ -36,6 +36,7 @@ const std::vector& audio::orchestra::genericSampleRate() { list.push_back(128000); list.push_back(176400); list.push_back(192000); + list.push_back(256000); } return list; }; diff --git a/audio/orchestra/DeviceInfo.cpp b/audio/orchestra/DeviceInfo.cpp index ca58a14..0786e86 100644 --- a/audio/orchestra/DeviceInfo.cpp +++ b/audio/orchestra/DeviceInfo.cpp @@ -19,24 +19,46 @@ void audio::orchestra::DeviceInfo::display(int32_t _tabNumber) const { for (int32_t iii=0; iii<_tabNumber; ++iii) { space += " "; } + if (isCorrect == false) { + ATA_PRINT(space + "NOT CORRECT INFORAMATIONS"); + return; + } ATA_PRINT(space + "mode=" << (input==true?"input":"output")); ATA_PRINT(space + "name=" << name); - ATA_PRINT(space + "desc=" << desc); + if (desc.size() != 0) { + ATA_PRINT(space + "desc=" << desc); + } ATA_PRINT(space + "channel" << (channels.size()>1?"s":"") << "=" << channels.size() << " : " << channels); ATA_PRINT(space + "rate" << (sampleRates.size()>1?"s":"") << "=" << sampleRates); ATA_PRINT(space + "native Format" << (nativeFormats.size()>1?"s":"") << ": " << nativeFormats); ATA_PRINT(space + "default=" << (isDefault==true?"true":"false")); } +void audio::orchestra::DeviceInfo::clear() { + isCorrect = false; + input = false; + name = ""; + desc = ""; + channels.clear(); + sampleRates.clear(); + nativeFormats.clear(); + isDefault = false; +} std::ostream& audio::orchestra::operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj) { _os << "{"; - _os << "name=" << _obj.name << ", "; - _os << "description=" << _obj.desc << ", "; - _os << "channels=" << _obj.channels << ", "; - _os << "default=" << _obj.isDefault << ", "; - _os << "rates=" << _obj.sampleRates << ", "; - _os << "native Format: " << _obj.nativeFormats; + if (_obj.isCorrect == false) { + _os << "NOT CORRECT INFORAMATIONS"; + } else { + _os << "name=" << _obj.name << ", "; + if (_obj.desc.size() != 0) { + _os << "description=" << _obj.desc << ", "; + } + _os << "channels=" << _obj.channels << ", "; + _os << "default=" << _obj.isDefault << ", "; + _os << "rates=" << _obj.sampleRates << ", "; + _os << "native Format: " << _obj.nativeFormats; + } _os << "}"; return _os; } diff --git a/audio/orchestra/DeviceInfo.h b/audio/orchestra/DeviceInfo.h index ec8875d..e6fe2eb 100644 --- a/audio/orchestra/DeviceInfo.h +++ b/audio/orchestra/DeviceInfo.h @@ -19,6 +19,7 @@ namespace audio { */ class DeviceInfo { public: + bool isCorrect; //!< the information is correct (the system can return information incorect). bool input; //!< true if the device in an input; false: output. std::string name; //!< Character string device identifier. std::string desc; //!< description of the device @@ -28,6 +29,7 @@ namespace audio { bool isDefault; //! is default input/output // Default constructor. DeviceInfo() : + isCorrect(false), input(false), name(), desc(), @@ -35,7 +37,14 @@ namespace audio { sampleRates(), nativeFormats(), isDefault(false) {} + /** + * @brief Display the current information of the device (on console) + */ void display(int32_t _tabNumber = 1) const; + /** + * @brief Clear all internal data + */ + void clear(); }; std::ostream& operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj); } diff --git a/audio/orchestra/api/Core.cpp b/audio/orchestra/api/Core.cpp index b8f85af..7bc3857 100644 --- a/audio/orchestra/api/Core.cpp +++ b/audio/orchestra/api/Core.cpp @@ -105,7 +105,7 @@ uint32_t audio::orchestra::api::Core::getDeviceCount() { ATA_ERROR("OS-X error getting device info!"); return 0; } - return dataSize / sizeof(AudioDeviceID); + return (dataSize / sizeof(AudioDeviceID)) * 2; } uint32_t audio::orchestra::api::Core::getDefaultInputDevice() { @@ -145,7 +145,7 @@ uint32_t audio::orchestra::api::Core::getDefaultInputDevice() { } for (uint32_t iii=0; iii= nDevices) { ATA_ERROR("device ID is invalid!"); + info.clear(); return info; } - AudioDeviceID deviceList[ nDevices ]; - uint32_t dataSize = sizeof(AudioDeviceID) * nDevices; + info.input = false; + if (_device%2 == 1) { + info.input = true; + } + // The /2 corespond of not mixing input and output ... ==< then the user number of devide is twice the number of real device ... + AudioDeviceID deviceList[nDevices/2]; + uint32_t dataSize = sizeof(AudioDeviceID) * nDevices/2; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, @@ -224,10 +230,13 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t (void*)&deviceList); if (result != noErr) { ATA_ERROR("OS-X system error getting device IDs."); + info.clear(); return info; } - AudioDeviceID id = deviceList[ _device ]; + AudioDeviceID id = deviceList[ _device/2 ]; + // ------------------------------------------------ // Get the device name. + // ------------------------------------------------ info.name.erase(); CFStringRef cfname; dataSize = sizeof(CFStringRef); @@ -235,102 +244,85 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting device manufacturer."); + info.clear(); return info; } //const char *mname = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding()); int32_t length = CFStringGetLength(cfname); - char *mname = (char *)malloc(length * 3 + 1); - CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding()); - info.name.append((const char *)mname, strlen(mname)); + std::vector name; + name.resize(length * 3 + 1, '\0'); + CFStringGetCString(cfname, &name[0], length * 3 + 1, CFStringGetSystemEncoding()); + info.name.append(&name[0], strlen(&name[0])); info.name.append(": "); CFRelease(cfname); - free(mname); property.mSelector = kAudioObjectPropertyName; result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname); if (result != noErr) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting device name."); + info.clear(); return info; } //const char *name = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding()); length = CFStringGetLength(cfname); - char *name = (char *)malloc(length * 3 + 1); - CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding()); - info.name.append((const char *)name, strlen(name)); + name.resize(length * 3 + 1, '\0'); + CFStringGetCString(cfname, &name[0], length * 3 + 1, CFStringGetSystemEncoding()); + info.name.append(&name[0], strlen(&name[0])); CFRelease(cfname); - free(name); + // ------------------------------------------------ // Get the output stream "configuration". - AudioBufferList *bufferList = nil; + // ------------------------------------------------ property.mSelector = kAudioDevicePropertyStreamConfiguration; - property.mScope = kAudioDevicePropertyScopeOutput; - // property.mElement = kAudioObjectPropertyElementWildcard; + + if (info.input == false) { + property.mScope = kAudioDevicePropertyScopeOutput; + } else { + property.mScope = kAudioDevicePropertyScopeInput; + } + AudioBufferList *bufferList = nullptr; dataSize = 0; result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); if (result != noErr || dataSize == 0) { - ATA_ERROR("system error (" << getErrorCode(result) << ") getting output stream configuration info for device (" << _device << ")."); + ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream configuration info for device (" << _device << ")."); + info.clear(); return info; } // Allocate the AudioBufferList. bufferList = (AudioBufferList *) malloc(dataSize); if (bufferList == nullptr) { - ATA_ERROR("memory error allocating output AudioBufferList."); + ATA_ERROR("memory error allocating AudioBufferList."); + info.clear(); return info; } result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList); if ( result != noErr || dataSize == 0) { free(bufferList); - ATA_ERROR("system error (" << getErrorCode(result) << ") getting output stream configuration for device (" << _device << ")."); + ATA_ERROR("system error (" << getErrorCode(result) << ") getting stream configuration for device (" << _device << ")."); + info.clear(); return info; } - // Get output channel information. - uint32_t i, nStreams = bufferList->mNumberBuffers; - for (i=0; imBuffers[i].mNumberChannels; + // Get channel information. + for (size_t iii=0; iiimNumberBuffers; ++iii) { + for (size_t jjj=0; jjjmBuffers[iii].mNumberChannels; ++jjj) { + info.channels.push_back(audio::channel_unknow); + } } free(bufferList); - // Get the input stream "configuration". - property.mScope = kAudioDevicePropertyScopeInput; - result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); - if ( result != noErr - || dataSize == 0) { - ATA_ERROR("system error (" << getErrorCode(result) << ") getting input stream configuration info for device (" << _device << ")."); + if (info.channels.size() == 0) { + ATA_DEBUG("system error (" << getErrorCode(result) << ") getting stream configuration for device (" << _device << ") ==> no channels."); + info.clear(); return info; } - // Allocate the AudioBufferList. - bufferList = (AudioBufferList *) malloc(dataSize); - if (bufferList == nullptr) { - ATA_ERROR("memory error allocating input AudioBufferList."); - return info; - } - result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList); - if (result != noErr || dataSize == 0) { - free(bufferList); - ATA_ERROR("system error (" << getErrorCode(result) << ") getting input stream configuration for device (" << _device << ")."); - return info; - } - // Get input channel information. - nStreams = bufferList->mNumberBuffers; - for (i=0; imBuffers[i].mNumberChannels; - } - free(bufferList); - // If device opens for both playback and capture, we determine the channels. - if ( info.outputChannels > 0 - && info.inputChannels > 0) { - info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; - } - // Probe the device sample rates. - bool isInput = false; - if (info.outputChannels == 0) { - isInput = true; - } + + // ------------------------------------------------ // Determine the supported sample rates. + // ------------------------------------------------ property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; - if (isInput == false) property.mScope = kAudioDevicePropertyScopeOutput; result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); if ( result != kAudioHardwareNoError || dataSize == 0) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rate info."); + info.clear(); return info; } uint32_t nRanges = dataSize / sizeof(AudioValueRange); @@ -338,6 +330,7 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &rangeList); if (result != kAudioHardwareNoError) { ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rates."); + info.clear(); return info; } double minimumRate = 100000000.0, maximumRate = 0.0; @@ -358,33 +351,40 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t } if (info.sampleRates.size() == 0) { ATA_ERROR("No supported sample rates found for device (" << _device << ")."); + info.clear(); return info; } + // ------------------------------------------------ + // Determine the format. + // ------------------------------------------------ // CoreAudio always uses 32-bit floating point data for PCM streams. // Thus, any other "physical" formats supported by the device are of // no interest to the client. info.nativeFormats.push_back(audio::format_float); - if (info.outputChannels > 0) { + // ------------------------------------------------ + // Determine the default channel. + // ------------------------------------------------ + + if (info.input == false) { if (getDefaultOutputDevice() == _device) { - info.isDefaultOutput = true; + info.isDefault = true; } - } - if (info.inputChannels > 0) { + } else { if (getDefaultInputDevice() == _device) { - info.isDefaultInput = true; + info.isDefault = true; } } - info.probed = true; + info.isCorrect = true; return info; } OSStatus audio::orchestra::api::Core::callbackEvent(AudioDeviceID _inDevice, - const AudioTimeStamp* _inNow, - const AudioBufferList* _inInputData, - const AudioTimeStamp* _inInputTime, - AudioBufferList* _outOutputData, - const AudioTimeStamp* _inOutputTime, - void* _userData) { + const AudioTimeStamp* _inNow, + const AudioBufferList* _inInputData, + const AudioTimeStamp* _inInputTime, + AudioBufferList* _outOutputData, + const AudioTimeStamp* _inOutputTime, + void* _userData) { audio::orchestra::api::Core* myClass = reinterpret_cast(_userData); audio::Time inputTime; audio::Time outputTime; @@ -453,8 +453,8 @@ bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device, ATA_ERROR("device ID is invalid!"); return false; } - AudioDeviceID deviceList[ nDevices ]; - uint32_t dataSize = sizeof(AudioDeviceID) * nDevices; + AudioDeviceID deviceList[ nDevices/2 ]; + uint32_t dataSize = sizeof(AudioDeviceID) * nDevices/2; AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, @@ -470,7 +470,7 @@ bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device, ATA_ERROR("OS-X system error getting device IDs."); return false; } - AudioDeviceID id = deviceList[ _device ]; + AudioDeviceID id = deviceList[ _device/2 ]; // Setup for stream mode. bool isInput = false; if (_mode == audio::orchestra::mode_input) { @@ -505,7 +505,7 @@ bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device, // channels. CoreAudio devices can have an arbitrary number of // streams and each stream can have an arbitrary number of channels. // For each stream, a single buffer of interleaved samples is - // provided. RtAudio prefers the use of one stream of interleaved + // provided. orchestra prefers the use of one stream of interleaved // data or multiple consecutive single-channel streams. However, we // now support multiple consecutive multi-channel streams of // interleaved data as well. diff --git a/audio/orchestra/api/CoreIos.mm b/audio/orchestra/api/CoreIos.mm index 08ef9f0..96eecd3 100644 --- a/audio/orchestra/api/CoreIos.mm +++ b/audio/orchestra/api/CoreIos.mm @@ -46,23 +46,19 @@ audio::orchestra::api::CoreIos::CoreIos(void) : ATA_ERROR("Get count devices : " << 2); audio::orchestra::DeviceInfo tmp; // Add default output format : - tmp.name = "out"; + tmp.name = "speaker"; tmp.sampleRates.push_back(48000); - tmp.outputChannels = 2; - tmp.inputChannels = 0; - tmp.duplexChannels = 0; - tmp.isDefaultOutput = true; - tmp.isDefaultInput = false; + tmp.channels.push_back(audio::channel_frontRight); + tmp.channels.push_back(audio::channel_frontLeft); + tmp.isDefault = true; tmp.nativeFormats.push_back(audio::format_int16); m_devices.push_back(tmp); // add default input format: - tmp.name = "in"; + tmp.name = "microphone"; tmp.sampleRates.push_back(48000); - tmp.outputChannels = 0; - tmp.inputChannels = 2; - tmp.duplexChannels = 0; - tmp.isDefaultOutput = false; - tmp.isDefaultInput = true; + tmp.channels.push_back(audio::channel_frontRight); + tmp.channels.push_back(audio::channel_frontLeft); + tmp.isDefault = true; tmp.nativeFormats.push_back(audio::format_int16); m_devices.push_back(tmp); ATA_INFO("Create CoreIOs interface (end)"); @@ -114,7 +110,7 @@ enum audio::orchestra::error audio::orchestra::api::CoreIos::abortStream(void) { void audio::orchestra::api::CoreIos::callBackEvent(void* _data, int32_t _nbChunk, - const audio::Time& _time) { + const audio::Time& _time) { int32_t doStopStream = 0; std::vector status; if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {