[DEBUG] correct the Mac audio interface

This commit is contained in:
Edouard DUPIN 2015-07-07 21:37:03 +02:00
parent 09e32a815a
commit 22dd01978a
5 changed files with 124 additions and 96 deletions

View File

@ -36,6 +36,7 @@ const std::vector<uint32_t>& audio::orchestra::genericSampleRate() {
list.push_back(128000); list.push_back(128000);
list.push_back(176400); list.push_back(176400);
list.push_back(192000); list.push_back(192000);
list.push_back(256000);
} }
return list; return list;
}; };

View File

@ -19,24 +19,46 @@ void audio::orchestra::DeviceInfo::display(int32_t _tabNumber) const {
for (int32_t iii=0; iii<_tabNumber; ++iii) { for (int32_t iii=0; iii<_tabNumber; ++iii) {
space += " "; space += " ";
} }
if (isCorrect == false) {
ATA_PRINT(space + "NOT CORRECT INFORAMATIONS");
return;
}
ATA_PRINT(space + "mode=" << (input==true?"input":"output")); ATA_PRINT(space + "mode=" << (input==true?"input":"output"));
ATA_PRINT(space + "name=" << name); 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 + "channel" << (channels.size()>1?"s":"") << "=" << channels.size() << " : " << channels);
ATA_PRINT(space + "rate" << (sampleRates.size()>1?"s":"") << "=" << sampleRates); ATA_PRINT(space + "rate" << (sampleRates.size()>1?"s":"") << "=" << sampleRates);
ATA_PRINT(space + "native Format" << (nativeFormats.size()>1?"s":"") << ": " << nativeFormats); ATA_PRINT(space + "native Format" << (nativeFormats.size()>1?"s":"") << ": " << nativeFormats);
ATA_PRINT(space + "default=" << (isDefault==true?"true":"false")); 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) { std::ostream& audio::orchestra::operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj) {
_os << "{"; _os << "{";
_os << "name=" << _obj.name << ", "; if (_obj.isCorrect == false) {
_os << "description=" << _obj.desc << ", "; _os << "NOT CORRECT INFORAMATIONS";
_os << "channels=" << _obj.channels << ", "; } else {
_os << "default=" << _obj.isDefault << ", "; _os << "name=" << _obj.name << ", ";
_os << "rates=" << _obj.sampleRates << ", "; if (_obj.desc.size() != 0) {
_os << "native Format: " << _obj.nativeFormats; _os << "description=" << _obj.desc << ", ";
}
_os << "channels=" << _obj.channels << ", ";
_os << "default=" << _obj.isDefault << ", ";
_os << "rates=" << _obj.sampleRates << ", ";
_os << "native Format: " << _obj.nativeFormats;
}
_os << "}"; _os << "}";
return _os; return _os;
} }

View File

