mirror of https://github.com/AxioDL/boo.git
WASAPI VoiceEngine implementation
This commit is contained in:
parent
1eb46301c0
commit
290d40641d
|
@ -28,12 +28,6 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, float* dataOut)
|
||||||
vox->pumpAndMix(m_mixInfo, frames, dataOut);
|
vox->pumpAndMix(m_mixInfo, frames, dataOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseAudioVoiceEngine::BaseAudioVoiceEngine
|
|
||||||
(const std::function<AudioVoiceEngineMixInfo()>& getEngineMixInfo)
|
|
||||||
{
|
|
||||||
m_mixInfo = getEngineMixInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<IAudioVoice>
|
std::unique_ptr<IAudioVoice>
|
||||||
BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate,
|
BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate,
|
||||||
IAudioVoiceCallback* cb,
|
IAudioVoiceCallback* cb,
|
||||||
|
|
|
@ -31,8 +31,6 @@ protected:
|
||||||
void _pumpAndMixVoices(size_t frames, float* dataOut);
|
void _pumpAndMixVoices(size_t frames, float* dataOut);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseAudioVoiceEngine(const std::function<AudioVoiceEngineMixInfo()>& getEngineMixInfo);
|
|
||||||
|
|
||||||
std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
|
std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
|
||||||
IAudioVoiceCallback* cb,
|
IAudioVoiceCallback* cb,
|
||||||
bool dynamicPitch=false);
|
bool dynamicPitch=false);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "../win/Win32Common.hpp"
|
#include "../win/Win32Common.hpp"
|
||||||
#include "boo/audiodev/IAudioVoiceAllocator.hpp"
|
#include "AudioVoiceEngine.hpp"
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
|
|
||||||
#include <Mmdeviceapi.h>
|
#include <Mmdeviceapi.h>
|
||||||
|
@ -14,177 +14,16 @@ namespace boo
|
||||||
{
|
{
|
||||||
static logvisor::Module Log("boo::WASAPI");
|
static logvisor::Module Log("boo::WASAPI");
|
||||||
|
|
||||||
struct WASAPIAudioVoice : IAudioVoice
|
struct WASAPIAudioVoiceEngine : BaseAudioVoiceEngine
|
||||||
{
|
|
||||||
struct WASAPIAudioVoiceAllocator& m_parent;
|
|
||||||
std::list<WASAPIAudioVoice*>::iterator m_parentIt;
|
|
||||||
|
|
||||||
ChannelMap m_map;
|
|
||||||
IAudioVoiceCallback* m_cb;
|
|
||||||
ComPtr<IAudioClient> m_audClient;
|
|
||||||
ComPtr<IAudioRenderClient> m_renderClient;
|
|
||||||
UINT32 m_bufferFrames = 1024;
|
|
||||||
size_t m_frameSize;
|
|
||||||
|
|
||||||
const ChannelMap& channelMap() const {return m_map;}
|
|
||||||
|
|
||||||
WASAPIAudioVoice(WASAPIAudioVoiceAllocator& parent, IMMDevice* dev, AudioChannelSet set,
|
|
||||||
unsigned sampleRate, IAudioVoiceCallback* cb)
|
|
||||||
: m_parent(parent), m_cb(cb)
|
|
||||||
{
|
|
||||||
unsigned chCount = ChannelCount(set);
|
|
||||||
|
|
||||||
WAVEFORMATEX desc = {};
|
|
||||||
desc.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
desc.nChannels = chCount;
|
|
||||||
desc.nSamplesPerSec = sampleRate;
|
|
||||||
desc.wBitsPerSample = 16;
|
|
||||||
desc.nBlockAlign = desc.nChannels * desc.wBitsPerSample / 8;
|
|
||||||
desc.nAvgBytesPerSec = desc.nSamplesPerSec * desc.nBlockAlign;
|
|
||||||
|
|
||||||
if (FAILED(dev->Activate(IID_IAudioClient, CLSCTX_ALL,
|
|
||||||
nullptr, &m_audClient)))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, "unable to create audio client");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WAVEFORMATEX* works;
|
|
||||||
m_audClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &desc, &works);
|
|
||||||
|
|
||||||
HRESULT hr = m_audClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0,
|
|
||||||
1000000, 0, &desc, nullptr);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, "unable to initialize audio client");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(m_audClient->GetBufferSize(&m_bufferFrames)))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, "unable to obtain audio buffer size");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(m_audClient->GetService(IID_IAudioRenderClient, &m_renderClient)))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, "unable to create audio render client");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (chCount)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
m_map.m_channelCount = 2;
|
|
||||||
m_map.m_channels[0] = AudioChannel::FrontLeft;
|
|
||||||
m_map.m_channels[1] = AudioChannel::FrontRight;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
m_map.m_channelCount = 4;
|
|
||||||
m_map.m_channels[0] = AudioChannel::FrontLeft;
|
|
||||||
m_map.m_channels[1] = AudioChannel::FrontRight;
|
|
||||||
m_map.m_channels[2] = AudioChannel::RearLeft;
|
|
||||||
m_map.m_channels[3] = AudioChannel::RearRight;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
m_map.m_channelCount = 5;
|
|
||||||
m_map.m_channels[0] = AudioChannel::FrontLeft;
|
|
||||||
m_map.m_channels[1] = AudioChannel::FrontRight;
|
|
||||||
m_map.m_channels[2] = AudioChannel::FrontCenter;
|
|
||||||
m_map.m_channels[3] = AudioChannel::RearLeft;
|
|
||||||
m_map.m_channels[4] = AudioChannel::RearRight;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
m_map.m_channelCount = 6;
|
|
||||||
m_map.m_channels[0] = AudioChannel::FrontLeft;
|
|
||||||
m_map.m_channels[1] = AudioChannel::FrontRight;
|
|
||||||
m_map.m_channels[2] = AudioChannel::FrontCenter;
|
|
||||||
m_map.m_channels[3] = AudioChannel::LFE;
|
|
||||||
m_map.m_channels[4] = AudioChannel::RearLeft;
|
|
||||||
m_map.m_channels[5] = AudioChannel::RearRight;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
m_map.m_channelCount = 8;
|
|
||||||
m_map.m_channels[0] = AudioChannel::FrontLeft;
|
|
||||||
m_map.m_channels[1] = AudioChannel::FrontRight;
|
|
||||||
m_map.m_channels[2] = AudioChannel::FrontCenter;
|
|
||||||
m_map.m_channels[3] = AudioChannel::LFE;
|
|
||||||
m_map.m_channels[4] = AudioChannel::RearLeft;
|
|
||||||
m_map.m_channels[5] = AudioChannel::RearRight;
|
|
||||||
m_map.m_channels[6] = AudioChannel::SideLeft;
|
|
||||||
m_map.m_channels[7] = AudioChannel::SideRight;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.report(logvisor::Error, "unknown channel layout %u; using stereo", chCount);
|
|
||||||
m_map.m_channelCount = 2;
|
|
||||||
m_map.m_channels[0] = AudioChannel::FrontLeft;
|
|
||||||
m_map.m_channels[1] = AudioChannel::FrontRight;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (m_map.m_channelCount < chCount)
|
|
||||||
m_map.m_channels[m_map.m_channelCount++] = AudioChannel::Unknown;
|
|
||||||
|
|
||||||
m_frameSize = chCount * 2;
|
|
||||||
|
|
||||||
for (unsigned i=0 ; i<3 ; ++i)
|
|
||||||
m_cb->needsNextBuffer(*this, m_bufferFrames);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bufferSampleData(const int16_t* data, size_t frames)
|
|
||||||
{
|
|
||||||
BYTE* dataOut;
|
|
||||||
if (FAILED(m_renderClient->GetBuffer(frames, &dataOut)))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, L"unable to obtain audio buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(dataOut, data, frames * m_frameSize);
|
|
||||||
|
|
||||||
if (FAILED(m_renderClient->ReleaseBuffer(frames, 0)))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, L"unable to release audio buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void start()
|
|
||||||
{
|
|
||||||
m_audClient->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop()
|
|
||||||
{
|
|
||||||
m_audClient->Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pump()
|
|
||||||
{
|
|
||||||
UINT32 padding;
|
|
||||||
if (FAILED(m_audClient->GetCurrentPadding(&padding)))
|
|
||||||
{
|
|
||||||
Log.report(logvisor::Fatal, L"unable to obtain audio buffer padding");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
INT32 available = m_bufferFrames - padding;
|
|
||||||
m_cb->needsNextBuffer(*this, available);
|
|
||||||
}
|
|
||||||
|
|
||||||
~WASAPIAudioVoice();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WASAPIAudioVoiceAllocator : IAudioVoiceAllocator
|
|
||||||
{
|
{
|
||||||
ComPtr<IMMDevice> m_device;
|
ComPtr<IMMDevice> m_device;
|
||||||
AudioChannelSet m_maxSet = AudioChannelSet::Unknown;
|
ComPtr<IAudioClient> m_audClient;
|
||||||
std::list<WASAPIAudioVoice*> m_allocatedVoices;
|
ComPtr<IAudioRenderClient> m_renderClient;
|
||||||
|
|
||||||
WASAPIAudioVoiceAllocator()
|
WASAPIAudioVoiceEngine()
|
||||||
{
|
{
|
||||||
|
/* Enumerate default audio device */
|
||||||
ComPtr<IMMDeviceEnumerator> pEnumerator;
|
ComPtr<IMMDeviceEnumerator> pEnumerator;
|
||||||
|
|
||||||
if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr,
|
if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr,
|
||||||
CLSCTX_ALL, IID_IMMDeviceEnumerator,
|
CLSCTX_ALL, IID_IMMDeviceEnumerator,
|
||||||
&pEnumerator)))
|
&pEnumerator)))
|
||||||
|
@ -196,79 +35,229 @@ struct WASAPIAudioVoiceAllocator : IAudioVoiceAllocator
|
||||||
if (FAILED(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device)))
|
if (FAILED(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device)))
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Fatal, L"unable to obtain default audio device");
|
Log.report(logvisor::Fatal, L"unable to obtain default audio device");
|
||||||
|
m_device.Reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<IAudioClient> pAudioClient;
|
if (FAILED(m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, &m_audClient)))
|
||||||
if (FAILED(m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, &pAudioClient)))
|
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Fatal, L"unable to create audio client from device");
|
Log.report(logvisor::Fatal, L"unable to create audio client from device");
|
||||||
|
m_device.Reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WAVEFORMATEXTENSIBLE* pwfx;
|
WAVEFORMATEXTENSIBLE* pwfx;
|
||||||
if (FAILED(pAudioClient->GetMixFormat((WAVEFORMATEX**)&pwfx)))
|
if (FAILED(m_audClient->GetMixFormat((WAVEFORMATEX**)&pwfx)))
|
||||||
{
|
{
|
||||||
Log.report(logvisor::Fatal, L"unable to obtain audio mix format from device");
|
Log.report(logvisor::Fatal, L"unable to obtain audio mix format from device");
|
||||||
|
m_device.Reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get channel information */
|
||||||
if ((pwfx->dwChannelMask & (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT))
|
if ((pwfx->dwChannelMask & (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT))
|
||||||
{
|
{
|
||||||
m_maxSet = AudioChannelSet::Stereo;
|
m_mixInfo.m_channels = AudioChannelSet::Stereo;
|
||||||
if ((pwfx->dwChannelMask & (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)) == (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT))
|
if ((pwfx->dwChannelMask & (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)) == (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT))
|
||||||
{
|
{
|
||||||
m_maxSet = AudioChannelSet::Quad;
|
m_mixInfo.m_channels = AudioChannelSet::Quad;
|
||||||
if ((pwfx->dwChannelMask & (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY)) == (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY))
|
if ((pwfx->dwChannelMask & (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY)) == (SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY))
|
||||||
{
|
{
|
||||||
m_maxSet = AudioChannelSet::Surround51;
|
m_mixInfo.m_channels = AudioChannelSet::Surround51;
|
||||||
if ((pwfx->dwChannelMask & (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)) == (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT))
|
if ((pwfx->dwChannelMask & (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)) == (SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT))
|
||||||
{
|
{
|
||||||
m_maxSet = AudioChannelSet::Surround71;
|
m_mixInfo.m_channels = AudioChannelSet::Surround71;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChannelMap& chMapOut = m_mixInfo.m_channelMap;
|
||||||
|
switch (pwfx->Format.nChannels)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
chMapOut.m_channelCount = 2;
|
||||||
|
chMapOut.m_channels[0] = AudioChannel::FrontLeft;
|
||||||
|
chMapOut.m_channels[1] = AudioChannel::FrontRight;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
chMapOut.m_channelCount = 4;
|
||||||
|
chMapOut.m_channels[0] = AudioChannel::FrontLeft;
|
||||||
|
chMapOut.m_channels[1] = AudioChannel::FrontRight;
|
||||||
|
chMapOut.m_channels[2] = AudioChannel::RearLeft;
|
||||||
|
chMapOut.m_channels[3] = AudioChannel::RearRight;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
chMapOut.m_channelCount = 5;
|
||||||
|
chMapOut.m_channels[0] = AudioChannel::FrontLeft;
|
||||||
|
chMapOut.m_channels[1] = AudioChannel::FrontRight;
|
||||||
|
chMapOut.m_channels[2] = AudioChannel::FrontCenter;
|
||||||
|
chMapOut.m_channels[3] = AudioChannel::RearLeft;
|
||||||
|
chMapOut.m_channels[4] = AudioChannel::RearRight;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
chMapOut.m_channelCount = 6;
|
||||||
|
chMapOut.m_channels[0] = AudioChannel::FrontLeft;
|
||||||
|
chMapOut.m_channels[1] = AudioChannel::FrontRight;
|
||||||
|
chMapOut.m_channels[2] = AudioChannel::FrontCenter;
|
||||||
|
chMapOut.m_channels[3] = AudioChannel::LFE;
|
||||||
|
chMapOut.m_channels[4] = AudioChannel::RearLeft;
|
||||||
|
chMapOut.m_channels[5] = AudioChannel::RearRight;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
chMapOut.m_channelCount = 8;
|
||||||
|
chMapOut.m_channels[0] = AudioChannel::FrontLeft;
|
||||||
|
chMapOut.m_channels[1] = AudioChannel::FrontRight;
|
||||||
|
chMapOut.m_channels[2] = AudioChannel::FrontCenter;
|
||||||
|
chMapOut.m_channels[3] = AudioChannel::LFE;
|
||||||
|
chMapOut.m_channels[4] = AudioChannel::RearLeft;
|
||||||
|
chMapOut.m_channels[5] = AudioChannel::RearRight;
|
||||||
|
chMapOut.m_channels[6] = AudioChannel::SideLeft;
|
||||||
|
chMapOut.m_channels[7] = AudioChannel::SideRight;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.report(logvisor::Warning, "unknown channel layout %u; using stereo", pwfx->Format.nChannels);
|
||||||
|
chMapOut.m_channelCount = 2;
|
||||||
|
chMapOut.m_channels[0] = AudioChannel::FrontLeft;
|
||||||
|
chMapOut.m_channels[1] = AudioChannel::FrontRight;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize audio client */
|
||||||
|
if (FAILED(m_audClient->Initialize(
|
||||||
|
AUDCLNT_SHAREMODE_SHARED,
|
||||||
|
0,
|
||||||
|
1000000,
|
||||||
|
0,
|
||||||
|
(WAVEFORMATEX*)pwfx,
|
||||||
|
nullptr)))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unable to initialize audio client");
|
||||||
|
m_device.Reset();
|
||||||
|
CoTaskMemFree(pwfx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mixInfo.m_sampleRate = pwfx->Format.nSamplesPerSec;
|
||||||
|
|
||||||
|
if (pwfx->Format.wFormatTag == WAVE_FORMAT_PCM ||
|
||||||
|
(pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_PCM))
|
||||||
|
{
|
||||||
|
if (pwfx->Format.wBitsPerSample == 16)
|
||||||
|
{
|
||||||
|
m_mixInfo.m_sampleFormat = SOXR_INT16_I;
|
||||||
|
m_mixInfo.m_bitsPerSample = 16;
|
||||||
|
}
|
||||||
|
else if (pwfx->Format.wBitsPerSample == 32)
|
||||||
|
{
|
||||||
|
m_mixInfo.m_sampleFormat = SOXR_INT32_I;
|
||||||
|
m_mixInfo.m_bitsPerSample = 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unsupported bits-per-sample %d", pwfx->Format.wBitsPerSample);
|
||||||
|
m_device.Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pwfx->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
|
||||||
|
(pwfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pwfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
|
||||||
|
{
|
||||||
|
if (pwfx->Format.wBitsPerSample == 32)
|
||||||
|
{
|
||||||
|
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
|
||||||
|
m_mixInfo.m_bitsPerSample = 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unsupported floating-point bits-per-sample %d", pwfx->Format.wBitsPerSample);
|
||||||
|
m_device.Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CoTaskMemFree(pwfx);
|
CoTaskMemFree(pwfx);
|
||||||
|
|
||||||
|
UINT32 bufferFrameCount;
|
||||||
|
if (FAILED(m_audClient->GetBufferSize(&bufferFrameCount)))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unable to get audio buffer frame count");
|
||||||
|
m_device.Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_mixInfo.m_periodFrames = bufferFrameCount;
|
||||||
|
|
||||||
|
if (FAILED(m_audClient->GetService(IID_IAudioRenderClient, &m_renderClient)))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unable to create audio render client");
|
||||||
|
m_device.Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~WASAPIAudioVoiceAllocator()
|
bool m_started = false;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioChannelSet getAvailableSet()
|
void pumpAndMixVoices()
|
||||||
{
|
{
|
||||||
return m_maxSet;
|
UINT32 numFramesPadding;
|
||||||
}
|
if (FAILED(m_audClient->GetCurrentPadding(&numFramesPadding)))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unable to get available buffer frames");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<IAudioVoice> allocateNewVoice(AudioChannelSet layoutOut,
|
size_t frames = m_mixInfo.m_periodFrames - numFramesPadding;
|
||||||
unsigned sampleRate,
|
if (frames <= 0)
|
||||||
IAudioVoiceCallback* cb)
|
return;
|
||||||
{
|
|
||||||
WASAPIAudioVoice* newVoice = new WASAPIAudioVoice(*this, m_device.Get(), layoutOut, sampleRate, cb);
|
|
||||||
newVoice->m_parentIt = m_allocatedVoices.insert(m_allocatedVoices.end(), newVoice);
|
|
||||||
std::unique_ptr<IAudioVoice> ret(newVoice);
|
|
||||||
if (!newVoice->m_audClient)
|
|
||||||
return {};
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pumpVoices()
|
BYTE* bufOut;
|
||||||
{
|
if (FAILED(m_renderClient->GetBuffer(frames, &bufOut)))
|
||||||
for (WASAPIAudioVoice* vox : m_allocatedVoices)
|
{
|
||||||
vox->pump();
|
Log.report(logvisor::Fatal, L"unable to map audio buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD flags = 0;
|
||||||
|
switch (m_mixInfo.m_sampleFormat)
|
||||||
|
{
|
||||||
|
case SOXR_INT16_I:
|
||||||
|
_pumpAndMixVoices(frames, reinterpret_cast<int16_t*>(bufOut));
|
||||||
|
break;
|
||||||
|
case SOXR_INT32_I:
|
||||||
|
_pumpAndMixVoices(frames, reinterpret_cast<int32_t*>(bufOut));
|
||||||
|
break;
|
||||||
|
case SOXR_FLOAT32_I:
|
||||||
|
_pumpAndMixVoices(frames, reinterpret_cast<float*>(bufOut));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flags = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(m_renderClient->ReleaseBuffer(frames, flags)))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unable to unmap audio buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_started)
|
||||||
|
{
|
||||||
|
if (FAILED(m_audClient->Start()))
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Fatal, L"unable to start audio client");
|
||||||
|
m_device.Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_started = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
WASAPIAudioVoice::~WASAPIAudioVoice()
|
std::unique_ptr<IAudioVoiceEngine> NewAudioVoiceEngine()
|
||||||
{
|
{
|
||||||
m_parent.m_allocatedVoices.erase(m_parentIt);
|
std::unique_ptr<IAudioVoiceEngine> ret = std::make_unique<WASAPIAudioVoiceEngine>();
|
||||||
}
|
if (!static_cast<WASAPIAudioVoiceEngine&>(*ret).m_device)
|
||||||
|
return {};
|
||||||
std::unique_ptr<IAudioVoiceAllocator> NewAudioVoiceAllocator()
|
return ret;
|
||||||
{
|
|
||||||
return std::make_unique<WASAPIAudioVoiceAllocator>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue