| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- #ifdef IRON_A2
- #include <iron_audio.h>
- #include <iron_system.h>
- #include <backends/windows_system.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 iron_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 iron_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;
- }
- iron_log("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) {
- iron_log("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) {
- iron_log("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) {
- iron_a2_internal_sample_rate_callback();
- }
- a2_buffer.channel_count = 2;
- bufferFrames = 0;
- audioClient->lpVtbl->GetBufferSize(audioClient, &bufferFrames);
- audioClient->lpVtbl->GetService(audioClient, &IID_IAudioRenderClient, (void **)&renderClient);
- bufferEndEvent = CreateEvent(0, FALSE, FALSE, 0);
- audioClient->lpVtbl->SetEventHandle(audioClient, bufferEndEvent);
- return true;
- }
- else {
- iron_log("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 (iron_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 iron_windows_co_initialize(void);
- static bool initialized = false;
- void iron_a2_init() {
- if (initialized) {
- return;
- }
- iron_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);
- iron_windows_co_initialize();
- CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void **)&deviceEnumerator);
- if (initDefaultDevice()) {
- CreateThread(0, 65536, audioThread, NULL, 0, 0);
- }
- }
- void iron_a2_update() {}
- #define SAFE_RELEASE(punk) \
- if ((punk) != NULL) { \
- (punk)->Release(); \
- (punk) = NULL; \
- }
- void iron_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)
- }
- #endif
|