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#ifndef __OAL_CONTEXT__
25#define __OAL_CONTEXT__
26
27#include "oalDevice.h"
28#include "alc.h"
29#include "MacOSX_OALExtensions.h"
30#include "oalCaptureMixer.h"
31#include "CAGuard.h"
32
33#include <Carbon/Carbon.h>
34#include <map>
35#include <libkern/OSAtomic.h>
36
37#define CAPTURE_AUDIO_TO_FILE 0
38
39#if	CAPTURE_AUDIO_TO_FILE
40	#include "CAAudioUnitOutputCapturer.h"
41#endif
42
43#define LOG_BUS_CONNECTIONS  	0
44#define LOG_CONTEXT_VERBOSE     0
45
46#define kDefaultReferenceDistance   1.0
47#define kDefaultMaximumDistance     1000000.0
48#define kDefaultRolloff             1.0
49#define kPreferredMixerVersion 		0x21000
50#define kMinimumMixerVersion 		0x10300
51
52// Default Low Quality Stereo Spatial Setting:
53#define	kDefaultLowQuality      kSpatializationAlgorithm_EqualPowerPanning
54
55// Default High Quality Stereo Spatial Setting:
56#define	kDefaultHighQuality     kSpatializationAlgorithm_HRTF
57
58// Default MultiChannel Spatial Setting:
59#define	kDefaultMultiChannelQuality kSpatializationAlgorithm_SoundField
60
61
62/*
63	An OALContext is basically the equivalent of a 'room' or 'scene'. It is attached to an OALDevice which
64	is a piece of hardware and contains a single 3DMixer. Each context has it's own source objects
65	and a single listener. It also has it's own settings for the 3DMixer, such as Reverb, Doppler, etc.
66*/
67
68enum { kNoSourceAttached = (ALuint)-1 };
69
70struct BusInfo {
71					ALuint		mSourceAttached;	// the token of the source attached
72					UInt32		mNumberChannels;    // mono/stereo setting of the bus
73                    UInt32      mReverbState;     // unused until Reverb extension is added to the implementation
74};
75
76// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77
78class OALSource;        // forward declaration
79class OALSourceMap;     // forward declaration
80
81// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
82// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
83// OALContexts
84// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
86#pragma mark _____OALContext_____
87
88class OALContext
89{
90	public:
91	OALContext(const uintptr_t	inSelfToken, OALDevice *inOALDevice, const ALCint *inAttributeList, UInt32  &inBusCount, Float64	&inMixerRate);
92	~OALContext();
93
94	bool			DoSetDistance() { return mCalculateDistance;}
95	UInt32			GetDesiredRenderChannels(UInt32	inDeviceChannels);
96	AudioUnit		GetMixerUnit() { return mMixerUnit;}
97	AUNode			GetMixerNode() { return mMixerNode;}
98	AUGraph			GetGraph()	   { return mOwningDevice->GetGraph(); }
99	UInt32			GetRenderQuality() {return mRenderQuality;}
100	Float32         GetFramesPerSlice() { return mOwningDevice->GetFramesPerSlice();}
101	Float64			GetMixerRate () const { return mMixerOutputRate; }
102	Float32         GetDefaultReferenceDistance() { return mDefaultReferenceDistance;}
103	Float32         GetDefaultMaxDistance() { return mDefaultMaxDistance;}
104	bool            IsDistanceScalingRequired() { return mDistanceScalingRequired;}
105	UInt32			GetAvailableMonoBus (ALuint inSourceToken);
106	UInt32			GetAvailableStereoBus (ALuint inSourceToken);
107	UInt32			GetBusCount () { return mBusCount;}
108	uintptr_t		GetDeviceToken () { return mOwningDevice->GetDeviceToken();}
109	UInt32			GetDistanceModel() { return mDistanceModel;}
110	Float32			GetSpeedOfSound() {return (mSpeedOfSound);}
111	Float32			GetDopplerFactor() {return (mDopplerFactor);}
112	Float32			GetDopplerVelocity() {return (mDopplerVelocity);}
113	Float32			GetListenerGain() {return (mListenerGain);}
114	void			GetListenerPosition(Float32	*posX, Float32	*posY, Float32	*posZ) {*posX = mListenerPosition[0];
115																								*posY = mListenerPosition[1];
116																								*posZ = mListenerPosition[2];}
117
118	void			GetListenerVelocity(Float32	*posX, Float32	*posY, Float32	*posZ) {	*posX = mListenerVelocity[0];
119																							*posY = mListenerVelocity[1];
120																							*posZ = mListenerVelocity[2];}
121
122	void			GetListenerOrientation(	Float32	*forwardX, Float32	*forwardY, Float32	*forwardZ,
123											Float32	*upX, Float32	*upY, Float32	*upZ) {		*forwardX = mListenerOrientationForward[0];
124																								*forwardY = mListenerOrientationForward[1];
125																								*forwardZ = mListenerOrientationForward[2];
126																								*upX = mListenerOrientationUp[0];
127																								*upY = mListenerOrientationUp[1];
128																								*upZ = mListenerOrientationUp[2];		}
129
130	UInt32			GetAttributeListSize(){return mAttributeListSize;}
131	void			CopyAttributeList( ALCint*	outAttrList);
132
133	void			SetReverbQuality(UInt32 inQuality);
134	void			SetReverbEQGain(Float32 inLevel);
135	void			SetReverbEQBandwidth(Float32 inBandwidth);
136	void			SetReverbEQFrequency(Float32 inFrequency);
137
138	UInt32			GetReverbQuality();
139	Float32			GetReverbEQGain();
140	Float32			GetReverbEQBandwidth();
141	Float32			GetReverbEQFrequency();
142
143
144	// set info methods
145	void			SetBusAsAvailable (UInt32 inBusIndex);
146	void			SetDistanceAttenuation(UInt32    inBusIndex, Float64 inRefDist, Float64 inMaxDist, Float64 inRolloff);
147	void			SetRenderQuality (UInt32 inRenderQuality);
148    void            SetSourceDesiredRenderQualityOnBus (UInt32 inRenderQuality, int inBus);
149    UInt32          GetRenderQualityForBus (int inBus);
150	void			SetDistanceModel(UInt32	inDistanceModel);
151	void			SetDopplerFactor(Float32	inDopplerFactor);
152	void			SetDopplerVelocity(Float32	inDopplerVelocity);
153	void			SetSpeedOfSound(Float32	inSpeedOfSound);
154	void			SetListenerPosition(Float32	posX, Float32	posY, Float32	posZ);
155	void			SetListenerVelocity(Float32	posX, Float32	posY, Float32	posZ);
156	void			SetListenerGain(Float32 inGain);
157	void			SetListenerOrientation( Float32  forwardX,   Float32  forwardY, Float32  forwardZ,
158											Float32  upX,        Float32  upY, 		Float32  upZ);
159	void			SetReverbPreset (FSRef* inRef);
160
161	// ASA Support: Reverb, Occlusion
162	void			SetReverbState(UInt32 inReverbState);
163	UInt32			GetReverbState() {return mASAReverbState;}
164	void			SetReverbRoomType(UInt32 inRoomType);
165	void			SetReverbLevel(Float32 inReverbLevel);
166	UInt32			GetReverbRoomType() {return mASAReverbRoomType;}
167	Float32			GetReverbLevel() {return mASAReverbGlobalLevel;}
168
169    // Context Output Capturer Methods
170    OSStatus        OutputCapturerCreate(Float64 inSampleRate, UInt32 inOALFormat, UInt32 inBufferSize);
171    OSStatus		OutputCapturerStart();
172	OSStatus		OutputCapturerStop();
173    OSStatus		OutputCapturerGetFrames(UInt32 inFrameCount, UInt8*	inBuffer);
174	UInt32			OutputCapturerAvailableFrames();
175
176	// notification proc methods
177	OSStatus			DoPostRender ();
178	OSStatus			DoPreRender ();
179	static	OSStatus	ContextNotificationProc (	void                        *inRefCon,
180													AudioUnitRenderActionFlags 	*inActionFlags,
181													const AudioTimeStamp 		*inTimeStamp,
182													UInt32 						inBusNumber,
183													UInt32 						inNumberFrames,
184													AudioBufferList 			*ioData);
185
186
187	// threading protection methods
188	bool				CallingInRenderThread () const { return (pthread_self() == mRenderThreadID); }
189
190	volatile int32_t	IsInUse()			{ return mInUseFlag; }
191	void				SetInUseFlag()		{ OSAtomicIncrement32Barrier(&mInUseFlag); }
192	void				ClearInUseFlag()	{ OSAtomicDecrement32Barrier(&mInUseFlag); }
193
194	// context activity methods
195	void			ProcessContext();
196	void			SuspendContext();
197
198	// source methods
199	void			AddSource(ALuint inSourceToken);
200	void			RemoveSource(ALuint inSourceToken);
201	OALSource*		ProtectSource(ALuint inSourceToken);
202	OALSource*		GetSourceForRender(ALuint inSourceToken);
203	OALSource*		GetDeadSourceForRender(ALuint inSourceToken);
204	void			ReleaseSource(OALSource* inSource);
205	UInt32			GetSourceCount();
206	void			CleanUpDeadSourceList();
207
208	// device methods
209	void			ConnectMixerToDevice();
210	void			DisconnectMixerFromDevice();
211	void			InitRenderQualityOnBusses();
212    void            InitRenderQualityOnSources();
213	void			ConfigureMixerFormat();
214
215	private:
216#if LOG_CONTEXT_VERBOSE
217		uintptr_t			mSelfToken;
218#endif
219//		bool				mProcessingActive;
220		OALDevice			*mOwningDevice;
221        AUNode				mMixerNode;
222        AudioUnit			mMixerUnit;
223		OALSourceMap		*mSourceMap;
224		CAGuard				mSourceMapLock;					// the map is not thread-safe. We need a mutex to serialize operations on it
225		OALSourceMap		*mDeadSourceMap;
226		CAGuard				mDeadSourceMapLock;					// the map is not thread-safe. We need a mutex to serialize operations on it
227		UInt32				mDistanceModel;
228		Float32				mSpeedOfSound;
229		Float32				mDopplerFactor;
230		Float32				mDopplerVelocity;
231		Float32				mListenerPosition[3];
232		Float32				mListenerVelocity[3];
233		Float32				mListenerGain;
234		Float32				mListenerOrientationForward[3];
235		Float32				mListenerOrientationUp[3];
236		UInt32				mAttributeListSize;
237		ALCint*				mAttributeList;
238        bool				mDistanceScalingRequired;
239		bool				mCalculateDistance;				// true except: for 1.3 mixer Inverse curve, OR pre 2.2 mixer and either Exponential or Linear curves
240		UInt32				mRenderQuality;                 // Hi or Lo for now
241        UInt32				mSpatialSetting;
242        UInt32				mBusCount;
243		volatile int32_t	mInUseFlag;
244        Float64				mMixerOutputRate;
245        Float32				mDefaultReferenceDistance;
246        Float32				mDefaultMaxDistance;
247		bool				mUserSpecifiedBusCounts;
248        BusInfo				*mBusInfo;
249   		pthread_t			mRenderThreadID;
250		bool				mSettableMixerAttenuationCurves;
251		UInt32				mASAReverbState;
252		UInt32				mASAReverbRoomType;
253		Float32				mASAReverbGlobalLevel;
254		UInt32				mASAReverbQuality;
255		Float32				mASAReverbEQGain;
256		Float32				mASAReverbEQBandwidth;
257		Float32				mASAReverbEQFrequency;
258        OALCaptureMixer*    mOutputCapturer;
259
260#if LOG_BUS_CONNECTIONS
261        UInt32		mMonoSourcesConnected;
262        UInt32		mStereoSourcesConnected;
263#endif
264#if CAPTURE_AUDIO_TO_FILE
265		CAAudioUnitOutputCapturer		*gTheCapturer;
266		CFURLRef						gFileURL;
267		AudioStreamBasicDescription		gCapturerDataFormat;
268#endif
269
270	void	InitializeMixer(UInt32	inStereoBusCount);
271
272};
273
274// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
275// OALDevices contain a single OALContextMap to keep track of the contexts that belong to it.
276#pragma mark _____OALContextMap_____
277class OALContextMap : std::multimap<uintptr_t, OALContext*, std::less<uintptr_t> > {
278public:
279
280    void Add (const	uintptr_t	inContextToken, OALContext **inContext)  {
281		iterator it = upper_bound(inContextToken);
282		insert(it, value_type (inContextToken, *inContext));
283	}
284
285    OALContext* Get (uintptr_t	inContextToken) {
286        iterator	it = find(inContextToken);
287        if (it != end())
288            return ((*it).second);
289		return (NULL);
290    }
291
292    bool Remove (const	uintptr_t	inContextToken) {
293        iterator 	it = find(inContextToken);
294        if (it != end()) {
295            erase(it);
296			return true; // success
297		}
298		return false;
299    }
300
301	OALContext* GetContextByIndex(UInt32	inIndex, uintptr_t	&outContextToken) {
302		iterator	it = begin();
303        std::advance(it, inIndex);
304		if (it != end())
305		{
306			outContextToken = (*it).first;
307			return (*it).second;
308		}
309		return (NULL);
310	}
311
312	uintptr_t	GetDeviceTokenForContext(uintptr_t	inContextToken) {
313		OALContext	*context = Get(inContextToken);
314		if (context != NULL)
315			return (context->GetDeviceToken());
316		else
317			return (0);
318	}
319
320    UInt32 Size() const { return size(); }
321    bool Empty() const { return empty(); }
322};
323
324#endif