Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,157 @@
#include <kinc/audio2/audio.h>
#include <kinc/system.h>
#include <kinc/backend/SystemMicrosoft.h>
#include <kinc/backend/Windows.h>
#include <dsound.h>
#include <assert.h>
namespace {
IDirectSound8 *dsound = nullptr;
IDirectSoundBuffer *dbuffer = nullptr;
const DWORD dsize = 50 * 1024;
const int samplesPerSecond = 44100;
const int bitsPerSample = 16;
DWORD lastPlayPosition = 0;
bool secondHalfFilled = false;
const int gap = 10 * 1024;
DWORD writePos = gap;
kinc_a2_buffer_t a2_buffer;
}
static bool initialized = false;
void kinc_a2_init() {
if (initialized) {
return;
}
kinc_a2_internal_init();
initialized = true;
a2_buffer.read_location = 0;
a2_buffer.write_location = 0;
a2_buffer.data_size = 128 * 1024;
a2_buffer.channel_count = 2;
a2_buffer.channels[0] = new float[a2_buffer.data_size];
a2_buffer.channels[1] = new float[a2_buffer.data_size];
kinc_microsoft_affirm(DirectSoundCreate8(nullptr, &dsound, nullptr));
// TODO (DK) only for the main window?
kinc_microsoft_affirm(dsound->SetCooperativeLevel(kinc_windows_window_handle(0), DSSCL_PRIORITY));
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nSamplesPerSec = samplesPerSecond;
waveFormat.wBitsPerSample = bitsPerSample;
waveFormat.nChannels = 2;
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0;
DSBUFFERDESC bufferDesc;
bufferDesc.dwSize = sizeof(DSBUFFERDESC);
bufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
bufferDesc.dwBufferBytes = dsize;
bufferDesc.dwReserved = 0;
bufferDesc.lpwfxFormat = &waveFormat;
bufferDesc.guid3DAlgorithm = GUID_NULL;
kinc_microsoft_affirm(dsound->CreateSoundBuffer(&bufferDesc, &dbuffer, nullptr));
DWORD size1;
uint8_t *buffer1 = NULL;
kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, nullptr, nullptr, 0));
assert(buffer1 != NULL);
for (DWORD i = 0; i < size1; ++i) {
buffer1[i] = 0;
}
kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, nullptr, 0));
kinc_microsoft_affirm(dbuffer->Play(0, 0, DSBPLAY_LOOPING));
}
uint32_t kinc_a2_samples_per_second(void) {
return samplesPerSecond;
}
namespace {
void copySample(uint8_t *buffer, DWORD &index, bool left) {
float value = *(float *)&a2_buffer.channels[left ? 0 : 1][a2_buffer.read_location];
if (!left) {
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
}
}
*(int16_t *)&buffer[index] = static_cast<int16_t>(value * 32767);
index += 2;
}
}
void kinc_a2_update() {
DWORD playPosition;
DWORD writePosition;
kinc_microsoft_affirm(dbuffer->GetCurrentPosition(&playPosition, &writePosition));
int dif;
if (writePos >= writePosition) {
dif = writePos - writePosition;
}
else {
dif = dsize - writePosition + writePos;
}
if (dif < gap) {
return;
}
if (writePos + gap >= dsize) {
if (playPosition >= writePos || playPosition <= gap) {
return;
}
if (writePosition >= writePos || writePosition <= gap) {
return;
}
}
else {
if (playPosition >= writePos && playPosition <= writePos + gap) {
return;
}
if (writePosition >= writePos && writePosition <= writePos + gap) {
return;
}
}
kinc_a2_internal_callback(&a2_buffer, (uint32_t)(gap / 4));
DWORD size1;
uint8_t *buffer1;
kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, NULL, NULL, 0));
for (DWORD i = 0; i < size1 - (bitsPerSample / 8 - 1);) {
copySample(buffer1, i, ((writePos + i) / 2) % 2 == 0);
}
writePos += size1;
kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, NULL, 0));
if (writePos >= dsize) {
writePos -= dsize;
}
}
void kinc_a2_shutdown() {
if (dbuffer != nullptr) {
dbuffer->Release();
dbuffer = nullptr;
}
if (dsound != nullptr) {
dsound->Release();
dsound = nullptr;
}
}

View File

@ -0,0 +1,308 @@
#include <kinc/audio2/audio.h>
#include <kinc/backend/SystemMicrosoft.h>
#include <kinc/error.h>
#include <kinc/log.h>
// Windows 7
#define WINVER 0x0601
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0601
#define NOATOM
#define NOCLIPBOARD
#define NOCOLOR
#define NOCOMM
#define NOCTLMGR
#define NODEFERWINDOWPOS
#define NODRAWTEXT
// #define NOGDI
#define NOGDICAPMASKS
#define NOHELP
#define NOICONS
#define NOKANJI
#define NOKEYSTATES
#define NOMB
#define NOMCX
#define NOMEMMGR
#define NOMENUS
#define NOMETAFILE
#define NOMINMAX
// #define NOMSG
#define NONLS
#define NOOPENFILE
#define NOPROFILER
#define NORASTEROPS
#define NOSCROLL
#define NOSERVICE
#define NOSHOWWINDOW
#define NOSOUND
#define NOSYSCOMMANDS
#define NOSYSMETRICS
#define NOTEXTMETRIC
// #define NOUSER
#define NOVIRTUALKEYCODES
#define NOWH
#define NOWINMESSAGES
#define NOWINOFFSETS
#define NOWINSTYLES
#define WIN32_LEAN_AND_MEAN
#include <initguid.h>
#include <AudioClient.h>
#include <mmdeviceapi.h>
#ifndef __MINGW32__
// MIDL_INTERFACE("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2")
DEFINE_GUID(IID_IAudioClient, 0x1CB9AD4C, 0xDBFA, 0x4c32, 0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2);
// MIDL_INTERFACE("F294ACFC-3146-4483-A7BF-ADDCA7C260E2")
DEFINE_GUID(IID_IAudioRenderClient, 0xF294ACFC, 0x3146, 0x4483, 0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2);
// MIDL_INTERFACE("A95664D2-9614-4F35-A746-DE8DB63617E6")
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
// DECLSPEC_UUID("BCDE0395-E52F-467C-8E3D-C4579291692E")
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
#endif
// based on the implementation in soloud and Microsoft sample code
static kinc_a2_buffer_t a2_buffer;
static IMMDeviceEnumerator *deviceEnumerator;
static IMMDevice *device;
static IAudioClient *audioClient = NULL;
static IAudioRenderClient *renderClient = NULL;
static HANDLE bufferEndEvent = 0;
static HANDLE audioProcessingDoneEvent;
static UINT32 bufferFrames;
static WAVEFORMATEX requestedFormat;
static WAVEFORMATEX *closestFormat;
static WAVEFORMATEX *format;
static uint32_t samples_per_second = 44100;
uint32_t kinc_a2_samples_per_second(void) {
return samples_per_second;
}
static bool initDefaultDevice() {
if (renderClient != NULL) {
renderClient->lpVtbl->Release(renderClient);
renderClient = NULL;
}
if (audioClient != NULL) {
audioClient->lpVtbl->Release(audioClient);
audioClient = NULL;
}
if (bufferEndEvent != 0) {
CloseHandle(bufferEndEvent);
bufferEndEvent = 0;
}
kinc_log(KINC_LOG_LEVEL_INFO, "Initializing a new default audio device.");
HRESULT hr = deviceEnumerator->lpVtbl->GetDefaultAudioEndpoint(deviceEnumerator, eRender, eConsole, &device);
if (hr == S_OK) {
hr = device->lpVtbl->Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (void **)&audioClient);
}
if (hr == S_OK) {
const int sampleRate = 48000;
format = &requestedFormat;
memset(&requestedFormat, 0, sizeof(WAVEFORMATEX));
requestedFormat.nChannels = 2;
requestedFormat.nSamplesPerSec = sampleRate;
requestedFormat.wFormatTag = WAVE_FORMAT_PCM;
requestedFormat.wBitsPerSample = sizeof(short) * 8;
requestedFormat.nBlockAlign = (requestedFormat.nChannels * requestedFormat.wBitsPerSample) / 8;
requestedFormat.nAvgBytesPerSec = requestedFormat.nSamplesPerSec * requestedFormat.nBlockAlign;
requestedFormat.cbSize = 0;
HRESULT supported = audioClient->lpVtbl->IsFormatSupported(audioClient, AUDCLNT_SHAREMODE_SHARED, format, &closestFormat);
if (supported == S_FALSE) {
kinc_log(KINC_LOG_LEVEL_WARNING, "Falling back to the system's preferred WASAPI mix format.", supported);
if (closestFormat != NULL) {
format = closestFormat;
}
else {
audioClient->lpVtbl->GetMixFormat(audioClient, &format);
}
}
HRESULT result =
audioClient->lpVtbl->Initialize(audioClient, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 40 * 1000 * 10, 0, format, 0);
if (result != S_OK) {
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize WASAPI audio, going silent (error code 0x%x).", result);
return false;
}
uint32_t old_samples_per_second = samples_per_second;
samples_per_second = format->nSamplesPerSec;
if (samples_per_second != old_samples_per_second) {
kinc_a2_internal_sample_rate_callback();
}
a2_buffer.channel_count = 2;
bufferFrames = 0;
kinc_microsoft_affirm(audioClient->lpVtbl->GetBufferSize(audioClient, &bufferFrames));
kinc_microsoft_affirm(audioClient->lpVtbl->GetService(audioClient, &IID_IAudioRenderClient, (void **)&renderClient));
bufferEndEvent = CreateEvent(0, FALSE, FALSE, 0);
kinc_affirm(bufferEndEvent != 0);
kinc_microsoft_affirm(audioClient->lpVtbl->SetEventHandle(audioClient, bufferEndEvent));
return true;
}
else {
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize WASAPI audio.");
return false;
}
}
static void copyS16Sample(int16_t *left, int16_t *right) {
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
}
*left = (int16_t)(left_value * 32767);
*right = (int16_t)(right_value * 32767);
}
static void copyFloatSample(float *left, float *right) {
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
}
*left = left_value;
*right = right_value;
}
static void submitEmptyBuffer(unsigned frames) {
BYTE *buffer = NULL;
HRESULT result = renderClient->lpVtbl->GetBuffer(renderClient, frames, &buffer);
if (FAILED(result)) {
return;
}
memset(buffer, 0, frames * format->nBlockAlign);
result = renderClient->lpVtbl->ReleaseBuffer(renderClient, frames, 0);
}
static void submitBuffer(unsigned frames) {
BYTE *buffer = NULL;
HRESULT result = renderClient->lpVtbl->GetBuffer(renderClient, frames, &buffer);
if (FAILED(result)) {
if (result == AUDCLNT_E_DEVICE_INVALIDATED) {
initDefaultDevice();
submitEmptyBuffer(bufferFrames);
audioClient->lpVtbl->Start(audioClient);
}
return;
}
if (kinc_a2_internal_callback(&a2_buffer, frames)) {
if (format->wFormatTag == WAVE_FORMAT_PCM) {
for (UINT32 i = 0; i < frames; ++i) {
copyS16Sample((int16_t *)&buffer[i * format->nBlockAlign], (int16_t *)&buffer[i * format->nBlockAlign + 2]);
}
}
else {
for (UINT32 i = 0; i < frames; ++i) {
copyFloatSample((float *)&buffer[i * format->nBlockAlign], (float *)&buffer[i * format->nBlockAlign + 4]);
}
}
}
else {
memset(buffer, 0, frames * format->nBlockAlign);
}
result = renderClient->lpVtbl->ReleaseBuffer(renderClient, frames, 0);
if (FAILED(result)) {
if (result == AUDCLNT_E_DEVICE_INVALIDATED) {
initDefaultDevice();
submitEmptyBuffer(bufferFrames);
audioClient->lpVtbl->Start(audioClient);
}
}
}
static DWORD WINAPI audioThread(LPVOID ignored) {
submitBuffer(bufferFrames);
audioClient->lpVtbl->Start(audioClient);
while (WAIT_OBJECT_0 != WaitForSingleObject(audioProcessingDoneEvent, 0)) {
WaitForSingleObject(bufferEndEvent, INFINITE);
UINT32 padding = 0;
HRESULT result = audioClient->lpVtbl->GetCurrentPadding(audioClient, &padding);
if (FAILED(result)) {
if (result == AUDCLNT_E_DEVICE_INVALIDATED) {
initDefaultDevice();
submitEmptyBuffer(bufferFrames);
audioClient->lpVtbl->Start(audioClient);
}
continue;
}
UINT32 frames = bufferFrames - padding;
submitBuffer(frames);
}
return 0;
}
void kinc_windows_co_initialize(void);
static bool initialized = false;
void kinc_a2_init() {
if (initialized) {
return;
}
kinc_a2_internal_init();
initialized = true;
a2_buffer.read_location = 0;
a2_buffer.write_location = 0;
a2_buffer.data_size = 128 * 1024;
a2_buffer.channel_count = 2;
a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));
audioProcessingDoneEvent = CreateEvent(0, FALSE, FALSE, 0);
kinc_affirm(audioProcessingDoneEvent != 0);
kinc_windows_co_initialize();
kinc_microsoft_affirm(CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **)&deviceEnumerator));
if (initDefaultDevice()) {
CreateThread(0, 65536, audioThread, NULL, 0, 0);
}
}
void kinc_a2_update() {}
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) { \
(punk)->Release(); \
(punk) = NULL; \
}
void kinc_a2_shutdown() {
// Wait for last data in buffer to play before stopping.
// Sleep((DWORD)(hnsActualDuration/REFTIMES_PER_MILLISEC/2));
// affirm(pAudioClient->Stop()); // Stop playing.
// CoTaskMemFree(pwfx);
// SAFE_RELEASE(pEnumerator)
// SAFE_RELEASE(pDevice)
// SAFE_RELEASE(pAudioClient)
// SAFE_RELEASE(pRenderClient)
}

View File

@ -0,0 +1,310 @@
#include <kinc/audio2/audio.h>
#include <kinc/backend/SystemMicrosoft.h>
#include <kinc/error.h>
#include <kinc/log.h>
#include <kinc/threads/thread.h>
#include <AudioClient.h>
#include <Windows.h>
#include <initguid.h>
#ifdef KINC_WINDOWSAPP
#include <mfapi.h>
#endif
#include <mmdeviceapi.h>
#include <wrl/implements.h>
#ifdef KINC_WINDOWSAPP
using namespace ::Microsoft::WRL;
using namespace Windows::Media::Devices;
using namespace Windows::Storage::Streams;
#endif
template <class T> void SafeRelease(__deref_inout_opt T **ppT) {
T *pTTemp = *ppT;
*ppT = nullptr;
if (pTTemp) {
pTTemp->Release();
}
}
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) { \
(punk)->Release(); \
(punk) = NULL; \
}
// based on the implementation in soloud and Microsoft sample code
namespace {
kinc_thread_t thread;
kinc_a2_buffer_t a2_buffer;
IMMDeviceEnumerator *deviceEnumerator;
IMMDevice *device;
IAudioClient *audioClient = NULL;
IAudioRenderClient *renderClient = NULL;
HANDLE bufferEndEvent = 0;
HANDLE audioProcessingDoneEvent;
UINT32 bufferFrames;
WAVEFORMATEX requestedFormat;
WAVEFORMATEX *closestFormat;
WAVEFORMATEX *format;
static uint32_t samples_per_second = 44100;
bool initDefaultDevice();
void audioThread(LPVOID);
#ifdef KINC_WINDOWSAPP
class AudioRenderer : public RuntimeClass<RuntimeClassFlags<ClassicCom>, FtmBase, IActivateAudioInterfaceCompletionHandler> {
public:
STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *operation) {
IUnknown *audioInterface = nullptr;
HRESULT hrActivateResult = S_OK;
HRESULT hr = operation->GetActivateResult(&hrActivateResult, &audioInterface);
if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult)) {
audioInterface->QueryInterface(IID_PPV_ARGS(&audioClient));
initDefaultDevice();
audioThread(nullptr);
}
return S_OK;
}
};
ComPtr<AudioRenderer> renderer;
#endif
bool initDefaultDevice() {
#ifdef KINC_WINDOWSAPP
HRESULT hr = S_OK;
#else
if (renderClient != NULL) {
renderClient->Release();
renderClient = NULL;
}
if (audioClient != NULL) {
audioClient->Release();
audioClient = NULL;
}
if (bufferEndEvent != 0) {
CloseHandle(bufferEndEvent);
bufferEndEvent = 0;
}
kinc_log(KINC_LOG_LEVEL_INFO, "Initializing a new default audio device.");
HRESULT hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
if (hr == S_OK) {
hr = device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, 0, reinterpret_cast<void **>(&audioClient));
}
#endif
if (hr == S_OK) {
const int sampleRate = 48000;
format = &requestedFormat;
memset(&requestedFormat, 0, sizeof(WAVEFORMATEX));
requestedFormat.nChannels = 2;
requestedFormat.nSamplesPerSec = sampleRate;
requestedFormat.wFormatTag = WAVE_FORMAT_PCM;
requestedFormat.wBitsPerSample = sizeof(short) * 8;
requestedFormat.nBlockAlign = (requestedFormat.nChannels * requestedFormat.wBitsPerSample) / 8;
requestedFormat.nAvgBytesPerSec = requestedFormat.nSamplesPerSec * requestedFormat.nBlockAlign;
requestedFormat.cbSize = 0;
HRESULT supported = audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, format, &closestFormat);
if (supported == S_FALSE) {
kinc_log(KINC_LOG_LEVEL_WARNING, "Falling back to the system's preferred WASAPI mix format.", supported);
if (closestFormat != nullptr) {
format = closestFormat;
}
else {
audioClient->GetMixFormat(&format);
}
}
HRESULT result = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 40 * 1000 * 10, 0, format, 0);
if (result != S_OK) {
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize WASAPI audio, going silent (error code 0x%x).", result);
return false;
}
uint32_t old_samples_per_second = samples_per_second;
samples_per_second = format->nSamplesPerSec;
if (samples_per_second != old_samples_per_second) {
kinc_a2_internal_sample_rate_callback();
}
a2_buffer.channel_count = 2;
bufferFrames = 0;
kinc_microsoft_affirm(audioClient->GetBufferSize(&bufferFrames));
kinc_microsoft_affirm(audioClient->GetService(__uuidof(IAudioRenderClient), reinterpret_cast<void **>(&renderClient)));
bufferEndEvent = CreateEvent(0, FALSE, FALSE, 0);
kinc_affirm(bufferEndEvent != 0);
kinc_microsoft_affirm(audioClient->SetEventHandle(bufferEndEvent));
return true;
}
else {
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize WASAPI audio.");
return false;
}
}
void copyS16Sample(int16_t *left, int16_t *right) {
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
}
*left = (int16_t)(left_value * 32767);
*right = (int16_t)(right_value * 32767);
}
void copyFloatSample(float *left, float *right) {
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
a2_buffer.read_location += 1;
if (a2_buffer.read_location >= a2_buffer.data_size) {
a2_buffer.read_location = 0;
}
*left = left_value;
*right = right_value;
}
void submitEmptyBuffer(unsigned frames) {
BYTE *buffer = nullptr;
HRESULT result = renderClient->GetBuffer(frames, &buffer);
if (FAILED(result)) {
return;
}
memset(buffer, 0, frames * format->nBlockAlign);
result = renderClient->ReleaseBuffer(frames, 0);
}
void submitBuffer(unsigned frames) {
BYTE *buffer = nullptr;
HRESULT result = renderClient->GetBuffer(frames, &buffer);
if (FAILED(result)) {
if (result == AUDCLNT_E_DEVICE_INVALIDATED) {
initDefaultDevice();
submitEmptyBuffer(bufferFrames);
audioClient->Start();
}
return;
}
if (kinc_a2_internal_callback(&a2_buffer, frames)) {
if (format->wFormatTag == WAVE_FORMAT_PCM) {
for (UINT32 i = 0; i < frames; ++i) {
copyS16Sample((int16_t *)&buffer[i * format->nBlockAlign], (int16_t *)&buffer[i * format->nBlockAlign + 2]);
}
}
else {
for (UINT32 i = 0; i < frames; ++i) {
copyFloatSample((float *)&buffer[i * format->nBlockAlign], (float *)&buffer[i * format->nBlockAlign + 4]);
}
}
}
else {
memset(buffer, 0, frames * format->nBlockAlign);
}
result = renderClient->ReleaseBuffer(frames, 0);
if (FAILED(result)) {
if (result == AUDCLNT_E_DEVICE_INVALIDATED) {
initDefaultDevice();
submitEmptyBuffer(bufferFrames);
audioClient->Start();
}
}
}
void audioThread(LPVOID) {
submitBuffer(bufferFrames);
audioClient->Start();
while (WAIT_OBJECT_0 != WaitForSingleObject(audioProcessingDoneEvent, 0)) {
WaitForSingleObject(bufferEndEvent, INFINITE);
UINT32 padding = 0;
HRESULT result = audioClient->GetCurrentPadding(&padding);
if (FAILED(result)) {
if (result == AUDCLNT_E_DEVICE_INVALIDATED) {
initDefaultDevice();
submitEmptyBuffer(bufferFrames);
audioClient->Start();
}
continue;
}
UINT32 frames = bufferFrames - padding;
submitBuffer(frames);
}
}
} // namespace
#ifndef KINC_WINDOWSAPP
extern "C" void kinc_windows_co_initialize(void);
#endif
static bool initialized = false;
void kinc_a2_init() {
if (initialized) {
return;
}
kinc_a2_internal_init();
initialized = true;
a2_buffer.read_location = 0;
a2_buffer.write_location = 0;
a2_buffer.data_size = 128 * 1024;
a2_buffer.channel_count = 2;
a2_buffer.channels[0] = (float *)malloc(a2_buffer.data_size * sizeof(float));
a2_buffer.channels[1] = (float *)malloc(a2_buffer.data_size * sizeof(float));
audioProcessingDoneEvent = CreateEvent(0, FALSE, FALSE, 0);
kinc_affirm(audioProcessingDoneEvent != 0);
#ifdef KINC_WINDOWSAPP
renderer = Make<AudioRenderer>();
IActivateAudioInterfaceAsyncOperation *asyncOp;
Platform::String ^ deviceId = MediaDevice::GetDefaultAudioRenderId(Windows::Media::Devices::AudioDeviceRole::Default);
kinc_microsoft_affirm(ActivateAudioInterfaceAsync(deviceId->Data(), __uuidof(IAudioClient2), nullptr, renderer.Get(), &asyncOp));
SafeRelease(&asyncOp);
#else
kinc_windows_co_initialize();
kinc_microsoft_affirm(
CoCreateInstance(__uuidof(MMDeviceEnumerator), 0, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), reinterpret_cast<void **>(&deviceEnumerator)));
if (initDefaultDevice()) {
kinc_thread_init(&thread, audioThread, NULL);
}
#endif
}
uint32_t kinc_a2_samples_per_second(void) {
return samples_per_second;
}
void kinc_a2_update() {}
void kinc_a2_shutdown() {
// Wait for last data in buffer to play before stopping.
// Sleep((DWORD)(hnsActualDuration/REFTIMES_PER_MILLISEC/2));
// affirm(pAudioClient->Stop()); // Stop playing.
// CoTaskMemFree(pwfx);
// SAFE_RELEASE(pEnumerator)
// SAFE_RELEASE(pDevice)
// SAFE_RELEASE(pAudioClient)
// SAFE_RELEASE(pRenderClient)
}