[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(176400);
list.push_back(192000);
list.push_back(256000);
}
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) {
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;
}

View File

@ -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);
}

View File

@ -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; iii++) {
if (id == deviceList[iii]) {
return iii;
return iii*2+1;
}
}
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++) {
if (id == deviceList[iii]) {
return iii;
return iii*2;
}
}
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 info;
info.probed = false;
// Get device ID
uint32_t nDevices = getDeviceCount();
if (nDevices == 0) {
ATA_ERROR("no devices found!");
info.clear();
return info;
}
if (_device >= 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<char> 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; i<nStreams; i++) {
info.outputChannels += bufferList->mBuffers[i].mNumberChannels;
// Get channel information.
for (size_t iii=0; iii<bufferList->mNumberBuffers; ++iii) {
for (size_t jjj=0; jjj<bufferList->mBuffers[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; 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.
// ------------------------------------------------
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<audio::orchestra::api::Core*>(_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.

View File

@ -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<enum audio::orchestra::status> status;
if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {