mirror of
https://github.com/quantum5/winscap.git
synced 2025-04-24 21:52:03 -04:00
Compare commits
No commits in common. "master" and "0.0.2" have entirely different histories.
12
.github/workflows/lint.yml
vendored
12
.github/workflows/lint.yml
vendored
|
@ -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
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
120
winscap.cpp
120
winscap.cpp
|
@ -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,39 +116,8 @@ 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;
|
|
||||||
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
DeviceChangeNotification deviceChangeNotification(deviceChanged, hEvent);
|
|
||||||
pEnumerator->RegisterEndpointNotificationCallback(&deviceChangeNotification);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
ResetEvent(hEvent);
|
|
||||||
|
|
||||||
IMMDevicePtr pDevice;
|
|
||||||
ensure(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice));
|
|
||||||
|
|
||||||
IAudioClientPtr pClient;
|
|
||||||
ensure(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void **)&pClient));
|
|
||||||
|
|
||||||
HRESULT hrInit = pClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK,
|
|
||||||
16 * REFTIMES_PER_MILLISEC, 0, &wfx, nullptr);
|
|
||||||
if (FAILED(hrInit)) {
|
|
||||||
_com_error err(hrInit);
|
|
||||||
|
|
||||||
IPropertyStorePtr pProps;
|
|
||||||
ensure(pDevice->OpenPropertyStore(STGM_READ, &pProps));
|
|
||||||
|
|
||||||
PROPVARIANT varName;
|
|
||||||
PropVariantInit(&varName);
|
|
||||||
ensure(pProps->GetValue(PKEY_Device_FriendlyName, &varName));
|
|
||||||
fwprintf(stderr, L"Failed to open: %s: %s\n", varName.pwszVal, error_message(err));
|
|
||||||
PropVariantClear(&varName);
|
|
||||||
WaitForSingleObject(hEvent, INFINITE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT32 bufferFrameCount;
|
UINT32 bufferFrameCount;
|
||||||
ensure(pClient->GetBufferSize(&bufferFrameCount));
|
ensure(pClient->GetBufferSize(&bufferFrameCount));
|
||||||
|
@ -202,18 +135,11 @@ int main(int argc, char *argv[]) {
|
||||||
ensure(pClient->Start());
|
ensure(pClient->Start());
|
||||||
EnsureCaptureStop autoStop(pClient);
|
EnsureCaptureStop autoStop(pClient);
|
||||||
|
|
||||||
while (!deviceChanged) {
|
for (;;) {
|
||||||
Sleep(dwDelay);
|
Sleep(dwDelay);
|
||||||
|
|
||||||
UINT32 packetLength;
|
UINT32 packetLength;
|
||||||
HRESULT hrNext = pCapture->GetNextPacketSize(&packetLength);
|
ensure(pCapture->GetNextPacketSize(&packetLength));
|
||||||
if (hrNext == AUDCLNT_E_DEVICE_INVALIDATED) {
|
|
||||||
while (!deviceChanged)
|
|
||||||
;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
ensure(hrNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (packetLength) {
|
while (packetLength) {
|
||||||
LPBYTE pData;
|
LPBYTE pData;
|
||||||
|
@ -230,6 +156,4 @@ int main(int argc, char *argv[]) {
|
||||||
ensure(pCapture->GetNextPacketSize(&packetLength));
|
ensure(pCapture->GetNextPacketSize(&packetLength));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deviceChanged = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue