diff --git a/mac/sound.cpp b/mac/sound.cpp index d053449a..8636d0b5 100755 --- a/mac/sound.cpp +++ b/mac/sound.cpp @@ -26,10 +26,30 @@ /* Implementation *************************************************************/ -void CSound::OpenCoreAudio() +CSound::CSound ( void (*fpNewProcessCallback) ( CVector& psData, void* arg ), void* arg ) : + CSoundBase ( "CoreAudio", true, fpNewProcessCallback, arg ) { - UInt32 size; - ComponentResult err; + // set up stream format + streamFormat.mSampleRate = SYSTEM_SAMPLE_RATE_HZ; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger; + streamFormat.mFramesPerPacket = 1; + streamFormat.mBytesPerFrame = 4; + streamFormat.mBytesPerPacket = 4; + streamFormat.mChannelsPerFrame = 2; // stereo + streamFormat.mBitsPerChannel = 16; + + // set up a callback struct for new input data + inputCallbackStruct.inputProc = processInput; + inputCallbackStruct.inputProcRefCon = this; + + // set up a callback struct for new output data + outputCallbackStruct.inputProc = processOutput; + outputCallbackStruct.inputProcRefCon = this; + + // allocate memory for buffer struct + pBufferList = (AudioBufferList*) malloc ( offsetof ( AudioBufferList, + mBuffers[0] ) + sizeof ( AudioBuffer ) ); // open the default unit ComponentDescription desc; @@ -57,20 +77,167 @@ void CSound::OpenCoreAudio() // we enable input and disable output for input component UInt32 enableIO = 1; - err = AudioUnitSetProperty ( audioInputUnit, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, - 1, // input element - &enableIO, - sizeof ( enableIO ) ); + AudioUnitSetProperty ( audioInputUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + 1, // input element + &enableIO, + sizeof ( enableIO ) ); enableIO = 0; - err = AudioUnitSetProperty ( audioInputUnit, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, - 0, // output element - &enableIO, - sizeof ( enableIO ) ); + AudioUnitSetProperty ( audioInputUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + 0, // output element + &enableIO, + sizeof ( enableIO ) ); + + + // Get available input/output devices -------------------------------------- + UInt32 iPropertySize; + + // first get property size of devices array and allocate memory + AudioHardwareGetPropertyInfo ( kAudioHardwarePropertyDevices, + &iPropertySize, + NULL ); + + AudioDeviceID* audioDevices = (AudioDeviceID*) malloc ( iPropertySize ); + + // now actually query all devices present in the system + AudioHardwareGetProperty ( kAudioHardwarePropertyDevices, + &iPropertySize, + audioDevices ); + + // calculate device count based on size of returned data array + const UInt32 deviceCount = ( iPropertySize / sizeof ( AudioDeviceID ) ); + + // always add system default devices for input and output as first entry + lNumDevs = 0; + strDriverNames[lNumDevs] = "System Default Device"; + lNumDevs++; + +/* + // add detected devices (also check for maximum allowed sound cards!) + for ( UInt32 i = 0; ( i < deviceCount ) && ( i < MAX_NUMBER_SOUND_CARDS - 1 ); i++ ) + { + +// TODO +//for ( UInt32 j = 0; ( j < deviceCount ) && ( j < MAX_NUMBER_SOUND_CARDS - 1 ); j++ ) +//{ +// if ( i != j ) +// { +// +// } +//} + + + QString strDevicName; + bool bIsInput; + bool bIsOutput; + + GetAudioDeviceInfos ( audioDevices[i], + strDevicName, + bIsInput, + bIsOutput ); + +// TEST +if ( bIsInput && bIsOutput ) + strDriverNames[lNumDevs] = "in/out"; +else if ( !bIsInput && !bIsOutput ) + strDriverNames[lNumDevs] = ""; +else if ( bIsInput ) + strDriverNames[lNumDevs] = "in"; +else if ( bIsOutput ) + strDriverNames[lNumDevs] = "out"; + + lNumDevs++; + } +*/ + + OpenCoreAudio(); + + // init device index as not initialized (invalid) + lCurDev = INVALID_SNC_CARD_DEVICE; +} + +void CSound::GetAudioDeviceInfos ( const AudioDeviceID DeviceID, + QString& strDeviceName, + bool& bIsInput, + bool& bIsOutput ) +{ + // get property name + UInt32 iPropertySize = sizeof ( CFStringRef ); + CFStringRef sPropertyStringValue; + + AudioDeviceGetProperty ( DeviceID, + 0, + false, + kAudioObjectPropertyName, //kAudioObjectPropertyManufacturer, + &iPropertySize, + &sPropertyStringValue ); + + // convert CFString in c-string (quick hack!) and then in QString + char* sC_strPropValue = + (char*) malloc ( CFStringGetLength ( sPropertyStringValue ) + 1 ); + + CFStringGetCString ( sPropertyStringValue, + sC_strPropValue, + CFStringGetLength ( sPropertyStringValue ) + 1, + kCFStringEncodingISOLatin1 ); + + strDeviceName = sC_strPropValue; + + // check if device is input or output or both (is that possible?) + bIsInput = !AudioUnitSetProperty ( audioInputUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 1, + &DeviceID, + sizeof ( audioInputDevice ) ); + + bIsOutput = !AudioUnitSetProperty ( audioOutputUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &DeviceID, + sizeof ( audioOutputDevice ) ); +} + +QString CSound::LoadAndInitializeDriver ( int iDriverIdx ) +{ +/* + // load driver + loadAsioDriver ( cDriverNames[iDriverIdx] ); + if ( ASIOInit ( &driverInfo ) != ASE_OK ) + { + // clean up and return error string + asioDrivers->removeCurrentDriver(); + return tr ( "The audio driver could not be initialized." ); + } + + // check device capabilities if it fullfills our requirements + const QString strStat = CheckDeviceCapabilities(); + + // check if device is capable + if ( strStat.isEmpty() ) + { + // store ID of selected driver if initialization was successful + lCurDev = iDriverIdx; + } + else + { + // driver cannot be used, clean up + asioDrivers->removeCurrentDriver(); + } + + return strStat; +*/ +return ""; // TEST +} + +void CSound::OpenCoreAudio() +{ + UInt32 size; // set input device size = sizeof ( AudioDeviceID ); @@ -92,16 +259,12 @@ void CSound::OpenCoreAudio() } // set up a callback function for new input data - AURenderCallbackStruct input; - input.inputProc = processInput; - input.inputProcRefCon = this; - if ( AudioUnitSetProperty ( audioInputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, - &input, - sizeof ( input ) ) ) + &inputCallbackStruct, + sizeof ( inputCallbackStruct ) ) ) { throw CGenErr ( tr ( "CoreAudio audio unit set property failed" ) ); } @@ -126,30 +289,15 @@ void CSound::OpenCoreAudio() } // set up a callback function for new output data - AURenderCallbackStruct output; - output.inputProc = processOutput; - output.inputProcRefCon = this; - if ( AudioUnitSetProperty ( audioOutputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, - &output, - sizeof ( output ) ) ) + &outputCallbackStruct, + sizeof ( outputCallbackStruct ) ) ) { throw CGenErr ( tr ( "CoreAudio audio unit set property failed" ) ); } - - // set up stream format - AudioStreamBasicDescription streamFormat; - streamFormat.mSampleRate = SYSTEM_SAMPLE_RATE_HZ; - streamFormat.mFormatID = kAudioFormatLinearPCM; - streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger; - streamFormat.mFramesPerPacket = 1; - streamFormat.mBytesPerFrame = 4; - streamFormat.mBytesPerPacket = 4; - streamFormat.mChannelsPerFrame = 2; // stereo - streamFormat.mBitsPerChannel = 16; // our output if ( AudioUnitSetProperty ( audioOutputUnit, @@ -173,10 +321,29 @@ void CSound::OpenCoreAudio() 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, + ComponentInstance& NewAudioOutputUnit ) +{ + UInt32 size; + // check input device sample rate size = sizeof ( Float64 ); Float64 inputSampleRate; - AudioUnitGetProperty ( audioInputUnit, + AudioUnitGetProperty ( NewAudioInputUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 1, @@ -185,16 +352,16 @@ void CSound::OpenCoreAudio() if ( static_cast ( inputSampleRate ) != SYSTEM_SAMPLE_RATE_HZ ) { - throw CGenErr ( QString ( tr ( "Current system audio input device sample " + return QString ( tr ( "Current system audio input device sample " "rate of %1 Hz is not supported. Please open the Audio-MIDI-Setup in " "Applications->Utilities and try to set a sample rate of %2 Hz." ) ).arg ( - static_cast ( inputSampleRate ) ).arg ( SYSTEM_SAMPLE_RATE_HZ ) ); + static_cast ( inputSampleRate ) ).arg ( SYSTEM_SAMPLE_RATE_HZ ); } // check output device sample rate size = sizeof ( Float64 ); Float64 outputSampleRate; - AudioUnitGetProperty ( audioOutputUnit, + AudioUnitGetProperty ( NewAudioOutputUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, @@ -203,15 +370,14 @@ void CSound::OpenCoreAudio() if ( static_cast ( outputSampleRate ) != SYSTEM_SAMPLE_RATE_HZ ) { - throw CGenErr ( QString ( tr ( "Current system audio output device sample " + return QString ( tr ( "Current system audio output device sample " "rate of %1 Hz is not supported. Please open the Audio-MIDI-Setup in " "Applications->Utilities and try to set a sample rate of %2 Hz." ) ).arg ( - static_cast ( outputSampleRate ) ).arg ( SYSTEM_SAMPLE_RATE_HZ ) ); + static_cast ( outputSampleRate ) ).arg ( SYSTEM_SAMPLE_RATE_HZ ); } - // allocate memory for buffer struct - pBufferList = (AudioBufferList*) malloc ( offsetof ( AudioBufferList, - mBuffers[0] ) + sizeof ( AudioBuffer ) ); + // everything is ok, return empty string for "no error" case + return ""; } void CSound::CloseCoreAudio() diff --git a/mac/sound.h b/mac/sound.h index a46f9226..58dbda0e 100755 --- a/mac/sound.h +++ b/mac/sound.h @@ -37,11 +37,10 @@ class CSound : public CSoundBase { public: - CSound ( void (*fpNewProcessCallback) ( CVector& psData, void* arg ), void* arg ) : - CSoundBase ( "CoreAudio", true, fpNewProcessCallback, arg ) { OpenCoreAudio(); } + CSound ( void (*fpNewProcessCallback) ( CVector& psData, void* arg ), void* arg ); virtual ~CSound() { CloseCoreAudio(); } - virtual int Init ( const int iNewPrefMonoBufferSize ); + virtual int Init ( const int iNewPrefMonoBufferSize ); virtual void Start(); virtual void Stop(); @@ -52,10 +51,21 @@ public: int iCoreAudioBufferSizeStero; protected: + virtual QString LoadAndInitializeDriver ( int iIdx ); + QString CheckDeviceCapabilities ( ComponentInstance& NewAudioInputUnit, + ComponentInstance& NewAudioOutputUnit ); + void OpenCoreAudio(); void CloseCoreAudio(); - UInt32 SetBufferSize ( AudioDeviceID& audioDeviceID, const bool bIsInput, - UInt32 iPrefBufferSize ); + + UInt32 SetBufferSize ( AudioDeviceID& audioDeviceID, + const bool bIsInput, + UInt32 iPrefBufferSize ); + + void GetAudioDeviceInfos ( const AudioDeviceID DeviceID, + QString& strDeviceName, + bool& bIsInput, + bool& bIsOutput ); // callbacks static OSStatus processInput ( void* inRefCon,AudioUnitRenderActionFlags* ioActionFlags, @@ -66,10 +76,15 @@ protected: const AudioTimeStamp*, UInt32, UInt32, AudioBufferList* ioData ); - ComponentInstance audioInputUnit; - AudioDeviceID audioInputDevice; - ComponentInstance audioOutputUnit; - AudioDeviceID audioOutputDevice; + AudioStreamBasicDescription streamFormat; + + AURenderCallbackStruct inputCallbackStruct; + AURenderCallbackStruct outputCallbackStruct; + + ComponentInstance audioInputUnit; + AudioDeviceID audioInputDevice; + ComponentInstance audioOutputUnit; + AudioDeviceID audioOutputDevice; AudioBufferList* pBufferList; diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp index 9f71c5a9..c6a22e09 100755 --- a/src/clientsettingsdlg.cpp +++ b/src/clientsettingsdlg.cpp @@ -263,11 +263,6 @@ CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, QWidget* parent, butDriverSetup->hide(); #endif - // set sound card selection to read-only for MacOS/Linux -#ifndef _WIN32 - cbxSoundcard->setEnabled ( false ); -#endif - // init delay and other information controls ledOverallDelay->SetUpdateTime ( 2 * PING_UPDATE_TIME_MS ); ledOverallDelay->Reset(); diff --git a/src/global.h b/src/global.h index 775b0012..f557a1ef 100755 --- a/src/global.h +++ b/src/global.h @@ -123,7 +123,7 @@ LED bar: lbr // maximum number of recognized sound cards installed in the system, // definition for "no device" -#define MAX_NUMBER_SOUND_CARDS 10 +#define MAX_NUMBER_SOUND_CARDS 30 #define INVALID_SNC_CARD_DEVICE -1 // define the maximum number of audio channel for input/output we can store diff --git a/src/soundbase.h b/src/soundbase.h index ed7911b9..76f017ea 100755 --- a/src/soundbase.h +++ b/src/soundbase.h @@ -77,7 +77,7 @@ public: protected: // driver handling - virtual QString LoadAndInitializeDriver ( int ) { return ""; }; + virtual QString LoadAndInitializeDriver ( int ) { return ""; } virtual void UnloadCurrentDriver() {} QVector LoadAndInitializeFirstValidDriver();