@ -19,6 +19,7 @@ namespace audio {
*/ */
class DeviceInfo { class DeviceInfo {
public: public:
bool isCorrect; //!< the information is correct (the system can return information incorect).
bool input; //!< true if the device in an input; false: output. bool input; //!< true if the device in an input; false: output.
std::string name; //!< Character string device identifier. std::string name; //!< Character string device identifier.
std::string desc; //!< description of the device std::string desc; //!< description of the device
@ -28,6 +29,7 @@ namespace audio {
bool isDefault; //! is default input/output bool isDefault; //! is default input/output
// Default constructor. // Default constructor.
DeviceInfo() : DeviceInfo() :
isCorrect(false),
input(false), input(false),
name(), name(),
desc(), desc(),
@ -35,7 +37,14 @@ namespace audio {
sampleRates(), sampleRates(),
nativeFormats(), nativeFormats(),
isDefault(false) {} isDefault(false) {}
/**
* @brief Display the current information of the device (on console)
*/
void display(int32_t _tabNumber = 1) const; 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); std::ostream& operator <<(std::ostream& _os, const audio::orchestra::DeviceInfo& _obj);
} }

View File

@ -105,7 +105,7 @@ uint32_t audio::orchestra::api::Core::getDeviceCount() {
ATA_ERROR("OS-X error getting device info!"); ATA_ERROR("OS-X error getting device info!");
return 0; return 0;
} }
return dataSize / sizeof(AudioDeviceID); return (dataSize / sizeof(AudioDeviceID)) * 2;
} }
uint32_t audio::orchestra::api::Core::getDefaultInputDevice() { 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; iii++) { for (uint32_t iii=0; iii<nDevices; iii++) {
if (id == deviceList[iii]) { if (id == deviceList[iii]) {
return iii; return iii*2+1;
} }
} }
ATA_ERROR("No default device found!"); ATA_ERROR("No default device found!");
@ -189,7 +189,7 @@ uint32_t audio::orchestra::api::Core::getDefaultOutputDevice() {
} }
for (uint32_t iii=0; iii<nDevices; iii++) { for (uint32_t iii=0; iii<nDevices; iii++) {
if (id == deviceList[iii]) { if (id == deviceList[iii]) {
return iii; return iii*2;
} }
} }
ATA_ERROR("No default device found!"); ATA_ERROR("No default device found!");
@ -198,19 +198,25 @@ uint32_t audio::orchestra::api::Core::getDefaultOutputDevice() {
audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t _device) { audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t _device) {
audio::orchestra::DeviceInfo info; audio::orchestra::DeviceInfo info;
info.probed = false;
// Get device ID // Get device ID
uint32_t nDevices = getDeviceCount(); uint32_t nDevices = getDeviceCount();
if (nDevices == 0) { if (nDevices == 0) {
ATA_ERROR("no devices found!"); ATA_ERROR("no devices found!");
info.clear();
return info; return info;
} }
if (_device >= nDevices) { if (_device >= nDevices) {
ATA_ERROR("device ID is invalid!"); ATA_ERROR("device ID is invalid!");
info.clear();
return info; return info;
} }
AudioDeviceID deviceList[ nDevices ]; info.input = false;
uint32_t dataSize = sizeof(AudioDeviceID) * nDevices; 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 = { AudioObjectPropertyAddress property = {
kAudioHardwarePropertyDevices, kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeGlobal,
@ -224,10 +230,13 @@ audio::orchestra::DeviceInfo audio::orchestra::api::Core::getDeviceInfo(uint32_t
(void*)&deviceList); (void*)&deviceList);
if (result != noErr) { if (result != noErr) {
ATA_ERROR("OS-X system error getting device IDs."); ATA_ERROR("OS-X system error getting device IDs.");
info.clear();
return info; return info;
} }
AudioDeviceID id = deviceList[ _device ]; AudioDeviceID id = deviceList[ _device/2 ];
// ------------------------------------------------
// Get the device name. // Get the device name.
// ------------------------------------------------
info.name.erase(); info.name.erase();
CFStringRef cfname; CFStringRef cfname;
dataSize = sizeof(CFStringRef); 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); result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname);
if (result != noErr) { if (result != noErr) {
ATA_ERROR("system error (" << getErrorCode(result) << ") getting device manufacturer."); ATA_ERROR("system error (" << getErrorCode(result) << ") getting device manufacturer.");
info.clear();
return info; return info;
} }
//const char *mname = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding()); //const char *mname = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding());
int32_t length = CFStringGetLength(cfname); int32_t length = CFStringGetLength(cfname);
char *mname = (char *)malloc(length * 3 + 1); std::vector<char> name;
CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding()); name.resize(length * 3 + 1, '\0');
info.name.append((const char *)mname, strlen(mname)); CFStringGetCString(cfname, &name[0], length * 3 + 1, CFStringGetSystemEncoding());
info.name.append(&name[0], strlen(&name[0]));
info.name.append(": "); info.name.append(": ");
CFRelease(cfname); CFRelease(cfname);
free(mname);
property.mSelector = kAudioObjectPropertyName; property.mSelector = kAudioObjectPropertyName;
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname); result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &cfname);
if (result != noErr) { if (result != noErr) {
ATA_ERROR("system error (" << getErrorCode(result) << ") getting device name."); ATA_ERROR("system error (" << getErrorCode(result) << ") getting device name.");
info.clear();
return info; return info;
} }
//const char *name = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding()); //const char *name = CFStringGetCStringPtr(cfname, CFStringGetSystemEncoding());
length = CFStringGetLength(cfname); length = CFStringGetLength(cfname);
char *name = (char *)malloc(length * 3 + 1); name.resize(length * 3 + 1, '\0');
CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding()); CFStringGetCString(cfname, &name[0], length * 3 + 1, CFStringGetSystemEncoding());
info.name.append((const char *)name, strlen(name)); info.name.append(&name[0], strlen(&name[0]));
CFRelease(cfname); CFRelease(cfname);
free(name); // ------------------------------------------------
// Get the output stream "configuration". // Get the output stream "configuration".
AudioBufferList *bufferList = nil; // ------------------------------------------------
property.mSelector = kAudioDevicePropertyStreamConfiguration; 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; dataSize = 0;
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
if (result != noErr || dataSize == 0) { 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; return info;
} }
// Allocate the AudioBufferList. // Allocate the AudioBufferList.
bufferList = (AudioBufferList *) malloc(dataSize); bufferList = (AudioBufferList *) malloc(dataSize);
if (bufferList == nullptr) { if (bufferList == nullptr) {
ATA_ERROR("memory error allocating output AudioBufferList."); ATA_ERROR("memory error allocating AudioBufferList.");
info.clear();
return info; return info;
} }
result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList); result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, bufferList);
if ( result != noErr if ( result != noErr
|| dataSize == 0) { || dataSize == 0) {
free(bufferList); 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; return info;
} }
// Get output channel information. // Get channel information.
uint32_t i, nStreams = bufferList->mNumberBuffers; for (size_t iii=0; iii<bufferList->mNumberBuffers; ++iii) {
for (i=0; i<nStreams; i++) { for (size_t jjj=0; jjj<bufferList->mBuffers[iii].mNumberChannels; ++jjj) {
info.outputChannels += bufferList->mBuffers[i].mNumberChannels; info.channels.push_back(audio::channel_unknow);
}
} }
free(bufferList); free(bufferList);
// Get the input stream "configuration". if (info.channels.size() == 0) {
property.mScope = kAudioDevicePropertyScopeInput; ATA_DEBUG("system error (" << getErrorCode(result) << ") getting stream configuration for device (" << _device << ") ==> no channels.");
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); info.clear();
if ( result != noErr
|| dataSize == 0) {
ATA_ERROR("system error (" << getErrorCode(result) << ") getting input stream configuration info for device (" << _device << ").");
return info; 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; i<nStreams; i++) {
info.inputChannels += bufferList->mBuffers[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. // Determine the supported sample rates.
// ------------------------------------------------
property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
if (isInput == false) property.mScope = kAudioDevicePropertyScopeOutput;
result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize); result = AudioObjectGetPropertyDataSize(id, &property, 0, nullptr, &dataSize);
if ( result != kAudioHardwareNoError if ( result != kAudioHardwareNoError
|| dataSize == 0) { || dataSize == 0) {
ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rate info."); ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rate info.");
info.clear();
return info; return info;
} }
uint32_t nRanges = dataSize / sizeof(AudioValueRange); 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); result = AudioObjectGetPropertyData(id, &property, 0, nullptr, &dataSize, &rangeList);
if (result != kAudioHardwareNoError) { if (result != kAudioHardwareNoError) {
ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rates."); ATA_ERROR("system error (" << getErrorCode(result) << ") getting sample rates.");
info.clear();
return info; return info;
} }
double minimumRate = 100000000.0, maximumRate = 0.0; 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) { if (info.sampleRates.size() == 0) {
ATA_ERROR("No supported sample rates found for device (" << _device << ")."); ATA_ERROR("No supported sample rates found for device (" << _device << ").");
info.clear();
return info; return info;
} }
// ------------------------------------------------
// Determine the format.
// ------------------------------------------------
// CoreAudio always uses 32-bit floating point data for PCM streams. // CoreAudio always uses 32-bit floating point data for PCM streams.
// Thus, any other "physical" formats supported by the device are of // Thus, any other "physical" formats supported by the device are of
// no interest to the client. // no interest to the client.
info.nativeFormats.push_back(audio::format_float); info.nativeFormats.push_back(audio::format_float);
if (info.outputChannels > 0) { // ------------------------------------------------
// Determine the default channel.
// ------------------------------------------------
if (info.input == false) {
if (getDefaultOutputDevice() == _device) { if (getDefaultOutputDevice() == _device) {
info.isDefaultOutput = true; info.isDefault = true;
} }
} } else {
if (info.inputChannels > 0) {
if (getDefaultInputDevice() == _device) { if (getDefaultInputDevice() == _device) {
info.isDefaultInput = true; info.isDefault = true;
} }
} }
info.probed = true; info.isCorrect = true;
return info; return info;
} }
OSStatus audio::orchestra::api::Core::callbackEvent(AudioDeviceID _inDevice, OSStatus audio::orchestra::api::Core::callbackEvent(AudioDeviceID _inDevice,
const AudioTimeStamp* _inNow, const AudioTimeStamp* _inNow,
const AudioBufferList* _inInputData, const AudioBufferList* _inInputData,
const AudioTimeStamp* _inInputTime, const AudioTimeStamp* _inInputTime,
AudioBufferList* _outOutputData, AudioBufferList* _outOutputData,
const AudioTimeStamp* _inOutputTime, const AudioTimeStamp* _inOutputTime,
void* _userData) { void* _userData) {
audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData); audio::orchestra::api::Core* myClass = reinterpret_cast<audio::orchestra::api::Core*>(_userData);
audio::Time inputTime; audio::Time inputTime;
audio::Time outputTime; audio::Time outputTime;
@ -453,8 +453,8 @@ bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device,
ATA_ERROR("device ID is invalid!"); ATA_ERROR("device ID is invalid!");
return false; return false;
} }
AudioDeviceID deviceList[ nDevices ]; AudioDeviceID deviceList[ nDevices/2 ];
uint32_t dataSize = sizeof(AudioDeviceID) * nDevices; uint32_t dataSize = sizeof(AudioDeviceID) * nDevices/2;
AudioObjectPropertyAddress property = { AudioObjectPropertyAddress property = {
kAudioHardwarePropertyDevices, kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeGlobal,
@ -470,7 +470,7 @@ bool audio::orchestra::api::Core::probeDeviceOpen(uint32_t _device,
ATA_ERROR("OS-X system error getting device IDs."); ATA_ERROR("OS-X system error getting device IDs.");
return false; return false;
} }
AudioDeviceID id = deviceList[ _device ]; AudioDeviceID id = deviceList[ _device/2 ];
// Setup for stream mode. // Setup for stream mode.
bool isInput = false; bool isInput = false;
if (_mode == audio::orchestra::mode_input) { 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 // channels. CoreAudio devices can have an arbitrary number of
// streams and each stream can have an arbitrary number of channels. // streams and each stream can have an arbitrary number of channels.
// For each stream, a single buffer of interleaved samples is // 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 // data or multiple consecutive single-channel streams. However, we
// now support multiple consecutive multi-channel streams of // now support multiple consecutive multi-channel streams of
// interleaved data as well. // interleaved data as well.

View File

@ -46,23 +46,19 @@ audio::orchestra::api::CoreIos::CoreIos(void) :
ATA_ERROR("Get count devices : " << 2); ATA_ERROR("Get count devices : " << 2);
audio::orchestra::DeviceInfo tmp; audio::orchestra::DeviceInfo tmp;
// Add default output format : // Add default output format :
tmp.name = "out"; tmp.name = "speaker";
tmp.sampleRates.push_back(48000); tmp.sampleRates.push_back(48000);
tmp.outputChannels = 2; tmp.channels.push_back(audio::channel_frontRight);
tmp.inputChannels = 0; tmp.channels.push_back(audio::channel_frontLeft);
tmp.duplexChannels = 0; tmp.isDefault = true;
tmp.isDefaultOutput = true;
tmp.isDefaultInput = false;
tmp.nativeFormats.push_back(audio::format_int16); tmp.nativeFormats.push_back(audio::format_int16);
m_devices.push_back(tmp); m_devices.push_back(tmp);
// add default input format: // add default input format:
tmp.name = "in"; tmp.name = "microphone";
tmp.sampleRates.push_back(48000); tmp.sampleRates.push_back(48000);
tmp.outputChannels = 0; tmp.channels.push_back(audio::channel_frontRight);
tmp.inputChannels = 2; tmp.channels.push_back(audio::channel_frontLeft);
tmp.duplexChannels = 0; tmp.isDefault = true;
tmp.isDefaultOutput = false;
tmp.isDefaultInput = true;
tmp.nativeFormats.push_back(audio::format_int16); tmp.nativeFormats.push_back(audio::format_int16);
m_devices.push_back(tmp); m_devices.push_back(tmp);
ATA_INFO("Create CoreIOs interface (end)"); 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, void audio::orchestra::api::CoreIos::callBackEvent(void* _data,
int32_t _nbChunk, int32_t _nbChunk,
const audio::Time& _time) { const audio::Time& _time) {
int32_t doStopStream = 0; int32_t doStopStream = 0;
std::vector<enum audio::orchestra::status> status; std::vector<enum audio::orchestra::status> status;
if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) { if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {