1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | #include "BsOAPrerequisites.h" |
6 | #include "Audio/BsAudio.h" |
7 | #include "AL/alc.h" |
8 | |
9 | namespace bs |
10 | { |
11 | /** @addtogroup OpenAudio |
12 | * @{ |
13 | */ |
14 | |
15 | /** Global manager for the audio implementation using OpenAL as the backend. */ |
16 | class OAAudio : public Audio |
17 | { |
18 | public: |
19 | OAAudio(); |
20 | virtual ~OAAudio(); |
21 | |
22 | /** @copydoc Audio::setVolume */ |
23 | void setVolume(float volume) override; |
24 | |
25 | /** @copydoc Audio::getVolume */ |
26 | float getVolume() const override; |
27 | |
28 | /** @copydoc Audio::setPaused */ |
29 | void setPaused(bool paused) override; |
30 | |
31 | /** @copydoc Audio::isPaused */ |
32 | bool isPaused() const override { return mIsPaused; } |
33 | |
34 | /** @copydoc Audio::_update */ |
35 | void _update() override; |
36 | |
37 | /** @copydoc Audio::setActiveDevice */ |
38 | void setActiveDevice(const AudioDevice& device) override; |
39 | |
40 | /** @copydoc Audio::getActiveDevice */ |
41 | AudioDevice getActiveDevice() const override { return mActiveDevice; } |
42 | |
43 | /** @copydoc Audio::getDefaultDevice */ |
44 | AudioDevice getDefaultDevice() const override { return mDefaultDevice; } |
45 | |
46 | /** @copydoc Audio::getAllDevices */ |
47 | const Vector<AudioDevice>& getAllDevices() const override { return mAllDevices; }; |
48 | |
49 | /** @name Internal |
50 | * @{ |
51 | */ |
52 | |
53 | /** Checks is a specific OpenAL extension supported. */ |
54 | bool _isExtensionSupported(const String& extension) const; |
55 | |
56 | /** Registers a new AudioListener. Should be called on listener creation. */ |
57 | void _registerListener(OAAudioListener* listener); |
58 | |
59 | /** Unregisters an existing AudioListener. Should be called before listener destruction. */ |
60 | void _unregisterListener(OAAudioListener* listener); |
61 | |
62 | /** Registers a new AudioSource. Should be called on source creation. */ |
63 | void _registerSource(OAAudioSource* source); |
64 | |
65 | /** Unregisters an existing AudioSource. Should be called before source destruction. */ |
66 | void _unregisterSource(OAAudioSource* source); |
67 | |
68 | /** Returns a list of all OpenAL contexts. Each listener has its own context. */ |
69 | const Vector<ALCcontext*>& _getContexts() const { return mContexts; } |
70 | |
71 | /** Returns an OpenAL context assigned to the provided listener. */ |
72 | ALCcontext* _getContext(const OAAudioListener* listener) const; |
73 | |
74 | /** |
75 | * Returns optimal format for the provided number of channels and bit depth. It is assumed the user has checked if |
76 | * extensions providing these formats are actually available. |
77 | */ |
78 | INT32 _getOpenALBufferFormat(UINT32 numChannels, UINT32 bitDepth); |
79 | |
80 | /** |
81 | * Writes provided samples into the OpenAL buffer with the provided ID. If the provided format is not supported the |
82 | * samples will first be converted into a valid format. |
83 | */ |
84 | void _writeToOpenALBuffer(UINT32 bufferId, UINT8* samples, const AudioDataInfo& info); |
85 | |
86 | /** @} */ |
87 | |
88 | private: |
89 | friend class OAAudioSource; |
90 | |
91 | /** Type of a command that can be queued for a streaming audio source. */ |
92 | enum class StreamingCommandType |
93 | { |
94 | Start, |
95 | Stop |
96 | }; |
97 | |
98 | /** Command queued for a streaming audio source. */ |
99 | struct StreamingCommand |
100 | { |
101 | StreamingCommandType type; |
102 | OAAudioSource* source; |
103 | }; |
104 | |
105 | /** @copydoc Audio::createClip */ |
106 | SPtr<AudioClip> createClip(const SPtr<DataStream>& samples, UINT32 streamSize, UINT32 numSamples, |
107 | const AUDIO_CLIP_DESC& desc) override; |
108 | |
109 | /** @copydoc Audio::createListener */ |
110 | SPtr<AudioListener> createListener() override; |
111 | |
112 | /** @copydoc Audio::createSource */ |
113 | SPtr<AudioSource> createSource() override; |
114 | |
115 | /** |
116 | * Delete all existing contexts and rebuild them according to the listener list. All audio sources will be rebuilt |
117 | * as well. |
118 | * |
119 | * This should be called when listener count changes, or audio device is changed. |
120 | */ |
121 | void rebuildContexts(); |
122 | |
123 | /** Delete all existing OpenAL contexts. */ |
124 | void clearContexts(); |
125 | |
126 | /** Streams new data to audio sources that require it. */ |
127 | void updateStreaming(); |
128 | |
129 | /** Starts data streaming for the provided source. */ |
130 | void startStreaming(OAAudioSource* source); |
131 | |
132 | /** Stops data streaming for the provided source. */ |
133 | void stopStreaming(OAAudioSource* source); |
134 | |
135 | float mVolume = 1.0f; |
136 | bool mIsPaused = false; |
137 | |
138 | ALCdevice* mDevice = nullptr; |
139 | Vector<AudioDevice> mAllDevices; |
140 | AudioDevice mDefaultDevice; |
141 | AudioDevice mActiveDevice; |
142 | |
143 | Vector<OAAudioListener*> mListeners; |
144 | Vector<ALCcontext*> mContexts; |
145 | UnorderedSet<OAAudioSource*> mSources; |
146 | |
147 | // Streaming thread |
148 | Vector<StreamingCommand> mStreamingCommandQueue; |
149 | UnorderedSet<OAAudioSource*> mStreamingSources; |
150 | UnorderedSet<OAAudioSource*> mDestroyedSources; |
151 | SPtr<Task> mStreamingTask; |
152 | mutable Mutex mMutex; |
153 | }; |
154 | |
155 | /** Provides easier access to OAAudio. */ |
156 | OAAudio& gOAAudio(); |
157 | |
158 | /** @} */ |
159 | } |