#include "AudioPlayerAsync.h" #include #ifdef __EMSCRIPTEN__ AudioPlayerAsync::AudioPlayerAsync() {} #else AudioPlayerAsync::AudioPlayerAsync() : worker(&AudioPlayerAsync::workerThread, this) {} #endif AudioPlayerAsync::~AudioPlayerAsync() { #ifndef __EMSCRIPTEN__ { std::unique_lock lock(mtx); stop = true; cv.notify_all(); } if (worker.joinable()) worker.join(); #endif shutdown(); } bool AudioPlayerAsync::init() { if (initialized) return true; if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { std::cerr << "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: " << SDL_GetError() << std::endl; return false; } if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { std::cerr << "Mix_OpenAudio failed: " << Mix_GetError() << std::endl; return false; } Mix_AllocateChannels(16); initialized = true; std::cout << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl; return true; } void AudioPlayerAsync::shutdown() { if (!initialized) return; { std::lock_guard lock(soundCacheMutex); for (auto& pair : soundCache) { Mix_FreeChunk(pair.second); } soundCache.clear(); } Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); initialized = false; std::cout << "AudioPlayerAsync shutdown" << std::endl; } void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, int channel) { if (!initialized) { std::cerr << "AudioPlayerAsync not initialized" << std::endl; return; } auto task = [this, filePath, loops, channel]() { Mix_Chunk* sound = nullptr; { std::lock_guard cacheLock(soundCacheMutex); auto it = soundCache.find(filePath); if (it != soundCache.end()) { sound = it->second; } } if (!sound) { sound = Mix_LoadWAV(filePath.c_str()); if (!sound) { std::cerr << "Failed to load sound " << filePath << ": " << Mix_GetError() << std::endl; return; } std::lock_guard cacheLock(soundCacheMutex); soundCache[filePath] = sound; } int result = Mix_PlayChannel(channel, sound, loops); if (result == -1) { std::cerr << "Mix_PlayChannel failed: " << Mix_GetError() << std::endl; } }; #ifdef __EMSCRIPTEN__ task(); #else std::unique_lock lock(mtx); taskQueue.push(std::move(task)); cv.notify_one(); #endif } void AudioPlayerAsync::playMusicAsync(const std::string& filePath, int loops) { if (!initialized) return; auto task = [filePath, loops]() { Mix_Music* music = Mix_LoadMUS(filePath.c_str()); if (!music) { std::cerr << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl; return; } if (Mix_PlayMusic(music, loops) == -1) { std::cerr << "Mix_PlayMusic failed: " << Mix_GetError() << std::endl; Mix_FreeMusic(music); } }; #ifdef __EMSCRIPTEN__ task(); #else std::unique_lock lock(mtx); taskQueue.push(std::move(task)); cv.notify_one(); #endif } void AudioPlayerAsync::stopMusicAsync() { if (!initialized) return; #ifdef __EMSCRIPTEN__ Mix_HaltMusic(); #else std::unique_lock lock(mtx); taskQueue.push([]() { Mix_HaltMusic(); }); cv.notify_one(); #endif } void AudioPlayerAsync::pauseMusicAsync() { if (!initialized) return; #ifdef __EMSCRIPTEN__ Mix_PauseMusic(); #else std::unique_lock lock(mtx); taskQueue.push([]() { Mix_PauseMusic(); }); cv.notify_one(); #endif } void AudioPlayerAsync::resumeMusicAsync() { if (!initialized) return; #ifdef __EMSCRIPTEN__ Mix_ResumeMusic(); #else std::unique_lock lock(mtx); taskQueue.push([]() { Mix_ResumeMusic(); }); cv.notify_one(); #endif } void AudioPlayerAsync::setMusicVolume(int volume) { if (!initialized) return; volume = std::max(0, std::min(128, volume)); #ifdef __EMSCRIPTEN__ Mix_VolumeMusic(volume); #else std::unique_lock lock(mtx); taskQueue.push([volume]() { Mix_VolumeMusic(volume); }); cv.notify_one(); #endif } void AudioPlayerAsync::setSoundVolume(int volume) { if (!initialized) return; volume = std::max(0, std::min(128, volume)); #ifdef __EMSCRIPTEN__ Mix_Volume(-1, volume); #else std::unique_lock lock(mtx); taskQueue.push([volume]() { Mix_Volume(-1, volume); // все каналы }); cv.notify_one(); #endif } #ifndef __EMSCRIPTEN__ void AudioPlayerAsync::workerThread() { while (true) { std::function task; { std::unique_lock lock(mtx); cv.wait(lock, [this] { return !taskQueue.empty() || stop; }); if (stop && taskQueue.empty()) break; task = std::move(taskQueue.front()); taskQueue.pop(); } task(); } } #endif