TTW_Bot/soundmanager.cpp

275 lines
7.9 KiB
C++

#include "soundmanager.h"
#include <QDebug>
#include <QFileInfo>
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<SoundChannel>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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;
}