123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../../idlib/precompiled.h"
- #include "../../sound/snd_local.h"
- #include <Carbon/Carbon.h>
- #include <CoreAudio/CoreAudio.h>
- idCVar s_device( "s_device", "-1", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "Sound device to use. -1 for default device" );
- class idAudioHardwareOSX : public idAudioHardware {
- public:
- idAudioHardwareOSX();
- ~idAudioHardwareOSX();
- bool Initialize( );
- // OSX driver doesn't support memory map API
- bool Lock( void **pDSLockedBuffer, ulong *dwDSLockedBufferSize ) { return false; }
- bool Unlock( void *pDSLockedBuffer, dword dwDSLockedBufferSize ) { return false; }
- bool GetCurrentPosition( ulong *pdwCurrentWriteCursor ) { return false; }
- int GetMixBufferSize( void ) { return 0; }
-
- int GetNumberOfSpeakers( void );
- // OSX driver doesn't support write API
- bool Flush( void ) { return false; }
- void Write( bool ) { }
- short* GetMixBuffer( void ) { return NULL; }
-
- private:
- AudioDeviceID selectedDevice;
- bool activeIOProc;
- void Reset( void );
- void InitFailed( void );
- const char* ExtractStatus( OSStatus status );
- void GetAvailableNominalSampleRates( void );
- // AudioDevicePropertyListenerProc
- static OSStatus DeviceListener( AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- void* inClientData );
- // AudioDeviceIOProc
- static OSStatus DeviceIOProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData );
- };
- /*
- ==========
- iAudioHardware::Alloc
- ==========
- */
- idAudioHardware *idAudioHardware::Alloc() { return new idAudioHardwareOSX; }
- /*
- ==========
- idAudioHardware::~idAudioHardware
- ==========
- */
- idAudioHardware::~idAudioHardware() { }
- /*
- ==========
- idAudioHardwareOSX::idAudioHardwareOSX
- ==========
- */
- idAudioHardwareOSX::idAudioHardwareOSX() {
- selectedDevice = kAudioDeviceUnknown;
- activeIOProc = false;
- }
- /*
- ==========
- idAudioHardwareOSX::~idAudioHardwareOSX
- ==========
- */
- idAudioHardwareOSX::~idAudioHardwareOSX() {
- Reset();
- }
- /*
- ==========
- idAudioHardwareOSX::Reset
- ==========
- */
- void idAudioHardwareOSX::Reset() {
- OSStatus status;
- if ( activeIOProc ) {
- status = AudioDeviceStop( selectedDevice, DeviceIOProc );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "idAudioHardwareOSX::Reset: AudioDeviceStop failed. status: %s", ExtractStatus( status ) );
- }
- status = AudioDeviceRemoveIOProc( selectedDevice, DeviceIOProc );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "idAudioHardwareOSX::Reset: AudioDeviceRemoveIOProc failed. status %s\n", ExtractStatus( status ) );
- }
- activeIOProc = false;
- }
- selectedDevice = kAudioDeviceUnknown;
- AudioHardwareUnload();
- }
- /*
- =================
- idAudioHardwareOSX::InitFailed
- =================
- */
- void idAudioHardwareOSX::InitFailed() {
- Reset();
- cvarSystem->SetCVarBool( "s_noSound", true );
- common->Warning( "sound subsystem disabled" );
- common->Printf( "------------------------------------------------\n" );
- }
- /*
- ==========
- idAudioHardwareOSX::DeviceListener
- ==========
- */
- OSStatus idAudioHardwareOSX::DeviceListener( AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- void* inClientData) {
- common->Printf( "DeviceListener\n" );
- return kAudioHardwareNoError;
- }
- /*
- ==========
- idAudioHardwareOSX::DeviceIOProc
- ==========
- */
- OSStatus idAudioHardwareOSX::DeviceIOProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData ) {
- // setup similar to async thread
- Sys_EnterCriticalSection();
- soundSystem->AsyncMix( (int)inOutputTime->mSampleTime, (float*)outOutputData->mBuffers[ 0 ].mData );
- Sys_LeaveCriticalSection();
- // doom mixes sound to -32768.0f 32768.0f range, scale down to -1.0f 1.0f
- SIMDProcessor->Mul( (Float32*)outOutputData->mBuffers[ 0 ].mData, 1.0f / 32768.0f, (Float32*)outOutputData->mBuffers[ 0 ].mData, MIXBUFFER_SAMPLES * 2 );
- return kAudioHardwareNoError;
- }
- /*
- ==========
- idAudioHardwareOSX::ExtractStatus
- ==========
- */
- const char* idAudioHardwareOSX::ExtractStatus( OSStatus status ) {
- static char buf[ sizeof( OSStatus ) + 1 ];
- strncpy( buf, (const char *)&status, sizeof( OSStatus ) );
- buf[ sizeof( OSStatus ) ] = '\0';
- return buf;
- }
- /*
- ==========
- idAudioHardwareOSX::Initialize
- ==========
- */
- bool idAudioHardwareOSX::Initialize( ) {
- UInt32 size;
- OSStatus status;
- int i, deviceCount;
- AudioDeviceID *deviceList;
- char buf[ 1024 ];
- status = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &size, NULL );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioHardwareGetPropertyInfo kAudioHardwarePropertyDevices failed. status: %s", ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- deviceCount = size / sizeof( AudioDeviceID );
- if ( !deviceCount ) {
- common->Printf( "No sound device found\n" );
- InitFailed();
- return false;
- }
- deviceList = (AudioDeviceID*)malloc( size );
- status = AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &size, deviceList );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioHardwareGetProperty kAudioHardwarePropertyDevices failed. status: %s", ExtractStatus( status ) );
- free( deviceList );
- InitFailed();
- return false;
- }
- common->Printf( "%d sound device(s)\n", deviceCount );
- for( i = 0; i < deviceCount; i++ ) {
- size = 1024;
- status = AudioDeviceGetProperty( deviceList[ i ], 0, false, kAudioDevicePropertyDeviceName, &size, buf );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty kAudioDevicePropertyDeviceName %d failed. status: %s", i, ExtractStatus( status ) );
- free( deviceList );
- InitFailed();
- return false;
- }
- common->Printf( " %d: ID %d, %s - ", i, deviceList[ i ], buf );
- size = 1024;
- status = AudioDeviceGetProperty( deviceList[ i ], 0, false, kAudioDevicePropertyDeviceManufacturer, &size, buf );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty kAudioDevicePropertyDeviceManufacturer %d failed. status: %s", i, ExtractStatus( status ) );
- free( deviceList );
- InitFailed();
- return false;
- }
- common->Printf( "%s\n", buf );
- }
- if ( s_device.GetInteger() != -1 && s_device.GetInteger() < deviceCount ) {
- selectedDevice = deviceList[ s_device.GetInteger() ];
- common->Printf( "s_device: device ID %d\n", selectedDevice );
- } else {
- size = sizeof( selectedDevice );
- status = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &size, &selectedDevice );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice failed. status: %s", ExtractStatus( status ) );
- free( deviceList );
- InitFailed();
- return false;
- }
- common->Printf( "select default device, ID %d\n", selectedDevice );
- }
- free( deviceList );
- deviceList = NULL;
- /*
- // setup a listener to watch for changes to properties
- status = AudioDeviceAddPropertyListener( selectedDevice, 0, false, kAudioDeviceProcessorOverload, DeviceListener, this );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceAddPropertyListener kAudioDeviceProcessorOverload failed. status: %s", ExtractStatus( status ) );
- InitFailed();
- return;
- }
- */
- Float64 sampleRate;
- size = sizeof( sampleRate );
- status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyNominalSampleRate, &size, &sampleRate );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyNominalSampleRate failed. status: %s", selectedDevice, ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- common->Printf( "current nominal rate: %g\n", sampleRate );
- if ( sampleRate != PRIMARYFREQ ) {
- GetAvailableNominalSampleRates();
- sampleRate = PRIMARYFREQ;
- common->Printf( "setting rate to: %g\n", sampleRate );
- status = AudioDeviceSetProperty( selectedDevice, NULL, 0, false, kAudioDevicePropertyNominalSampleRate, size, &sampleRate );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceSetProperty %d kAudioDevicePropertyNominalSampleRate %g failed. status: %s", selectedDevice, sampleRate, ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- }
- UInt32 frameSize;
- size = sizeof( UInt32 );
- status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyBufferFrameSize, &size, &frameSize );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyBufferFrameSize failed.status: %s", selectedDevice, ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- common->Printf( "current frame size: %d\n", frameSize );
- // get the allowed frame size range
- AudioValueRange frameSizeRange;
- size = sizeof( AudioValueRange );
- status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &frameSizeRange );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyBufferFrameSizeRange failed. status: %s", selectedDevice, ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- common->Printf( "frame size allowed range: %g %g\n", frameSizeRange.mMinimum, frameSizeRange.mMaximum );
- if ( frameSizeRange.mMaximum < MIXBUFFER_SAMPLES ) {
- common->Warning( "can't obtain the required frame size of %d bits", MIXBUFFER_SAMPLES );
- InitFailed();
- return false;
- }
- if ( frameSize != (unsigned int)MIXBUFFER_SAMPLES ) {
- frameSize = MIXBUFFER_SAMPLES;
- common->Printf( "setting frame size to: %d\n", frameSize );
- size = sizeof( frameSize );
- status = AudioDeviceSetProperty( selectedDevice, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, size, &frameSize );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceSetProperty %d kAudioDevicePropertyBufferFrameSize failed. status: %s", selectedDevice, ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- }
- if ( idSoundSystemLocal::s_numberOfSpeakers.GetInteger() != 2 ) {
- common->Warning( "only stereo sound currently supported" );
- idSoundSystemLocal::s_numberOfSpeakers.SetInteger( 2 );
- }
- UInt32 channels[ 2 ];
- size = 2 * sizeof( UInt32 );
- status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyPreferredChannelsForStereo failed. status: %s", selectedDevice, ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- common->Printf( "using stereo channel IDs %d %d\n", channels[ 0 ], channels[ 1 ] );
- status = AudioDeviceAddIOProc( selectedDevice, DeviceIOProc, NULL );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceAddIOProc failed. status: %s", ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- activeIOProc = true;
- status = AudioDeviceStart( selectedDevice, DeviceIOProc );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceStart failed. status: %s", ExtractStatus( status ) );
- InitFailed();
- return false;
- }
- /*
- // allocate the mix buffer
- // it has the space for ROOM_SLICES_IN_BUFFER DeviceIOProc loops
- mixBufferSize = dwSpeakers * dwSampleSize * dwPrimaryBitRate * ROOM_SLICES_IN_BUFFER / 8;
- mixBuffer = malloc( mixBufferSize );
- memset( mixBuffer, 0, mixBufferSize );
- */
- return true;
- }
- /*
- ==========
- idAudioHardwareOSX::GetAvailableNominalSampleRates
- ==========
- */
- void idAudioHardwareOSX::GetAvailableNominalSampleRates( void ) {
- UInt32 size;
- OSStatus status;
- int i, rangeCount;
- AudioValueRange *rangeArray;
- status = AudioDeviceGetPropertyInfo( selectedDevice, 0, false, kAudioDevicePropertyAvailableNominalSampleRates, &size, NULL );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetPropertyInfo %d kAudioDevicePropertyAvailableNominalSampleRates failed. status: %s", selectedDevice, ExtractStatus( status ) );
- return;
- }
- rangeCount = size / sizeof( AudioValueRange );
- rangeArray = (AudioValueRange *)malloc( size );
- common->Printf( "%d possible rate(s)\n", rangeCount );
- status = AudioDeviceGetProperty( selectedDevice, 0, false, kAudioDevicePropertyAvailableNominalSampleRates, &size, rangeArray );
- if ( status != kAudioHardwareNoError ) {
- common->Warning( "AudioDeviceGetProperty %d kAudioDevicePropertyAvailableNominalSampleRates failed. status: %s", selectedDevice, ExtractStatus( status ) );
- free( rangeArray );
- return;
- }
- for( i = 0; i < rangeCount; i++ ) {
- common->Printf( " %d: min %g max %g\n", i, rangeArray[ i ].mMinimum, rangeArray[ i ].mMaximum );
- }
- free( rangeArray );
- }
- /*
- ==========
- idAudioHardwareOSX::GetNumberOfSpeakers
- ==========
- */
- int idAudioHardwareOSX::GetNumberOfSpeakers() {
- return idSoundSystemLocal::s_numberOfSpeakers.GetInteger();
- }
- /*
- ===============
- Sys_LoadOpenAL
- ===============
- */
- bool Sys_LoadOpenAL( void ) {
- OSErr err;
- long gestaltOSVersion;
- err = Gestalt(gestaltSystemVersion, &gestaltOSVersion);
- if ( err || gestaltOSVersion < 0x1040 ) {
- return false;
- }
- return true;
- }
|