fixed win core audio driver

This commit is contained in:
Igor Korsukov 2021-02-24 15:28:23 +03:00 committed by pereverzev+v
parent ccf7d0cb5d
commit 132b381872
4 changed files with 79 additions and 55 deletions

View file

@ -22,10 +22,10 @@ set(MODULE audio)
include(GetPlatformInfo)
if (OS_IS_WIN)
set(DRIVER_SRC
${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.h
#${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/wincoreaudiodriver.cpp
#${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/wincoreaudiodriver.h
#${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.cpp
#${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/winmmdriver.h
${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/wincoreaudiodriver.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/platform/win/wincoreaudiodriver.h
)
elseif(OS_IS_LIN)
set(DRIVER_SRC

View file

@ -62,10 +62,10 @@ static std::shared_ptr<IAudioDriver> s_audioDriver = std::shared_ptr<IAudioDrive
#endif
#ifdef Q_OS_WIN
#include "internal/platform/win/winmmdriver.h"
static std::shared_ptr<IAudioDriver> s_audioDriver = std::shared_ptr<IAudioDriver>(new WinmmDriver());
//#include "internal/platform/win/wincoreaudiodriver.h"
//static std::shared_ptr<IAudioDriver> s_audioDriver = std::shared_ptr<IAudioDriver>(new CoreAudioDriver());
//#include "internal/platform/win/winmmdriver.h"
//static std::shared_ptr<IAudioDriver> s_audioDriver = std::shared_ptr<IAudioDriver>(new WinmmDriver());
#include "internal/platform/win/wincoreaudiodriver.h"
static std::shared_ptr<IAudioDriver> s_audioDriver = std::shared_ptr<IAudioDriver>(new CoreAudioDriver());
#endif
#ifdef Q_OS_MACOS

View file

@ -20,6 +20,8 @@
#include <system_error>
#include "mmdeviceapi.h"
#include "windows.h"
#include "audioclient.h"
#include "log.h"
#define CHECK_HRESULT(hr); if (hr != S_OK) { \
@ -29,6 +31,18 @@
using namespace mu::audio;
struct WinCoreData {
IAudioClient* audioClient = nullptr;
IAudioRenderClient* renderClient = nullptr;
IAudioDriver::Callback callback;
WAVEFORMATEX pFormat;
HANDLE hEvent;
};
static void logError(HRESULT hr);
static WinCoreData* s_data = nullptr;
CoreAudioDriver::CoreAudioDriver()
{
}
@ -45,13 +59,19 @@ std::string CoreAudioDriver::name() const
bool CoreAudioDriver::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec)
{
if (s_data) {
delete s_data;
}
s_data = new WinCoreData();
HRESULT hr = S_OK;
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
const IID MU_IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID MU_IID_IAudioClient = __uuidof(IAudioClient);
const IID MU_IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
IMMDeviceEnumerator* pEnumerator = nullptr;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,CLSCTX_ALL, MU_IID_IMMDeviceEnumerator, (void**)&pEnumerator);
CHECK_HRESULT(hr);
IMMDevice* pDdevice = nullptr;
@ -59,79 +79,79 @@ bool CoreAudioDriver::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a
pEnumerator->Release();
CHECK_HRESULT(hr);
hr = pDdevice->Activate(IID_IAudioClient, CLSCTX_ALL,NULL, (void**)&m_audioClient);
hr = pDdevice->Activate(MU_IID_IAudioClient, CLSCTX_ALL,NULL, (void**)&s_data->audioClient);
pDdevice->Release();
CHECK_HRESULT(hr);
WAVEFORMATEX pFormat, * deviceFormat;
hr = m_audioClient->GetMixFormat(&deviceFormat);
WAVEFORMATEX* deviceFormat;
hr = s_data->audioClient->GetMixFormat(&deviceFormat);
CHECK_HRESULT(hr);
REFERENCE_TIME defaultTime, minimumTime;
hr = m_audioClient->GetDevicePeriod(&defaultTime, &minimumTime);
hr = s_data->audioClient->GetDevicePeriod(&defaultTime, &minimumTime);
CHECK_HRESULT(hr);
pFormat = *deviceFormat;
pFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
pFormat.nChannels = spec.channels;
LOGI() << pFormat.nSamplesPerSec;
pFormat.wBitsPerSample = 32;
pFormat.nAvgBytesPerSec = pFormat.nSamplesPerSec * pFormat.nChannels * sizeof(float);
pFormat.nBlockAlign = (pFormat.nChannels * pFormat.wBitsPerSample) / 8;
pFormat.cbSize = 0;
s_data->pFormat = *deviceFormat;
s_data->pFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
s_data->pFormat.nChannels = spec.channels;
LOGI() << s_data->pFormat.nSamplesPerSec;
s_data->pFormat.wBitsPerSample = 32;
s_data->pFormat.nAvgBytesPerSec = s_data->pFormat.nSamplesPerSec * s_data->pFormat.nChannels * sizeof(float);
s_data->pFormat.nBlockAlign = (s_data->pFormat.nChannels * s_data->pFormat.wBitsPerSample) / 8;
s_data->pFormat.cbSize = 0;
s_data->callback = spec.callback;
if (activeSpec) {
*activeSpec = spec;
activeSpec->format = Format::AudioF32;
activeSpec->sampleRate = pFormat.nSamplesPerSec;
activeSpec->sampleRate = s_data->pFormat.nSamplesPerSec;
}
hr = m_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
defaultTime, defaultTime, &pFormat, NULL);
hr = s_data->audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
defaultTime, defaultTime, &s_data->pFormat, NULL);
CHECK_HRESULT(hr);
UINT32 bufferFrameCount;
hr = m_audioClient->GetBufferSize(&bufferFrameCount);
hr = s_data->audioClient->GetBufferSize(&bufferFrameCount);
CHECK_HRESULT(hr);
hr = m_audioClient->GetService(IID_IAudioRenderClient, (void**)&m_renderClient);
hr = s_data->audioClient->GetService(MU_IID_IAudioRenderClient, (void**)&s_data->renderClient);
CHECK_HRESULT(hr);
auto hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
s_data->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
CHECK_HRESULT(hr);
hr = m_audioClient->SetEventHandle(hEvent);
hr = s_data->audioClient->SetEventHandle(s_data->hEvent);
m_active = true;
m_thread = std::thread([=]() {
m_thread = std::thread([this]() {
BYTE* pData;
HRESULT hr = S_OK;
do {
UINT32 bufferFrameCount, bufferPading;
hr = m_audioClient->GetBufferSize(&bufferFrameCount);
hr = s_data->audioClient->GetBufferSize(&bufferFrameCount);
logError(hr);
hr = m_audioClient->GetCurrentPadding(&bufferPading);
hr = s_data->audioClient->GetCurrentPadding(&bufferPading);
logError(hr);
auto bufferSize = bufferFrameCount - bufferPading;
hr = m_renderClient->GetBuffer(bufferSize, &pData);
hr = s_data->renderClient->GetBuffer(bufferSize, &pData);
logError(hr);
if (!pData || hr != S_OK) {
continue;
}
activeSpec->callback(nullptr, reinterpret_cast<uint8_t*>(pData),
bufferSize * pFormat.wBitsPerSample * pFormat.nChannels / 8);
hr = m_renderClient->ReleaseBuffer(bufferSize, 0);
s_data->callback(nullptr, reinterpret_cast<uint8_t*>(pData),
bufferSize * s_data->pFormat.wBitsPerSample * s_data->pFormat.nChannels / 8);
hr = s_data->renderClient->ReleaseBuffer(bufferSize, 0);
logError(hr);
DWORD waitResult = WaitForSingleObject(hEvent, INFINITE);
DWORD waitResult = WaitForSingleObject(s_data->hEvent, INFINITE);
if (waitResult != WAIT_OBJECT_0) {
LOGE() << "audio driver wait for signal failed: " << waitResult;
break;
}
} while(m_active);
} while (m_active);
});
m_thread.detach();
hr = m_audioClient->Start();
hr = s_data->audioClient->Start();
CHECK_HRESULT(hr);
LOGI() << "Core Audio driver started";
@ -140,8 +160,12 @@ bool CoreAudioDriver::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a
void CoreAudioDriver::close()
{
if (m_audioClient) {
m_audioClient->Stop();
if (!s_data) {
return;
}
if (s_data->audioClient) {
s_data->audioClient->Stop();
}
m_active = false;
if (m_thread.joinable()) {
@ -156,7 +180,7 @@ bool CoreAudioDriver::isOpened() const
return m_active;
}
void CoreAudioDriver::logError(HRESULT hr)
void logError(HRESULT hr)
{
switch (hr) {
case S_OK: return;
@ -235,12 +259,15 @@ void CoreAudioDriver::logError(HRESULT hr)
void CoreAudioDriver::clean()
{
if (m_audioClient) {
m_audioClient->Release();
if (s_data->audioClient) {
s_data->audioClient->Release();
}
if (m_renderClient) {
m_renderClient->Release();
if (s_data->renderClient) {
s_data->renderClient->Release();
}
delete s_data;
s_data = nullptr;
}
void CoreAudioDriver::resume()
@ -259,6 +286,7 @@ std::string CoreAudioDriver::outputDevice() const
bool CoreAudioDriver::selectOutputDevice(const std::string& name)
{
UNUSED(name);
NOT_IMPLEMENTED;
return false;
}

View file

@ -21,8 +21,7 @@
#include "iaudiodriver.h"
#include <thread>
#include "windows.h"
#include "audioclient.h"
#include <atomic>
namespace mu::audio {
class CoreAudioDriver : public IAudioDriver
@ -43,13 +42,10 @@ public:
void suspend() override;
private:
void logError(HRESULT hr);
void clean();
bool m_active = false;
std::atomic<bool> m_active { false };
std::thread m_thread;
IAudioClient* m_audioClient = nullptr;
IAudioRenderClient* m_renderClient = nullptr;
};
}