281 lines
7.2 KiB
C++
281 lines
7.2 KiB
C++
#include <iostream>
|
|
|
|
#define COBJMACROS
|
|
#include <mmdeviceapi.h>
|
|
#include <audioclient.h>
|
|
|
|
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;
|
|
}
|