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
9namespace 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}