1/********************************************************************************************************************************** 2* 3* OpenAL cross platform audio library 4* Copyright (c) 2004, Apple Computer, Inc., Copyright (c) 2012, Apple Inc. All rights reserved. 5* 6* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following 7* conditions are met: 8* 9* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 11* disclaimer in the documentation and/or other materials provided with the distribution. 12* 3. Neither the name of Apple Inc. ("Apple") nor the names of its contributors may be used to endorse or promote products derived 13* from this software without specific prior written permission. 14* 15* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS 17* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 18* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 19* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 20* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21* 22**********************************************************************************************************************************/ 23 24#include "oalContext.h" 25#include "oalSource.h" 26 27// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29// OALContexts 30// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32#pragma mark ***** OALContexts - Public Methods ***** 33OALContext::OALContext (const uintptr_t inSelfToken, OALDevice *inOALDevice, const ALCint *inAttributeList, UInt32 &inBusCount, Float64 &inMixerRate) 34 : 35#if LOG_CONTEXT_VERBOSE 36 mSelfToken (inSelfToken), 37#endif 38// mProcessingActive(true), 39 mOwningDevice(inOALDevice), 40 mMixerNode(0), 41 mMixerUnit (0), 42 mSourceMap (NULL), 43 mSourceMapLock ("OALContext::SourceMapLock"), 44 mDeadSourceMap (NULL), 45 mDeadSourceMapLock ("OALContext::DeadSourceMapLock"), 46 mDistanceModel(AL_INVERSE_DISTANCE_CLAMPED), 47 mSpeedOfSound(343.3), 48 mDopplerFactor(1.0), 49 mDopplerVelocity(1.0), 50 mListenerGain(1.0), 51 mAttributeListSize(0), 52 mAttributeList(NULL), 53 mDistanceScalingRequired(false), 54 mCalculateDistance(true), 55 mRenderQuality(ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_LOW), 56 mSpatialSetting(0), 57 mBusCount(inBusCount), 58 mInUseFlag(0), 59 mMixerOutputRate(inMixerRate), 60 mDefaultReferenceDistance(1.0), 61 mDefaultMaxDistance(100000.0), 62 mUserSpecifiedBusCounts(false), 63 mRenderThreadID(0), 64 mSettableMixerAttenuationCurves(false), 65 mASAReverbState(0), 66 mASAReverbRoomType(0), 67 mASAReverbGlobalLevel(0.0), 68 mASAReverbQuality(ALC_ASA_REVERB_QUALITY_Low), 69 mASAReverbEQGain(0.0), 70 mASAReverbEQBandwidth(3.0), 71 mASAReverbEQFrequency(800.0) 72#if LOG_BUS_CONNECTIONS 73 , mMonoSourcesConnected(0), 74 mStereoSourcesConnected(0) 75#endif 76{ 77#if LOG_CONTEXT_VERBOSE 78 DebugMessageN1("OALContext::OALContext() - OALContext = %ld", (long int) mSelfToken); 79#endif 80 mBusInfo = (BusInfo *) calloc (1, sizeof(BusInfo) * mBusCount); 81 82 UInt32 monoSources = 0, 83 stereoSources = 1; // default 84 85 UInt32 inAttributeListSize = 0; 86 Boolean userSetMixerOutputRate = false; 87 88 if (inAttributeList) 89 { 90 ALCint* currentAttribute = ( ALCint*) inAttributeList; 91 // ATTRIBUTE LIST 92 while (*currentAttribute != 0) 93 { 94 switch (*currentAttribute) 95 { 96 case ALC_FREQUENCY: 97 mMixerOutputRate = (Float64)currentAttribute[1]; 98 userSetMixerOutputRate = true; 99 break; 100 case ALC_REFRESH: 101 break; 102 case ALC_SYNC: 103 break; 104 case ALC_MONO_SOURCES: 105 mUserSpecifiedBusCounts = true; 106 monoSources = currentAttribute[1]; 107 break; 108 case ALC_STEREO_SOURCES: 109 mUserSpecifiedBusCounts = true; 110 stereoSources = currentAttribute[1]; 111 break; 112 default: 113 // is this a failure? 114 break; 115 } 116 currentAttribute += 2; 117 inAttributeListSize += 2; 118 } 119 120 // if no mixer output rate was set, pound in the default rate 121 if (!userSetMixerOutputRate) 122 { 123 // add 2 for the key and value, and 1 for the terminator 124 mAttributeListSize = inAttributeListSize + 3; 125 mAttributeList = (ALCint*) calloc (1, mAttributeListSize * sizeof(ALCint)); 126 mAttributeList[inAttributeListSize] = (ALCint)ALC_FREQUENCY; 127 mAttributeList[inAttributeListSize+1] = (ALCint)mMixerOutputRate; 128 // add the null terminator 129 mAttributeList[inAttributeListSize+2] = 0; 130 } 131 132 else { 133 // add for the terminator 134 mAttributeListSize = inAttributeListSize + 1; 135 mAttributeList = (ALCint*) calloc (1, mAttributeListSize * sizeof(ALCint)); 136 } 137 138 memcpy(mAttributeList, inAttributeList, inAttributeListSize * sizeof(ALCint)); 139 } 140 141 // initialize mContextInfo 142 mListenerPosition[0] = 0.0; 143 mListenerPosition[1] = 0.0; 144 mListenerPosition[2] = 0.0; 145 146 mListenerVelocity[0] = 0.0; 147 mListenerVelocity[1] = 0.0; 148 mListenerVelocity[2] = 0.0; 149 150 mListenerOrientationForward[0] = 0.0; 151 mListenerOrientationForward[1] = 0.0; 152 mListenerOrientationForward[2] = -1.0; 153 154 mListenerOrientationUp[0] = 0.0; 155 mListenerOrientationUp[1] = 1.0; 156 mListenerOrientationUp[2] = 0.0; 157 158 InitializeMixer(stereoSources); 159 160 mSourceMap = new OALSourceMap(); 161 mDeadSourceMap = new OALSourceMap(); 162} 163 164// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 165OALContext::~OALContext() 166{ 167#if LOG_CONTEXT_VERBOSE 168 DebugMessageN1("OALContext::~OALContext() - OALContext = %ld", (long int) mSelfToken); 169#endif 170 171#if CAPTURE_AUDIO_TO_FILE 172 gTheCapturer->Stop(); 173 delete(gTheCapturer); 174 gTheCapturer = NULL; 175#endif 176 177 mOwningDevice->RemoveContext(this); 178 179 // delete all the sources that were created by this context 180 if (mSourceMap) 181 { 182 for (UInt32 i = 0; i < mSourceMap->Size(); i++) 183 { 184 OALSource *oalSource = mSourceMap->GetSourceByIndex(0); 185 if (oalSource) 186 { 187 mSourceMap->Remove(oalSource->GetToken()); 188 delete oalSource; 189 } 190 } 191 delete mSourceMap; 192 } 193 194 if (mDeadSourceMap) 195 { 196 CleanUpDeadSourceList(); 197 delete mDeadSourceMap; 198 } 199 200 if (mAttributeList) 201 free(mAttributeList); 202 203 if(mBusInfo) 204 free(mBusInfo); 205 206} 207 208// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 209void OALContext::CleanUpDeadSourceList() 210{ 211#if LOG_CONTEXT_VERBOSE 212 DebugMessageN1("OALContext::CleanUpDeadSourceList() - OALContext = %ld", (long int) mSelfToken); 213#endif 214 if (mDeadSourceMap) 215 { 216 UInt32 index = 0; 217 for (UInt32 i = 0; i < mDeadSourceMap->Size(); i++) 218 { 219 OALSource* source = mDeadSourceMap->GetSourceByIndex(index); 220 if (source) 221 { 222 if (source->IsSafeForDeletion()) 223 { 224 //DebugMessageN1("OALContext::CleanUpTheDeadSourceList removing source id = %ld", source->GetToken()); 225 mDeadSourceMap->Remove(source->GetToken()); 226 delete (source); 227 } 228 else 229 { 230 //DebugMessageN1("OALContext::CleanUpTheDeadSourceList NOT SAFE RIGHT NOW to delete source id = %ld", source->GetToken()); 231 index++; 232 } 233 } 234 else 235 index++; 236 } 237 } 238} 239 240// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 241/* 242 3DMixer Version Info 243 244 - Pre 2.0 Mixer must be at least version 1.3 for OpenAL 245 - 3DMixer 2.0 246 Bug in Distance Attenuationg/Reverb code requires that distances be scaled in OAL before passing to mixer 247 - 3DMixer 2.1 248 Fixes bug in 2.0 but also has a bug related to OAL fixes for correctly caclulating the vector of moving object 249 - 3DMixer 2.1.x 250 Fixes bugs in 2.1 and adds support for Linear Attenuation 251 - 3DMixer 2.2 252 Adds Linear/Exponential Attenuation and Reverb/Occlusion/Obstruction. 253 (note) Linear & Exponential Attenuation is done manually by the OALSource object if 2.2 Mixer is not present 254*/ 255 256void OALContext::InitializeMixer(UInt32 inStereoBusCount) 257{ 258#if LOG_CONTEXT_VERBOSE 259 DebugMessageN2("OALContext::InitializeMixer() - OALContext:inStereoBusCount = %ld:%d", (long int) mSelfToken, inStereoBusCount); 260#endif 261 OSStatus result = noErr; 262 UInt32 propSize; 263 264 try { 265 // ~~~~~~~~~~~~~~~~~~~ GET 3DMIXER VERSION 266 if (Get3DMixerVersion() < k3DMixerVersion_1_3) 267 throw -1; // should not happen because OpenDevice should have failed beforehand 268 269 if (Get3DMixerVersion() == k3DMixerVersion_2_0) 270 { 271 mDistanceScalingRequired = true; 272 } 273 else if (Get3DMixerVersion() >= k3DMixerVersion_2_2) 274 { 275 mSettableMixerAttenuationCurves = true; 276 } 277 278 ComponentDescription mixerCD; 279 mixerCD.componentFlags = 0; 280 mixerCD.componentFlagsMask = 0; 281 mixerCD.componentType = kAudioUnitType_Mixer; 282 mixerCD.componentSubType = kAudioUnitSubType_3DMixer; 283 mixerCD.componentManufacturer = kAudioUnitManufacturer_Apple; 284 285 // CREATE NEW NODE FOR THE GRAPH 286 result = AUGraphNewNode (mOwningDevice->GetGraph(), &mixerCD, 0, NULL, &mMixerNode); 287 THROW_RESULT 288 289 result = AUGraphGetNodeInfo (mOwningDevice->GetGraph(), mMixerNode, 0, 0, 0, &mMixerUnit); 290 THROW_RESULT 291 292 // Get Default Distance Setting when the good 3DMixer is around 293 if (Get3DMixerVersion() >= k3DMixerVersion_2_0) 294 { 295 MixerDistanceParams distanceParams; 296 propSize = sizeof(distanceParams); 297 result = AudioUnitGetProperty(mMixerUnit, kAudioUnitProperty_3DMixerDistanceParams, kAudioUnitScope_Input, 1, &distanceParams, &propSize); 298 if (result == noErr) 299 { 300 mDefaultReferenceDistance = distanceParams.mReferenceDistance; 301 mDefaultMaxDistance = distanceParams.mMaxDistance; 302 } 303 } 304 305 // Set the Output Format of the Mixer AU 306 CAStreamBasicDescription format; 307 UInt32 propSize = sizeof(format); 308 result = AudioUnitGetProperty(mOwningDevice->GetOutputAU(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, &propSize); 309 310 format.SetCanonical (mOwningDevice->GetDesiredRenderChannelCount(), false); // determine how many channels to render to 311 format.mSampleRate = GetMixerRate(); // Sample Rate (either the default out rate of the Output AU or a User Specified rate) 312 313 result = AudioUnitSetProperty (mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format)); 314 THROW_RESULT 315 316 // Frames Per Slice - moved from ConnectContext call in device class 317 UInt32 mixerFPS = 0; 318 UInt32 dataSize = sizeof(mixerFPS); 319 result = AudioUnitGetProperty(mMixerUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &mixerFPS, &dataSize); 320 if (mixerFPS < mOwningDevice->GetFramesPerSlice()) 321 { 322 mixerFPS = mOwningDevice->GetFramesPerSlice(); 323 result = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &mixerFPS, sizeof(mixerFPS)); 324 THROW_RESULT 325 } 326 327 // REVERB off by default 328 result = AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_UsesInternalReverb, kAudioUnitScope_Global, 0, &mASAReverbState, sizeof(mASAReverbState)); 329 // ignore result 330 331 // MIXER BUS COUNT 332 if (Get3DMixerVersion() < k3DMixerVersion_2_0) 333 { 334 mBusCount = kDefaultMaximumMixerBusCount; // 1.3 version of the mixer did not allow a change in the bus count 335 } 336 else 337 { 338 // set the bus count on the mixer if necessary 339 UInt32 currentBusCount; 340 propSize = sizeof(currentBusCount); 341 result = AudioUnitGetProperty ( mMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, ¤tBusCount, &propSize); 342 if ((result == noErr) && (mBusCount != currentBusCount)) 343 { 344 result = AudioUnitSetProperty ( mMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &mBusCount, propSize); 345 if (result != noErr) 346 { 347 // couldn't set the bus count so make sure we know just how many busses there are 348 propSize = sizeof(mBusCount); 349 AudioUnitGetProperty ( mMixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &mBusCount, &propSize); 350 } 351 } 352 } 353 354 // SET UP STEREO/MONO BUSSES 355 CAStreamBasicDescription theOutFormat; 356 theOutFormat.mSampleRate = mMixerOutputRate; 357 theOutFormat.mFormatID = kAudioFormatLinearPCM; 358 theOutFormat.mFramesPerPacket = 1; 359 theOutFormat.mBytesPerFrame = sizeof (Float32); 360 theOutFormat.mBitsPerChannel = sizeof (Float32) * 8; 361 theOutFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; 362 theOutFormat.mBytesPerPacket = sizeof (Float32); 363 364 for (UInt32 i = 0; i < mBusCount; i++) 365 { 366 // Distance Attenuation: for pre v2.0 mixer 367 SetDistanceAttenuation (i, kDefaultReferenceDistance, kDefaultMaximumDistance, kDefaultRolloff); 368 369 theOutFormat.mChannelsPerFrame = (i < inStereoBusCount) ? 2 : 1; 370 OSStatus result = AudioUnitSetProperty ( mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 371 i, &theOutFormat, sizeof(CAStreamBasicDescription)); 372 THROW_RESULT 373 374 mBusInfo[i].mNumberChannels = theOutFormat.mChannelsPerFrame; 375 mBusInfo[i].mSourceAttached = kNoSourceAttached; 376 mBusInfo[i].mReverbState = mASAReverbState; 377 378 // set kAudioUnitProperty_SpatializationAlgorithm 379 UInt32 spatAlgo = (theOutFormat.mChannelsPerFrame == 2) ? kSpatializationAlgorithm_StereoPassThrough : mSpatialSetting; 380 AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, i, &spatAlgo, sizeof(spatAlgo)); 381 382 // set kAudioUnitProperty_3DMixerRenderingFlags (distance attenuation) for mono busses 383 if (theOutFormat.mChannelsPerFrame == 1) 384 { 385 UInt32 render_flags_3d = k3DMixerRenderingFlags_DistanceAttenuation; 386 if (mRenderQuality == ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_HIGH) 387 render_flags_3d += k3DMixerRenderingFlags_InterAuralDelay; // off by default, on if the user sets High Quality rendering 388 389 // Render Flags 390 result = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_3DMixerRenderingFlags, kAudioUnitScope_Input, i, &render_flags_3d, sizeof(render_flags_3d)); 391 } 392 } 393 394 // Initialize Busses - attributes may affect this operation 395 InitRenderQualityOnBusses(); 396 } 397 catch(OSStatus result){ 398 throw result; 399 } 400 catch(...){ 401 throw -1; 402 } 403} 404 405// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 406// should only be called when the mixer is NOT connected 407void OALContext::ConfigureMixerFormat() 408{ 409#if LOG_CONTEXT_VERBOSE 410 DebugMessageN1("OALContext::ConfigureMixerFormat() - OALContext = %ld", (long int) mSelfToken); 411#endif 412 // Set the Output Format of the Mixer AU 413 CAStreamBasicDescription format; 414 UInt32 propSize = sizeof(format); 415 OSStatus result = AudioUnitGetProperty(mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, &propSize); 416 417 format.SetCanonical (mOwningDevice->GetDesiredRenderChannelCount(), false); // determine how many channels to render to 418 format.mSampleRate = GetMixerRate(); // Sample Rate (either the default out rate of the Output AU or a User Specified rate) 419 420 result = AudioUnitSetProperty (mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format)); 421 THROW_RESULT 422 423 // Initialize Busses - render channel attributes attributes may affect this operation 424 InitRenderQualityOnBusses(); 425} 426 427// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 428void OALContext::CopyAttributeList( ALCint* outAttrList) 429{ 430#if LOG_CONTEXT_VERBOSE 431 DebugMessageN1("OALContext::CopyAttributeList() - OALContext = %ld", (long int) mSelfToken); 432#endif 433 memcpy(outAttrList, mAttributeList, mAttributeListSize*sizeof(ALCint)); 434} 435 436// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 437void OALContext::AddSource(ALuint inSourceToken) 438{ 439#if LOG_CONTEXT_VERBOSE 440 DebugMessageN2("OALContext::AddSource() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 441#endif 442 try { 443 OALSource *newSource = new OALSource (inSourceToken, this); 444 445 { 446 CAGuard::Locker locked(mSourceMapLock); 447 mSourceMap->Add(inSourceToken, &newSource); 448 } 449 { 450 CAGuard::Locker locked(mDeadSourceMapLock); 451 CleanUpDeadSourceList(); 452 } 453 } 454 catch (...) { 455 throw; 456 } 457} 458 459// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 460// You MUST call ReleaseSource after you have completed use of the source object 461OALSource* OALContext::ProtectSource(ALuint inSourceToken) 462{ 463#if LOG_CONTEXT_VERBOSE 464 DebugMessageN2("OALContext::ProtectSource() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 465#endif 466 OALSource *newSource = NULL; 467 468 CAGuard::Locker locked(mSourceMapLock); 469 470 newSource = mSourceMap->Get(inSourceToken); 471 472 if (newSource) 473 newSource->SetInUseFlag(); 474 475 return newSource; 476} 477 478// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 479// You MUST call ReleaseSource after you have completed use of the source object 480OALSource* OALContext::GetSourceForRender(ALuint inSourceToken) 481{ 482#if LOG_CONTEXT_VERBOSE 483 DebugMessageN2("OALContext::GetSourceForRender() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 484#endif 485 OALSource *newSource = NULL; 486 487 CAMutex::Tryer tryer(mSourceMapLock); 488 489 if (tryer.HasLock()) 490 { 491 newSource = mSourceMap->Get(inSourceToken); 492 493 if (newSource) 494 newSource->SetInUseFlag(); 495 } 496 497 return newSource; 498} 499 500// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 501// You MUST call ReleaseSource after you have completed use of the dead source object 502OALSource* OALContext::GetDeadSourceForRender(ALuint inSourceToken) 503{ 504#if LOG_CONTEXT_VERBOSE 505 DebugMessageN2("OALContext::GetDeadSourceForRender() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 506#endif 507 OALSource *deadSource = NULL; 508 509 CAMutex::Tryer tryer(mDeadSourceMapLock); 510 511 if (tryer.HasLock()) 512 { 513 deadSource = mDeadSourceMap->Get(inSourceToken); 514 515 if (deadSource) 516 deadSource->SetInUseFlag(); 517 } 518 519 return deadSource; 520} 521 522// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 523void OALContext::ReleaseSource(OALSource* inSource) 524{ 525#if LOG_CONTEXT_VERBOSE 526 DebugMessageN2("OALContext::ReleaseSource() - OALContext:inSource = %ld:%d", (long int) mSelfToken, inSource->GetToken()); 527#endif 528 if (inSource) 529 inSource->ClearInUseFlag(); 530} 531 532// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 533void OALContext::RemoveSource(ALuint inSourceToken) 534{ 535#if LOG_CONTEXT_VERBOSE 536 DebugMessageN2("OALContext::RemoveSource() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 537#endif 538 OALSource *oalSource = mSourceMap->Get(inSourceToken); 539 if (oalSource != NULL) 540 { 541 oalSource->SetUpDeconstruction(); 542 543 { 544 CAGuard::Locker locked(mSourceMapLock); 545 mSourceMap->Remove(inSourceToken); // do not allow any more threads to use this source object 546 } 547 { 548 CAGuard::Locker locked(mDeadSourceMapLock); 549 mDeadSourceMap->Add(inSourceToken, &oalSource); // remove it later when it is safe 550 CleanUpDeadSourceList(); // now is a good time to actually delete other sources marked for deletion 551 } 552 } 553} 554 555// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 556void OALContext::ProcessContext() 557{ 558#if LOG_CONTEXT_VERBOSE 559 DebugMessageN1("OALContext::ProcessContext() - OALContext = %ld", (long int) mSelfToken); 560#endif 561 return; // NO OP 562 563#if 0 564 // This code breaks Doom 3 [4554491] - The 1.0 implementation was a no op. 565 // Since alcProcessContext()/alcSuspendContext() are also no ops on sound c ards with OpenAL imps, this should be ok 566 567 if (mProcessingActive == true) 568 return; // NOP 569 570 ConnectMixerToDevice(); 571 mProcessingActive = true; 572 return; 573#endif 574} 575 576// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 577void OALContext::SuspendContext() 578{ 579#if LOG_CONTEXT_VERBOSE 580 DebugMessageN1("OALContext::SuspendContext() - OALContext = %ld", (long int) mSelfToken); 581#endif 582 return; // NO OP 583 584#if 0 585 // This code breaks Doom 3 [4554491] - The 1.0 implementation was a no op. 586 // Since alcProcessContext()/alcSuspendContext() are also no ops on sound c ards with OpenAL imps, this should be ok 587 588 if (mProcessingActive == false) 589 return; // NOP 590 591 DeviceDisconnect(); 592 mProcessingActive = false; 593#endif 594} 595 596// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 597void OALContext::ConnectMixerToDevice() 598{ 599#if LOG_CONTEXT_VERBOSE 600 DebugMessageN1("OALContext::ConnectMixerToDevice() - OALContext = %ld", (long int) mSelfToken); 601#endif 602 mOwningDevice->ConnectContext(this); 603 604#if CAPTURE_AUDIO_TO_FILE 605 DebugMessage ("ABOUT TO START CAPTURE"); 606 607 gCapturerDataFormat.mSampleRate = 44100.0; 608 gCapturerDataFormat.mFormatID = kAudioFormatLinearPCM; 609 gCapturerDataFormat.mFormatFlags = kAudioFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; 610 gCapturerDataFormat.mBytesPerPacket = 4; 611 gCapturerDataFormat.mFramesPerPacket = 1; 612 gCapturerDataFormat.mBytesPerFrame = 4; 613 gCapturerDataFormat.mChannelsPerFrame = 2; 614 gCapturerDataFormat.mBitsPerChannel = 16; 615 gCapturerDataFormat.mReserved = 0; 616 617 gFileURL = CFURLCreateWithFileSystemPath(NULL, CFSTR("<PathToCapturedFileLocation>CapturedAudio.wav"), kCFURLPOSIXPathStyle, false); 618 gTheCapturer = new CAAudioUnitOutputCapturer(mMixerUnit, gFileURL, 'WAVE', gCapturerDataFormat); 619 620 gTheCapturer->Start(); 621#endif 622 623 OSStatus result = AUGraphAddRenderNotify(mOwningDevice->GetGraph(), ContextNotificationProc, this); 624 THROW_RESULT 625} 626 627void OALContext::DisconnectMixerFromDevice() 628{ 629 mOwningDevice->DisconnectContext(this); 630 631#if CAPTURE_AUDIO_TO_FILE 632 DebugMessage ("STOPPING CAPTURE"); 633 634 gTheCapturer->Stop(); 635#endif 636 637 OSStatus result = AUGraphRemoveRenderNotify(mOwningDevice->GetGraph(), ContextNotificationProc, this); 638 THROW_RESULT 639} 640 641 642// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 643void OALContext::SetDistanceModel(UInt32 inDistanceModel) 644{ 645#if LOG_CONTEXT_VERBOSE || LOG_GRAPH_AND_MIXER_CHANGES 646 DebugMessageN2("OALContext::SetDistanceModel() - OALContext:inDistanceModel = %ld:%d", (long int) mSelfToken, inDistanceModel); 647#endif 648 OSStatus result = noErr; 649 UInt32 curve; 650 651 if (mDistanceModel != inDistanceModel) 652 { 653 //UInt32 curve; 654 switch (inDistanceModel) 655 { 656 case AL_INVERSE_DISTANCE: 657 case AL_INVERSE_DISTANCE_CLAMPED: 658 mCalculateDistance = true; 659 if (mSettableMixerAttenuationCurves) 660 { 661 curve =2 /* k3DMixerAttenuationCurve_Inverse*/; 662 for (UInt32 i = 0; i < mBusCount; i++) 663 { 664 result = AudioUnitSetProperty( mMixerUnit, 3013 /*kAudioUnitProperty_3DMixerAttenuationCurve*/, kAudioUnitScope_Input, i, &curve, sizeof(curve)); 665 } 666 } 667 else 668 { 669 // NOTHING TO DO 670 if (Get3DMixerVersion() >= k3DMixerVersion_2_0) 671 { 672 // unnecessary if changing between AL_INVERSE_DISTANCE & AL_INVERSE_DISTANCE_CLAMPED 673 if ((mDistanceModel != AL_INVERSE_DISTANCE) && (mDistanceModel != AL_INVERSE_DISTANCE_CLAMPED)) 674 { 675 // this is the 2.0-2.1 mixer 676 } 677 } 678 else 679 { 680 // kAudioUnitProperty_3DMixerDistanceAtten gets set by the source each time via a call to SetDistanceAttenuation() 681 // nothing more to do now 682 } 683 } 684 685 break; 686 687 case AL_LINEAR_DISTANCE: 688 case AL_LINEAR_DISTANCE_CLAMPED: 689 if (mSettableMixerAttenuationCurves) 690 { 691 mCalculateDistance = true; 692 curve = 3 /*k3DMixerAttenuationCurve_Linear*/; 693 for (UInt32 i = 0; i < mBusCount; i++) 694 { 695 result = AudioUnitSetProperty( mMixerUnit, 3013 /*kAudioUnitProperty_3DMixerAttenuationCurve*/, kAudioUnitScope_Input, i, &curve, sizeof(curve)); 696 } 697 } 698 else 699 { 700 mCalculateDistance = false; 701 // turn off distance attenuation altogether 702 // the source will then apply the linear distance formula as a gain scalar and set the bus gain instead of setting any distance 703 } 704 break; 705 706 case AL_EXPONENT_DISTANCE: 707 case AL_EXPONENT_DISTANCE_CLAMPED: 708 if (mSettableMixerAttenuationCurves) 709 { 710 mCalculateDistance = true; 711 // set the mixer for Exponential Attenuation 712 curve = 1 /*k3DMixerAttenuationCurve_Exponential*/; 713 for (UInt32 i = 0; i < mBusCount; i++) 714 { 715 result = AudioUnitSetProperty( mMixerUnit, 3013 /*kAudioUnitProperty_3DMixerAttenuationCurve*/, kAudioUnitScope_Input, i, &curve, sizeof(curve)); 716 } 717 } 718 else 719 { 720 mCalculateDistance = false; 721 // turn off distance attenuation altogether 722 // the source will then apply the exponential distance formula as a gain scalar and set the bus gain instead of setting any distance 723 } 724 break; 725 726 case AL_NONE: 727 { 728 mCalculateDistance = false; 729 // turn off distance attenuation altogether 730 } 731 732 break; 733 734 735 default: 736 break; 737 } 738 739 mDistanceModel = inDistanceModel; 740 if (mSourceMap) 741 { 742 CAGuard::Locker locked(mSourceMapLock); 743 mSourceMap->MarkAllSourcesForRecalculation(); 744 } 745 } 746} 747 748// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 749void OALContext::SetDopplerFactor(Float32 inDopplerFactor) 750{ 751#if LOG_CONTEXT_VERBOSE 752 DebugMessageN2("OALContext::SetDopplerFactor() - OALContext:inDopplerFactor = %ld:%f", (long int) mSelfToken, inDopplerFactor); 753#endif 754 if (mDopplerFactor != inDopplerFactor) 755 { 756 mDopplerFactor = inDopplerFactor; 757 if (mSourceMap) 758 { 759 CAGuard::Locker locked(mSourceMapLock); 760 mSourceMap->MarkAllSourcesForRecalculation(); 761 } 762 } 763} 764 765// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 766void OALContext::SetDopplerVelocity(Float32 inDopplerVelocity) 767{ 768#if LOG_CONTEXT_VERBOSE 769 DebugMessageN2("OALContext::SetDopplerVelocity() - OALContext:inDopplerVelocity = %ld:%f", (long int) mSelfToken, inDopplerVelocity); 770#endif 771 if (mDopplerVelocity != inDopplerVelocity) 772 { 773 mDopplerVelocity = inDopplerVelocity; 774 // if (mSourceMap) 775 // mSourceMap->MarkAllSourcesForRecalculation(); 776 } 777} 778 779// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 780void OALContext::SetSpeedOfSound(Float32 inSpeedOfSound) 781{ 782#if LOG_CONTEXT_VERBOSE 783 DebugMessageN2("OALContext::SetSpeedOfSound() - OALContext:inSpeedOfSound = %ld:%f", (long int) mSelfToken, inSpeedOfSound); 784#endif 785 if (mSpeedOfSound != inSpeedOfSound) 786 { 787 mSpeedOfSound = inSpeedOfSound; 788 if (mSourceMap) 789 { 790 CAGuard::Locker locked(mSourceMapLock); 791 mSourceMap->MarkAllSourcesForRecalculation(); 792 } 793 } 794} 795 796// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 797void OALContext::SetListenerGain(Float32 inGain) 798{ 799#if LOG_CONTEXT_VERBOSE 800 DebugMessageN2("OALContext::SetListenerGain() - OALContext:inGain = %ld:%f", (long int) mSelfToken, inGain); 801#endif 802 if (inGain < 0.0f) 803 throw (OSStatus) AL_INVALID_VALUE; 804 805 if (mListenerGain != inGain) 806 { 807 mListenerGain = inGain; 808 809 Float32 db = 20.0 * log10(inGain); // convert to db 810 AudioUnitSetParameter (mMixerUnit, k3DMixerParam_Gain, kAudioUnitScope_Output, 0, db, 0); 811 } 812} 813 814// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 815UInt32 OALContext::GetSourceCount() 816{ 817#if LOG_CONTEXT_VERBOSE 818 DebugMessageN1("OALContext::GetSourceCount() - OALContext = %ld", (long int) mSelfToken); 819#endif 820 UInt32 count = 0; 821 822 if (mSourceMap) 823 { 824 CAGuard::Locker locked(mSourceMapLock); 825 count = mSourceMap->Size(); 826 } 827 828 return count; 829} 830 831// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 832void OALContext::SetListenerPosition(Float32 posX, Float32 posY, Float32 posZ) 833{ 834#if LOG_CONTEXT_VERBOSE 835 DebugMessageN4("OALContext::SetListenerPosition() - OALContext:posX:posY:posZ = %ld:%f:%f:%f", (long int) mSelfToken, posX, posY, posZ); 836#endif 837 if (isnan(posX) || isnan(posY) || isnan(posZ)) 838 throw ((OSStatus) AL_INVALID_VALUE); 839 840 if ( (mListenerPosition[0] == posX) && 841 (mListenerPosition[1] == posY ) && 842 (mListenerPosition[2] == posZ) ) 843 return; 844 845 mListenerPosition[0] = posX; 846 mListenerPosition[1] = posY; 847 mListenerPosition[2] = posZ; 848 849 if (mSourceMap) 850 { 851#if LOG_GRAPH_AND_MIXER_CHANGES 852 DebugMessageN4("OALContext::SetListenerPosition called - OALSource = %f:%f:%f/%ld\n", posX, posY, posZ, mSelfToken); 853#endif 854 CAGuard::Locker locked(mSourceMapLock); 855 // moving the listener effects the coordinate translation for ALL the sources 856 mSourceMap->MarkAllSourcesForRecalculation(); 857 } 858} 859 860// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 861void OALContext::SetListenerVelocity(Float32 posX, Float32 posY, Float32 posZ) 862{ 863#if LOG_CONTEXT_VERBOSE 864 DebugMessageN4("OALContext::SetListenerVelocity() - OALContext:posX:posY:posZ = %ld:%f:%f:%f", (long int) mSelfToken, posX, posY, posZ); 865#endif 866 mListenerVelocity[0] = posX; 867 mListenerVelocity[1] = posY; 868 mListenerVelocity[2] = posZ; 869 870 if (mSourceMap) 871 { 872#if LOG_GRAPH_AND_MIXER_CHANGES 873 DebugMessage("OALContext::SetListenerVelocity: MarkAllSourcesForRecalculation called\n"); 874#endif 875 CAGuard::Locker locked(mSourceMapLock); 876 // moving the listener effects the coordinate translation for ALL the sources 877 mSourceMap->MarkAllSourcesForRecalculation(); 878 } 879} 880 881// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 882void OALContext::SetListenerOrientation( Float32 forwardX, Float32 forwardY, Float32 forwardZ, 883 Float32 upX, Float32 upY, Float32 upZ) 884{ 885#if LOG_CONTEXT_VERBOSE 886 DebugMessageN7("OALContext::SetListenerOrientation() - OALContext:forwardX:forwardY:forwardZ:upX:upY:upZ = %ld:%f:%f:%f:%f:%f:%f", (long int) mSelfToken, forwardX, forwardY, forwardZ, upX, upY, upZ); 887#endif 888 889 if (isnan(forwardX) || isnan(forwardY) || isnan(forwardZ) || isnan(upX) || isnan(upY) || isnan(upZ)) 890 throw ((OSStatus) AL_INVALID_VALUE); 891 892 if ( (mListenerOrientationForward[0] == forwardX) && 893 (mListenerOrientationForward[1] == forwardY ) && 894 (mListenerOrientationForward[2] == forwardZ) && 895 (mListenerOrientationUp[0] == upX) && 896 (mListenerOrientationUp[1] == upY ) && 897 (mListenerOrientationUp[2] == upZ) ) 898 return; 899 900 mListenerOrientationForward[0] = forwardX; 901 mListenerOrientationForward[1] = forwardY; 902 mListenerOrientationForward[2] = forwardZ; 903 mListenerOrientationUp[0] = upX; 904 mListenerOrientationUp[1] = upY; 905 mListenerOrientationUp[2] = upZ; 906 907 if (mSourceMap) 908 { 909#if LOG_GRAPH_AND_MIXER_CHANGES 910 DebugMessage("OALContext::SetListenerOrientation: MarkAllSourcesForRecalculation called\n"); 911#endif 912 CAGuard::Locker locked(mSourceMapLock); 913 // moving the listener effects the coordinate translation for ALL the sources 914 mSourceMap->MarkAllSourcesForRecalculation(); 915 } 916} 917 918// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 919UInt32 OALContext::GetDesiredRenderChannels(UInt32 inDeviceChannels) 920{ 921#if LOG_CONTEXT_VERBOSE 922 DebugMessageN2("OALContext::GetDesiredRenderChannels() - OALContext:inDeviceChannels = %ld:%d", (long int) mSelfToken, inDeviceChannels); 923#endif 924 UInt32 returnValue = inDeviceChannels; 925 926 if ((Get3DMixerVersion() < k3DMixerVersion_2_0) && (returnValue == 4)) 927 { 928 // quad did not work properly before version 2.0 of the 3DMixer, so just render to stereo 929 returnValue = 2; 930 } 931 else if (inDeviceChannels < 4) 932 { 933 // guard against the possibility of multi channel hw that has never been given a preferred channel layout 934 // Or, that a 3 channel layout was returned (which is unsupported by the 3DMixer) 935 returnValue = 2; 936 } 937 else if ((inDeviceChannels > 5) && (Get3DMixerVersion() < k3DMixerVersion_2_3)) 938 { 939 // 3DMixer ver. 2.2 and below could only render a maximum of 5 channels 940 returnValue = 5; 941 } 942 else if(inDeviceChannels > 8) 943 { 944 // Current 3DMixer can handle a maximum of 8 channels 945 returnValue = 8; 946 } 947 948 return returnValue; 949} 950 951// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 952void OALContext::InitRenderQualityOnBusses() 953{ 954#if LOG_CONTEXT_VERBOSE 955 DebugMessageN1("OALContext::InitRenderQualityOnBusses() - OALContext = %ld", (long int) mSelfToken); 956#endif 957 UInt32 channelCount = mOwningDevice->GetDesiredRenderChannelCount(); 958 959 if (channelCount > 2) 960 { 961 // at this time, there is only one spatial quality being used for multi channel hw 962 DebugMessage("********** InitRenderQualityOnBusses:kDefaultMultiChannelQuality ***********"); 963 mSpatialSetting = kDefaultMultiChannelQuality; 964 } 965 else if (mRenderQuality == ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_LOW) 966 { 967 // this is the default case for stereo 968 DebugMessage("********** InitRenderQualityOnBusses:kDefaultLowQuality ***********"); 969 mSpatialSetting = kDefaultLowQuality; 970 } 971 else 972 { 973 DebugMessage("********** InitRenderQualityOnBusses:kDefaultHighQuality ***********"); 974 mSpatialSetting = kDefaultHighQuality; 975 } 976 977 UInt32 render_flags_3d = k3DMixerRenderingFlags_DistanceAttenuation; 978 if (mRenderQuality == ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_HIGH) 979 { 980 // off by default, on if the user sets High Quality rendering, as HRTF requires InterAuralDelay to be on 981 render_flags_3d += k3DMixerRenderingFlags_InterAuralDelay; 982 } 983 984 if (mASAReverbState > 0) 985 { 986 // off by default, on if the user turns on Reverb, as it requires DistanceDiffusion to be on 987 render_flags_3d += k3DMixerRenderingFlags_DistanceDiffusion; 988 render_flags_3d += (1L << 6 /* k3DMixerRenderingFlags_ConstantReverbBlend*/); 989 } 990 991 OSStatus result = noErr; 992 UInt32 propSize; 993 CAStreamBasicDescription format; 994 for (UInt32 i = 0; i < mBusCount; i++) 995 { 996 propSize = sizeof(format); 997 result = AudioUnitGetProperty ( mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, i, &format, &propSize); 998 999 // only reset the mono channels, stereo channels are always set to stereo pass thru regardless of render quality setting 1000 if ((result == noErr) && (format.NumberChannels() == 1)) 1001 { 1002 // Spatialization 1003 result = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, 1004 i, &mSpatialSetting, sizeof(mSpatialSetting)); 1005 1006 // Render Flags 1007 result = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_3DMixerRenderingFlags, kAudioUnitScope_Input, 1008 i, &render_flags_3d, sizeof(render_flags_3d)); 1009 } 1010 } 1011} 1012 1013// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1014void OALContext::SetRenderQuality (UInt32 inRenderQuality) 1015{ 1016#if LOG_CONTEXT_VERBOSE 1017 DebugMessageN2("OALContext::SetRenderQuality() - OALContext:inRenderQuality = %ld:%d", (long int) mSelfToken, inRenderQuality); 1018#endif 1019 if (mRenderQuality == inRenderQuality) 1020 return; // nothing to do; 1021 1022 // make sure a valid quality setting is requested 1023 if (!IsValidRenderQuality(inRenderQuality)) 1024 throw (OSStatus) AL_INVALID_VALUE; 1025 1026 mRenderQuality = inRenderQuality; 1027 1028 // change the spatialization for all mono busses on the mixer 1029 InitRenderQualityOnBusses(); 1030} 1031 1032// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1033void OALContext::SetDistanceAttenuation(UInt32 inBusIndex, Float64 inRefDist, Float64 inMaxDist, Float64 inRolloff) 1034{ 1035 if (Get3DMixerVersion() >= k3DMixerVersion_2_0) 1036 return; // unnecessary with v2.0 mixer 1037 1038 Float64 maxattenuationDB = 20 * log10(inRefDist / (inRefDist + (inRolloff * (inMaxDist - inRefDist)))); 1039 Float64 maxattenuation = pow(10, (maxattenuationDB/20)); 1040 Float64 distAttenuation = (log(1/maxattenuation))/(log(inMaxDist)) - 1.0; 1041 1042 #if 0 1043 DebugMessageN1("SetDistanceAttenuation:Reference Distance = %f", inRefDist); 1044 DebugMessageN1("SetDistanceAttenuation:Maximum Distance = %f", inMaxDist); 1045 DebugMessageN1("SetDistanceAttenuation:Rolloff = %f", inRolloff); 1046 DebugMessageN1("SetDistanceAttenuati2on:Max Attenuation DB = %f", maxattenuationDB); 1047 DebugMessageN1("SetDistanceAttenuation:Max Attenuation Scalar = %f", maxattenuation); 1048 DebugMessageN1("SetDistanceAttenuation:distAttenuation = %f", distAttenuation); 1049 1050 #endif 1051 1052 AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_3DMixerDistanceAtten, kAudioUnitScope_Input, inBusIndex, &distAttenuation, sizeof(distAttenuation)); 1053 return; 1054} 1055 1056// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1057UInt32 OALContext::GetAvailableMonoBus (ALuint inSourceToken) 1058{ 1059#if LOG_CONTEXT_VERBOSE 1060 DebugMessageN2("OALContext::GetAvailableMonoBus() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 1061#endif 1062 // look for a bus already set for mono 1063 for (UInt32 i = 0; i < mBusCount; i++) 1064 { 1065 if ((mBusInfo[i].mSourceAttached == kNoSourceAttached) && mBusInfo[i].mNumberChannels == 1) 1066 { 1067 mBusInfo[i].mSourceAttached = inSourceToken; 1068#if LOG_BUS_CONNECTIONS 1069 mMonoSourcesConnected++; 1070 DebugMessageN2("GetAvailableMonoBus1: Sources Connected, Mono = %ld, Stereo = %ld", mMonoSourcesConnected, mStereoSourcesConnected); 1071 DebugMessageN1("GetAvailableMonoBus1: BUS_NUMBER = %ld", i); 1072#endif 1073 return (i); 1074 } 1075 } 1076 1077 // do not try and switch a bus to mono if the appliction specified mono and stereo bus counts 1078 if (!mUserSpecifiedBusCounts) 1079 { 1080 // couldn't find a mono bus, so find any available channel and make it mono 1081 for (UInt32 i = 0; i < mBusCount; i++) 1082 { 1083 if (mBusInfo[i].mSourceAttached == kNoSourceAttached) 1084 { 1085 #if LOG_BUS_CONNECTIONS 1086 mMonoSourcesConnected++; 1087 DebugMessageN2("GetAvailableMonoBus2: Sources Connected, Mono = %ld, Stereo = %ld", mMonoSourcesConnected, mStereoSourcesConnected); 1088 #endif 1089 CAStreamBasicDescription theOutFormat; 1090 theOutFormat.mChannelsPerFrame = 1; 1091 theOutFormat.mSampleRate = GetMixerRate(); // as a default, set the bus to the mixer's output rate, it should get reset if necessary later on 1092 theOutFormat.mFormatID = kAudioFormatLinearPCM; 1093 theOutFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; 1094 theOutFormat.mBytesPerPacket = sizeof (Float32); 1095 theOutFormat.mFramesPerPacket = 1; 1096 theOutFormat.mBytesPerFrame = sizeof (Float32); 1097 theOutFormat.mBitsPerChannel = sizeof (Float32) * 8; 1098 OSStatus result = AudioUnitSetProperty ( mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1099 i, &theOutFormat, sizeof(CAStreamBasicDescription)); 1100 THROW_RESULT 1101 1102 mBusInfo[i].mSourceAttached = inSourceToken; 1103 mBusInfo[i].mNumberChannels = 1; 1104 AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, 1105 i, &mSpatialSetting, sizeof(mSpatialSetting)); 1106 1107 UInt32 render_flags_3d = k3DMixerRenderingFlags_DistanceAttenuation; 1108 if (mRenderQuality == ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_HIGH) 1109 render_flags_3d += k3DMixerRenderingFlags_InterAuralDelay; // off by default, on if the user sets High Quality rendering 1110 1111 // Render Flags 1112 result = AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_3DMixerRenderingFlags, kAudioUnitScope_Input, 1113 i, &render_flags_3d, sizeof(render_flags_3d)); 1114 1115 return (i); 1116 } 1117 } 1118 } 1119 1120 DebugMessage("ERROR: GetAvailableMonoBus: COULD NOT GET A MONO BUS"); 1121 throw (-1); // no inputs available 1122} 1123 1124// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1125UInt32 OALContext::GetAvailableStereoBus (ALuint inSourceToken) 1126{ 1127#if LOG_CONTEXT_VERBOSE 1128 DebugMessageN2("OALContext::GetAvailableStereoBus() - OALContext:inSourceToken = %ld:%d", (long int) mSelfToken, inSourceToken); 1129#endif 1130 for (UInt32 i = 0; i < mBusCount; i++) 1131 { 1132 if ((mBusInfo[i].mSourceAttached == kNoSourceAttached) && mBusInfo[i].mNumberChannels == 2) 1133 { 1134 mBusInfo[i].mSourceAttached = inSourceToken; 1135#if LOG_BUS_CONNECTIONS 1136 mStereoSourcesConnected++; 1137 DebugMessageN2("GetAvailableStereoBus1: Sources Connected, Mono = %ld, Stereo = %ld", mMonoSourcesConnected, mStereoSourcesConnected); 1138 DebugMessageN1("GetAvailableStereoBus1: BUS_NUMBER = %ld", i); 1139#endif 1140 return (i); 1141 } 1142 } 1143 1144 // do not try and switch a bus to stereo if the appliction specified mono and stereo bus counts 1145 if (!mUserSpecifiedBusCounts) 1146 { 1147 // couldn't find one, so look for a mono channel, make it stereo and set to kSpatializationAlgorithm_StereoPassThrough 1148 for (UInt32 i = 0; i < mBusCount; i++) 1149 { 1150 if (mBusInfo[i].mSourceAttached == kNoSourceAttached) 1151 { 1152 1153 #if LOG_BUS_CONNECTIONS 1154 mStereoSourcesConnected++; 1155 DebugMessageN2("GetAvailableStereoBus2: Sources Connected, Mono = %ld, Stereo = %ld", mMonoSourcesConnected, mStereoSourcesConnected); 1156 DebugMessageN1("GetAvailableStereoBus2: BUS_NUMBER = %ld", i); 1157 #endif 1158 CAStreamBasicDescription theOutFormat; 1159 theOutFormat.mChannelsPerFrame = 2; 1160 theOutFormat.mSampleRate = GetMixerRate(); 1161 theOutFormat.mFormatID = kAudioFormatLinearPCM; 1162 theOutFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; 1163 theOutFormat.mBytesPerPacket = sizeof (Float32); 1164 theOutFormat.mFramesPerPacket = 1; 1165 theOutFormat.mBytesPerFrame = sizeof (Float32); 1166 theOutFormat.mBitsPerChannel = sizeof (Float32) * 8; 1167 OSStatus result = AudioUnitSetProperty ( mMixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1168 i, &theOutFormat, sizeof(CAStreamBasicDescription)); 1169 THROW_RESULT 1170 1171 mBusInfo[i].mSourceAttached = inSourceToken; 1172 mBusInfo[i].mNumberChannels = 2; 1173 1174 UInt32 spatAlgo = kSpatializationAlgorithm_StereoPassThrough; 1175 AudioUnitSetProperty( mMixerUnit, kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, 1176 i, &spatAlgo, sizeof(spatAlgo)); 1177 1178 return (i); 1179 } 1180 } 1181 } 1182 1183 DebugMessage("ERROR: GetAvailableStereoBus: COULD NOT GET A STEREO BUS"); 1184 throw (-1); // no inputs available 1185} 1186 1187// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1188void OALContext::SetBusAsAvailable (UInt32 inBusIndex) 1189{ 1190#if LOG_CONTEXT_VERBOSE 1191 DebugMessageN2("OALContext::SetBusAsAvailable() - OALContext:inBusIndex = %ld:%d", (long int) mSelfToken, inBusIndex); 1192#endif 1193 mBusInfo[inBusIndex].mSourceAttached = kNoSourceAttached; 1194 1195#if LOG_BUS_CONNECTIONS 1196 if (mBusInfo[inBusIndex].mNumberChannels == 1) 1197 mMonoSourcesConnected--; 1198 else 1199 mStereoSourcesConnected--; 1200 1201 DebugMessageN2("SetBusAsAvailable: Sources Connected, Mono = %ld, Stereo = %ld", mMonoSourcesConnected, mStereoSourcesConnected); 1202#endif 1203} 1204 1205// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1206// Apple Environmental Audio (ASA) Extension 1207// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1208void OALContext::SetReverbRoomType(UInt32 inRoomType) 1209{ 1210#if LOG_CONTEXT_VERBOSE 1211 DebugMessageN2("OALContext::SetReverbRoomType() - OALContext:inRoomType = %ld:%d", (long int) mSelfToken, inRoomType); 1212#endif 1213 if (mASAReverbRoomType == inRoomType) 1214 return; // nothing to do; 1215 1216 mASAReverbRoomType = inRoomType; 1217 1218 OSStatus result = AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_ReverbRoomType, kAudioUnitScope_Global, 0, &mASAReverbRoomType, sizeof(mASAReverbRoomType)); 1219 THROW_RESULT 1220} 1221 1222// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1223void OALContext::SetReverbLevel(Float32 inReverbLevel) 1224{ 1225#if LOG_CONTEXT_VERBOSE 1226 DebugMessageN2("OALContext::SetReverbLevel() - OALContext:inReverbLevel = %ld:%f", (long int) mSelfToken, inReverbLevel); 1227#endif 1228 1229 if (mASAReverbGlobalLevel == inReverbLevel) 1230 return; // nothing to do; 1231 1232 mASAReverbGlobalLevel = inReverbLevel; 1233 1234 OSStatus result = AudioUnitSetParameter (mMixerUnit, 6 /*k3DMixerParam_GlobalReverbGain*/, kAudioUnitScope_Global, 0, mASAReverbGlobalLevel, 0); 1235 THROW_RESULT 1236} 1237 1238// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1239void OALContext::SetReverbState(UInt32 inReverbState) 1240{ 1241#if LOG_CONTEXT_VERBOSE 1242 DebugMessageN2("OALContext::SetReverbState() - OALContext:inReverbState = %ld:%d", (long int) mSelfToken, inReverbState); 1243#endif 1244 if (mASAReverbState == inReverbState) 1245 return; // nothing to do; 1246 1247 mASAReverbState = inReverbState; 1248 1249 OSStatus result = AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_UsesInternalReverb, kAudioUnitScope_Global, 0, &mASAReverbState, sizeof(mASAReverbState)); 1250 if (result == noErr) 1251 InitRenderQualityOnBusses(); // distance diffusion needs to be reset on the busses now 1252} 1253 1254// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1255void OALContext::SetReverbQuality(UInt32 inQuality) 1256{ 1257#if LOG_CONTEXT_VERBOSE 1258 DebugMessageN2("OALContext::SetReverbQuality() - OALContext:inQuality = %ld:%d", (long int) mSelfToken, inQuality); 1259#endif 1260 if (mASAReverbQuality == inQuality) 1261 return; // nothing to do; 1262 1263 mASAReverbQuality = inQuality; 1264 1265 AudioUnitSetProperty(mMixerUnit, kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, 0, &mASAReverbQuality, sizeof(mASAReverbQuality)); 1266} 1267 1268// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1269void OALContext::SetReverbEQGain(Float32 inGain) 1270{ 1271#if LOG_CONTEXT_VERBOSE 1272 DebugMessageN2("OALContext::SetReverbEQGain() - OALContext:inGain = %ld:%f", (long int) mSelfToken, inGain); 1273#endif 1274 if (mASAReverbEQGain != inGain) 1275 { 1276 mASAReverbEQGain = inGain; 1277 OSStatus result = AudioUnitSetParameter (mMixerUnit, 20000 + 16 /*kReverbParam_FilterGain*/, kAudioUnitScope_Global, 0, mASAReverbEQGain, 0); 1278 THROW_RESULT 1279 } 1280} 1281 1282// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1283void OALContext::SetReverbEQBandwidth(Float32 inBandwidth) 1284{ 1285#if LOG_CONTEXT_VERBOSE 1286 DebugMessageN2("OALContext::SetReverbEQBandwidth() - OALContext:inBandwidth = %ld:%f", (long int) mSelfToken, inBandwidth); 1287#endif 1288 if (mASAReverbEQBandwidth != inBandwidth) 1289 { 1290 mASAReverbEQBandwidth = inBandwidth; 1291 OSStatus result = AudioUnitSetParameter (mMixerUnit, 20000 + 15 /*kReverbParam_FilterBandwidth*/, kAudioUnitScope_Global, 0, mASAReverbEQBandwidth, 0); 1292 THROW_RESULT 1293 } 1294} 1295 1296// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1297void OALContext::SetReverbEQFrequency(Float32 inFrequency) 1298{ 1299#if LOG_CONTEXT_VERBOSE 1300 DebugMessageN2("OALContext::SetReverbEQFrequency() - OALContext:inFrequency = %ld:%f", (long int) mSelfToken, inFrequency); 1301#endif 1302 if (mASAReverbEQFrequency != inFrequency) 1303 { 1304 mASAReverbEQFrequency = inFrequency; 1305 OSStatus result = AudioUnitSetParameter (mMixerUnit, 20000 + 14 /*kReverbParam_FilterFrequency*/, kAudioUnitScope_Global, 0, mASAReverbEQFrequency, 0); 1306 THROW_RESULT 1307 } 1308} 1309 1310// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1311UInt32 OALContext::GetReverbQuality() 1312{ 1313#if LOG_CONTEXT_VERBOSE 1314 DebugMessageN1("OALContext::GetReverbQuality() - OALContext = %ld", (long int) mSelfToken); 1315#endif 1316 return mASAReverbQuality; 1317} 1318 1319// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1320Float32 OALContext::GetReverbEQGain() 1321{ 1322#if LOG_CONTEXT_VERBOSE 1323 DebugMessageN1("OALContext::GetReverbEQGain() - OALContext = %ld", (long int) mSelfToken); 1324#endif 1325 OSStatus result = AudioUnitGetParameter(mMixerUnit, 20000 + 16 /*kReverbParam_FilterGain*/,kAudioUnitScope_Global,0, &mASAReverbEQGain); 1326 if (result) 1327 return 0.0; 1328 1329 return mASAReverbEQGain; 1330} 1331 1332// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1333Float32 OALContext::GetReverbEQBandwidth() 1334{ 1335#if LOG_CONTEXT_VERBOSE 1336 DebugMessageN1("OALContext::GetReverbEQBandwidth() - OALContext = %ld", (long int) mSelfToken); 1337#endif 1338 OSStatus result = AudioUnitGetParameter(mMixerUnit, 20000 + 15 /*kReverbParam_FilterBandwidth*/,kAudioUnitScope_Global,0, &mASAReverbEQBandwidth); 1339 if (result) 1340 return 0.0; 1341 1342 return mASAReverbEQBandwidth; 1343} 1344 1345// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1346Float32 OALContext::GetReverbEQFrequency() 1347{ 1348#if LOG_CONTEXT_VERBOSE 1349 DebugMessageN1("OALContext::GetReverbEQFrequency() - OALContext = %ld", (long int) mSelfToken); 1350#endif 1351 OSStatus result = AudioUnitGetParameter(mMixerUnit, 20000 + 14 /*kReverbParam_FilterFrequency*/,kAudioUnitScope_Global,0, &mASAReverbEQFrequency); 1352 if (result) 1353 return 0.0; 1354 1355 return mASAReverbEQFrequency; 1356} 1357 1358// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1359void OALContext::SetReverbPreset (FSRef* inRef) 1360{ 1361#if LOG_CONTEXT_VERBOSE 1362 DebugMessageN1("OALContext::SetReverbPreset() - OALContext = %ld", (long int) mSelfToken); 1363#endif 1364 try { 1365 Boolean status; 1366 SInt32 result = 0; 1367 CFURLRef fileURL = CFURLCreateFromFSRef (kCFAllocatorDefault, inRef); 1368 if (fileURL) 1369 { 1370 // Read the XML file. 1371 CFDataRef resourceData = NULL; 1372 1373 status = CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault, fileURL, &resourceData, NULL, NULL, &result); 1374 CFRelease (fileURL); // no longer needed 1375 1376 if (status == false || result) 1377 throw (OSStatus) -1; 1378 else 1379 { 1380 CFStringRef errString = NULL; 1381 CFPropertyListRef theData = NULL; 1382 theData = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, resourceData, kCFPropertyListImmutable, &errString); 1383 CFRelease (resourceData); 1384 if (errString) 1385 CFRelease (errString); 1386 1387 if (theData == NULL || errString) 1388 { 1389 if (theData) 1390 CFRelease (theData); 1391 throw (OSStatus) -1; 1392 } 1393 else 1394 { 1395 result = AudioUnitSetProperty(mMixerUnit, 3012 /*kAudioUnitProperty_ReverbPreset*/, kAudioUnitScope_Global, 0, &theData, sizeof(theData) ); 1396 CFRelease (theData); 1397 THROW_RESULT 1398 } 1399 } 1400 } 1401 else 1402 throw (OSStatus) -1; 1403 } 1404 catch (OSStatus result) { 1405 throw result; 1406 } 1407 catch (...) { 1408 throw (OSStatus) -1; 1409 } 1410 1411 return; 1412} 1413 1414// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1415OSStatus OALContext::ContextNotificationProc ( void *inRefCon, 1416 AudioUnitRenderActionFlags *inActionFlags, 1417 const AudioTimeStamp *inTimeStamp, 1418 UInt32 inBusNumber, 1419 UInt32 inNumberFrames, 1420 AudioBufferList *ioData) 1421{ 1422#if LOG_CONTEXT_VERBOSE 1423 DebugMessage("OALContext::ContextNotificationProc()"); 1424#endif 1425 OALContext* THIS = (OALContext*)inRefCon; 1426 1427 // we have no use for a pre-render notification, we only care about the post-render 1428 if (*inActionFlags & kAudioUnitRenderAction_PreRender) 1429 { 1430 THIS->mRenderThreadID = pthread_self(); 1431 THIS->DoPreRender(); 1432 } 1433 1434 else if (*inActionFlags & kAudioUnitRenderAction_PostRender) 1435 return THIS->DoPostRender(); 1436 1437 return (noErr); 1438} 1439 1440// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1441OSStatus OALContext::DoPreRender () 1442{ 1443#if LOG_CONTEXT_VERBOSE 1444 DebugMessageN1("OALContext::DoPreRender() - OALContext = %ld", (long int) mSelfToken); 1445#endif 1446#if LOG_MESSAGE_QUEUE 1447 DebugMessageN1("OALContext::DoPreRender"); 1448#endif 1449 1450 for (UInt32 i=0; i < mBusCount; i++) 1451 { 1452 OALSource *oalSource = GetSourceForRender(mBusInfo[i].mSourceAttached); 1453 if (oalSource != NULL) 1454 { 1455 oalSource->DoPreRender(); 1456 ReleaseSource(oalSource); 1457 } 1458 } 1459 1460 return noErr; 1461} 1462 1463// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1464OSStatus OALContext::DoPostRender () 1465{ 1466#if LOG_CONTEXT_VERBOSE 1467 DebugMessageN1("OALContext::DoPostRender() - OALContext = %ld", (long int) mSelfToken); 1468#endif 1469#if LOG_MESSAGE_QUEUE 1470 DebugMessageN1("OALContext::DoPostRender"); 1471#endif 1472 1473 for (UInt32 i=0; i < mBusCount; i++) 1474 { 1475 OALSource *oalSource = GetSourceForRender(mBusInfo[i].mSourceAttached); 1476 if (oalSource == NULL) 1477 { 1478 //if we have a source that needs post-render but has been deleted. We need to just deconstruct 1479 oalSource = GetDeadSourceForRender(mBusInfo[i].mSourceAttached); 1480 if (oalSource) 1481 { 1482 //clear all the current messages 1483 oalSource->ClearMessageQueue(); 1484 oalSource->AddPlaybackMessage((UInt32)kMQ_DeconstructionStop, NULL, 0); 1485 } 1486 else continue; 1487 } 1488 1489 oalSource->DoPostRender(); 1490 ReleaseSource(oalSource); 1491 } 1492 1493 return noErr; 1494} 1495