ao_wasapi: deduplicate wasapi sample format selection

This commit is contained in:
Kevin Mitchell 2017-07-29 01:37:00 -07:00
parent 15eb1e1ad3
commit 434d3d4976
1 changed files with 40 additions and 49 deletions

View File

@ -94,6 +94,20 @@ static const struct wasapi_sample_fmt wasapi_formats[] = {
{0}, {0},
}; };
static void wasapi_get_best_sample_formats(
int src_format, struct wasapi_sample_fmt *out_formats)
{
int mp_formats[AF_FORMAT_COUNT];
af_get_best_sample_formats(src_format, mp_formats);
for (int n = 0; mp_formats[n]; n++) {
for (int i = 0; wasapi_formats[i].mp_format; i++) {
if (wasapi_formats[i].mp_format == mp_formats[n])
*out_formats++ = wasapi_formats[i];
}
}
*out_formats = (struct wasapi_sample_fmt) {0};
}
static const GUID *format_to_subtype(int format) static const GUID *format_to_subtype(int format)
{ {
for (int i = 0; wasapi_formats[i].mp_format; i++) { for (int i = 0; wasapi_formats[i].mp_format; i++) {
@ -120,54 +134,21 @@ static void update_waveformat_datarate(WAVEFORMATEXTENSIBLE *wformat)
} }
static void set_waveformat(WAVEFORMATEXTENSIBLE *wformat, static void set_waveformat(WAVEFORMATEXTENSIBLE *wformat,
struct wasapi_sample_fmt format, struct wasapi_sample_fmt *format,
DWORD samplerate, struct mp_chmap *channels) DWORD samplerate, struct mp_chmap *channels)
{ {
wformat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wformat->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wformat->Format.nChannels = channels->num; wformat->Format.nChannels = channels->num;
wformat->Format.nSamplesPerSec = samplerate; wformat->Format.nSamplesPerSec = samplerate;
wformat->Format.wBitsPerSample = format.bits; wformat->Format.wBitsPerSample = format->bits;
wformat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); wformat->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
wformat->SubFormat = *format_to_subtype(format.mp_format); wformat->SubFormat = *format_to_subtype(format->mp_format);
wformat->Samples.wValidBitsPerSample = format.used_msb; wformat->Samples.wValidBitsPerSample = format->used_msb;
wformat->dwChannelMask = mp_chmap_to_waveext(channels); wformat->dwChannelMask = mp_chmap_to_waveext(channels);
update_waveformat_datarate(wformat); update_waveformat_datarate(wformat);
} }
// This implicitly transforms all pcm formats to: interleaved / signed (except
// 8-bit is unsigned) / waveext channel order. "Special" formats should be
// exempt as they should already satisfy these properties.
static void set_waveformat_with_ao(WAVEFORMATEXTENSIBLE *wformat, struct ao *ao)
{
struct mp_chmap channels = ao->channels;
if (mp_chmap_is_unknown(&channels))
mp_chmap_from_channels(&channels, channels.num);
mp_chmap_reorder_to_waveext(&channels);
if (!mp_chmap_is_valid(&channels))
mp_chmap_from_channels(&channels, 2);
// First find a format that is actually representable.
// (Notably excludes AF_FORMAT_DOUBLE.)
struct wasapi_sample_fmt format =
{AF_FORMAT_S16, 16, 16, &KSDATAFORMAT_SUBTYPE_PCM};
int alt_formats[AF_FORMAT_COUNT];
af_get_best_sample_formats(ao->format, alt_formats);
for (int n = 0; alt_formats[n]; n++) {
for (int i = 0; wasapi_formats[i].mp_format; i++) {
if (wasapi_formats[i].mp_format == alt_formats[n]) {
format = wasapi_formats[i];
goto found_format;
}
}
}
found_format:
set_waveformat(wformat, format, ao->samplerate, &channels);
}
// other wformat parameters must already be set with set_waveformat // other wformat parameters must already be set with set_waveformat
static void change_waveformat_samplerate(WAVEFORMATEXTENSIBLE *wformat, static void change_waveformat_samplerate(WAVEFORMATEXTENSIBLE *wformat,
DWORD samplerate) DWORD samplerate)
@ -331,16 +312,12 @@ static bool try_format_exclusive(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat)
static bool search_sample_formats(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat, static bool search_sample_formats(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat,
int samplerate, struct mp_chmap *channels) int samplerate, struct mp_chmap *channels)
{ {
int alt_formats[AF_FORMAT_COUNT]; struct wasapi_sample_fmt alt_formats[MP_ARRAY_SIZE(wasapi_formats)];
af_get_best_sample_formats(ao->format, alt_formats); wasapi_get_best_sample_formats(ao->format, alt_formats);
for (int n = 0; alt_formats[n]; n++) { for (int n = 0; alt_formats[n].mp_format; n++) {
for (int i = 0; wasapi_formats[i].mp_format; i++) { set_waveformat(wformat, &alt_formats[n], samplerate, channels);
if (wasapi_formats[i].mp_format == alt_formats[n]) { if (try_format_exclusive(ao, wformat))
set_waveformat(wformat, wasapi_formats[i], samplerate, channels); return true;
if (try_format_exclusive(ao, wformat))
return true;
}
}
} }
wformat->Format.wBitsPerSample = 0; wformat->Format.wBitsPerSample = 0;
@ -483,10 +460,24 @@ exit_label:
static bool find_formats(struct ao *ao) static bool find_formats(struct ao *ao)
{ {
struct wasapi_state *state = ao->priv; struct wasapi_state *state = ao->priv;
struct mp_chmap channels = ao->channels;
if (mp_chmap_is_unknown(&channels))
mp_chmap_from_channels(&channels, channels.num);
mp_chmap_reorder_to_waveext(&channels);
if (!mp_chmap_is_valid(&channels))
mp_chmap_from_channels(&channels, 2);
struct wasapi_sample_fmt alt_formats[MP_ARRAY_SIZE(wasapi_formats)];
wasapi_get_best_sample_formats(ao->format, alt_formats);
struct wasapi_sample_fmt wasapi_format =
{AF_FORMAT_S16, 16, 16, &KSDATAFORMAT_SUBTYPE_PCM};;
if (alt_formats[0].mp_format)
wasapi_format = alt_formats[0];
AUDCLNT_SHAREMODE share_mode; AUDCLNT_SHAREMODE share_mode;
WAVEFORMATEXTENSIBLE wformat; WAVEFORMATEXTENSIBLE wformat;
set_waveformat(&wformat, &wasapi_format, ao->samplerate, &channels);
set_waveformat_with_ao(&wformat, ao);
if (state->opt_exclusive || af_fmt_is_spdif(ao->format)) { if (state->opt_exclusive || af_fmt_is_spdif(ao->format)) {
share_mode = AUDCLNT_SHAREMODE_EXCLUSIVE; share_mode = AUDCLNT_SHAREMODE_EXCLUSIVE;