#include "soundmanager.h" #include #include SoundManager::SoundManager(QObject *parent) : QObject(parent) { // Инициализация COM CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // Инициализация каналов for (int i = 0; i < 2; i++) { m_channels[i].graphBuilder = NULL; m_channels[i].mediaControl = NULL; m_channels[i].mediaPosition = NULL; m_channels[i].basicAudio = NULL; m_channels[i].audioRenderer = NULL; m_channels[i].sessionManager = NULL; m_channels[i].sessionControl = NULL; m_channels[i].isLoaded = false; } } SoundManager::~SoundManager() { // Очистка ресурсов for (int i = 0; i < 2; i++) { cleanupChannel(static_cast(i)); } CoUninitialize(); } IBaseFilter* SoundManager::createAudioRenderer() { IBaseFilter* renderer = NULL; // Создаем отдельный аудио рендерер для каждого канала HRESULT hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&renderer); if (FAILED(hr)) { return NULL; } return renderer; } bool SoundManager::initializeChannel(SoundChannel channel) { int idx = static_cast(channel); // Создаем GraphBuilder HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&m_channels[idx].graphBuilder); if (FAILED(hr)) { return false; } // Создаем отдельный аудио рендерер для этого канала m_channels[idx].audioRenderer = createAudioRenderer(); if (!m_channels[idx].audioRenderer) { cleanupChannel(channel); return false; } // Добавляем рендерер в граф WCHAR filterName[64]; swprintf_s(filterName, 64, L"Audio Renderer Channel %d", idx + 1); hr = m_channels[idx].graphBuilder->AddFilter(m_channels[idx].audioRenderer, filterName); if (FAILED(hr)) { cleanupChannel(channel); return false; } // Пытаемся получить интерфейс аудио сессии для отдельного управления IAudioSessionManager2* pSessionManager = NULL; hr = m_channels[idx].audioRenderer->QueryInterface(__uuidof(IAudioSessionManager2), (void**)&m_channels[idx].sessionManager); if (SUCCEEDED(hr)) { // Получаем контроль над сессией hr = m_channels[idx].sessionManager->GetAudioSessionControl(NULL, 0, &m_channels[idx].sessionControl); if (SUCCEEDED(hr)) { // Устанавливаем уникальное отображаемое имя для сессии WCHAR sessionName[64]; swprintf_s(sessionName, 64, L"Channel %d", idx + 1); m_channels[idx].sessionControl->SetDisplayName(sessionName, NULL); } } // Получаем интерфейсы управления hr = m_channels[idx].graphBuilder->QueryInterface(IID_IMediaControl, (void**)&m_channels[idx].mediaControl); if (FAILED(hr)) { cleanupChannel(channel); return false; } hr = m_channels[idx].graphBuilder->QueryInterface(IID_IMediaPosition, (void**)&m_channels[idx].mediaPosition); if (FAILED(hr)) { cleanupChannel(channel); return false; } hr = m_channels[idx].graphBuilder->QueryInterface(IID_IBasicAudio, (void**)&m_channels[idx].basicAudio); if (FAILED(hr)) { cleanupChannel(channel); return false; } return true; } void SoundManager::cleanupChannel(SoundChannel channel) { int idx = static_cast(channel); if (m_channels[idx].mediaControl) { m_channels[idx].mediaControl->Stop(); m_channels[idx].mediaControl->Release(); m_channels[idx].mediaControl = NULL; } if (m_channels[idx].mediaPosition) { m_channels[idx].mediaPosition->Release(); m_channels[idx].mediaPosition = NULL; } if (m_channels[idx].basicAudio) { m_channels[idx].basicAudio->Release(); m_channels[idx].basicAudio = NULL; } if (m_channels[idx].sessionControl) { m_channels[idx].sessionControl->Release(); m_channels[idx].sessionControl = NULL; } if (m_channels[idx].sessionManager) { m_channels[idx].sessionManager->Release(); m_channels[idx].sessionManager = NULL; } if (m_channels[idx].audioRenderer) { m_channels[idx].audioRenderer->Release(); m_channels[idx].audioRenderer = NULL; } if (m_channels[idx].graphBuilder) { m_channels[idx].graphBuilder->Release(); m_channels[idx].graphBuilder = NULL; } m_channels[idx].isLoaded = false; } bool SoundManager::loadSound(SoundChannel channel, const QString &filePath) { int idx = static_cast(channel); // Проверяем существование файла if (!QFileInfo(filePath).exists()) { return false; } // Очищаем предыдущий звук на канале cleanupChannel(channel); // Инициализируем канал if (!initializeChannel(channel)) { return false; } // Конвертируем QString в WCHAR std::wstring wideFilePath = filePath.toStdWString(); // Рендерим файл HRESULT hr = m_channels[idx].graphBuilder->RenderFile(wideFilePath.c_str(), NULL); if (FAILED(hr)) { cleanupChannel(channel); return false; } m_channels[idx].isLoaded = true; return true; } bool SoundManager::playSound(SoundChannel channel) { int idx = static_cast(channel); if (!m_channels[idx].isLoaded || !m_channels[idx].mediaControl) { return false; } HRESULT hr = m_channels[idx].mediaControl->Run(); if (FAILED(hr)) { return false; } return true; } bool SoundManager::pauseSound(SoundChannel channel) { int idx = static_cast(channel); if (!m_channels[idx].isLoaded || !m_channels[idx].mediaControl) { return false; } HRESULT hr = m_channels[idx].mediaControl->Pause(); return SUCCEEDED(hr); } bool SoundManager::stopSound(SoundChannel channel) { int idx = static_cast(channel); if (!m_channels[idx].isLoaded || !m_channels[idx].mediaControl) { return false; } HRESULT hr = m_channels[idx].mediaControl->Stop(); // Сбрасываем позицию воспроизведения if (m_channels[idx].mediaPosition) { m_channels[idx].mediaPosition->put_CurrentPosition(0); } return SUCCEEDED(hr); } void SoundManager::setVolume(SoundChannel channel, int volume) { int idx = static_cast(channel); if (!m_channels[idx].isLoaded || !m_channels[idx].basicAudio) { return; } // Конвертируем 0-100 в диапазон DirectShow (-10000 до 0) long directShowVolume = (volume - 100) * 100; // 0 = -10000, 100 = 0 m_channels[idx].basicAudio->put_Volume(directShowVolume); } bool SoundManager::isPlaying(SoundChannel channel) { int idx = static_cast(channel); if (!m_channels[idx].isLoaded || !m_channels[idx].mediaControl) { return false; } OAFilterState state; HRESULT hr = m_channels[idx].mediaControl->GetState(10, &state); if (SUCCEEDED(hr)) { return (state == State_Running); } return false; }