Compare commits

..

No commits in common. "master" and "0.0.2" have entirely different histories.

3 changed files with 48 additions and 137 deletions

View file

@ -1,12 +0,0 @@
name: lint
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: DoozyX/clang-format-lint-action@v0.5
with:
source: '.'
extensions: 'h,c,cpp'
clangFormatVersion: 9

View file

@ -46,7 +46,6 @@ Replace `48000` with whatever sampling rate you use with `winscap`.
Then, run `winscap` as follows: Then, run `winscap` as follows:
```sh ```sh
$ mkfifo /tmp/cava.fifo
$ /mnt/c/path/to/winscap.exe 2 48000 16 > /tmp/cava.fifo $ /mnt/c/path/to/winscap.exe 2 48000 16 > /tmp/cava.fifo
``` ```

View file

@ -11,8 +11,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <windows.h> #include <windows.h>
#include <functiondiscoverykeys_devpkey.h>
#define REFTIMES_PER_SEC 10000000 #define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000 #define REFTIMES_PER_MILLISEC 10000
@ -33,48 +31,6 @@ _COM_SMARTPTR_TYPEDEF(IMMDeviceEnumerator, __uuidof(IMMDeviceEnumerator));
_COM_SMARTPTR_TYPEDEF(IMMDevice, __uuidof(IMMDevice)); _COM_SMARTPTR_TYPEDEF(IMMDevice, __uuidof(IMMDevice));
_COM_SMARTPTR_TYPEDEF(IAudioClient, __uuidof(IAudioClient)); _COM_SMARTPTR_TYPEDEF(IAudioClient, __uuidof(IAudioClient));
_COM_SMARTPTR_TYPEDEF(IAudioCaptureClient, __uuidof(IAudioCaptureClient)); _COM_SMARTPTR_TYPEDEF(IAudioCaptureClient, __uuidof(IAudioCaptureClient));
_COM_SMARTPTR_TYPEDEF(IPropertyStore, __uuidof(IPropertyStore));
class DeviceChangeNotification : public IMMNotificationClient {
volatile ULONG ref;
volatile bool &changed;
HANDLE hEvent;
public:
DeviceChangeNotification(volatile bool &changed, HANDLE hEvent)
: changed(changed), hEvent(hEvent) {}
// This is meant to be allocated on stack, so we don't actually free.
STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&ref); }
STDMETHODIMP_(ULONG) Release() { return InterlockedDecrement(&ref); }
STDMETHODIMP QueryInterface(REFIID iid, void **ppv) {
if (iid == IID_IUnknown) {
AddRef();
*ppv = (IUnknown *)this;
} else if (iid == __uuidof(IMMNotificationClient)) {
AddRef();
*ppv = (IMMNotificationClient *)this;
} else {
*ppv = nullptr;
return E_NOINTERFACE;
}
return S_OK;
}
STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR) {
if (flow == eRender && role == eConsole) {
changed = true;
SetEvent(hEvent);
}
return S_OK;
}
STDMETHODIMP OnDeviceAdded(LPCWSTR) { return S_OK; }
STDMETHODIMP OnDeviceRemoved(LPCWSTR) { return S_OK; }
STDMETHODIMP OnDeviceStateChanged(LPCWSTR, DWORD) { return S_OK; }
STDMETHODIMP OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) { return S_OK; }
};
class EnsureCaptureStop { class EnsureCaptureStop {
IAudioClientPtr m_client; IAudioClientPtr m_client;
@ -99,20 +55,19 @@ struct {
{AUDCLNT_E_UNSUPPORTED_FORMAT, L"Requested sound format unsupported"}, {AUDCLNT_E_UNSUPPORTED_FORMAT, L"Requested sound format unsupported"},
}; };
LPCWSTR error_message(const _com_error &err) {
for (int i = 0; i < sizeof error_table / sizeof error_table[0]; ++i) {
if (error_table[i].hr == err.Error()) {
return error_table[i].error;
}
}
return err.ErrorMessage();
}
#define ensure(hr) ensure_(__FILE__, __LINE__, hr) #define ensure(hr) ensure_(__FILE__, __LINE__, hr)
void ensure_(const char *file, int line, HRESULT hr) { void ensure_(const char *file, int line, HRESULT hr) {
if (FAILED(hr)) { if (FAILED(hr)) {
_com_error err(hr); _com_error err(hr);
fwprintf(stderr, L"Error at %S:%d (0x%08x): %s\n", file, line, hr, error_message(err)); LPCWSTR msg = err.ErrorMessage();
for (int i = 0; i < sizeof error_table / sizeof error_table[0]; ++i) {
if (error_table[i].hr == hr) {
msg = error_table[i].error;
}
}
fwprintf(stderr, L"Error at %S:%d (0x%08x): %s\n", file, line, hr, msg);
exit(1); exit(1);
} }
} }
@ -144,6 +99,15 @@ int main(int argc, char *argv[]) {
CCoInitialize comInit; CCoInitialize comInit;
ensure(comInit); ensure(comInit);
IMMDeviceEnumeratorPtr pEnumerator;
ensure(pEnumerator.CreateInstance(__uuidof(MMDeviceEnumerator)));
IMMDevicePtr pDevice;
ensure(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice));
IAudioClientPtr pClient;
ensure(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void **)&pClient));
WAVEFORMATEX wfx; WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = (WORD)channels; wfx.nChannels = (WORD)channels;
@ -152,84 +116,44 @@ int main(int argc, char *argv[]) {
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8; wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
IMMDeviceEnumeratorPtr pEnumerator; ensure(pClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK,
ensure(pEnumerator.CreateInstance(__uuidof(MMDeviceEnumerator))); 16 * REFTIMES_PER_MILLISEC, 0, &wfx, nullptr));
volatile bool deviceChanged = false; UINT32 bufferFrameCount;
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ensure(pClient->GetBufferSize(&bufferFrameCount));
DeviceChangeNotification deviceChangeNotification(deviceChanged, hEvent);
pEnumerator->RegisterEndpointNotificationCallback(&deviceChangeNotification); IAudioCaptureClientPtr pCapture;
ensure(pClient->GetService(__uuidof(IAudioCaptureClient), (void **)&pCapture));
DWORD dwDelay = (DWORD)(((double)REFTIMES_PER_SEC * bufferFrameCount / wfx.nSamplesPerSec) /
REFTIMES_PER_MILLISEC / 2);
LPBYTE pSilence = (LPBYTE)malloc(bufferFrameCount * wfx.nBlockAlign);
EnsureFree freeSilence(pSilence);
ZeroMemory(pSilence, bufferFrameCount * wfx.nBlockAlign);
ensure(pClient->Start());
EnsureCaptureStop autoStop(pClient);
for (;;) { for (;;) {
ResetEvent(hEvent); Sleep(dwDelay);
IMMDevicePtr pDevice; UINT32 packetLength;
ensure(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice)); ensure(pCapture->GetNextPacketSize(&packetLength));
IAudioClientPtr pClient; while (packetLength) {
ensure(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void **)&pClient)); LPBYTE pData;
UINT32 numFramesAvailable;
DWORD flags;
HRESULT hrInit = pClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, ensure(pCapture->GetBuffer(&pData, &numFramesAvailable, &flags, nullptr, nullptr));
16 * REFTIMES_PER_MILLISEC, 0, &wfx, nullptr);
if (FAILED(hrInit)) {
_com_error err(hrInit);
IPropertyStorePtr pProps; if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
ensure(pDevice->OpenPropertyStore(STGM_READ, &pProps)); pData = pSilence;
PROPVARIANT varName; _write(_fileno(stdout), pData, wfx.nBlockAlign * numFramesAvailable);
PropVariantInit(&varName); ensure(pCapture->ReleaseBuffer(numFramesAvailable));
ensure(pProps->GetValue(PKEY_Device_FriendlyName, &varName)); ensure(pCapture->GetNextPacketSize(&packetLength));
fwprintf(stderr, L"Failed to open: %s: %s\n", varName.pwszVal, error_message(err));
PropVariantClear(&varName);
WaitForSingleObject(hEvent, INFINITE);
continue;
} }
UINT32 bufferFrameCount;
ensure(pClient->GetBufferSize(&bufferFrameCount));
IAudioCaptureClientPtr pCapture;
ensure(pClient->GetService(__uuidof(IAudioCaptureClient), (void **)&pCapture));
DWORD dwDelay = (DWORD)(((double)REFTIMES_PER_SEC * bufferFrameCount / wfx.nSamplesPerSec) /
REFTIMES_PER_MILLISEC / 2);
LPBYTE pSilence = (LPBYTE)malloc(bufferFrameCount * wfx.nBlockAlign);
EnsureFree freeSilence(pSilence);
ZeroMemory(pSilence, bufferFrameCount * wfx.nBlockAlign);
ensure(pClient->Start());
EnsureCaptureStop autoStop(pClient);
while (!deviceChanged) {
Sleep(dwDelay);
UINT32 packetLength;
HRESULT hrNext = pCapture->GetNextPacketSize(&packetLength);
if (hrNext == AUDCLNT_E_DEVICE_INVALIDATED) {
while (!deviceChanged)
;
break;
} else {
ensure(hrNext);
}
while (packetLength) {
LPBYTE pData;
UINT32 numFramesAvailable;
DWORD flags;
ensure(pCapture->GetBuffer(&pData, &numFramesAvailable, &flags, nullptr, nullptr));
if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
pData = pSilence;
_write(_fileno(stdout), pData, wfx.nBlockAlign * numFramesAvailable);
ensure(pCapture->ReleaseBuffer(numFramesAvailable));
ensure(pCapture->GetNextPacketSize(&packetLength));
}
}
deviceChanged = false;
} }
} }