Skip to content

Commit

Permalink
new release. added better error messages and code documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasArvidsson committed Jan 21, 2018
1 parent 15822f2 commit f3fd6d2
Show file tree
Hide file tree
Showing 19 changed files with 433 additions and 366 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ x64
*.ipdb
*.ipdb
*.pdb
*.vspx
*.vcxproj.filters
*.zip
\[stuff\]/
159 changes: 68 additions & 91 deletions AudioDevice.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "AudioDevice.h"
#include "Functiondiscoverykeys_devpkey.h"
#include "Functiondiscoverykeys_devpkey.h" //PKEY_Device_FriendlyName

#define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; }

Expand All @@ -10,16 +10,16 @@ std::vector<AudioDevice*> AudioDevice::getDevices() {
initStatic();
IMMDeviceCollection *pCollection;
HRESULT hr = _pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
assertHrResult(hr);
assertHresult(hr);
UINT count;
hr = pCollection->GetCount(&count);
assertHrResult(hr);
assertHresult(hr);
std::vector<AudioDevice*> devices;
for (ULONG i = 0; i < count; i++) {
IMMDevice *pDevice;
hr = pCollection->Item(i, &pDevice);
devices.push_back(new AudioDevice(pDevice));
assertHrResult(hr);
assertHresult(hr);
}
SAFE_RELEASE(pCollection);
return devices;
Expand All @@ -28,9 +28,9 @@ std::vector<AudioDevice*> AudioDevice::getDevices() {
void AudioDevice::initStatic() {
if (!_initStatic) {
HRESULT hr = CoInitialize(nullptr);
assertHrResult(hr);
assertHresult(hr);
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&_pEnumerator);
assertHrResult(hr);
assertHresult(hr);
_initStatic = true;
}
}
Expand All @@ -41,82 +41,104 @@ void AudioDevice::destroyStatic() {
}

AudioDevice::AudioDevice() {
init();
initDefault();
HRESULT hr = _pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &_pDevice);
assertHrResult(hr);
assertHresult(hr);
init(_pDevice);
}

AudioDevice::AudioDevice(const std::string &id) : AudioDevice(std::wstring(id.begin(), id.end())) {
}

AudioDevice::AudioDevice(const std::wstring &id) {
init();
initDefault();
HRESULT hr = _pEnumerator->GetDevice(id.c_str(), &_pDevice);
assertHrResult(hr);
assertHresult(hr);
init(_pDevice);
}

AudioDevice::AudioDevice(IMMDevice *pDevice) {
initDefault();
init(pDevice);
}

void AudioDevice::init() {
AudioDevice::~AudioDevice() {
//Stop service;
_pAudioClient->Stop();
//Free resources
CoTaskMemFree(_pFormat);
SAFE_RELEASE(_pDevice);
SAFE_RELEASE(_pAudioClient);
SAFE_RELEASE(_pCaptureClient);
SAFE_RELEASE(_pRenderClient);
SAFE_RELEASE(_pSimpleVolume);
}

void AudioDevice::initDefault() {
initStatic();
_pFormat = nullptr;
_pDevice = nullptr;
_pAudioClient = nullptr;
_pCaptureClient = nullptr;
_pRenderClient = nullptr;
_pSimpleVolume = nullptr;
_bufferFrameCount = 0;
}

void AudioDevice::init(IMMDevice *pDevice) {
_pDevice = pDevice;

HRESULT hr = _pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&_pAudioClient);
assertHrResult(hr);

assertHresult(hr);
hr = _pAudioClient->GetMixFormat(&_pFormat);
assertHrResult(hr);
assertHresult(hr);
}

_initMode = false;
_bufferFrameCount = -1;
void AudioDevice::startCaptureService() {
startService(true);
}

void AudioDevice::initMode(const bool capture) {
if (!_initMode) {
HRESULT hr;
if (capture) {
hr = _pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, _pFormat, 0);
}
else {
hr = _pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, _pFormat, 0);
}
assertHrResult(hr);
void AudioDevice::startRenderService() {
startService(false);
}

//Get the size of the allocated buffer.
hr = _pAudioClient->GetBufferSize(&_bufferFrameCount);
assertHrResult(hr);
void AudioDevice::startService(const bool capture) {
HRESULT hr;
if (capture) {
hr = _pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, _pFormat, 0);
assertHresult(hr);
hr = _pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&_pCaptureClient);
assertHresult(hr);
}
else {
hr = _pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, _pFormat, 0);
assertHresult(hr);
hr = _pAudioClient->GetService(__uuidof(IAudioRenderClient), (void**)&_pRenderClient);
assertHresult(hr);
}

