29 audio_device(), _previous_state(audio_device_state::uninitialized), _device(device), _audio_client(
nullptr)
31 hi_assert(_device !=
nullptr);
34 hi_hresult_check(_device->QueryInterface(&_end_point));
35 hi_hresult_check(_device->OpenPropertyStore(
STGM_READ, &_property_store));
38 hi_hresult_check(_end_point->GetDataFlow(&
data_flow));
41 _direction = audio_direction::output;
44 _direction = audio_direction::input;
47 _direction = audio_direction::bidirectional;
58 _property_store->Release();
59 _end_point->Release();
62 if (_audio_client !=
nullptr) {
63 _audio_client->Release();
79 hi_hresult_check(device->GetId(&device_id));
89 void update_state()
noexcept override
91 hi_axiom(loop::main().on_thread());
93 _name = end_point_name();
98 if (_previous_state == audio_device_state::uninitialized) {
99 hi_log_info(
" * Found new audio device '{}' {} ({})",
name(),
id(), state());
101 }
else if (_previous_state !=
new_state) {
102 hi_log_info(
" * Audio device changed state '{}' {} ({})",
name(),
id(), state());
106 if (_previous_state == audio_device_state::active
and new_state != audio_device_state::active) {
107 _audio_client->Release();
108 _audio_client =
nullptr;
110 }
else if (_previous_state != audio_device_state::active
and new_state == audio_device_state::active) {
112 hi_log_error(
"Audio device {} does not have IAudioClient interface",
name());
113 _audio_client =
nullptr;
116 update_supported_formats();
119 set_exclusive(
false);
126 return {elusive_icon::Speaker, txt(
"{}",
name())};
132 hi_hresult_check(_device->GetState(&state));
136 return audio_device_state::active;
138 return audio_device_state::disabled;
140 return audio_device_state::not_present;
142 return audio_device_state::unplugged;
158 void set_exclusive(
bool exclusive)
noexcept override
161 _current_stream_format = find_exclusive_stream_format(_sample_rate, _speaker_mapping);
163 _current_stream_format = shared_stream_format();
166 _exclusive = exclusive;
174 void set_sample_rate(
double sample_rate)
noexcept override
176 _sample_rate = sample_rate;
181 switch (direction()) {
182 case audio_direction::input:
184 case audio_direction::bidirectional:
185 return _speaker_mapping;
186 case audio_direction::output:
187 return hi::speaker_mapping::none;
193 void set_input_speaker_mapping(hi::speaker_mapping speaker_mapping)
noexcept override
195 switch (direction()) {
196 case audio_direction::input:
198 case audio_direction::bidirectional:
199 _speaker_mapping = speaker_mapping;
201 case audio_direction::output:
215 switch (direction()) {
216 case audio_direction::output:
218 case audio_direction::bidirectional:
219 return _speaker_mapping;
220 case audio_direction::input:
221 return hi::speaker_mapping::none;
227 void set_output_speaker_mapping(hi::speaker_mapping speaker_mapping)
noexcept override
229 switch (direction()) {
230 case audio_direction::output:
232 case audio_direction::bidirectional:
233 _speaker_mapping = speaker_mapping;
235 case audio_direction::input:
247 [[
nodiscard]]
bool supports_format(audio_stream_format
const& format)
const noexcept
249 if (
not win32_use_extensible(format)) {
251 auto format_ = audio_stream_format_to_win32(format,
false);
252 switch (_audio_client->IsFormatSupported(
266 auto format_ = audio_stream_format_to_win32(format,
true);
267 switch (_audio_client->IsFormatSupported(
284 audio_device_state _previous_state;
285 audio_direction _direction;
286 bool _exclusive =
false;
287 double _sample_rate = 0.0;
288 hi::speaker_mapping _speaker_mapping = hi::speaker_mapping::none;
289 audio_stream_format _current_stream_format;
299 hi_not_implemented();
319 throw io_error(std::format(
"Unexpected property value type {}.",
static_cast<int>(
property_value.vt)));
339 throw io_error(std::format(
"Unexpected property value type {}.",
static_cast<int>(
property_value.vt)));
359 throw io_error(std::format(
"Unexpected property value type {}.",
static_cast<int>(
property_value.vt)));
367 }
catch (io_error
const&) {
368 return "<unknown name>";
380 }
catch (io_error
const&) {
381 return "<unknown device name>";
392 }
catch (io_error
const&) {
393 return "<unknown end point name>";
401 }
catch (io_error
const& e) {
402 hi_log_error(
"Could not get pin-category for audio end-point {}: {}",
name(), e.what());
480 void update_supported_formats()
noexcept
503 find_exclusive_stream_format(
double sample_rate, hi::speaker_mapping speaker_mapping)
noexcept
510 [[
nodiscard]] audio_stream_format shared_stream_format()
const
512 if (
not _audio_client) {
517 hi_hresult_check(_audio_client->GetMixFormat(&
ex));
518 hi_assert_not_null(
ex);
519 auto const r = audio_stream_format_from_win32(*
ex);
527 auto wave_device = win32_wave_device::find_matching_end_point(direction(), _end_point_id);
538 auto const format = audio_stream_format{
it->format,
it->min_sample_rate,
it->num_channels};
541 if (
not supports_format(format)) {
547 it->surround_mode_mask = surround_mode::none;
548 for (
auto const mode : enumerate_surround_modes()) {
554 it->surround_mode_mask |= mode;
563 for (
auto sample_rate : common_sample_rates) {
569 tmp.emplace_back(
it->format,
it->num_channels, sample_rate, sample_rate,
it->surround_mode_mask);
584 return equal_except_bit_depth(lhs, rhs);