src/win32: Add ComWorker to run all COM function on same thread
This commit is contained in:

committed by
Max Kellermann

parent
b1d7567226
commit
2974737746
@@ -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>
|
||||
@@ -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;
|
||||
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");
|
||||
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;
|
||||
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");
|
||||
}
|
||||
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 = 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");
|
||||
result = session_volume->SetMasterVolume(volume_level,
|
||||
nullptr);
|
||||
if (FAILED(result)) {
|
||||
throw FormatHResultError(
|
||||
result, "Unable to set master volume");
|
||||
}
|
||||
}
|
||||
}
|
||||
}).get();
|
||||
}
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user