_initMode = true;
//Get the size of the allocated buffer.
hr = _pAudioClient->GetBufferSize(&_bufferFrameCount);
assertHresult(hr);

if (!capture) {
//Get and release render buffer first time. Needed to not get audio glitches
BYTE *pRenderBuffer;
hr = _pRenderClient->GetBuffer(_bufferFrameCount, &pRenderBuffer);
assertHresult(hr);
hr = _pRenderClient->ReleaseBuffer(_bufferFrameCount, AUDCLNT_BUFFERFLAGS_SILENT);
assertHresult(hr);
}
}

AudioDevice::~AudioDevice() {
CoTaskMemFree(_pFormat);
SAFE_RELEASE(_pDevice);
SAFE_RELEASE(_pAudioClient);
SAFE_RELEASE(_pCaptureClient);
SAFE_RELEASE(_pRenderClient);
SAFE_RELEASE(_pSimpleVolume);
//Start aduio service on device.
hr = _pAudioClient->Start();
assertHresult(hr);
}

const std::string AudioDevice::getId() {
if (!_id.size()) {
LPWSTR id;
HRESULT hr = _pDevice->GetId(&id);
assertHrResult(hr);
assertHresult(hr);
std::wstring tmp(id);
_id = std::string(tmp.begin(), tmp.end());
CoTaskMemFree(id);
Expand All @@ -129,15 +151,15 @@ const std::string AudioDevice::getName() {
IPropertyStore *pProps = NULL;

HRESULT hr = _pDevice->OpenPropertyStore(STGM_READ, &pProps);
assertHrResult(hr);
assertHresult(hr);

//Initialize container for property value.
PROPVARIANT varName;
PropVariantInit(&varName);

//Get the endpoint's friendly-name property.
hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
assertHrResult(hr);
assertHresult(hr);

std::wstring tmp(varName.pwszVal);
_name = std::string(tmp.begin(), tmp.end());
Expand All @@ -159,59 +181,14 @@ UINT32 AudioDevice::getBufferFrameCount() const {
UINT32 AudioDevice::getBufferFrameCountAvailable() const {
UINT32 numFramesPadding;
HRESULT hr = _pAudioClient->GetCurrentPadding(&numFramesPadding);
assertHrResult(hr);
assertHresult(hr);
return _bufferFrameCount - numFramesPadding;
}

IAudioCaptureClient* AudioDevice::getCaptureClient() {
if (!_pCaptureClient) {
initMode(true);
HRESULT hr = _pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&_pCaptureClient);
assertHrResult(hr);
}
return _pCaptureClient;
}

IAudioRenderClient* AudioDevice::getRenderClient() {
if (!_pRenderClient) {
initMode(false);
HRESULT hr = _pAudioClient->GetService(__uuidof(IAudioRenderClient), (void**)&_pRenderClient);
assertHrResult(hr);
}
return _pRenderClient;
}

ISimpleAudioVolume* AudioDevice::getVolume() {
ISimpleAudioVolume* AudioDevice::getVolumeControl() {
if (!_pSimpleVolume) {
HRESULT hr = _pAudioClient->GetService(__uuidof(ISimpleAudioVolume), (void**)&_pSimpleVolume);
assertHrResult(hr);
assertHresult(hr);
}
return _pSimpleVolume;
}

void AudioDevice::start() {
HRESULT hr = _pAudioClient->Start();
assertHrResult(hr);
}

void AudioDevice::stop() {
HRESULT hr = _pAudioClient->Stop();
assertHrResult(hr);
}

void AudioDevice::printInfo() {
printf("%s '%s'\n", getName().c_str(), getId().c_str());
}



//_pFormat->wFormatTag = WAVE_FORMAT_PCM;
//_pFormat->nChannels = 2;
//_pFormat->wBitsPerSample = 16;
//_pFormat->nSamplesPerSec = 44100;
//_pFormat->nBlockAlign = _pFormat->nChannels * _pFormat->wBitsPerSample / 8;
//_pFormat->nAvgBytesPerSec = _pFormat->nSamplesPerSec * _pFormat->nBlockAlign;
//_pFormat->cbSize = 0;
//hr = _pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, _pFormat, 0);
//AUDCLNT_E_UNSUPPORTED_FORMAT
//hr = _pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, 0, 0, 0, _pFormat, 0);
}
Loading

0 comments on commit f3fd6d2

Please sign in to comment.