support for selecting audio device for Mac
This commit is contained in:
parent
02c0bcb1ac
commit
e31c59e0f2
2 changed files with 133 additions and 151 deletions
244
mac/sound.cpp
244
mac/sound.cpp
|
@ -92,6 +92,51 @@ CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* ar
|
||||||
&enableIO,
|
&enableIO,
|
||||||
sizeof ( enableIO ) );
|
sizeof ( enableIO ) );
|
||||||
|
|
||||||
|
// set up a callback function for new input data
|
||||||
|
if ( AudioUnitSetProperty ( audioInputUnit,
|
||||||
|
kAudioOutputUnitProperty_SetInputCallback,
|
||||||
|
kAudioUnitScope_Global,
|
||||||
|
0,
|
||||||
|
&inputCallbackStruct,
|
||||||
|
sizeof ( inputCallbackStruct ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio audio unit set property failed" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// set input stream format
|
||||||
|
if ( AudioUnitSetProperty ( audioInputUnit,
|
||||||
|
kAudioUnitProperty_StreamFormat,
|
||||||
|
kAudioUnitScope_Output,
|
||||||
|
1,
|
||||||
|
&streamFormat,
|
||||||
|
sizeof ( streamFormat ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio stream format set property failed" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set up a callback function for new output data
|
||||||
|
if ( AudioUnitSetProperty ( audioOutputUnit,
|
||||||
|
kAudioUnitProperty_SetRenderCallback,
|
||||||
|
kAudioUnitScope_Global,
|
||||||
|
0,
|
||||||
|
&outputCallbackStruct,
|
||||||
|
sizeof ( outputCallbackStruct ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio audio unit set property failed" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ste output stream format
|
||||||
|
if ( AudioUnitSetProperty ( audioOutputUnit,
|
||||||
|
kAudioUnitProperty_StreamFormat,
|
||||||
|
kAudioUnitScope_Input,
|
||||||
|
0,
|
||||||
|
&streamFormat,
|
||||||
|
sizeof ( streamFormat ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio stream format set property failed" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get available input/output devices --------------------------------------
|
// Get available input/output devices --------------------------------------
|
||||||
UInt32 iPropertySize;
|
UInt32 iPropertySize;
|
||||||
|
@ -114,8 +159,27 @@ CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* ar
|
||||||
// always add system default devices for input and output as first entry
|
// always add system default devices for input and output as first entry
|
||||||
lNumDevs = 0;
|
lNumDevs = 0;
|
||||||
strDriverNames[lNumDevs] = "System Default In/Out Devices";
|
strDriverNames[lNumDevs] = "System Default In/Out Devices";
|
||||||
lNumDevs++;
|
|
||||||
/*
|
iPropertySize = sizeof ( AudioDeviceID );
|
||||||
|
if ( AudioHardwareGetProperty ( kAudioHardwarePropertyDefaultInputDevice,
|
||||||
|
&iPropertySize,
|
||||||
|
&audioInputDevice[lNumDevs] ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio input AudioHardwareGetProperty call failed. "
|
||||||
|
"It seems that no sound card is available in the system." ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
iPropertySize = sizeof ( AudioDeviceID );
|
||||||
|
if ( AudioHardwareGetProperty ( kAudioHardwarePropertyDefaultOutputDevice,
|
||||||
|
&iPropertySize,
|
||||||
|
&audioOutputDevice[lNumDevs] ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio output AudioHardwareGetProperty call failed. "
|
||||||
|
"It seems that no sound card is available in the system." ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
lNumDevs++; // next device
|
||||||
|
|
||||||
// add detected devices (also check for maximum allowed sound cards!)
|
// add detected devices (also check for maximum allowed sound cards!)
|
||||||
//
|
//
|
||||||
// we add combined entries for input and output for each device so that we
|
// we add combined entries for input and output for each device so that we
|
||||||
|
@ -126,20 +190,20 @@ CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* ar
|
||||||
for ( UInt32 j = 0; ( j < deviceCount ) && ( j < MAX_NUMBER_SOUND_CARDS - 1 ); j++ )
|
for ( UInt32 j = 0; ( j < deviceCount ) && ( j < MAX_NUMBER_SOUND_CARDS - 1 ); j++ )
|
||||||
{
|
{
|
||||||
// get device infos for both current devices
|
// get device infos for both current devices
|
||||||
QString strDevicName_i;
|
QString strDeviceName_i;
|
||||||
|
QString strDeviceName_j;
|
||||||
bool bIsInput_i;
|
bool bIsInput_i;
|
||||||
bool bIsOutput_i;
|
|
||||||
QString strDevicName_j;
|
|
||||||
bool bIsInput_j;
|
bool bIsInput_j;
|
||||||
|
bool bIsOutput_i;
|
||||||
bool bIsOutput_j;
|
bool bIsOutput_j;
|
||||||
|
|
||||||
GetAudioDeviceInfos ( audioDevices[i],
|
GetAudioDeviceInfos ( audioDevices[i],
|
||||||
strDevicName_i,
|
strDeviceName_i,
|
||||||
bIsInput_i,
|
bIsInput_i,
|
||||||
bIsOutput_i );
|
bIsOutput_i );
|
||||||
|
|
||||||
GetAudioDeviceInfos ( audioDevices[j],
|
GetAudioDeviceInfos ( audioDevices[j],
|
||||||
strDevicName_j,
|
strDeviceName_j,
|
||||||
bIsInput_j,
|
bIsInput_j,
|
||||||
bIsOutput_j );
|
bIsOutput_j );
|
||||||
|
|
||||||
|
@ -147,15 +211,17 @@ CSound::CSound ( void (*fpNewProcessCallback) ( CVector<short>& psData, void* ar
|
||||||
if ( bIsInput_i && bIsOutput_j )
|
if ( bIsInput_i && bIsOutput_j )
|
||||||
{
|
{
|
||||||
strDriverNames[lNumDevs] = "in: " +
|
strDriverNames[lNumDevs] = "in: " +
|
||||||
strDevicName_i + "/out: " +
|
strDeviceName_i + "/out: " +
|
||||||
strDevicName_j;
|
strDeviceName_j;
|
||||||
|
|
||||||
lNumDevs++;
|
// store audio device IDs
|
||||||
|
audioInputDevice[lNumDevs] = audioDevices[i];
|
||||||
|
audioOutputDevice[lNumDevs] = audioDevices[j];
|
||||||
|
|
||||||
|
lNumDevs++; // next device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
OpenCoreAudio();
|
|
||||||
|
|
||||||
// init device index as not initialized (invalid)
|
// init device index as not initialized (invalid)
|
||||||
lCurDev = INVALID_SNC_CARD_DEVICE;
|
lCurDev = INVALID_SNC_CARD_DEVICE;
|
||||||
|
@ -173,7 +239,7 @@ void CSound::GetAudioDeviceInfos ( const AudioDeviceID DeviceID,
|
||||||
AudioDeviceGetProperty ( DeviceID,
|
AudioDeviceGetProperty ( DeviceID,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
kAudioObjectPropertyName, //kAudioObjectPropertyManufacturer,
|
kAudioObjectPropertyName,
|
||||||
&iPropertySize,
|
&iPropertySize,
|
||||||
&sPropertyStringValue );
|
&sPropertyStringValue );
|
||||||
|
|
||||||
|
@ -189,35 +255,51 @@ void CSound::GetAudioDeviceInfos ( const AudioDeviceID DeviceID,
|
||||||
strDeviceName = sC_strPropValue;
|
strDeviceName = sC_strPropValue;
|
||||||
|
|
||||||
// check if device is input or output or both (is that possible?)
|
// check if device is input or output or both (is that possible?)
|
||||||
|
// we do this by trying to set the current device for the audio unit
|
||||||
|
// with the parameter input and output and then we simply check the
|
||||||
|
// error/ok result
|
||||||
bIsInput = !AudioUnitSetProperty ( audioInputUnit,
|
bIsInput = !AudioUnitSetProperty ( audioInputUnit,
|
||||||
kAudioOutputUnitProperty_CurrentDevice,
|
kAudioOutputUnitProperty_CurrentDevice,
|
||||||
kAudioUnitScope_Global,
|
kAudioUnitScope_Global,
|
||||||
1,
|
1,
|
||||||
&DeviceID,
|
&DeviceID,
|
||||||
sizeof ( audioInputDevice ) );
|
sizeof ( AudioDeviceID ) );
|
||||||
|
|
||||||
bIsOutput = !AudioUnitSetProperty ( audioOutputUnit,
|
bIsOutput = !AudioUnitSetProperty ( audioOutputUnit,
|
||||||
kAudioOutputUnitProperty_CurrentDevice,
|
kAudioOutputUnitProperty_CurrentDevice,
|
||||||
kAudioUnitScope_Global,
|
kAudioUnitScope_Global,
|
||||||
0,
|
0,
|
||||||
&DeviceID,
|
&DeviceID,
|
||||||
sizeof ( audioOutputDevice ) );
|
sizeof ( AudioDeviceID ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CSound::LoadAndInitializeDriver ( int iDriverIdx )
|
QString CSound::LoadAndInitializeDriver ( int iDriverIdx )
|
||||||
{
|
{
|
||||||
/*
|
// set input device
|
||||||
// load driver
|
if ( AudioUnitSetProperty ( audioInputUnit,
|
||||||
loadAsioDriver ( cDriverNames[iDriverIdx] );
|
kAudioOutputUnitProperty_CurrentDevice,
|
||||||
if ( ASIOInit ( &driverInfo ) != ASE_OK )
|
kAudioUnitScope_Global,
|
||||||
|
1,
|
||||||
|
&audioInputDevice[iDriverIdx],
|
||||||
|
sizeof ( AudioDeviceID ) ) )
|
||||||
{
|
{
|
||||||
// clean up and return error string
|
throw CGenErr ( tr ( "CoreAudio input AudioUnitSetProperty call failed" ) );
|
||||||
asioDrivers->removeCurrentDriver();
|
}
|
||||||
return tr ( "The audio driver could not be initialized." );
|
|
||||||
|
// set output device
|
||||||
|
if ( AudioUnitSetProperty ( audioOutputUnit,
|
||||||
|
kAudioOutputUnitProperty_CurrentDevice,
|
||||||
|
kAudioUnitScope_Global,
|
||||||
|
0,
|
||||||
|
&audioOutputDevice[iDriverIdx],
|
||||||
|
sizeof ( AudioDeviceID ) ) )
|
||||||
|
{
|
||||||
|
throw CGenErr ( tr ( "CoreAudio output AudioUnitSetProperty call failed" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// check device capabilities if it fullfills our requirements
|
// check device capabilities if it fullfills our requirements
|
||||||
const QString strStat = CheckDeviceCapabilities();
|
const QString strStat =
|
||||||
|
CheckDeviceCapabilities ( audioInputUnit, audioOutputUnit );
|
||||||
|
|
||||||
// check if device is capable
|
// check if device is capable
|
||||||
if ( strStat.isEmpty() )
|
if ( strStat.isEmpty() )
|
||||||
|
@ -225,115 +307,8 @@ QString CSound::LoadAndInitializeDriver ( int iDriverIdx )
|
||||||
// store ID of selected driver if initialization was successful
|
// store ID of selected driver if initialization was successful
|
||||||
lCurDev = iDriverIdx;
|
lCurDev = iDriverIdx;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// driver cannot be used, clean up
|
|
||||||
asioDrivers->removeCurrentDriver();
|
|
||||||
}
|
|
||||||
|
|
||||||
return strStat;
|
return strStat;
|
||||||
*/
|
|
||||||
return ""; // TEST
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSound::OpenCoreAudio()
|
|
||||||
{
|
|
||||||
UInt32 size;
|
|
||||||
|
|
||||||
// set input device
|
|
||||||
size = sizeof ( AudioDeviceID );
|
|
||||||
if ( AudioHardwareGetProperty ( kAudioHardwarePropertyDefaultInputDevice,
|
|
||||||
&size,
|
|
||||||
&audioInputDevice ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio input AudioHardwareGetProperty call failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( AudioUnitSetProperty ( audioInputUnit,
|
|
||||||
kAudioOutputUnitProperty_CurrentDevice,
|
|
||||||
kAudioUnitScope_Global,
|
|
||||||
1,
|
|
||||||
&audioInputDevice,
|
|
||||||
sizeof ( audioInputDevice ) ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio input AudioUnitSetProperty call failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up a callback function for new input data
|
|
||||||
if ( AudioUnitSetProperty ( audioInputUnit,
|
|
||||||
kAudioOutputUnitProperty_SetInputCallback,
|
|
||||||
kAudioUnitScope_Global,
|
|
||||||
0,
|
|
||||||
&inputCallbackStruct,
|
|
||||||
sizeof ( inputCallbackStruct ) ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio audio unit set property failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// set output device
|
|
||||||
size = sizeof ( AudioDeviceID );
|
|
||||||
if ( AudioHardwareGetProperty ( kAudioHardwarePropertyDefaultOutputDevice,
|
|
||||||
&size,
|
|
||||||
&audioOutputDevice ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio output AudioHardwareGetProperty call failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( AudioUnitSetProperty ( audioOutputUnit,
|
|
||||||
kAudioOutputUnitProperty_CurrentDevice,
|
|
||||||
kAudioUnitScope_Global,
|
|
||||||
0,
|
|
||||||
&audioOutputDevice,
|
|
||||||
sizeof ( audioOutputDevice ) ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio output AudioUnitSetProperty call failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up a callback function for new output data
|
|
||||||
if ( AudioUnitSetProperty ( audioOutputUnit,
|
|
||||||
kAudioUnitProperty_SetRenderCallback,
|
|
||||||
kAudioUnitScope_Global,
|
|
||||||
0,
|
|
||||||
&outputCallbackStruct,
|
|
||||||
sizeof ( outputCallbackStruct ) ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio audio unit set property failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// our output
|
|
||||||
if ( AudioUnitSetProperty ( audioOutputUnit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Input,
|
|
||||||
0,
|
|
||||||
&streamFormat,
|
|
||||||
sizeof(streamFormat) ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio stream format set property failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// our input
|
|
||||||
if ( AudioUnitSetProperty ( audioInputUnit,
|
|
||||||
kAudioUnitProperty_StreamFormat,
|
|
||||||
kAudioUnitScope_Output,
|
|
||||||
1,
|
|
||||||
&streamFormat,
|
|
||||||
sizeof(streamFormat) ) )
|
|
||||||
{
|
|
||||||
throw CGenErr ( tr ( "CoreAudio stream format set property failed" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// check device capabilities if it fullfills our requirements
|
|
||||||
const QString strStat = CheckDeviceCapabilities ( audioInputUnit, audioOutputUnit );
|
|
||||||
|
|
||||||
// check if device is capable
|
|
||||||
if ( strStat.isEmpty() )
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw CGenErr ( strStat );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CSound::CheckDeviceCapabilities ( ComponentInstance& NewAudioInputUnit,
|
QString CSound::CheckDeviceCapabilities ( ComponentInstance& NewAudioInputUnit,
|
||||||
|
@ -414,20 +389,21 @@ int CSound::Init ( const int iNewPrefMonoBufferSize )
|
||||||
{
|
{
|
||||||
UInt32 iActualMonoBufferSize;
|
UInt32 iActualMonoBufferSize;
|
||||||
|
|
||||||
// Error message string: in case buffer sizes on input and output cannot be set to the same value
|
// Error message string: in case buffer sizes on input and output cannot be
|
||||||
|
// set to the same value
|
||||||
const QString strErrBufSize = tr ( "The buffer sizes of the current "
|
const QString strErrBufSize = tr ( "The buffer sizes of the current "
|
||||||
"input and output audio device cannot be set to a common value. Please "
|
"input and output audio device cannot be set to a common value. Please "
|
||||||
"choose other input/output audio devices in your system settings." );
|
"choose other input/output audio devices in your system settings." );
|
||||||
|
|
||||||
// try to set input buffer size
|
// try to set input buffer size
|
||||||
iActualMonoBufferSize =
|
iActualMonoBufferSize =
|
||||||
SetBufferSize ( audioInputDevice, true, iNewPrefMonoBufferSize );
|
SetBufferSize ( audioInputDevice[lCurDev], true, iNewPrefMonoBufferSize );
|
||||||
|
|
||||||
if ( iActualMonoBufferSize != static_cast<UInt32> ( iNewPrefMonoBufferSize ) )
|
if ( iActualMonoBufferSize != static_cast<UInt32> ( iNewPrefMonoBufferSize ) )
|
||||||
{
|
{
|
||||||
// try to set the input buffer size to the output so that we
|
// try to set the input buffer size to the output so that we
|
||||||
// have a matching pair
|
// have a matching pair
|
||||||
if ( SetBufferSize ( audioOutputDevice, false, iActualMonoBufferSize ) !=
|
if ( SetBufferSize ( audioOutputDevice[lCurDev], false, iActualMonoBufferSize ) !=
|
||||||
iActualMonoBufferSize )
|
iActualMonoBufferSize )
|
||||||
{
|
{
|
||||||
throw CGenErr ( strErrBufSize );
|
throw CGenErr ( strErrBufSize );
|
||||||
|
@ -436,7 +412,7 @@ int CSound::Init ( const int iNewPrefMonoBufferSize )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// try to set output buffer size
|
// try to set output buffer size
|
||||||
if ( SetBufferSize ( audioOutputDevice, false, iNewPrefMonoBufferSize ) !=
|
if ( SetBufferSize ( audioOutputDevice[lCurDev], false, iNewPrefMonoBufferSize ) !=
|
||||||
static_cast<UInt32> ( iNewPrefMonoBufferSize ) )
|
static_cast<UInt32> ( iNewPrefMonoBufferSize ) )
|
||||||
{
|
{
|
||||||
throw CGenErr ( strErrBufSize );
|
throw CGenErr ( strErrBufSize );
|
||||||
|
|
20
mac/sound.h
20
mac/sound.h
|
@ -52,10 +52,10 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QString LoadAndInitializeDriver ( int iIdx );
|
virtual QString LoadAndInitializeDriver ( int iIdx );
|
||||||
|
|
||||||
QString CheckDeviceCapabilities ( ComponentInstance& NewAudioInputUnit,
|
QString CheckDeviceCapabilities ( ComponentInstance& NewAudioInputUnit,
|
||||||
ComponentInstance& NewAudioOutputUnit );
|
ComponentInstance& NewAudioOutputUnit );
|
||||||
|
|
||||||
void OpenCoreAudio();
|
|
||||||
void CloseCoreAudio();
|
void CloseCoreAudio();
|
||||||
|
|
||||||
UInt32 SetBufferSize ( AudioDeviceID& audioDeviceID,
|
UInt32 SetBufferSize ( AudioDeviceID& audioDeviceID,
|
||||||
|
@ -68,12 +68,18 @@ protected:
|
||||||
bool& bIsOutput );
|
bool& bIsOutput );
|
||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
static OSStatus processInput ( void* inRefCon,AudioUnitRenderActionFlags* ioActionFlags,
|
static OSStatus processInput ( void* inRefCon,
|
||||||
const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
|
AudioUnitRenderActionFlags* ioActionFlags,
|
||||||
|
const AudioTimeStamp* inTimeStamp,
|
||||||
|
UInt32 inBusNumber,
|
||||||
|
UInt32 inNumberFrames,
|
||||||
AudioBufferList* );
|
AudioBufferList* );
|
||||||
|
|
||||||
static OSStatus processOutput ( void* inRefCon,AudioUnitRenderActionFlags*,
|
static OSStatus processOutput ( void* inRefCon,
|
||||||
const AudioTimeStamp*, UInt32, UInt32,
|
AudioUnitRenderActionFlags*,
|
||||||
|
const AudioTimeStamp*,
|
||||||
|
UInt32,
|
||||||
|
UInt32,
|
||||||
AudioBufferList* ioData );
|
AudioBufferList* ioData );
|
||||||
|
|
||||||
AudioStreamBasicDescription streamFormat;
|
AudioStreamBasicDescription streamFormat;
|
||||||
|
@ -82,9 +88,9 @@ protected:
|
||||||
AURenderCallbackStruct outputCallbackStruct;
|
AURenderCallbackStruct outputCallbackStruct;
|
||||||
|
|
||||||
ComponentInstance audioInputUnit;
|
ComponentInstance audioInputUnit;
|
||||||
AudioDeviceID audioInputDevice;
|
AudioDeviceID audioInputDevice[MAX_NUMBER_SOUND_CARDS];
|
||||||
ComponentInstance audioOutputUnit;
|
ComponentInstance audioOutputUnit;
|
||||||
AudioDeviceID audioOutputDevice;
|
AudioDeviceID audioOutputDevice[MAX_NUMBER_SOUND_CARDS];
|
||||||
|
|
||||||
AudioBufferList* pBufferList;
|
AudioBufferList* pBufferList;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue