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