// Port of pflib/external/openal/oalDevice.h (Apple OpenAL, Playground SDK 4.0): OALDevice, an ALC device: an // AUGraph with the default output unit, the context mixer connected to it, and the render channel count of the // HAL device. Layout from the DWARF of parity-out/sdk/dbgobj/oalDevice.o (game offsets identical, constructor // game @0x001234b0): // // OALDevice (size 56): +0x00 mSelfToken, +0x04 mCurrentError, +0x08 mHALDevice, +0x0c mDistanceScalingRequired, // +0x0d mGraphInitialized, +0x10 mAUGraph, +0x14 mOutputNode, +0x18 mOutputUnit, +0x1c mMixerNode, // +0x20 mConnectedContext, +0x24 mDeviceSampleRate, +0x2c mRenderChannelCount, +0x30 mRenderChannelSetting, // +0x34 mFramesPerSlice. // // Header code (inline members below) is emitted out of line in the SDK objects (addresses at each member) and // inlined in the game. OALDeviceMap (also declared in Apple's oalDevice.h) is oalImp code and ported at the // bottom of this header: its out-of-line code is in the SDK's oalImp.o (sdk @); the game inlines its calls. // Members declared without a definition have no game code and are not ported (listed in oalDevice.cpp). #ifndef OALDEVICE_H_INCLUDED #define OALDEVICE_H_INCLUDED #include "oal_sysdecls.h" #include #include #include class OALContext; class OALDevice { public: OALDevice(const char* inDeviceName, uintptr_t inSelfToken, UInt32 inRenderChannelSetting); ~OALDevice(); void ConnectContext(OALContext* inContext); void DisconnectContext(OALContext* inContext); void RemoveContext(OALContext* inContext); void StopGraph(); void SetRenderChannelSetting(UInt32 inRenderChannelSetting); void SetError(ALenum errorCode); // sdk @0x5a8da (oalImp.o) uintptr_t GetDeviceToken() const { return mSelfToken; } // sdk @0x5a8e8 (oalImp.o) Float64 GetDeviceSampleRate() const { return mDeviceSampleRate; } // sdk @0x5a900 (oalImp.o) UInt32 GetRenderChannelSetting() { return mRenderChannelSetting; } ALenum GetError(); // sdk @0x1f6e2 (oalContext.o) UInt32 GetFramesPerSlice() { return mFramesPerSlice; } // sdk @0x34a8e (oalSource.o), @0x1f6f0 (oalContext.o) AUGraph GetGraph() { return mAUGraph; } // sdk @0x1f6fe (oalContext.o) AudioUnit GetOutputAU() { return mOutputUnit; } UInt32 GetDesiredRenderChannelCount(); bool IsValidRenderQuality(UInt32 inRenderQuality); static void GraphFormatPropertyListener(void* inRefCon, AudioUnit ci, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement); // sdk @0x9108 (oalDevice.o; inlined in the game's ConnectContext) bool IsGraphStillRunning() { Boolean running; OSStatus result = AUGraphIsRunning(mAUGraph, &running); if (result != noErr) { throw ((OALStatusException)result); } return bool(running); } void Print(); private: void InitializeGraph(const char* inDeviceName); void TeardownGraph(); void ResetRenderChannelSettings(); UInt32 GetChannelLayoutTag(); uintptr_t mSelfToken; ALenum mCurrentError; AudioDeviceID mHALDevice; bool mDistanceScalingRequired; bool mGraphInitialized; AUGraph mAUGraph; AUNode mOutputNode; AudioUnit mOutputUnit; AUNode mMixerNode; OALContext* mConnectedContext; Float64 mDeviceSampleRate; UInt32 mRenderChannelCount; UInt32 mRenderChannelSetting; UInt32 mFramesPerSlice; }; // The device map of oalImp.cpp (gOALDeviceMap). Every member's out-of-line code is in the SDK's oalImp.o // (sdk @ below); the game inlines all of them. The map is deleted in alcCloseDevice once it is empty (the // destructor is emitted out of line in the SDK build). class OALDeviceMap : std::multimap > { public: // sdk @0x5cf98 (oalImp.o) OALDeviceMap() {} // sdk @0x5c4e0 (oalImp.o) ~OALDeviceMap() {} // sdk @0x5d518 (oalImp.o) void Add(const uintptr_t inDeviceToken, OALDevice** inDevice) { iterator it = upper_bound(inDeviceToken); insert(it, value_type(inDeviceToken, *inDevice)); } // sdk @0x5b7e4 (oalImp.o) OALDevice* Get(uintptr_t inDeviceToken) { iterator it = find(inDeviceToken); if (it != end()) { return ((*it).second); } return (NULL); } // sdk @0x5b8da (oalImp.o) OALDevice* GetDeviceByIndex(UInt32 inIndex, uintptr_t& outDeviceToken) { iterator it = begin(); std::advance(it, inIndex); if (it != end()) { outDeviceToken = (*it).first; return (*it).second; } return (NULL); } // sdk @0x5c3c8 (oalImp.o) void Remove(const uintptr_t inDeviceToken) { iterator it = find(inDeviceToken); if (it != end()) { erase(it); } } // sdk @0x5ae14 (oalImp.o) UInt32 Size() const { return (UInt32)size(); } // sdk @0x5ae54 (oalImp.o) bool Empty() const { return empty(); } }; #endif