diff options
author | Shen-Ta Hsieh <ibmibmibm.tw@gmail.com> | 2020-05-30 21:59:53 +0800 |
---|---|---|
committer | Shen-Ta Hsieh <ibmibmibm.tw@gmail.com> | 2020-05-30 22:21:03 +0800 |
commit | 93d87854e985836e66ddac8bb00ab1d12f95094a (patch) | |
tree | cb0c0db78c8f25e0c42123446603ee696fd55c85 /src/mixer | |
parent | e5eac71d720b03a85ac5372c1814deba6ef59ebc (diff) |
src/output: add wasapi output and mixer plugin
Diffstat (limited to 'src/mixer')
-rw-r--r-- | src/mixer/MixerList.hxx | 1 | ||||
-rw-r--r-- | src/mixer/plugins/WasapiMixerPlugin.cxx | 128 | ||||
-rw-r--r-- | src/mixer/plugins/meson.build | 5 |
3 files changed, 133 insertions, 1 deletions
diff --git a/src/mixer/MixerList.hxx b/src/mixer/MixerList.hxx index 7f68d84f5..5cd9e9d60 100644 --- a/src/mixer/MixerList.hxx +++ b/src/mixer/MixerList.hxx @@ -36,6 +36,7 @@ extern const MixerPlugin oss_mixer_plugin; extern const MixerPlugin osx_mixer_plugin; extern const MixerPlugin pulse_mixer_plugin; extern const MixerPlugin winmm_mixer_plugin; +extern const MixerPlugin wasapi_mixer_plugin; extern const MixerPlugin sndio_mixer_plugin; #endif diff --git a/src/mixer/plugins/WasapiMixerPlugin.cxx b/src/mixer/plugins/WasapiMixerPlugin.cxx new file mode 100644 index 000000000..370e7eb79 --- /dev/null +++ b/src/mixer/plugins/WasapiMixerPlugin.cxx @@ -0,0 +1,128 @@ +/* + * Copyright 2020 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "mixer/MixerInternal.hxx" +#include "output/plugins/WasapiOutputPlugin.hxx" +#include "win32/Com.hxx" +#include "win32/HResult.hxx" + +#include <cmath> +#include <endpointvolume.h> +#include <optional> + +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 Close() noexcept override { com.reset(); } + + 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"); + } + + 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); + } + + 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"); + } + } + } +}; + +static Mixer *wasapi_mixer_init(EventLoop &, AudioOutput &ao, MixerListener &listener, + const ConfigBlock &) { + return new WasapiMixer(wasapi_output_downcast(ao), listener); +} + +const MixerPlugin wasapi_mixer_plugin = { + wasapi_mixer_init, + false, +}; diff --git a/src/mixer/plugins/meson.build b/src/mixer/plugins/meson.build index ed9df39b3..351ce1857 100644 --- a/src/mixer/plugins/meson.build +++ b/src/mixer/plugins/meson.build @@ -31,7 +31,10 @@ if libsndio_dep.found() endif if is_windows - mixer_plugins_sources += 'WinmmMixerPlugin.cxx' + mixer_plugins_sources += [ + 'WinmmMixerPlugin.cxx', + 'WasapiMixerPlugin.cxx', + ] endif if is_android |