From 130ef65078d4c387512793d2d46f4a0b3b2451fe Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 23 Aug 2024 13:49:50 -0400 Subject: [PATCH] First Stabs at Windows Sound (See winsoundcat.cpp) --- CMakeLists.txt | 8 +- src/windows/ReMixer.cpp | 3 + winsoundcat.cpp | 280 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 src/windows/ReMixer.cpp create mode 100644 winsoundcat.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bea0a8c..4992d25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,8 @@ endif() target_link_libraries(ReMixer-Test PUBLIC ReMixer) add_executable(pacat pacat_simple.cpp - pacat_advanced.cpp) + pacat_advanced.cpp + src/windows/ReMixer.cpp) target_link_libraries(pacat pulse-simple pulse) add_executable(vorbis_decode vorbis_decode.cpp) @@ -58,3 +59,8 @@ target_link_libraries(vorbis_decode vorbisfile vorbis) add_executable(pacat_advanced pacat_advanced.cpp) target_link_libraries(pacat_advanced pulse) + +if (WIN32) + add_executable(winsoundcat winsoundcat.cpp) + target_link_libraries(winsoundcat) +endif() \ No newline at end of file diff --git a/src/windows/ReMixer.cpp b/src/windows/ReMixer.cpp new file mode 100644 index 0000000..c2ad628 --- /dev/null +++ b/src/windows/ReMixer.cpp @@ -0,0 +1,3 @@ +// +// Created by Josh on 8/22/2024. +// diff --git a/winsoundcat.cpp b/winsoundcat.cpp new file mode 100644 index 0000000..fa09e3c --- /dev/null +++ b/winsoundcat.cpp @@ -0,0 +1,280 @@ +#include + +#define COBJMACROS +#include +#include + +int enumerate_sound_devices() +{ + // Initialize COM-interface subsystem + CoInitializeEx(NULL, 0); + + IMMDeviceEnumerator *enu; + const GUID _CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}}; + const GUID _IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}}; + CoCreateInstance(_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, _IID_IMMDeviceEnumerator, (void**)&enu); + + bool playback = true; + + IMMDeviceCollection *dcoll; + EDataFlow mode = (playback) ? eRender : eCapture; + enu->EnumAudioEndpoints(mode, DEVICE_STATE_ACTIVE, &dcoll); + + for (int i = 0; ; i++) + { + IMMDevice *dev; + if (0 != dcoll->Item(i, &dev)) + break; + + IPropertyStore *props; + dev->OpenPropertyStore(STGM_READ, &props); + + PROPVARIANT name; + + PropVariantInit(&name); + const PROPERTYKEY PKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}}, 14}; + + props->GetValue(PKEY_Device_FriendlyName, &name); + + const wchar_t *device_name = name.pwszVal; + + + wchar_t* device_id = NULL; + dev->GetId(&device_id); + + IMMDevice *def_dev = NULL; + enu->GetDefaultAudioEndpoint(mode, eConsole, &def_dev); + + def_dev->Release(); + + CoTaskMemFree(device_id); + + PropVariantClear(&name); + + dev->Release(); + } + + //IMMDeviceEnumerator_Release(enu); + dcoll->Release(); + enu->Release(); + + return 0; +} + +int open_shared_buffer() +{ + bool playback = true; + + IMMDeviceEnumerator *enu; + const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}}; + const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}}; + CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enu); + + + IMMDevice *dev; + + wchar_t* device_id = NULL; + if (device_id == NULL) + { + EDataFlow mode = (playback) ? eRender : eCapture; + enu->GetDefaultAudioEndpoint(mode, eConsole, &dev); + } else { + enu->GetDevice(device_id, &dev); + } + + IAudioClient* client; + const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}}; + dev->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client); + + WAVEFORMATEX *wf; + client->GetMixFormat(&wf); + + int buffer_length_msec = 500; + REFERENCE_TIME dur = buffer_length_msec * 1000 * 10; + + AUDCLNT_SHAREMODE mode = AUDCLNT_SHAREMODE_SHARED; + int aflags = 0; + + client->Initialize(mode, aflags, dur, dur, wf, NULL); + + u_int buf_frames; + + client->GetBufferSize(&buf_frames); + + buffer_length_msec = buf_frames * 1000 / wf->nSamplesPerSec; + + CoTaskMemFree(wf); + client->Release(); + dev->Release(); + enu->Release(); + + return 0; +} + +int record_shared() +{ + bool playback = true; + + IMMDeviceEnumerator *enu; + const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}}; + const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}}; + CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enu); + + + IMMDevice *dev; + + wchar_t* device_id = NULL; + if (device_id == NULL) + { + EDataFlow mode = (playback) ? eRender : eCapture; + enu->GetDefaultAudioEndpoint(mode, eConsole, &dev); + } else { + enu->GetDevice(device_id, &dev); + } + + IAudioClient* client; + const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}}; + dev->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client); + + WAVEFORMATEX *wf; + client->GetMixFormat(&wf); + + int buffer_length_msec = 500; + REFERENCE_TIME dur = buffer_length_msec * 1000 * 10; + + AUDCLNT_SHAREMODE mode = AUDCLNT_SHAREMODE_SHARED; + int aflags = 0; + + client->Initialize(mode, aflags, dur, dur, wf, NULL); + + u_int buf_frames; + + client->GetBufferSize(&buf_frames); + + buffer_length_msec = buf_frames * 1000 / wf->nSamplesPerSec; + + IAudioCaptureClient* capt; + const GUID IID_IAudioCaptureClient = {0xc8adbd64, 0xe71e, 0x48a0, {0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17}}; + client->GetService(IID_IAudioCaptureClient, (void**)&capt); + + client->Start(); + + for (;;) + { + u_char * data; + u_int nframes; + u_long flags; + int r = capt->GetBuffer(&data, &nframes, &flags, NULL, NULL); + + + if (r == AUDCLNT_S_BUFFER_EMPTY) { + // Buffer is empty. Wait for more data/ + int period_ms = 100; + Sleep(period_ms); + continue; + } else if (r != 0) { + // error + } + + capt->ReleaseBuffer(nframes); + } + + CoTaskMemFree(wf); + client->Release(); + dev->Release(); + enu->Release(); + + return 0; +} + +int play_shared() +{ + bool playback = true; + + IMMDeviceEnumerator *enu; + const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e}}; + const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}}; + CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enu); + + + IMMDevice *dev; + + wchar_t* device_id = NULL; + if (device_id == NULL) + { + EDataFlow mode = (playback) ? eRender : eCapture; + enu->GetDefaultAudioEndpoint(mode, eConsole, &dev); + } else { + enu->GetDevice(device_id, &dev); + } + + IAudioClient* client; + const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}}; + dev->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client); + + WAVEFORMATEX *wf; + client->GetMixFormat(&wf); + + int buffer_length_msec = 500; + REFERENCE_TIME dur = buffer_length_msec * 1000 * 10; + + AUDCLNT_SHAREMODE mode = AUDCLNT_SHAREMODE_SHARED; + int aflags = 0; + + client->Initialize(mode, aflags, dur, dur, wf, NULL); + + u_int buf_frames; + + client->GetBufferSize(&buf_frames); + + buffer_length_msec = buf_frames * 1000 / wf->nSamplesPerSec; + + IAudioRenderClient *render; + const GUID IID_IAudioRenderClient = {0xf294acfc, 0x3146, 0x4483, {0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2}}; + client->GetService(IID_IAudioRenderClient, (void**)&render); + + + u_int filled; + client->GetCurrentPadding(&filled); + + int n_free_frames = buf_frames - filled; + + int started = 0; + + if (!started) + { + client->Start(); + started = 1; + } + + u_char *data; + render->GetBuffer(n_free_frames, &data); + + // Drain the audio buffer + for (;;) + { + u_int filled; + client->GetCurrentPadding(&filled); + if (filled == 0) + break; + } + + render->ReleaseBuffer(n_free_frames, 0); + render->Release(); + CoTaskMemFree(wf); + client->Release(); + dev->Release(); + enu->Release(); + return 0; +} + + +int main() +{ + enumerate_sound_devices(); + open_shared_buffer(); + play_shared(); + + std::cout << "Windows Program" << std::endl; + return 0; +}