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