22#include "utility/sound/audio_manager.hpp"
26 _device = alcOpenDevice(
nullptr);
29 <<
"Failed to open audio device; audio is disabled";
34 _context = alcCreateContext(_device,
nullptr);
37 <<
"Failed to create audio context; audio is disabled";
38 alcCloseDevice(_device);
44 getLogger().info() <<
"Audio manager initialized successfully";
46 _audioThread = std::thread(&AudioManager::threadLoop,
this);
53 if (_audioThread.joinable())
56 alcDestroyContext(_context);
57 alcCloseDevice(_device);
59 getLogger().info() <<
"Audio manager shut down";
64 std::lock_guard<std::mutex> lock(_commandQueueMutex);
65 _commandQueue.push_back(command);
68std::unique_ptr<utility::sound::AudioSource>
70 std::shared_ptr<AudioBuffer> buffer)
72 auto id = _nextSourceID++;
74 auto audioSource = std::make_unique<AudioSource>(
id, *
this);
76 submitCommand({ AudioCommandType::CreateSource, id, {} });
79 std::lock_guard<std::mutex> lock(_sourcesMutex);
83 getLogger().debug() <<
"Created audio source with ID: " << id;
85 audioSource->setBuffer(buffer);
92 std::lock_guard lock(_sourcesMutex);
94 auto it = _sources.find(sourceID);
96 if (it == _sources.end())
99 ALuint alId = it->second;
102 alSourcei(alId, AL_BUFFER, 0);
103 alDeleteSources(1, &alId);
110 getLogger().info() <<
"Stopping audio manager";
119void utility::sound::AudioManager::threadLoop()
121 alcMakeContextCurrent(_context);
125 std::this_thread::sleep_for(std::chrono::milliseconds(1));
130 alcMakeContextCurrent(
nullptr);
133void utility::sound::AudioManager::processCommands()
135 std::deque<AudioCommand> commandsToProcess;
138 std::lock_guard<std::mutex> lock(_commandQueueMutex);
139 commandsToProcess.swap(_commandQueue);
142 while (!commandsToProcess.empty()) {
143 executeCommand(commandsToProcess.front());
144 commandsToProcess.pop_front();
148void utility::sound::AudioManager::executeCommand(
const AudioCommand &command)
152 std::lock_guard<std::mutex> lock(_sourcesMutex);
153 auto it = _sources.find(command.sourceID);
154 if (it == _sources.end()) {
155 getLogger().warning()
156 <<
"Audio command failed: source not found (ID: "
157 << command.sourceID <<
")";
163 switch (command.type) {
164 case AudioCommandType::Play:
167 case AudioCommandType::Stop:
170 case AudioCommandType::Pause:
173 case AudioCommandType::SetPosition:
176 case AudioCommandType::SetGain:
177 alSourcef(alId, AL_GAIN, command.data.gain);
179 case AudioCommandType::SetPitch:
180 alSourcef(alId, AL_PITCH, command.data.pitch);
182 case AudioCommandType::SetLooping:
183 alSourcei(alId, AL_LOOPING,
184 command.data.looping ? AL_TRUE : AL_FALSE);
186 case AudioCommandType::CreateSource: {
188 alGenSources(1, &newSource);
190 std::lock_guard<std::mutex> lock(_sourcesMutex);
191 _sources[command.sourceID] = newSource;
194 case AudioCommandType::SetBuffer:
195 alSourcei(alId, AL_BUFFER, command.data.bufferID);
197 case AudioCommandType::DestroySource:
199 alDeleteSources(1, &alId);
201 std::lock_guard<std::mutex> lock(_sourcesMutex);
202 _sources.erase(command.sourceID);
206 getLogger().warning() <<
"Unknown audio command type";
LoggerType & getLogger(void)
Get the internal logger.
bool isRunning() const
Indicates whether the audio manager is running.
AudioManager()
Creates and initializes the audio subsystem.
void stop()
Requests termination of the audio thread.
~AudioManager()
Stops the audio thread and releases OpenAL resources.
void submitCommand(const AudioCommand &command)
Submits an audio command for asynchronous execution.
std::unique_ptr< AudioSource > createAudioSource(std::shared_ptr< AudioBuffer > buffer)
Creates a new audio source.
void destroyAudioSource(uint32_t sourceID)
Destroys an existing audio source.
Represents a command submitted to the audio thread.