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 7* that the following 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 13* products derived 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 TO, 16* 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 LIMITED 18* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 19* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 20* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21* 22**********************************************************************************************************************************/ 23 24#ifndef __OAL_SOURCE__ 25#define __OAL_SOURCE__ 26 27#include "oalImp.h" 28#include "oalDevice.h" 29#include "oalContext.h" 30#include "al.h" 31 32#include <Carbon/Carbon.h> 33#include <AudioToolbox/AudioConverter.h> 34#include <list> 35#include <libkern/OSAtomic.h> 36#include <vector> 37#include <queue> 38#include <dispatch/dispatch.h> 39 40#include "CAStreamBasicDescription.h" 41#include "CAAtomicStack.h" 42#include "CAGuard.h" 43 44class OALBuffer; // forward declaration 45 46// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 47// buffer info state constants 48enum { 49 kSecondsOffset = 1, 50 kSampleOffset = 2, 51 kByteOffset = 3 52}; 53 54enum { 55 kPendingProcessing = 0, 56 kInProgress = 1, 57 kProcessed = 2 58}; 59 60enum { 61 kRampingComplete = -2, 62 kRampDown = -1, 63 kNoRamping = 0, 64 kRampUp = 1 65}; 66 67enum { 68 kMQ_NoMessage = 0, 69 kMQ_Stop = 1, 70 kMQ_Rewind = 2, 71 kMQ_SetBuffer = 3, 72 kMQ_Play = 4, 73 kMQ_Pause = 5, 74 kMQ_Resume = 6, 75 kMQ_SetFramePosition = 7, 76 kMQ_ClearBuffersFromQueue = 8, 77 kMQ_DeconstructionStop = 9, 78 kMQ_Retrigger = 10, 79 kMQ_AddBuffersToQueue = 11 80}; 81 82#define OALSourceError_CallConverterAgain 'agan' 83#define kSourceNeedsBus -1 84 85// do not change kDistanceScalar from 10.0 - it is used to compensate for a reverb related problem in the 3DMixer 86#define kDistanceScalar 10.0 87 88#define kTransitionToStop 0XDD01 89#define kTransitionToPlay 0XDD02 90#define kTransitionToPause 0XDD03 91#define kTransitionToRewind 0XDD04 92#define kTransitionToRetrigger 0XDD05 93#define kTransitionToResume 0XDD06 94 95#pragma mark _____PlaybackMessage_____ 96 97class PlaybackMessage { 98public: 99 PlaybackMessage(UInt32 inMessage, OALBuffer* inBuffer, UInt32 inNumBuffers) : 100 mMessageID(inMessage), 101 mBuffer(inBuffer), 102 mNumBuffers(inNumBuffers) 103 { }; 104 105 ~PlaybackMessage(){}; 106 107 PlaybackMessage* mNext; 108 UInt32 mMessageID; 109 OALBuffer* mBuffer; 110 UInt32 mNumBuffers; 111 112 PlaybackMessage *& next() { return mNext; } 113 void set_next(PlaybackMessage *next) { mNext = next; } 114}; 115 116// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 117#pragma mark _____BufferQueue_____ 118// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 119// This struct is used by OAL source to store info about the buffers in it's queue 120struct BufferInfo { 121 ALuint mBufferToken; // the buffer name that the user was returned when the buffer was created 122 OALBuffer *mBuffer; // buffer object 123 UInt32 mOffset; // current read position offset of this data 124 UInt32 mProcessedState; // mark as true when data of this buffer is finished playing and looping is off 125 ALuint mACToken; // use this AC from the ACMap for converting the data to the mixer format, when 126 // set to zero, then NO AC is needed, the data has already been converted 127}; 128 129class BufferQueue : std::vector<BufferInfo> { 130public: 131 132 BufferQueue() { mBufferQueueSize = 0;} 133 void AppendBuffer(OALSource* thisSource, ALuint inBufferToken, OALBuffer *inBuffer, ALuint inACToken); 134 ALuint RemoveQueueEntryByIndex(OALSource* thisSource, UInt32 inIndex, bool inReleaseIt); 135 UInt32 GetQueueSizeInFrames() ; 136 UInt32 GetBufferFrameCount(UInt32 inBufferIndex); 137 void SetFirstBufferOffset(UInt32 inFrameOffset) ; 138 ALuint GetBufferTokenByIndex(UInt32 inBufferIndex); 139 UInt32 GetCurrentFrame(UInt32 inBufferIndex); 140 141 BufferInfo* Get(short inBufferIndex) { 142 iterator it = begin(); 143 std::advance(it, inBufferIndex); 144 if (it != end()) 145 return(&(*it)); 146 return (NULL); 147 } 148 149 void SetBufferAsProcessed(UInt32 inBufferIndex) { 150 iterator it = begin(); 151 std::advance(it, inBufferIndex); 152 if (it != end()) 153 it->mProcessedState = kProcessed; 154 } 155 156 // mark all the buffers in the queue as unprocessed and offset 0 157 void ResetBuffers() { 158 iterator it = begin(); 159 while (it != end()) 160 { 161 it->mProcessedState = kPendingProcessing; 162 it->mOffset = 0; 163 ++it; 164 } 165 } 166 167 UInt32 GetQueueSize () { return mBufferQueueSize; } 168 void SetQueueSize () { mBufferQueueSize = Size(); } 169 bool Empty () const { return empty(); } 170 void Reserve(UInt32 reserveSize) {return reserve(reserveSize); } 171 172private: 173 UInt32 GetPacketSize() ; 174 UInt32 FrameOffsetToPacketOffset(UInt32 inFrameOffset); 175 UInt32 Size () const { return size(); } 176 177 volatile int32_t mBufferQueueSize; // shadow variable to store the size of the queue 178}; 179typedef BufferQueue BufferQueue; 180 181// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 182#pragma mark _____ACMap_____ 183// ACMap - map the AudioConverters for the sources queue 184// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 185// This struct is used by OAL source to store info about the ACs used by it's queue 186struct ACInfo { 187 AudioConverterRef mConverter; 188 CAStreamBasicDescription mInputFormat; 189}; 190 191class ACMap : std::multimap<ALuint, ACInfo, std::less<ALuint> > { 192public: 193 194 // add a new context to the map 195 void Add (const ALuint inACToken, ACInfo *inACInfo) { 196 iterator it = upper_bound(inACToken); 197 insert(it, value_type (inACToken, *inACInfo)); 198 } 199 200 AudioConverterRef Get(ALuint inACToken) { 201 const_iterator it = find(inACToken); 202 iterator theEnd = end(); 203 204 if (it != theEnd) 205 return ((*it).second.mConverter); 206 207 return (NULL); 208 } 209 210 void GetACForFormat (CAStreamBasicDescription* inFormat, ALuint &outToken) { 211 iterator it = begin(); 212 213 outToken = 0; // 0 means there is none yet 214 while (it != end()) { 215 if( (*it).second.mInputFormat == *inFormat) { 216 outToken = (*it).first; 217 it = end(); 218 } 219 else 220 ++it; 221 } 222 return; 223 } 224 225 void Remove (const ALuint inACToken) { 226 iterator it = find(inACToken); 227 if (it != end()) { 228 AudioConverterDispose((*it).second.mConverter); 229 erase(it); 230 } 231 } 232 233 // the map should be disposed after making this call 234 void RemoveAllConverters () { 235 iterator it = begin(); 236 iterator theEnd = end(); 237 238 while (it != theEnd) { 239 AudioConverterDispose((*it).second.mConverter); 240 ++it; 241 } 242 } 243 244 UInt32 Size () const { return size(); } 245 bool Empty () const { return empty(); } 246}; 247typedef ACMap ACMap; 248 249// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 250#pragma mark _____SourceNotifyInfo_____ 251// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 252class SourceNotifyInfo 253{ 254public: 255 SourceNotifyInfo() 256 : mID(0), 257 mProc(0), 258 mUserData(0) 259 {} 260 261friend class SourceNotifications; 262private: 263 ALuint mID; 264 alSourceNotificationProc mProc; 265 void *mUserData; 266}; 267 268class SourceNotifications : public std::vector<SourceNotifyInfo> 269{ 270public: 271 SourceNotifications(ALuint inSourceID) 272 : mSourceToken(inSourceID) 273 { 274 mNotifyMutex = new CAMutex("Notifcation Mutex"); 275 } 276 277 ~SourceNotifications() 278 { 279 delete mNotifyMutex; 280 } 281 282 283 OSStatus AddSourceNotification(ALuint inID, alSourceNotificationProc inProc, void *inUserData) 284 { 285 CAMutex::Locker lock(*mNotifyMutex); 286 return AddSourceNotificationImp(inID, inProc, inUserData); 287 } 288 289 OSStatus RemoveSourceNotification(ALuint inID, alSourceNotificationProc inProc, void *inUserData) 290 { 291 CAMutex::Locker lock(*mNotifyMutex); 292 return RemoveSourceNotificationImp(inID, inProc, inUserData); 293 } 294 295 OSStatus RemoveAllSourceNotifications(ALuint inID) 296 { 297 CAMutex::Locker lock(*mNotifyMutex); 298 return RemoveAllSourceNotificationsImp(inID); 299 } 300 301 void CallSourceNotifications(ALuint inID) 302 { 303 if (mNotifyMutex != NULL) { 304 CAMutex::Locker lock(*mNotifyMutex); 305 return CallSourceNotificationsImp(inID); 306 } 307 } 308 309private: 310 const SourceNotifications::iterator FindNotificationInfo(ALuint inID, alSourceNotificationProc inProc, void *inUserData) 311 { 312 SourceNotifications::iterator it; 313 for (it = begin(); it != end(); ++it) { 314 if ((it->mID == inID) && (it->mProc == inProc) && (it->mUserData == inUserData)) 315 return it; 316 } 317 return it; // end() 318 } 319 320 OSStatus AddSourceNotificationImp(ALuint inID, alSourceNotificationProc inProc, void *inUserData) 321 { 322 OSStatus status = noErr; 323 324 SourceNotifications::iterator it = FindNotificationInfo(inID, inProc, inUserData); 325 if (it == end()) { 326 SourceNotifyInfo info; 327 info.mID = inID; 328 info.mProc = inProc; 329 info.mUserData = inUserData; 330 push_back(info); 331 } 332 else { 333 status = -50; 334 } 335 336 return status; 337 } 338 339 OSStatus RemoveSourceNotificationImp(ALuint inID, alSourceNotificationProc inProc, void *inUserData) 340 { 341 OSStatus status = noErr; 342 343 SourceNotifications::iterator it = FindNotificationInfo(inID, inProc, inUserData); 344 if (it != end()) 345 { 346 erase(it); 347 348 for (it = begin(); it != end(); ++it) { 349 if (it->mID == inID) 350 break; 351 } 352 } 353 else { 354 status = -50; 355 } 356 357 return status; 358 } 359 360 OSStatus RemoveAllSourceNotificationsImp(ALuint inID) 361 { 362 SourceNotifications::iterator it; 363 for (int index = size() - 1; index >= 0; index--) 364 { 365 it = begin() + index; 366 if (it->mID == inID) 367 erase(it); 368 } 369 370 OSStatus status = noErr; 371 372 return status; 373 } 374 375 void CallSourceNotificationsImp(ALuint inID) 376 { 377 SourceNotifications::iterator it; 378 for (it = begin(); it != end(); ++it) 379 if (it->mID == inID) 380 { 381 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 382 it->mProc(mSourceToken, inID, it->mUserData); 383 }); 384 } 385 } 386 387 CAMutex* mNotifyMutex; 388 ALuint mSourceToken; 389}; 390 391#pragma mark _____OALRenderLocker_____ 392 393class OALRenderLocker { 394 int mAcquireFlag, mTryFlag; 395 396 OALRenderLocker& operator= (const OALRenderLocker& as) { return *this; } 397 OALRenderLocker (const OALRenderLocker& as) {} 398 399public: 400 OALRenderLocker () : mAcquireFlag(0), mTryFlag (0) {} 401 402 class RenderLocker { 403 OALRenderLocker &mEditor; 404 bool mInRenderThread; 405 406 public: 407 RenderLocker (OALRenderLocker &editor, bool inRenderThread) 408 : mEditor(editor), 409 mInRenderThread(inRenderThread) 410 { 411 if (!mInRenderThread) 412 { 413 OSAtomicIncrement32Barrier(&mEditor.mAcquireFlag); 414 while (mEditor.mTryFlag) { usleep(500); } 415 } 416 } 417 ~RenderLocker () 418 { 419 if (!mInRenderThread) 420 { 421 OSAtomicDecrement32Barrier (&mEditor.mAcquireFlag); 422 } 423 } 424 }; 425 426 class RenderTryer { 427 OALRenderLocker &mTrier; 428 public: 429 RenderTryer (OALRenderLocker & trier) 430 : mTrier (trier) 431 { 432 OSAtomicIncrement32Barrier(&mTrier.mTryFlag); 433 } 434 ~RenderTryer () 435 { 436 OSAtomicDecrement32Barrier (&mTrier.mTryFlag); 437 } 438 bool Acquired () const { return !mTrier.mAcquireFlag; } 439 }; 440}; 441 442// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 443// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 444// OALSources 445// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 446// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 447#pragma mark _____OALSource_____ 448class OALSource 449{ 450#pragma mark __________ PRIVATE __________ 451 private: 452 453 ALuint mSelfToken; // the token returned to the caller upon alGenSources() 454 bool mSafeForDeletion; 455 OALContext *mOwningContext; 456 bool mIsSuspended; 457 bool mCalculateDistance; 458 bool mResetBusFormat; 459 bool mResetBus; 460 bool mResetPitch; 461 462 BufferQueue *mBufferQueueActive; // map of buffers for queueing 463 BufferQueue *mBufferQueueInactive; // map of buffers already queued 464 BufferQueue *mBufferQueueTemp; // map of buffers for temporary queueing 465 volatile int32_t mQueueLength; // snapshot of the queue length (mBufferQueueActive + mBufferQueueInactive) 466 volatile int32_t mTempQueueLength; // queue length returned when source is transitioning to flush Qs 467 UInt32 mBuffersQueuedForClear; // number of buffers pending removal from the inactive queue 468 ALuint mCurrentBufferIndex; // index of the current buffer being played 469 bool mQueueIsProcessed; // state of the entire buffer queue 470 471 volatile int32_t mInUseFlag; // flag to indicate a source is currently being used by one or more threads 472 CAGuard mSourceLock; 473 AURenderCallbackStruct mPlayCallback; 474 int mCurrentPlayBus; // the mixer bus currently used by this source 475 476 ACMap *mACMap; 477 478 bool mOutputSilence; 479 Float32 mPosition[3]; 480 Float32 mVelocity[3]; 481 Float32 mConeDirection[3]; 482 UInt32 mLooping; 483 UInt32 mSourceRelative; 484 UInt32 mSourceType; 485 Float32 mConeInnerAngle; 486 Float32 mConeOuterAngle; 487 Float32 mConeOuterGain; 488 489 // Gain Scalers 490 Float32 mConeGainScaler; 491 Float32 mAttenuationGainScaler; 492 493 // support for pre 2.0 3DMixer 494 float mReadIndex; 495 float mCachedInputL1; 496 float mCachedInputL2; 497 float mCachedInputR1; 498 float mCachedInputR2; 499 UInt32 mTempSourceStorageBufferSize; 500 AudioBufferList *mTempSourceStorage; 501 502 UInt32 mState; // playback state: Playing, Stopped, Paused, Initial, Transitioning (to stop) 503 float mGain; 504 Float32 mPitch; 505 Float32 mDopplerScaler; 506 Float32 mRollOffFactor; 507 Float32 mReferenceDistance; 508 Float32 mMaxDistance; 509 Float32 mMinGain; 510 Float32 mMaxGain; 511 512 SInt32 mRampState; 513 UInt32 mBufferCountToUnqueueInPostRender; 514 bool mTransitioningToFlushQ; 515 516 UInt32 mPlaybackHeadPosition; // stored for a deferred repositioning of playbackHead as a frame index 517 518 Float32 mASAReverbSendLevel; 519 Float32 mASAOcclusion; 520 Float32 mASAObstruction; 521 522 UInt32 mRenderQuality; 523 524 // thread protection 525 OALRenderLocker mRenderLocker; 526 527 // Audio Units and properties for RogerBeep and Distortion 528 AUNode mRogerBeepNode; 529 AudioUnit mRogerBeepAU; 530 Boolean mASARogerBeepEnable; 531 Boolean mASARogerBeepOn; 532 Float32 mASARogerBeepGain; 533 SInt32 mASARogerBeepSensitivity; 534 SInt32 mASARogerBeepType; 535 char* mASARogerBeepPreset; 536 537 AUNode mDistortionNode; 538 AudioUnit mDistortionAU; 539 Boolean mASADistortionEnable; 540 Boolean mASADistortionOn; 541 Float32 mASADistortionMix; 542 SInt32 mASADistortionType; 543 char* mASADistortionPreset; 544 545 AudioUnit mRenderUnit; 546 UInt32 mRenderElement; 547 548 SourceNotifications* mSourceNotifications; 549 550 typedef TAtomicStack<PlaybackMessage> PlaybackMessageList; 551 552 PlaybackMessageList mMessageQueue; 553 554 555 void JoinBufferLists(); 556 void LoopToBeginning(); 557 void ChangeChannelSettings(); 558 void InitSource(); 559 void SetState(UInt32 inState); 560 OSStatus DoRender (AudioBufferList *ioData); 561 OSStatus DoSRCRender (AudioBufferList *ioData); // support for pre 2.0 3DMixer 562 bool ConeAttenuation(); 563 void CalculateDistanceAndAzimuth(Float32 *outDistance, Float32 *outAzimuth, Float32 *outElevation, Float32 *outDopplerShift); 564 void UpdateBusGain (); 565 void UpdateMinBusGain (); 566 void UpdateMaxBusGain (); 567 void UpdateBusFormat (); 568 void UpdateBusRenderQuality (); 569 void UpdateBusReverb (); 570 void UpdateBusOcclusion (); 571 void UpdateBusObstruction (); 572 573 void UpdateQueue (); 574 void RampDown (AudioBufferList *ioData); 575 void RampUp (AudioBufferList *ioData); 576 void ClearActiveQueue(); 577 void AddNotifyAndRenderProcs(); 578 void ReleaseNotifyAndRenderProcs(); 579 void DisconnectFromBus(); 580 void SetupMixerBus(); 581 void ResetMixerBus(); 582 void SetupDistortionAU(); 583 void SetupRogerBeepAU(); 584 585 bool PrepBufferQueueForPlayback(); 586 587 UInt32 SecondsToFrames(Float32 inSeconds); 588 UInt32 BytesToFrames(Float32 inBytes); 589 void AppendBufferToQueue(ALuint inBufferToken, OALBuffer *inBuffer); 590 UInt32 FramesToSecondsInt(UInt32 inFrames); 591 Float32 FramesToSecondsFloat(UInt32 inFrames); 592 UInt32 FramesToBytes(UInt32 inFrames); 593 594 void PostRenderSetBuffer(ALuint inBufferToken, OALBuffer *inBuffer); 595 void PostRenderAddBuffersToQueue(UInt32 inNumBuffersToQueue); 596 void PostRenderRemoveBuffersFromQueue(UInt32 inBuffersToUnqueue); 597 void FlushBufferQueue(); 598 void FlushTempBufferQueue(); 599 600 void AdvanceQueueToFrameIndex(UInt32 inFrameOffset); 601 OSStatus SetDistanceParams(bool inChangeReferenceDistance, bool inChangeMaxDistance); 602 Float32 GetMaxAttenuation(Float32 inRefDistance, Float32 inMaxDistance, Float32 inRolloff); 603 BufferInfo* NextPlayableBufferInActiveQ(); 604 605 inline bool InRenderThread() { return mOwningContext->CallingInRenderThread(); } 606 607 void SetQueueLength() { mQueueLength = mBufferQueueActive->GetQueueSize() + mBufferQueueInactive->GetQueueSize() - mBuffersQueuedForClear; } 608 609/* 610 OSStatus MuteCurrentPlayBus () const 611 { 612 return AudioUnitSetParameter ( mOwningContext->GetMixerUnit(), k3DMixerParam_Gain, kAudioUnitScope_Input, mCurrentPlayBus, 0.0, 0); 613 } 614*/ 615 616 static OSStatus SourceNotificationProc (void *inRefCon, 617 AudioUnitRenderActionFlags *inActionFlags, 618 const AudioTimeStamp *inTimeStamp, 619 UInt32 inBusNumber, 620 UInt32 inNumberFrames, 621 AudioBufferList *ioData); 622 623 static OSStatus SourceInputProc ( void *inRefCon, 624 AudioUnitRenderActionFlags *inActionFlags, 625 const AudioTimeStamp *inTimeStamp, 626 UInt32 inBusNumber, 627 UInt32 inNumberFrames, 628 AudioBufferList *ioData); 629 630 static OSStatus ACComplexInputDataProc ( AudioConverterRef inAudioConverter, 631 UInt32 *ioNumberDataPackets, 632 AudioBufferList *ioData, 633 AudioStreamPacketDescription **outDataPacketDescription, 634 void* inUserData); 635 636#pragma mark __________ PUBLIC __________ 637 public: 638 OALSource(ALuint inSelfToken, OALContext *inOwningContext); 639 ~OALSource(); 640 641 // set info methods - these may be called from either the render thread or the API caller 642 void SetPitch (Float32 inPitch); 643 void SetGain (Float32 inGain); 644 void SetMinGain (Float32 inMinGain); 645 void SetMaxGain (Float32 inMaxGain); 646 void SetReferenceDistance (Float32 inReferenceDistance); 647 void SetMaxDistance (Float32 inMaxDistance); 648 void SetRollOffFactor (Float32 inRollOffFactor); 649 void SetLooping (UInt32 inLooping); 650 void SetPosition (Float32 inX, Float32 inY, Float32 inZ); 651 void SetVelocity (Float32 inX, Float32 inY, Float32 inZ); 652 void SetDirection (Float32 inX, Float32 inY, Float32 inZ); 653 void SetSourceRelative (UInt32 inSourceRelative); 654 void SetChannelParameters (); 655 void SetConeInnerAngle (Float32 inConeInnerAngle); 656 void SetConeOuterAngle (Float32 inConeOuterAngle); 657 void SetConeOuterGain (Float32 inConeOuterGain); 658 void SetQueueOffset(UInt32 inOffsetType, Float32 inSecondOffset); 659 void SetUpDeconstruction(); 660 661 // get info methods 662 Float32 GetPitch (); 663 Float32 GetDopplerScaler (); 664 Float32 GetGain (); 665 Float32 GetMinGain (); 666 Float32 GetMaxGain (); 667 Float32 GetReferenceDistance (); 668 Float32 GetMaxDistance (); 669 Float32 GetRollOffFactor (); 670 UInt32 GetLooping (); 671 void GetPosition (Float32 &inX, Float32 &inY, Float32 &inZ); 672 void GetVelocity (Float32 &inX, Float32 &inY, Float32 &inZ); 673 void GetDirection (Float32 &inX, Float32 &inY, Float32 &inZ); 674 UInt32 GetSourceRelative (); 675 UInt32 GetSourceType (); 676 Float32 GetConeInnerAngle (); 677 Float32 GetConeOuterAngle (); 678 Float32 GetConeOuterGain (); 679 UInt32 GetState(); 680 ALuint GetToken(); 681 UInt32 GetQueueFrameOffset(); 682 UInt32 GetQueueOffset(UInt32 inOffsetType); 683 Float32 GetQueueOffsetSecondsFloat(); 684 685 // thread safety 686 void SetInUseFlag() { OSAtomicIncrement32Barrier(&mInUseFlag); } 687 void ClearInUseFlag() { OSAtomicDecrement32Barrier(&mInUseFlag); } 688 689 // buffer queue 690 UInt32 GetQLengthPriv(); 691 UInt32 GetQLength(); 692 UInt32 GetBuffersProcessed(); 693 void SetBuffer (ALuint inBufferToken, OALBuffer *inBuffer); 694 ALuint GetBuffer (); 695 void AddToQueue(ALuint inBufferToken, OALBuffer *inBuffer); 696 void AddToTempQueue(ALuint inBufferToken, OALBuffer *inBuffer); 697 void RemoveBuffersFromQueue(UInt32 inCount, ALuint *outBufferTokens); 698 bool IsSourceTransitioningToFlushQ(); 699 bool IsSafeForDeletion () { return (mSafeForDeletion && (mInUseFlag <= 0) && mSourceLock.IsFree()); } 700 701 // source notification methods 702 ALenum AddNotification(ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData); 703 void RemoveNotification(ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData); 704 705 // source spatialization methods 706 OSStatus SetRenderQuality(ALuint inValue); 707 ALint GetRenderQuality(); 708 709 // notification methods 710 void ClearMessageQueue(); 711 void SwapBufferQueues(); 712 void AddPlaybackMessage(UInt32 inMessage, OALBuffer* inBuffer, UInt32 inNumBuffers); 713 void SetPlaybackState(ALuint inState, bool sendSourceStateChangeNotification=false); 714 715 OSStatus DoPreRender (); 716 OSStatus DoPostRender (); 717 718 // playback methods 719 void Play(); 720 void Pause(); 721 void Resume(); 722 void Rewind(); 723 void Stop(); 724 725 void Suspend(); 726 void Unsuspend(); 727 728 // ASA methods 729 void SetReverbSendLevel(Float32 inReverbLevel); 730 void SetOcclusion(Float32 inOcclusion); 731 void SetObstruction(Float32 inObstruction); 732 733 void SetRogerBeepEnable(Boolean inEnable); 734 void SetRogerBeepOn(Boolean inOn); 735 void SetRogerBeepGain(Float32 inGain); 736 void SetRogerBeepSensitivity(SInt32 inSensitivity); 737 void SetRogerBeepType(SInt32 inType); 738 void SetRogerBeepPreset(FSRef* inRef); 739 740 void SetDistortionEnable(Boolean inEnable); 741 void SetDistortionOn(Boolean inOn); 742 void SetDistortionMix(Float32 inMix); 743 void SetDistortionType(SInt32 inType); 744 void SetDistortionPreset(FSRef* inRef); 745 746 Float32 GetReverbSendLevel() {return mASAReverbSendLevel;} 747 Float32 GetOcclusion() {return mASAOcclusion;} 748 Float32 GetObstruction() {return mASAObstruction;} 749 750 Boolean GetRogerBeepEnable() {return mASARogerBeepEnable;} 751 Boolean GetRogerBeepOn() {return mASARogerBeepOn;} 752 Float32 GetRogerBeepGain() {return mASARogerBeepGain;} 753 UInt32 GetRogerBeepSensitivity() {return mASARogerBeepSensitivity;} 754 UInt32 GetRogerBeepType() {return mASARogerBeepType;} 755 756 Boolean GetDistortionEnable() {return mASADistortionEnable;} 757 Boolean GetDistortionOn() {return mASADistortionOn;} 758 Float32 GetDistortionMix() {return mASADistortionMix;} 759 SInt32 GetDistortionType() {return mASADistortionType;} 760}; 761 762// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 763#pragma mark _____OALSourceMap_____ 764// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 765class OALSourceMap : std::multimap<ALuint, OALSource*, std::less<ALuint> > { 766public: 767 768 // add a new context to the map 769 void Add (const ALuint inSourceToken, OALSource **inSource) { 770 iterator it = upper_bound(inSourceToken); 771 insert(it, value_type (inSourceToken, *inSource)); 772 } 773 774 OALSource* GetSourceByIndex(UInt32 inIndex) { 775 iterator it = begin(); 776 777 for (UInt32 i = 0; i < inIndex; i++) { 778 if (it != end()) 779 ++it; 780 else 781 i = inIndex; 782 } 783 784 if (it != end()) 785 return ((*it).second); 786 return (NULL); 787 } 788 789 OALSource* Get(ALuint inSourceToken) { 790 iterator it = find(inSourceToken); 791 if (it != end()) 792 return ((*it).second); 793 return (NULL); 794 } 795 796 void MarkAllSourcesForRecalculation() { 797 iterator it = begin(); 798 while (it != end()) { 799 (*it).second->SetChannelParameters(); 800 ++it; 801 } 802 return; 803 } 804 805 void SuspendAllSources() { 806 iterator it = begin(); 807 while (it != end()) 808 { 809 (*it).second->Suspend(); 810 ++it; 811 } 812 return; 813 } 814 815 void UnsuspendAllSources() { 816 iterator it = begin(); 817 while (it != end()) 818 { 819 (*it).second->Unsuspend(); 820 ++it; 821 } 822 return; 823 } 824 825 void Remove (const ALuint inSourceToken) { 826 iterator it = find(inSourceToken); 827 if (it != end()) 828 erase(it); 829 } 830 831 UInt32 Size () const { return size(); } 832 bool Empty () const { return empty(); } 833}; 834 835#endif