Skip to content

Commit

Permalink
src/output: add algorithm for finding usable AudioFormat
Browse files Browse the repository at this point in the history
* Add ComWorker to run all COM relative function in same thread
* Use WinEvent for as a condition_variable without lock

See MusicPlayerDaemon#967
  • Loading branch information
ibmibmibm committed Nov 26, 2020
1 parent ac4975c commit 8eee6f4
Show file tree
Hide file tree
Showing 8 changed files with 550 additions and 342 deletions.
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ sources = [
'src/LogInit.cxx',
'src/ls.cxx',
'src/Instance.cxx',
'src/win32/ComWorker.cxx',
'src/win32/Win32Main.cxx',
'src/MusicBuffer.cxx',
'src/MusicPipe.cxx',
Expand Down
157 changes: 84 additions & 73 deletions src/mixer/plugins/WasapiMixerPlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#include "mixer/MixerInternal.hxx"
#include "output/plugins/WasapiOutputPlugin.hxx"
#include "win32/Com.hxx"
#include "win32/ComWorker.hxx"
#include "win32/HResult.hxx"

#include <cmath>
Expand All @@ -28,92 +28,103 @@

class WasapiMixer final : public Mixer {
WasapiOutput &output;
std::optional<COM> com;

public:
WasapiMixer(WasapiOutput &_output, MixerListener &_listener)
: Mixer(wasapi_mixer_plugin, _listener), output(_output) {}

void Open() override { com.emplace(); }
void Open() override {}

void Close() noexcept override { com.reset(); }
void Close() noexcept override {}

int GetVolume() override {
HRESULT result;
float volume_level;

if (wasapi_is_exclusive(output)) {
ComPtr<IAudioEndpointVolume> endpoint_volume;
result = wasapi_output_get_device(output)->Activate(
__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr,
endpoint_volume.AddressCast());
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to get device endpoint volume");
auto future = COMWorker::Async([&]() -> int {
HRESULT result;
float volume_level;

if (wasapi_is_exclusive(output)) {
ComPtr<IAudioEndpointVolume> endpoint_volume;
result = wasapi_output_get_device(output)->Activate(
__uuidof(IAudioEndpointVolume), CLSCTX_ALL,
nullptr, endpoint_volume.AddressCast());
if (FAILED(result)) {
throw FormatHResultError(result,
"Unable to get device "
"endpoint volume");
}

result = endpoint_volume->GetMasterVolumeLevelScalar(
&volume_level);
if (FAILED(result)) {
throw FormatHResultError(result,
"Unable to get master "
"volume level");
}
} else {
ComPtr<ISimpleAudioVolume> session_volume;
result = wasapi_output_get_client(output)->GetService(
__uuidof(ISimpleAudioVolume),
session_volume.AddressCast<void>());
if (FAILED(result)) {
throw FormatHResultError(result,
"Unable to get client "
"session volume");
}

result = session_volume->GetMasterVolume(&volume_level);
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to get master volume");
}
}

result = endpoint_volume->GetMasterVolumeLevelScalar(
&volume_level);
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to get master volume level");
}
} else {
ComPtr<ISimpleAudioVolume> session_volume;
result = wasapi_output_get_client(output)->GetService(
__uuidof(ISimpleAudioVolume),
session_volume.AddressCast<void>());
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to get client session volume");
}

result = session_volume->GetMasterVolume(&volume_level);
if (FAILED(result)) {
throw FormatHResultError(result,
"Unable to get master volume");
}
}

return std::lround(volume_level * 100.0f);
return std::lround(volume_level * 100.0f);
});
return future.get();
}

void SetVolume(unsigned volume) override {
HRESULT result;
const float volume_level = volume / 100.0f;

if (wasapi_is_exclusive(output)) {
ComPtr<IAudioEndpointVolume> endpoint_volume;
result = wasapi_output_get_device(output)->Activate(
__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr,
endpoint_volume.AddressCast());
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to get device endpoint volume");
}

result = endpoint_volume->SetMasterVolumeLevelScalar(volume_level,
nullptr);
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to set master volume level");
}
} else {
ComPtr<ISimpleAudioVolume> session_volume;
result = wasapi_output_get_client(output)->GetService(
__uuidof(ISimpleAudioVolume),
session_volume.AddressCast<void>());
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to get client session volume");
}

result = session_volume->SetMasterVolume(volume_level, nullptr);
if (FAILED(result)) {
throw FormatHResultError(result,
"Unable to set master volume");
COMWorker::Async([&]() {
HRESULT result;
const float volume_level = volume / 100.0f;

if (wasapi_is_exclusive(output)) {
ComPtr<IAudioEndpointVolume> endpoint_volume;
result = wasapi_output_get_device(output)->Activate(
__uuidof(IAudioEndpointVolume), CLSCTX_ALL,
nullptr, endpoint_volume.AddressCast());
if (FAILED(result)) {
throw FormatHResultError(
result,
"Unable to get device endpoint volume");
}

result = endpoint_volume->SetMasterVolumeLevelScalar(
volume_level, nullptr);
if (FAILED(result)) {
throw FormatHResultError(
result,
"Unable to set master volume level");
}
} else {
ComPtr<ISimpleAudioVolume> session_volume;
result = wasapi_output_get_client(output)->GetService(
__uuidof(ISimpleAudioVolume),
session_volume.AddressCast<void>());
if (FAILED(result)) {
throw FormatHResultError(
result,
"Unable to get client session volume");
}

result = session_volume->SetMasterVolume(volume_level,
nullptr);
if (FAILED(result)) {
throw FormatHResultError(
result, "Unable to set master volume");
}
}
}
}).get();
}
};

Expand Down

0 comments on commit 8eee6f4

Please sign in to comment.