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_DEVICE__
25#define __OAL_DEVICE__
26
27#include <Carbon/Carbon.h>
28#include <CoreAudio/AudioHardware.h>
29#include <AudioToolbox/AudioToolbox.h>
30#include <AudioUnit/AudioUnit.h>
31#include <libkern/OSAtomic.h>
32#include <map>
33
34#include "oalImp.h"
35
36#include  "CAStreamBasicDescription.h"
37
38
39class OALContext;        // forward declaration
40
41// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42// Some build flags for gathering performance and data flow information
43
44#if USE_AU_TRACER
45	#include "AUTracer.h"
46#endif
47
48#if DEBUG
49	#define AUHAL_LOG_OUTPUT 0
50#endif
51
52#if AUHAL_LOG_OUTPUT
53	#include "AudioLogger.h"
54#endif
55
56// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
57// Device Constants
58// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
59
60// Default Mixer Output Sample Rate Setting:
61#define	kDefaultMixerRate       44100.0
62
63// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
64// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65// OALDevices
66// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
68
69#pragma mark _____OALDevice_____
70class OALDevice
71{
72	public:
73
74	OALDevice(const char* 	 inDeviceName, uintptr_t   inSelfToken, UInt32	inRenderChannelSetting);
75	~OALDevice();
76
77	void				ConnectContext		(OALContext*	inContext);
78	void				DisconnectContext	(OALContext*	inContext);
79	void				RemoveContext		(OALContext*	inContext);
80	void				StopGraph();
81
82	// thread safety
83	volatile int32_t	IsInUse()			{ return mInUseFlag; }
84	void				SetInUseFlag()		{ OSAtomicIncrement32Barrier(&mInUseFlag); }
85	void				ClearInUseFlag()	{ OSAtomicDecrement32Barrier(&mInUseFlag); }
86
87	// set info
88	void				SetRenderChannelSetting (UInt32 inRenderChannelSetting);
89	void				SetError(ALenum errorCode);
90
91	// get info
92	uintptr_t			GetDeviceToken () const { return mSelfToken; }
93	Float64				GetDeviceSampleRate () const { return mDeviceSampleRate; }
94	UInt32				GetRenderChannelSetting() { return  mRenderChannelSetting; }
95	ALenum				GetError();
96	UInt32				GetFramesPerSlice() { return mFramesPerSlice;}
97	AUGraph				GetGraph () {return mAUGraph;}
98	AudioUnit			GetOutputAU(){return mOutputUnit;}
99	OSStatus			UpdateDeviceChannelLayout();
100	UInt32				GetDesiredRenderChannelCount ();
101
102	// misc.
103	bool				IsValidRenderQuality (UInt32 inRenderQuality);
104    static void			GraphFormatPropertyListener 	(	void 					*inRefCon,
105															AudioUnit 				ci,
106															AudioUnitPropertyID 	inID,
107															AudioUnitScope 			inScope,
108															AudioUnitElement 		inElement);
109
110	bool	IsGraphStillRunning ()
111	{
112		Boolean running;
113		OSStatus result = AUGraphIsRunning (mAUGraph, &running);
114			THROW_RESULT
115		return bool(running);
116	}
117
118	void 	Print () const
119	{
120#if	DEBUG || CoreAudio_Debug
121		CAShow (mAUGraph);
122#endif
123	}
124
125	private:
126		uintptr_t				mSelfToken;
127		ALenum					mCurrentError;
128        AudioDeviceID			mHALDevice;                     // the HAL device used to render audio to the user
129        bool					mDistanceScalingRequired;
130		bool					mGraphInitialized;
131		AUGraph					mAUGraph;
132        AUNode					mOutputNode;
133        AudioUnit				mOutputUnit;
134        AUNode					mMixerNode;
135		AudioChannelLayoutTag	mChannelLayoutTag;
136		OALContext*				mConnectedContext;
137		Float64					mDeviceSampleRate;
138        UInt32					mRenderChannelCount;
139        UInt32					mRenderChannelSetting;			// currently either stereo or multichannel
140		UInt32					mFramesPerSlice;
141		volatile int32_t		mInUseFlag;						// flag to indicate if the device is currently being edited by one or more threads
142#if AUHAL_LOG_OUTPUT
143        AudioLogger			mLogger;
144#endif
145#if USE_AU_TRACER
146        AUTracer			mAUTracer;
147#endif
148
149	void					InitializeGraph (const char* 		inDeviceName);
150	void					TeardownGraph();
151	void					ResetRenderChannelSettings();
152	AudioChannelLayoutTag	GetLayoutTagForLayout(AudioChannelLayout *inLayout, UInt32 inNumChannels);
153	UInt32					GetChannelLayoutTag();
154};
155
156// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157#pragma mark _____OALDeviceMap_____
158// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
159class OALDeviceMap : std::multimap<uintptr_t, OALDevice*, std::less<uintptr_t> > {
160public:
161
162    void Add (const	uintptr_t	inDeviceToken, OALDevice **inDevice)  {
163		iterator it = upper_bound(inDeviceToken);
164		insert(it, value_type (inDeviceToken, *inDevice));
165	}
166
167    OALDevice* Get(uintptr_t	inDeviceToken) {
168        iterator	it = find(inDeviceToken);
169        if (it != end())
170            return ((*it).second);
171		return (NULL);
172    }
173
174	OALDevice* GetDeviceByIndex(UInt32	inIndex, uintptr_t	&outDeviceToken) {
175		iterator	it = begin();
176        std::advance(it, inIndex);
177		if (it != end())
178		{
179			outDeviceToken = (*it).first;
180			return (*it).second;
181		}
182		return (NULL);
183	}
184
185    void Remove (const	uintptr_t	inDeviceToken) {
186        iterator 	it = find(inDeviceToken);
187        if (it != end())
188            erase(it);
189    }
190
191    UInt32 Size () const { return size(); }
192    bool Empty () const { return empty(); }
193};
194
195#endif
196