Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Conflicts: # Graphics/screenshot.png # README.md
- Loading branch information
Showing
44 changed files
with
2,568 additions
and
1,036 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -194,3 +194,5 @@ FakesAssemblies/ | |
|
||
# Visual Studio 6 workspace options file | ||
*.opt | ||
/EarTrumpet.VC.VC.opendb | ||
/EarTrumpet.VC.db |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
#include "common.h" | ||
#include "Mmdeviceapi.h" | ||
#include "AudioDeviceService.h" | ||
#include "Functiondiscoverykeys_devpkey.h" | ||
#include "PolicyConfig.h" | ||
#include "Propidl.h" | ||
#include "Endpointvolume.h" | ||
|
||
using namespace std; | ||
using namespace std::tr1; | ||
using namespace EarTrumpet::Interop; | ||
|
||
AudioDeviceService* AudioDeviceService::__instance = nullptr; | ||
|
||
void AudioDeviceService::CleanUpAudioDevices() | ||
{ | ||
for (auto device = _devices.begin(); device != _devices.end(); device++) | ||
{ | ||
CoTaskMemFree(device->Id); | ||
CoTaskMemFree(device->DisplayName); | ||
} | ||
|
||
_devices.clear(); | ||
} | ||
|
||
HRESULT AudioDeviceService::RefreshAudioDevices() | ||
{ | ||
CleanUpAudioDevices(); | ||
|
||
CComPtr<IMMDeviceEnumerator> deviceEnumerator; | ||
FAST_FAIL(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&deviceEnumerator))); | ||
|
||
CComPtr<IMMDeviceCollection> deviceCollection; | ||
FAST_FAIL(deviceEnumerator->EnumAudioEndpoints(EDataFlow::eRender, ERole::eMultimedia, &deviceCollection)); | ||
|
||
CComPtr<IMMDevice> defaultDevice; | ||
FAST_FAIL(deviceEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &defaultDevice)); | ||
|
||
CComHeapPtr<wchar_t> defaultDeviceId; | ||
FAST_FAIL(defaultDevice->GetId(&defaultDeviceId)); | ||
|
||
UINT numDevices; | ||
FAST_FAIL(deviceCollection->GetCount(&numDevices)); | ||
|
||
for (UINT i = 0; i < numDevices; i++) | ||
{ | ||
CComPtr<IMMDevice> device; | ||
if (FAILED(deviceCollection->Item(i, &device))) | ||
{ | ||
continue; | ||
} | ||
|
||
CComHeapPtr<wchar_t> deviceId; | ||
FAST_FAIL(device->GetId(&deviceId)); | ||
|
||
CComPtr<IPropertyStore> propertyStore; | ||
FAST_FAIL(device->OpenPropertyStore(STGM_READ, &propertyStore)); | ||
|
||
PROPVARIANT friendlyName; | ||
PropVariantInit(&friendlyName); | ||
FAST_FAIL(propertyStore->GetValue(PKEY_Device_FriendlyName, &friendlyName)); | ||
|
||
CComPtr<IAudioEndpointVolume> audioEndpointVol; | ||
FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); | ||
|
||
BOOL isMuted; | ||
FAST_FAIL(audioEndpointVol->GetMute(&isMuted)); | ||
|
||
EarTrumpetAudioDevice audioDevice = {}; | ||
FAST_FAIL(SHStrDup(friendlyName.pwszVal, &audioDevice.DisplayName)); | ||
FAST_FAIL(SHStrDup(deviceId, &audioDevice.Id)); | ||
audioDevice.IsDefault = (wcscmp(defaultDeviceId, deviceId) == 0); | ||
audioDevice.IsMuted = !!isMuted; | ||
_devices.push_back(audioDevice); | ||
|
||
PropVariantClear(&friendlyName); | ||
} | ||
|
||
return S_OK; | ||
} | ||
|
||
HRESULT AudioDeviceService::SetDefaultAudioDevice(LPWSTR deviceId) | ||
{ | ||
CComPtr<IPolicyConfig> policyConfig; | ||
FAST_FAIL(CoCreateInstance(__uuidof(CPolicyConfigClient), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&policyConfig))); | ||
return policyConfig->SetDefaultEndpoint(deviceId, ERole::eMultimedia); | ||
} | ||
|
||
HRESULT AudioDeviceService::GetDeviceByDeviceId(PWSTR deviceId, IMMDevice** device) | ||
{ | ||
CComPtr<IMMDeviceEnumerator> deviceEnumerator; | ||
FAST_FAIL(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&deviceEnumerator))); | ||
|
||
return deviceEnumerator->GetDevice(deviceId, device); | ||
} | ||
|
||
HRESULT AudioDeviceService::GetAudioDeviceVolume(LPWSTR deviceId, float* volume) | ||
{ | ||
CComPtr<IMMDevice> device; | ||
FAST_FAIL(this->GetDeviceByDeviceId(deviceId, &device)); | ||
|
||
CComPtr<IAudioEndpointVolume> audioEndpointVol; | ||
FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); | ||
|
||
return audioEndpointVol->GetMasterVolumeLevelScalar(volume); | ||
} | ||
|
||
HRESULT AudioDeviceService::SetAudioDeviceVolume(LPWSTR deviceId, float volume) | ||
{ | ||
CComPtr<IMMDevice> device; | ||
FAST_FAIL(this->GetDeviceByDeviceId(deviceId, &device)); | ||
|
||
CComPtr<IAudioEndpointVolume> audioEndpointVol; | ||
FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); | ||
|
||
return audioEndpointVol->SetMasterVolumeLevelScalar(volume, nullptr); | ||
} | ||
|
||
HRESULT AudioDeviceService::GetAudioDevices(void** audioDevices) | ||
{ | ||
if (_devices.size() == 0) | ||
{ | ||
return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); | ||
} | ||
|
||
*audioDevices = &_devices[0]; | ||
return S_OK; | ||
} | ||
|
||
HRESULT AudioDeviceService::SetMuteBoolForDevice(LPWSTR deviceId, BOOL value) | ||
{ | ||
CComPtr<IMMDevice> device; | ||
FAST_FAIL(this->GetDeviceByDeviceId(deviceId, &device)); | ||
|
||
CComPtr<IAudioEndpointVolume> audioEndpointVol; | ||
FAST_FAIL(device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC, nullptr, reinterpret_cast<void**>(&audioEndpointVol))); | ||
|
||
return audioEndpointVol->SetMute(value, nullptr); | ||
} | ||
|
||
HRESULT AudioDeviceService::MuteAudioDevice(LPWSTR deviceId) | ||
{ | ||
return SetMuteBoolForDevice(deviceId, TRUE); | ||
} | ||
|
||
HRESULT AudioDeviceService::UnmuteAudioDevice(LPWSTR deviceId) | ||
{ | ||
return SetMuteBoolForDevice(deviceId, FALSE); | ||
} | ||
|
||
int AudioDeviceService::GetAudioDeviceCount() | ||
{ | ||
return _devices.size(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#pragma once | ||
|
||
namespace EarTrumpet | ||
{ | ||
namespace Interop | ||
{ | ||
struct EarTrumpetAudioDevice | ||
{ | ||
LPWSTR Id; | ||
LPWSTR DisplayName; | ||
bool IsDefault; | ||
bool IsMuted; | ||
}; | ||
|
||
class AudioDeviceService | ||
{ | ||
private: | ||
static AudioDeviceService* __instance; | ||
std::vector<EarTrumpetAudioDevice> _devices; | ||
|
||
void CleanUpAudioDevices(); | ||
HRESULT GetDeviceByDeviceId(PWSTR deviceId, IMMDevice** device); | ||
HRESULT SetMuteBoolForDevice(LPWSTR deviceId, BOOL value); | ||
|
||
public: | ||
static AudioDeviceService* instance() | ||
{ | ||
if (!__instance) | ||
{ | ||
__instance = new AudioDeviceService; | ||
} | ||
return __instance; | ||
} | ||
|
||
HRESULT GetAudioDevices(void** audioDevices); | ||
HRESULT GetAudioDeviceVolume(LPWSTR deviceId, float* volume); | ||
HRESULT SetAudioDeviceVolume(LPWSTR deviceId, float volume); | ||
HRESULT SetDefaultAudioDevice(LPWSTR deviceId); | ||
HRESULT MuteAudioDevice(LPWSTR deviceId); | ||
HRESULT UnmuteAudioDevice(LPWSTR deviceId); | ||
HRESULT RefreshAudioDevices(); | ||
int GetAudioDeviceCount(); | ||
}; | ||
} | ||
} |
Oops, something went wrong.