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		// thread protection
523		OALRenderLocker				mRenderLocker;
524
525		// Audio Units and properties for RogerBeep and Distortion
526		AUNode						mRogerBeepNode;
527		AudioUnit					mRogerBeepAU;
528		Boolean						mASARogerBeepEnable;
529		Boolean						mASARogerBeepOn;
530		Float32						mASARogerBeepGain;
531		SInt32						mASARogerBeepSensitivity;
532		SInt32						mASARogerBeepType;
533		char*						mASARogerBeepPreset;
534
535		AUNode						mDistortionNode;
536		AudioUnit					mDistortionAU;
537		Boolean						mASADistortionEnable;
538		Boolean						mASADistortionOn;
539		Float32						mASADistortionMix;
540		SInt32						mASADistortionType;
541		char*						mASADistortionPreset;
542
543		AudioUnit					mRenderUnit;
544		UInt32						mRenderElement;
545
546		SourceNotifications*		mSourceNotifications;
547
548	typedef TAtomicStack<PlaybackMessage>	PlaybackMessageList;
549
550		PlaybackMessageList			mMessageQueue;
551
552
553	void        JoinBufferLists();
554	void        LoopToBeginning();
555	void        ChangeChannelSettings();
556	void		InitSource();
557	void		SetState(UInt32		inState);
558	OSStatus 	DoRender (AudioBufferList 	*ioData);
559	OSStatus 	DoSRCRender (AudioBufferList 	*ioData);           // support for pre 2.0 3DMixer
560	bool		ConeAttenuation();
561	void 		CalculateDistanceAndAzimuth(Float32 *outDistance, Float32 *outAzimuth, Float32 *outElevation, Float32	*outDopplerShift);
562	void        UpdateBusGain ();
563    void        UpdateMinBusGain ();
564    void        UpdateMaxBusGain ();
565	void        UpdateBusFormat ();
566	void        UpdateBusReverb ();
567	void        UpdateBusOcclusion ();
568	void        UpdateBusObstruction ();
569
570	void		UpdateQueue ();
571	void		RampDown (AudioBufferList 			*ioData);
572	void		RampUp (AudioBufferList 			*ioData);
573	void		ClearActiveQueue();
574	void		AddNotifyAndRenderProcs();
575	void		ReleaseNotifyAndRenderProcs();
576	void		DisconnectFromBus();
577	void		SetupMixerBus();
578    void        ResetMixerBus();
579	void		SetupDistortionAU();
580	void		SetupRogerBeepAU();
581
582	bool		PrepBufferQueueForPlayback();
583
584	UInt32		SecondsToFrames(Float32	inSeconds);
585	UInt32		BytesToFrames(Float32	inBytes);
586	void		AppendBufferToQueue(ALuint	inBufferToken, OALBuffer	*inBuffer);
587	UInt32		FramesToSecondsInt(UInt32	inFrames);
588	Float32		FramesToSecondsFloat(UInt32	inFrames);
589	UInt32		FramesToBytes(UInt32	inFrames);
590
591	void		PostRenderSetBuffer(ALuint inBufferToken, OALBuffer	*inBuffer);
592    void        PostRenderAddBuffersToQueue(UInt32 inNumBuffersToQueue);
593	void        PostRenderRemoveBuffersFromQueue(UInt32	inBuffersToUnqueue);
594	void		FlushBufferQueue();
595    void		FlushTempBufferQueue();
596
597	void		AdvanceQueueToFrameIndex(UInt32	inFrameOffset);
598	OSStatus	SetDistanceParams(bool	inChangeReferenceDistance, bool inChangeMaxDistance);
599	Float32		GetMaxAttenuation(Float32	inRefDistance, Float32 inMaxDistance, Float32 inRolloff);
600	BufferInfo* NextPlayableBufferInActiveQ();
601
602	inline bool		InRenderThread() { return mOwningContext->CallingInRenderThread(); }
603
604    void        SetQueueLength()                { mQueueLength = mBufferQueueActive->GetQueueSize() + mBufferQueueInactive->GetQueueSize() - mBuffersQueuedForClear; }
605
606/*
607	OSStatus	MuteCurrentPlayBus () const
608	{
609		return AudioUnitSetParameter (	mOwningContext->GetMixerUnit(), k3DMixerParam_Gain, kAudioUnitScope_Input, mCurrentPlayBus, 0.0, 0);
610	}
611*/
612
613	static	OSStatus	SourceNotificationProc (void                        *inRefCon,
614												AudioUnitRenderActionFlags 	*inActionFlags,
615												const AudioTimeStamp 		*inTimeStamp,
616												UInt32 						inBusNumber,
617												UInt32 						inNumberFrames,
618												AudioBufferList 			*ioData);
619
620	static	OSStatus	SourceInputProc (	void                        *inRefCon,
621											AudioUnitRenderActionFlags 	*inActionFlags,
622											const AudioTimeStamp 		*inTimeStamp,
623											UInt32 						inBusNumber,
624											UInt32 						inNumberFrames,
625											AudioBufferList 			*ioData);
626
627	static OSStatus     ACComplexInputDataProc	(	AudioConverterRef				inAudioConverter,
628                                                    UInt32							*ioNumberDataPackets,
629                                                    AudioBufferList					*ioData,
630                                                    AudioStreamPacketDescription	**outDataPacketDescription,
631                                                    void*							inUserData);
632
633#pragma mark __________ PUBLIC __________
634	public:
635	OALSource(ALuint 	 	inSelfToken, OALContext	*inOwningContext);
636	~OALSource();
637
638	// set info methods - these may be called from either the render thread or the API caller
639	void	SetPitch (Float32	inPitch);
640	void	SetGain (Float32	inGain);
641	void	SetMinGain (Float32	inMinGain);
642	void	SetMaxGain (Float32	inMaxGain);
643	void	SetReferenceDistance (Float32	inReferenceDistance);
644	void	SetMaxDistance (Float32	inMaxDistance);
645	void	SetRollOffFactor (Float32	inRollOffFactor);
646	void	SetLooping (UInt32	inLooping);
647	void	SetPosition (Float32 inX, Float32 inY, Float32 inZ);
648	void	SetVelocity (Float32 inX, Float32 inY, Float32 inZ);
649	void	SetDirection (Float32 inX, Float32 inY, Float32 inZ);
650	void	SetSourceRelative (UInt32	inSourceRelative);
651	void	SetChannelParameters ();
652	void	SetConeInnerAngle (Float32	inConeInnerAngle);
653	void	SetConeOuterAngle (Float32	inConeOuterAngle);
654	void	SetConeOuterGain (Float32	inConeOuterGain);
655	void	SetQueueOffset(UInt32	inOffsetType, Float32	inSecondOffset);
656	void	SetUpDeconstruction();
657
658	// get info methods
659	Float32	GetPitch ();
660	Float32	GetDopplerScaler ();
661	Float32	GetGain ();
662	Float32	GetMinGain ();
663	Float32	GetMaxGain ();
664	Float32	GetReferenceDistance ();
665	Float32	GetMaxDistance ();
666	Float32	GetRollOffFactor ();
667	UInt32	GetLooping ();
668	void	GetPosition (Float32 &inX, Float32 &inY, Float32 &inZ);
669	void	GetVelocity (Float32 &inX, Float32 &inY, Float32 &inZ);
670	void	GetDirection (Float32 &inX, Float32 &inY, Float32 &inZ);
671	UInt32	GetSourceRelative ();
672	UInt32	GetSourceType ();
673	Float32	GetConeInnerAngle ();
674	Float32	GetConeOuterAngle ();
675	Float32	GetConeOuterGain ();
676	UInt32	GetState();
677    ALuint	GetToken();
678	UInt32	GetQueueFrameOffset();
679	UInt32	GetQueueOffset(UInt32	inOffsetType);
680	Float32	GetQueueOffsetSecondsFloat();
681
682	// thread safety
683	void	SetInUseFlag()		{ OSAtomicIncrement32Barrier(&mInUseFlag); }
684	void	ClearInUseFlag()	{ OSAtomicDecrement32Barrier(&mInUseFlag); }
685
686    // buffer queue
687    UInt32	GetQLengthPriv();
688	UInt32	GetQLength();
689	UInt32	GetBuffersProcessed();
690	void	SetBuffer (ALuint	inBufferToken, OALBuffer	*inBuffer);
691	ALuint	GetBuffer ();
692	void	AddToQueue(ALuint	inBufferToken, OALBuffer	*inBuffer);
693    void    AddToTempQueue(ALuint	inBufferToken, OALBuffer	*inBuffer);
694	void	RemoveBuffersFromQueue(UInt32	inCount, ALuint	*outBufferTokens);
695	bool	IsSourceTransitioningToFlushQ();
696	bool    IsSafeForDeletion ()  { return (mSafeForDeletion && (mInUseFlag <= 0) && mSourceLock.IsFree()); }
697
698	// source notification methods
699	ALenum		AddNotification(ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData);
700	void		RemoveNotification(ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData);
701
702	// notification methods
703	void		ClearMessageQueue();
704	void		SwapBufferQueues();
705	void		AddPlaybackMessage(UInt32 inMessage, OALBuffer* inBuffer, UInt32	inNumBuffers);
706	void		SetPlaybackState(ALuint inState, bool sendSourceStateChangeNotification=false);
707
708	OSStatus 	DoPreRender ();
709	OSStatus 	DoPostRender ();
710
711	// playback methods
712	void	Play();
713	void	Pause();
714	void	Resume();
715	void	Rewind();
716	void	Stop();
717
718	void	Suspend();
719	void	Unsuspend();
720
721	// ASA methods
722	void			SetReverbSendLevel(Float32 inReverbLevel);
723	void			SetOcclusion(Float32 inOcclusion);
724	void			SetObstruction(Float32 inObstruction);
725
726	void			SetRogerBeepEnable(Boolean inEnable);
727	void			SetRogerBeepOn(Boolean inOn);
728	void			SetRogerBeepGain(Float32 inGain);
729	void			SetRogerBeepSensitivity(SInt32 inSensitivity);
730	void			SetRogerBeepType(SInt32 inType);
731	void			SetRogerBeepPreset(FSRef* inRef);
732
733	void			SetDistortionEnable(Boolean inEnable);
734	void			SetDistortionOn(Boolean inOn);
735	void			SetDistortionMix(Float32 inMix);
736	void			SetDistortionType(SInt32 inType);
737	void			SetDistortionPreset(FSRef* inRef);
738
739	Float32			GetReverbSendLevel() {return mASAReverbSendLevel;}
740	Float32			GetOcclusion() {return mASAOcclusion;}
741	Float32			GetObstruction() {return mASAObstruction;}
742
743	Boolean			GetRogerBeepEnable() {return mASARogerBeepEnable;}
744	Boolean			GetRogerBeepOn() {return mASARogerBeepOn;}
745	Float32			GetRogerBeepGain() {return mASARogerBeepGain;}
746	UInt32			GetRogerBeepSensitivity() {return mASARogerBeepSensitivity;}
747	UInt32			GetRogerBeepType() {return mASARogerBeepType;}
748
749	Boolean			GetDistortionEnable() {return mASADistortionEnable;}
750	Boolean			GetDistortionOn() {return mASADistortionOn;}
751	Float32			GetDistortionMix() {return mASADistortionMix;}
752	SInt32			GetDistortionType() {return mASADistortionType;}
753};
754
755// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
756#pragma mark _____OALSourceMap_____
757// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
758class OALSourceMap : std::multimap<ALuint, OALSource*, std::less<ALuint> > {
759public:
760
761    // add a new context to the map
762    void Add (const	ALuint	inSourceToken, OALSource **inSource)  {
763		iterator it = upper_bound(inSourceToken);
764		insert(it, value_type (inSourceToken, *inSource));
765	}
766
767    OALSource* GetSourceByIndex(UInt32	inIndex) {
768        iterator	it = begin();
769
770		for (UInt32 i = 0; i < inIndex; i++) {
771            if (it != end())
772                ++it;
773            else
774                i = inIndex;
775        }
776
777        if (it != end())
778            return ((*it).second);
779		return (NULL);
780    }
781
782    OALSource* Get(ALuint	inSourceToken) {
783        iterator	it = find(inSourceToken);
784        if (it != end())
785            return ((*it).second);
786		return (NULL);
787    }
788
789    void MarkAllSourcesForRecalculation() {
790        iterator	it = begin();
791        while (it != end()) {
792			(*it).second->SetChannelParameters();
793			++it;
794		}
795		return;
796    }
797
798    void SuspendAllSources() {
799        iterator	it = begin();
800        while (it != end())
801		{
802			(*it).second->Suspend();
803			++it;
804		}
805		return;
806    }
807
808    void UnsuspendAllSources() {
809        iterator	it = begin();
810        while (it != end())
811		{
812			(*it).second->Unsuspend();
813			++it;
814		}
815		return;
816    }
817
818    void Remove (const	ALuint	inSourceToken) {
819        iterator 	it = find(inSourceToken);
820        if (it != end())
821            erase(it);
822    }
823
824    UInt32 Size () const { return size(); }
825    bool Empty () const { return empty(); }
826};
827
828#endif