static int try_format(struct wasapi_state *state, struct ao *const ao, int bits, int samplerate, const struct mp_chmap channels) { WAVEFORMATEXTENSIBLE wformat; set_format(&wformat, bits / 8, samplerate, channels.num, mp_chmap_to_waveext(&channels)); int af_format = format_set_bits(ao->format, bits, bits == 32); EnterCriticalSection(&state->print_lock); mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: trying %dch %s @ %dhz\n", channels.num, af_fmt_to_str(af_format), samplerate); LeaveCriticalSection(&state->print_lock); union WAVEFMT u; u.extensible = &wformat; WAVEFORMATEX *closestMatch; HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient, state->share_mode, u.ex, &closestMatch); if (closestMatch) { if (closestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { u.ex = closestMatch; wformat = *u.extensible; } else { wformat.Format = *closestMatch; } CoTaskMemFree(closestMatch); } if (hr == S_FALSE) { if (set_ao_format(state, ao, wformat)) { EnterCriticalSection(&state->print_lock); mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: accepted as %dch %s @ %dhz\n", ao->channels.num, af_fmt_to_str(ao->format), ao->samplerate); LeaveCriticalSection(&state->print_lock); return 1; } } if (hr == S_OK || (!state->opt_exclusive && hr == AUDCLNT_E_UNSUPPORTED_FORMAT)) { // AUDCLNT_E_UNSUPPORTED_FORMAT here means "works in shared, doesn't in exclusive" if (set_ao_format(state, ao, wformat)) { EnterCriticalSection(&state->print_lock); mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: %dch %s @ %dhz accepted\n", ao->channels.num, af_fmt_to_str(af_format), samplerate); LeaveCriticalSection(&state->print_lock); return 1; } } return 0; }
static int set_ao_format(struct wasapi_state *state, struct ao *const ao, WAVEFORMATEXTENSIBLE wformat) { // .Data1 == 1 is PCM, .Data1 == 3 is IEEE_FLOAT int format = format_set_bits(ao->format, wformat.Format.wBitsPerSample, wformat.SubFormat.Data1 == 3); if (wformat.SubFormat.Data1 != 1 && wformat.SubFormat.Data1 != 3) { MP_ERR(ao, "unknown SubFormat %"PRIu32"\n", (uint32_t)wformat.SubFormat.Data1); return 0; } ao->samplerate = wformat.Format.nSamplesPerSec; ao->bps = wformat.Format.nAvgBytesPerSec; ao->format = format; if (ao->channels.num != wformat.Format.nChannels) { mp_chmap_from_channels(&ao->channels, wformat.Format.nChannels); } state->format = wformat; return 1; }