Reformat code

This commit is contained in:
badaix 2020-04-10 09:45:19 +02:00
parent 1fcb8b4fc2
commit 5cc37f98f4
8 changed files with 293 additions and 315 deletions

View file

@ -59,7 +59,7 @@ void ClientConnection::socketRead(void* _to, size_t _bytes)
std::string ClientConnection::getMacAddress() std::string ClientConnection::getMacAddress()
{ {
std::string mac = std::string mac =
#ifndef WINDOWS #ifndef WINDOWS
::getMacAddress(socket_.native_handle()); ::getMacAddress(socket_.native_handle());
#else #else

View file

@ -48,8 +48,8 @@ struct ClientSettings
PcmDevice pcm_device; PcmDevice pcm_device;
SampleFormat sample_format; SampleFormat sample_format;
#ifdef HAS_WASAPI #ifdef HAS_WASAPI
WasapiMode wasapi_mode{ WasapiMode::SHARED }; WasapiMode wasapi_mode{WasapiMode::SHARED};
#endif #endif
}; };
struct LoggingSettings struct LoggingSettings

View file

@ -2,19 +2,19 @@
#include <initguid.h> #include <initguid.h>
#include <mmdeviceapi.h> #include <mmdeviceapi.h>
//#include <functiondiscoverykeys_devpkey.h> //#include <functiondiscoverykeys_devpkey.h>
#include <functional> #include "common/aixlog.hpp"
#include "common/snap_exception.hpp"
#include <assert.h>
#include <audioclient.h> #include <audioclient.h>
#include <mmdeviceapi.h> #include <avrt.h>
#include <chrono>
#include <codecvt>
#include <comdef.h> #include <comdef.h>
#include <comip.h> #include <comip.h>
#include <avrt.h> #include <functional>
#include <ksmedia.h> #include <ksmedia.h>
#include <chrono>
#include <assert.h>
#include <codecvt>
#include <locale> #include <locale>
#include "common/snap_exception.hpp" #include <mmdeviceapi.h>
#include "common/aixlog.hpp"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -22,23 +22,23 @@ using namespace std::chrono_literals;
static constexpr auto LOG_TAG = "WASAPI"; static constexpr auto LOG_TAG = "WASAPI";
template<typename T> template <typename T>
struct COMMemDeleter struct COMMemDeleter
{ {
void operator() (T* obj) void operator()(T* obj)
{ {
if (obj != NULL) if (obj != NULL)
{ {
CoTaskMemFree(obj); CoTaskMemFree(obj);
obj = NULL; obj = NULL;
} }
} }
}; };
template<typename T> template <typename T>
using com_mem_ptr = unique_ptr<T, COMMemDeleter<T> >; using com_mem_ptr = unique_ptr<T, COMMemDeleter<T>>;
using com_handle = unique_ptr<void, function<BOOL(HANDLE)> >; using com_handle = unique_ptr<void, function<BOOL(HANDLE)>>;
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
@ -46,190 +46,184 @@ const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
const IID IID_IAudioClock = __uuidof(IAudioClock); const IID IID_IAudioClock = __uuidof(IAudioClock);
_COM_SMARTPTR_TYPEDEF(IMMDevice,__uuidof(IMMDevice)); _COM_SMARTPTR_TYPEDEF(IMMDevice, __uuidof(IMMDevice));
_COM_SMARTPTR_TYPEDEF(IMMDeviceCollection,__uuidof(IMMDeviceCollection)); _COM_SMARTPTR_TYPEDEF(IMMDeviceCollection, __uuidof(IMMDeviceCollection));
_COM_SMARTPTR_TYPEDEF(IMMDeviceEnumerator,__uuidof(IMMDeviceEnumerator)); _COM_SMARTPTR_TYPEDEF(IMMDeviceEnumerator, __uuidof(IMMDeviceEnumerator));
_COM_SMARTPTR_TYPEDEF(IAudioClient,__uuidof(IAudioClient)); _COM_SMARTPTR_TYPEDEF(IAudioClient, __uuidof(IAudioClient));
_COM_SMARTPTR_TYPEDEF(IPropertyStore,__uuidof(IPropertyStore)); _COM_SMARTPTR_TYPEDEF(IPropertyStore, __uuidof(IPropertyStore));
_COM_SMARTPTR_TYPEDEF(IAudioSessionManager, __uuidof(IAudioSessionManager)); _COM_SMARTPTR_TYPEDEF(IAudioSessionManager, __uuidof(IAudioSessionManager));
_COM_SMARTPTR_TYPEDEF(IAudioSessionControl, __uuidof(IAudioSessionControl)); _COM_SMARTPTR_TYPEDEF(IAudioSessionControl, __uuidof(IAudioSessionControl));
#define REFTIMES_PER_SEC 10000000 #define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000 #define REFTIMES_PER_MILLISEC 10000
EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd, { 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0 } }, 14 }; EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY PKEY_Device_FriendlyName = {{0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}}, 14};
#define CHECK_HR(hres) if(FAILED(hres)){stringstream ss;ss<<"HRESULT fault status: "<<hex<<(hres)<<" line "<<dec<<__LINE__<<endl; LOG(FATAL, LOG_TAG) << ss.str();throw SnapException(ss.str());} #define CHECK_HR(hres) \
if (FAILED(hres)) \
{ \
stringstream ss; \
ss << "HRESULT fault status: " << hex << (hres) << " line " << dec << __LINE__ << endl; \
LOG(FATAL, LOG_TAG) << ss.str(); \
throw SnapException(ss.str()); \
}
WASAPIPlayer::WASAPIPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream, ClientSettings::WasapiMode mode) : Player(pcmDevice, stream), mode_(mode) WASAPIPlayer::WASAPIPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream, ClientSettings::WasapiMode mode) : Player(pcmDevice, stream), mode_(mode)
{ {
HRESULT hr = CoInitializeEx( HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
NULL, CHECK_HR(hr);
COINIT_MULTITHREADED);
CHECK_HR(hr);
audioEventListener_ = new AudioSessionEventListener(); audioEventListener_ = new AudioSessionEventListener();
} }
WASAPIPlayer::~WASAPIPlayer() WASAPIPlayer::~WASAPIPlayer()
{ {
WASAPIPlayer::stop(); WASAPIPlayer::stop();
} }
inline PcmDevice convertToDevice(int idx, IMMDevicePtr& device) inline PcmDevice convertToDevice(int idx, IMMDevicePtr& device)
{ {
HRESULT hr; HRESULT hr;
PcmDevice desc; PcmDevice desc;
LPWSTR id = NULL; LPWSTR id = NULL;
hr = device->GetId(&id); hr = device->GetId(&id);
CHECK_HR(hr); CHECK_HR(hr);
IPropertyStorePtr properties = nullptr; IPropertyStorePtr properties = nullptr;
hr = device->OpenPropertyStore(STGM_READ, &properties); hr = device->OpenPropertyStore(STGM_READ, &properties);
PROPVARIANT deviceName; PROPVARIANT deviceName;
PropVariantInit(&deviceName); PropVariantInit(&deviceName);
hr = properties->GetValue(PKEY_Device_FriendlyName, &deviceName); hr = properties->GetValue(PKEY_Device_FriendlyName, &deviceName);
CHECK_HR(hr); CHECK_HR(hr);
desc.idx = idx; desc.idx = idx;
desc.name = wstring_convert<codecvt_utf8<wchar_t>, wchar_t>().to_bytes(id); desc.name = wstring_convert<codecvt_utf8<wchar_t>, wchar_t>().to_bytes(id);
desc.description = wstring_convert<codecvt_utf8<wchar_t>, wchar_t>().to_bytes(deviceName.pwszVal); desc.description = wstring_convert<codecvt_utf8<wchar_t>, wchar_t>().to_bytes(deviceName.pwszVal);
CoTaskMemFree(id); CoTaskMemFree(id);
return desc; return desc;
} }
vector<PcmDevice> WASAPIPlayer::pcm_list() vector<PcmDevice> WASAPIPlayer::pcm_list()
{ {
HRESULT hr; HRESULT hr;
IMMDeviceCollectionPtr devices = nullptr; IMMDeviceCollectionPtr devices = nullptr;
IMMDeviceEnumeratorPtr deviceEnumerator = nullptr; IMMDeviceEnumeratorPtr deviceEnumerator = nullptr;
hr = CoInitializeEx(
NULL,
COINIT_MULTITHREADED);
if (hr != CO_E_ALREADYINITIALIZED)
CHECK_HR(hr);
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_SERVER, IID_IMMDeviceEnumerator,
(void**)&deviceEnumerator);
CHECK_HR(hr);
hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices); hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECK_HR(hr); if (hr != CO_E_ALREADYINITIALIZED)
CHECK_HR(hr);
UINT deviceCount; hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_SERVER, IID_IMMDeviceEnumerator, (void**)&deviceEnumerator);
devices->GetCount(&deviceCount); CHECK_HR(hr);
if (deviceCount == 0) hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);
throw SnapException("no valid devices"); CHECK_HR(hr);
vector<PcmDevice> deviceList;
{
IMMDevicePtr defaultDevice = nullptr;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
CHECK_HR(hr);
auto dev = convertToDevice(0, defaultDevice); UINT deviceCount;
dev.name = "default"; devices->GetCount(&deviceCount);
deviceList.push_back(dev);
}
for (UINT i = 0; i < deviceCount; ++i)
{
IMMDevicePtr device = nullptr;
hr = devices->Item(i, &device); if (deviceCount == 0)
CHECK_HR(hr); throw SnapException("no valid devices");
deviceList.push_back(convertToDevice(i+1, device));
}
return deviceList; vector<PcmDevice> deviceList;
{
IMMDevicePtr defaultDevice = nullptr;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
CHECK_HR(hr);
auto dev = convertToDevice(0, defaultDevice);
dev.name = "default";
deviceList.push_back(dev);
}
for (UINT i = 0; i < deviceCount; ++i)
{
IMMDevicePtr device = nullptr;
hr = devices->Item(i, &device);
CHECK_HR(hr);
deviceList.push_back(convertToDevice(i + 1, device));
}
return deviceList;
} }
void WASAPIPlayer::worker() void WASAPIPlayer::worker()
{ {
assert(sizeof(char) == sizeof(BYTE)); assert(sizeof(char) == sizeof(BYTE));
HRESULT hr;
// Create the format specifier HRESULT hr;
com_mem_ptr<WAVEFORMATEX> waveformat((WAVEFORMATEX*)(CoTaskMemAlloc(sizeof(WAVEFORMATEX))));
waveformat->wFormatTag = WAVE_FORMAT_PCM;
waveformat->nChannels = stream_->getFormat().channels();
waveformat->nSamplesPerSec = stream_->getFormat().rate();
waveformat->wBitsPerSample = stream_->getFormat().bits();
waveformat->nBlockAlign = waveformat->nChannels * waveformat->wBitsPerSample / 8; // Create the format specifier
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nBlockAlign; com_mem_ptr<WAVEFORMATEX> waveformat((WAVEFORMATEX*)(CoTaskMemAlloc(sizeof(WAVEFORMATEX))));
waveformat->wFormatTag = WAVE_FORMAT_PCM;
waveformat->nChannels = stream_->getFormat().channels();
waveformat->nSamplesPerSec = stream_->getFormat().rate();
waveformat->wBitsPerSample = stream_->getFormat().bits();
waveformat->cbSize = 0; waveformat->nBlockAlign = waveformat->nChannels * waveformat->wBitsPerSample / 8;
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nBlockAlign;
com_mem_ptr<WAVEFORMATEXTENSIBLE> waveformatExtended((WAVEFORMATEXTENSIBLE*)(CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)))); waveformat->cbSize = 0;
waveformatExtended->Format = *waveformat;
waveformatExtended->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; com_mem_ptr<WAVEFORMATEXTENSIBLE> waveformatExtended((WAVEFORMATEXTENSIBLE*)(CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE))));
waveformatExtended->Format.cbSize = 22; waveformatExtended->Format = *waveformat;
waveformatExtended->Samples.wValidBitsPerSample = waveformat->wBitsPerSample; waveformatExtended->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
waveformatExtended->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; waveformatExtended->Format.cbSize = 22;
waveformatExtended->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; waveformatExtended->Samples.wValidBitsPerSample = waveformat->wBitsPerSample;
waveformatExtended->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
waveformatExtended->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
// Retrieve the device enumerator // Retrieve the device enumerator
IMMDeviceEnumeratorPtr deviceEnumerator = nullptr; IMMDeviceEnumeratorPtr deviceEnumerator = nullptr;
hr = CoCreateInstance( hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_SERVER, IID_IMMDeviceEnumerator, (void**)&deviceEnumerator);
CLSID_MMDeviceEnumerator, NULL, CHECK_HR(hr);
CLSCTX_SERVER, IID_IMMDeviceEnumerator,
(void**)&deviceEnumerator);
CHECK_HR(hr);
// Register the default playback device (eRender for playback) // Register the default playback device (eRender for playback)
IMMDevicePtr device = nullptr; IMMDevicePtr device = nullptr;
if (pcmDevice_.idx == 0) if (pcmDevice_.idx == 0)
{ {
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
CHECK_HR(hr); CHECK_HR(hr);
} }
else else
{ {
IMMDeviceCollectionPtr devices = nullptr; IMMDeviceCollectionPtr devices = nullptr;
hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices); hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);
CHECK_HR(hr); CHECK_HR(hr);
devices->Item(pcmDevice_.idx-1, &device); devices->Item(pcmDevice_.idx - 1, &device);
} }
IPropertyStorePtr properties = nullptr; IPropertyStorePtr properties = nullptr;
hr = device->OpenPropertyStore(STGM_READ, &properties); hr = device->OpenPropertyStore(STGM_READ, &properties);
CHECK_HR(hr); CHECK_HR(hr);
PROPVARIANT format; PROPVARIANT format;
hr = properties->GetValue(PKEY_AudioEngine_DeviceFormat, &format); hr = properties->GetValue(PKEY_AudioEngine_DeviceFormat, &format);
CHECK_HR(hr); CHECK_HR(hr);
PWAVEFORMATEX formatEx = (PWAVEFORMATEX)format.blob.pBlobData; PWAVEFORMATEX formatEx = (PWAVEFORMATEX)format.blob.pBlobData;
LOG(INFO, LOG_TAG) << "Device accepts format: " << formatEx->nSamplesPerSec << ":" << formatEx->wBitsPerSample << ":" << formatEx->nChannels << "\n"; LOG(INFO, LOG_TAG) << "Device accepts format: " << formatEx->nSamplesPerSec << ":" << formatEx->wBitsPerSample << ":" << formatEx->nChannels << "\n";
// Activate the device // Activate the device
IAudioClientPtr audioClient = nullptr; IAudioClientPtr audioClient = nullptr;
hr = device->Activate(IID_IAudioClient, CLSCTX_SERVER, NULL, (void**)&audioClient); hr = device->Activate(IID_IAudioClient, CLSCTX_SERVER, NULL, (void**)&audioClient);
CHECK_HR(hr); CHECK_HR(hr);
if(mode_ == ClientSettings::WasapiMode::EXCLUSIVE) if (mode_ == ClientSettings::WasapiMode::EXCLUSIVE)
{ {
hr = audioClient->IsFormatSupported( hr = audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &(waveformatExtended->Format), NULL);
AUDCLNT_SHAREMODE_EXCLUSIVE, CHECK_HR(hr);
&(waveformatExtended->Format), }
NULL);
CHECK_HR(hr);
}
IAudioSessionManagerPtr sessionManager = nullptr; IAudioSessionManagerPtr sessionManager = nullptr;
// Get the session manager for the endpoint device. // Get the session manager for the endpoint device.
hr = device->Activate(__uuidof(IAudioSessionManager), CLSCTX_INPROC_SERVER, NULL, (void**)&sessionManager); hr = device->Activate(__uuidof(IAudioSessionManager), CLSCTX_INPROC_SERVER, NULL, (void**)&sessionManager);
CHECK_HR(hr); CHECK_HR(hr);
@ -245,100 +239,83 @@ void WASAPIPlayer::worker()
// register // register
hr = control->RegisterAudioSessionNotification(audioEventListener_); hr = control->RegisterAudioSessionNotification(audioEventListener_);
CHECK_HR(hr); CHECK_HR(hr);
// Get the device period
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
hr = audioClient->GetDevicePeriod(NULL, &hnsRequestedDuration);
CHECK_HR(hr);
LOG(INFO, LOG_TAG) << "Initializing WASAPI in " << (mode_ == ClientSettings::WasapiMode::SHARED ? "shared" : "exclusive") << " mode\n";
_AUDCLNT_SHAREMODE share_mode = mode_ == ClientSettings::WasapiMode::SHARED ? AUDCLNT_SHAREMODE_SHARED : AUDCLNT_SHAREMODE_EXCLUSIVE; // Get the device period
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
hr = audioClient->GetDevicePeriod(NULL, &hnsRequestedDuration);
CHECK_HR(hr);
LOG(INFO, LOG_TAG) << "Initializing WASAPI in " << (mode_ == ClientSettings::WasapiMode::SHARED ? "shared" : "exclusive") << " mode\n";
_AUDCLNT_SHAREMODE share_mode = mode_ == ClientSettings::WasapiMode::SHARED ? AUDCLNT_SHAREMODE_SHARED : AUDCLNT_SHAREMODE_EXCLUSIVE;
DWORD stream_flags = mode_ == ClientSettings::WasapiMode::SHARED DWORD stream_flags = mode_ == ClientSettings::WasapiMode::SHARED
? AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
: AUDCLNT_STREAMFLAGS_EVENTCALLBACK; : AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
// Initialize the client at minimum latency // Initialize the client at minimum latency
hr = audioClient->Initialize( hr = audioClient->Initialize(share_mode, stream_flags, hnsRequestedDuration, hnsRequestedDuration, &(waveformatExtended->Format), NULL);
share_mode,
stream_flags,
hnsRequestedDuration,
hnsRequestedDuration,
&(waveformatExtended->Format),
NULL);
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
{ {
UINT32 alignedBufferSize; UINT32 alignedBufferSize;
hr = audioClient->GetBufferSize(&alignedBufferSize); hr = audioClient->GetBufferSize(&alignedBufferSize);
CHECK_HR(hr); CHECK_HR(hr);
audioClient.Attach(NULL, false); audioClient.Attach(NULL, false);
hnsRequestedDuration = (REFERENCE_TIME)((10000.0 * 1000 / waveformatExtended->Format.nSamplesPerSec * alignedBufferSize) + 0.5); hnsRequestedDuration = (REFERENCE_TIME)((10000.0 * 1000 / waveformatExtended->Format.nSamplesPerSec * alignedBufferSize) + 0.5);
hr = device->Activate(IID_IAudioClient, CLSCTX_SERVER, NULL, (void**)&audioClient); hr = device->Activate(IID_IAudioClient, CLSCTX_SERVER, NULL, (void**)&audioClient);
CHECK_HR(hr); CHECK_HR(hr);
hr = audioClient->Initialize( hr = audioClient->Initialize(share_mode, stream_flags, hnsRequestedDuration, hnsRequestedDuration, &(waveformatExtended->Format), NULL);
share_mode, }
stream_flags, CHECK_HR(hr);
hnsRequestedDuration,
hnsRequestedDuration,
&(waveformatExtended->Format),
NULL);
}
CHECK_HR(hr);
// Register an event to refill the buffer // Register an event to refill the buffer
com_handle eventHandle(CreateEvent(NULL, FALSE, FALSE, NULL), &::CloseHandle); com_handle eventHandle(CreateEvent(NULL, FALSE, FALSE, NULL), &::CloseHandle);
if (eventHandle == NULL) if (eventHandle == NULL)
CHECK_HR(E_FAIL); CHECK_HR(E_FAIL);
hr = audioClient->SetEventHandle(HANDLE(eventHandle.get())); hr = audioClient->SetEventHandle(HANDLE(eventHandle.get()));
CHECK_HR(hr); CHECK_HR(hr);
// Get size of buffer // Get size of buffer
UINT32 bufferFrameCount; UINT32 bufferFrameCount;
hr = audioClient->GetBufferSize(&bufferFrameCount); hr = audioClient->GetBufferSize(&bufferFrameCount);
CHECK_HR(hr); CHECK_HR(hr);
// Get the rendering service // Get the rendering service
IAudioRenderClient* renderClient = NULL; IAudioRenderClient* renderClient = NULL;
hr = audioClient->GetService( hr = audioClient->GetService(IID_IAudioRenderClient, (void**)&renderClient);
IID_IAudioRenderClient, CHECK_HR(hr);
(void**)&renderClient);
CHECK_HR(hr);
// Grab the clock service // Grab the clock service
IAudioClock* clock = NULL; IAudioClock* clock = NULL;
hr = audioClient->GetService( hr = audioClient->GetService(IID_IAudioClock, (void**)&clock);
IID_IAudioClock, CHECK_HR(hr);
(void**)&clock);
CHECK_HR(hr);
// Boost our priority // Boost our priority
DWORD taskIndex = 0; DWORD taskIndex = 0;
com_handle taskHandle(AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &taskIndex), com_handle taskHandle(AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &taskIndex), &::AvRevertMmThreadCharacteristics);
&::AvRevertMmThreadCharacteristics); if (taskHandle == NULL)
if (taskHandle == NULL) CHECK_HR(E_FAIL);
CHECK_HR(E_FAIL);
// And, action! // And, action!
hr = audioClient->Start(); hr = audioClient->Start();
CHECK_HR(hr); CHECK_HR(hr);
size_t bufferSize = bufferFrameCount * waveformatExtended->Format.nBlockAlign; size_t bufferSize = bufferFrameCount * waveformatExtended->Format.nBlockAlign;
BYTE* buffer; BYTE* buffer;
unique_ptr<char[]> queueBuffer(new char[bufferSize]); unique_ptr<char[]> queueBuffer(new char[bufferSize]);
UINT64 position = 0, bufferPosition = 0, frequency; UINT64 position = 0, bufferPosition = 0, frequency;
clock->GetFrequency(&frequency); clock->GetFrequency(&frequency);
while (active_) while (active_)
{ {
DWORD returnVal = WaitForSingleObject(eventHandle.get(), 2000); DWORD returnVal = WaitForSingleObject(eventHandle.get(), 2000);
if (returnVal != WAIT_OBJECT_0) if (returnVal != WAIT_OBJECT_0)
{ {
//stop(); // stop();
LOG(INFO, LOG_TAG) << "Got timeout waiting for audio device callback\n"; LOG(INFO, LOG_TAG) << "Got timeout waiting for audio device callback\n";
CHECK_HR(ERROR_TIMEOUT); CHECK_HR(ERROR_TIMEOUT);
hr = audioClient->Stop(); hr = audioClient->Stop();
CHECK_HR(hr); CHECK_HR(hr);
hr = audioClient->Reset(); hr = audioClient->Reset();
CHECK_HR(hr); CHECK_HR(hr);
@ -350,61 +327,59 @@ void WASAPIPlayer::worker()
CHECK_HR(hr); CHECK_HR(hr);
bufferPosition = 0; bufferPosition = 0;
break; break;
} }
// Thread was sleeping above, double check that we are still running // Thread was sleeping above, double check that we are still running
if (!active_) if (!active_)
break; break;
// update our volume from IAudioControl // update our volume from IAudioControl
volCorrection_ = audioEventListener_->getVolume(); volCorrection_ = audioEventListener_->getVolume();
clock->GetPosition(&position, NULL); clock->GetPosition(&position, NULL);
UINT32 padding = 0; UINT32 padding = 0;
if(mode_ == ClientSettings::WasapiMode::SHARED) if (mode_ == ClientSettings::WasapiMode::SHARED)
{ {
hr = audioClient->GetCurrentPadding(&padding); hr = audioClient->GetCurrentPadding(&padding);
CHECK_HR(hr); CHECK_HR(hr);
} }
int available = bufferFrameCount - padding; int available = bufferFrameCount - padding;
if (stream_->getPlayerChunk(queueBuffer.get(), microseconds( if (stream_->getPlayerChunk(queueBuffer.get(),
((bufferPosition * 1000000) / waveformat->nSamplesPerSec) - microseconds(((bufferPosition * 1000000) / waveformat->nSamplesPerSec) - ((position * 1000000) / frequency)), available))
((position * 1000000) / frequency)), {
available)) if (available > 0)
{ {
if (available > 0) adjustVolume(queueBuffer.get(), available);
{ hr = renderClient->GetBuffer(available, &buffer);
adjustVolume(queueBuffer.get(), available); CHECK_HR(hr);
hr = renderClient->GetBuffer(available, &buffer); memcpy(buffer, queueBuffer.get(), bufferSize);
CHECK_HR(hr); hr = renderClient->ReleaseBuffer(available, 0);
memcpy(buffer, queueBuffer.get(), bufferSize); CHECK_HR(hr);
hr = renderClient->ReleaseBuffer(available, 0);
CHECK_HR(hr); bufferPosition += available;
}
bufferPosition += available; }
} else
} {
else std::clog << static_cast<AixLog::Severity>(INFO) << AixLog::Tag(LOG_TAG);
{ LOG(INFO, LOG_TAG) << "Failed to get chunk\n";
std::clog << static_cast<AixLog::Severity>(INFO) << AixLog::Tag(LOG_TAG);
LOG(INFO, LOG_TAG) << "Failed to get chunk\n"; hr = audioClient->Stop();
CHECK_HR(hr);
hr = audioClient->Stop(); hr = audioClient->Reset();
CHECK_HR(hr); CHECK_HR(hr);
hr = audioClient->Reset();
CHECK_HR(hr); while (active_ && !stream_->waitForChunk(std::chrono::milliseconds(100)))
LOG(INFO, LOG_TAG) << "Waiting for chunk\n";
while (active_ && !stream_->waitForChunk(std::chrono::milliseconds(100)))
LOG(INFO, LOG_TAG) << "Waiting for chunk\n"; hr = audioClient->Start();
CHECK_HR(hr);
hr = audioClient->Start(); bufferPosition = 0;
CHECK_HR(hr); }
bufferPosition = 0; }
}
}
} }
HRESULT STDMETHODCALLTYPE AudioSessionEventListener::QueryInterface(REFIID riid, VOID** ppvInterface) HRESULT STDMETHODCALLTYPE AudioSessionEventListener::QueryInterface(REFIID riid, VOID** ppvInterface)

