#include "GpAudioChannelXAudio2.h" #include "GpAudioDriverXAudio2.h" #include "IGpAudioChannelCallbacks.h" #include "IGpLogDriver.h" #include #include GpAudioChannelXAudio2 *GpAudioChannelXAudio2::Create(GpAudioDriverXAudio2 *driver) { IGpLogDriver *logger = driver->GetProperties().m_logger; void *storage = malloc(sizeof(GpAudioChannelXAudio2)); if (!storage) { if (!logger) logger->Printf(IGpLogDriver::Category_Error, "GpAudioChannelXAudio2::Create failed, malloc failed"); return nullptr; } GpAudioChannelXAudio2 *channel = new (storage) GpAudioChannelXAudio2(driver); if (!channel->Init()) { if (!logger) logger->Printf(IGpLogDriver::Category_Error, "GpAudioChannelXAudio2::Init failed"); channel->Destroy(); return nullptr; } return channel; } bool GpAudioChannelXAudio2::Init() { IGpLogDriver *logger = m_driver->GetProperties().m_logger; const unsigned int sampleRate = m_driver->GetRealSampleRate(); IXAudio2 *const xa2 = m_driver->GetXA2(); WAVEFORMATEX format; ZeroMemory(&format, sizeof(format)); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 1; format.nSamplesPerSec = sampleRate; format.wBitsPerSample = 8; format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.nAvgBytesPerSec = format.nBlockAlign * format.nSamplesPerSec; XAUDIO2_SEND_DESCRIPTOR sendsList[1]; sendsList[0].Flags = 0; sendsList[0].pOutputVoice = m_driver->GetMasteringVoice(); XAUDIO2_VOICE_SENDS sends; sends.pSends = sendsList; sends.SendCount = sizeof(sendsList) / sizeof(sendsList[0]); XAUDIO2_VOICE_DETAILS dets; m_driver->GetMasteringVoice()->GetVoiceDetails(&dets); HRESULT hr = xa2->CreateSourceVoice(&m_sourceVoice, &format, XAUDIO2_VOICE_NOPITCH | XAUDIO2_VOICE_NOSRC, 1.0f, &m_xAudioCallbacks, nullptr, nullptr); if (hr != S_OK) { if (!logger) logger->Printf(IGpLogDriver::Category_Error, "CreateSourceVoice failed with code %lx", hr); return false; } return true; } void GpAudioChannelXAudio2::SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) { m_contextCallbacks = callbacks; } void GpAudioChannelXAudio2::PostBuffer(const void *buffer, size_t bufferSize) { XAUDIO2_BUFFER xa2Buffer; xa2Buffer.Flags = 0; xa2Buffer.AudioBytes = static_cast(bufferSize); xa2Buffer.pAudioData = static_cast(buffer); xa2Buffer.PlayBegin = 0; xa2Buffer.PlayLength = 0; xa2Buffer.LoopBegin = 0; xa2Buffer.LoopLength = 0; xa2Buffer.LoopCount = 0; xa2Buffer.pContext = nullptr; m_sourceVoice->SubmitSourceBuffer(&xa2Buffer, nullptr); if (m_voiceState == VoiceState_Idle) { m_voiceState = VoiceState_Active; m_sourceVoice->Start(0, 0); } } void GpAudioChannelXAudio2::Stop() { // Set voice state BEFORE calling FlushSourceBuffers so state is idle before any callbacks trigger m_sourceVoice->Stop(0, 0); m_voiceState = VoiceState_Idle; m_sourceVoice->FlushSourceBuffers(); } void GpAudioChannelXAudio2::Destroy() { this->~GpAudioChannelXAudio2(); free(this); } void GpAudioChannelXAudio2::OnBufferEnd() { if (m_contextCallbacks) m_contextCallbacks->NotifyBufferFinished(); } GpAudioChannelXAudio2::GpAudioChannelXAudio2(GpAudioDriverXAudio2 *driver) : m_driver(driver) , m_xAudioCallbacks(this) , m_sourceVoice(nullptr) , m_contextCallbacks(nullptr) , m_voiceState(VoiceState_Idle) { } GpAudioChannelXAudio2::~GpAudioChannelXAudio2() { if (m_sourceVoice) m_sourceVoice->DestroyVoice(); }