View file

@ -18,9 +18,9 @@
#ifndef WASAPI_PLAYER_H #ifndef WASAPI_PLAYER_H
#define WASAPI_PLAYER_H #define WASAPI_PLAYER_H
#include "client_settings.hpp"
#include "player.hpp" #include "player.hpp"
#include <audiopolicy.h> #include <audiopolicy.h>
#include "client_settings.hpp"
class AudioSessionEventListener : public IAudioSessionEvents class AudioSessionEventListener : public IAudioSessionEvents
{ {
@ -94,11 +94,12 @@ class WASAPIPlayer : public Player
{ {
public: public:
WASAPIPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream, ClientSettings::WasapiMode mode); WASAPIPlayer(const PcmDevice& pcmDevice, std::shared_ptr<Stream> stream, ClientSettings::WasapiMode mode);
virtual ~WASAPIPlayer(); virtual ~WASAPIPlayer();
static std::vector<PcmDevice> pcm_list(void); static std::vector<PcmDevice> pcm_list(void);
protected: protected:
virtual void worker(); virtual void worker();
private: private:
AudioSessionEventListener* audioEventListener_; AudioSessionEventListener* audioEventListener_;

View file

@ -245,27 +245,28 @@ int main(int argc, char** argv)
#ifdef HAS_WASAPI #ifdef HAS_WASAPI
if (wasapi_mode->is_set()) if (wasapi_mode->is_set())
{ {
settings.player.wasapi_mode = (strcmp(wasapi_mode->value().c_str(), "exclusive") == 0) ? settings.player.wasapi_mode =
ClientSettings::WasapiMode::EXCLUSIVE : ClientSettings::WasapiMode::SHARED; (strcmp(wasapi_mode->value().c_str(), "exclusive") == 0) ? ClientSettings::WasapiMode::EXCLUSIVE : ClientSettings::WasapiMode::SHARED;
} }
#endif #endif
bool active = true; bool active = true;
std::shared_ptr<Controller> controller; std::shared_ptr<Controller> controller;
auto signal_handler = install_signal_handler({ auto signal_handler = install_signal_handler(
{
#ifndef WINDOWS // no sighup on windows #ifndef WINDOWS // no sighup on windows
SIGHUP, SIGHUP,
#endif #endif
SIGTERM, SIGINT}, SIGTERM, SIGINT},
[&active, &controller](int signal, const std::string& strsignal) { [&active, &controller](int signal, const std::string& strsignal) {
SLOG(INFO) << "Received signal " << signal << ": " << strsignal << "\n"; SLOG(INFO) << "Received signal " << signal << ": " << strsignal << "\n";
active = false; active = false;
if (controller) if (controller)
{ {
LOG(INFO) << "Stopping controller\n"; LOG(INFO) << "Stopping controller\n";
controller->stop(); controller->stop();
} }
}); });
if (settings.server.host.empty()) if (settings.server.host.empty())
{ {
#if defined(HAS_AVAHI) || defined(HAS_BONJOUR) #if defined(HAS_AVAHI) || defined(HAS_BONJOUR)

View file

@ -38,11 +38,11 @@
#include <fstream> #include <fstream>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <map>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <map>
#include <thread>
#include <sstream> #include <sstream>
#include <thread>
#include <vector> #include <vector>
#ifdef __ANDROID__ #ifdef __ANDROID__
@ -109,9 +109,10 @@
#define TIMESTAMP AixLog::Timestamp(std::chrono::system_clock::now()) #define TIMESTAMP AixLog::Timestamp(std::chrono::system_clock::now())
// stijnvdb: sorry! :) LOG(SEV, "tag") was not working for Windows and I couldn't figure out how to fix it for windows without potentially breaking everything else... // stijnvdb: sorry! :) LOG(SEV, "tag") was not working for Windows and I couldn't figure out how to fix it for windows without potentially breaking everything
// else...
// https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros (Jason Deng) // https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros (Jason Deng)
#ifdef WIN32 #ifdef WIN32
#define LOG_2(severity, tag) AIXLOG_INTERNAL__LOG_SEVERITY_TAG(severity, tag) #define LOG_2(severity, tag) AIXLOG_INTERNAL__LOG_SEVERITY_TAG(severity, tag)
#define LOG_1(severity) AIXLOG_INTERNAL__LOG_SEVERITY(severity) #define LOG_1(severity) AIXLOG_INTERNAL__LOG_SEVERITY(severity)
#define LOG_0() LOG_1(0) #define LOG_0() LOG_1(0)

View file

@ -36,7 +36,7 @@
namespace chronos namespace chronos
{ {
using clk = using clk =
#ifndef WINDOWS #ifndef WINDOWS
std::chrono::steady_clock; std::chrono::steady_clock;
#else #else
@ -108,7 +108,7 @@ inline ToDuration diff(const timeval& tv1, const timeval& tv2)
inline static long getTickCount() inline static long getTickCount()
{ {
#if defined (MACOS) #if defined(MACOS)
clock_serv_t cclock; clock_serv_t cclock;
mach_timespec_t mts; mach_timespec_t mts;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);

View file

@ -36,8 +36,8 @@
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <unistd.h>
#endif #endif
#include <sstream> #include <sstream>
#include <string> #include <string>
@ -58,11 +58,11 @@
#endif #endif
#ifdef WINDOWS #ifdef WINDOWS
#include <chrono> #include <chrono>
#include <windows.h>
#include <direct.h> #include <direct.h>
#include <winsock2.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#include <versionhelpers.h> #include <versionhelpers.h>
#include <windows.h>
#include <winsock2.h>
#endif #endif