X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Fwasapi.c;h=7a4716177aa550908cd21cd80b209ba7e733a14a;hb=fc81c4e2b55c1367bbf67cb7a2b98bb63d4ca6d1;hp=6d715f59e903b111d4483d0a5509910fcdb2e788;hpb=51087cc213962a3135b820571a9847b995e21d5f;p=vlc diff --git a/modules/audio_output/wasapi.c b/modules/audio_output/wasapi.c index 6d715f59e9..7a4716177a 100644 --- a/modules/audio_output/wasapi.c +++ b/modules/audio_output/wasapi.c @@ -32,7 +32,8 @@ #include #include -#include "mmdevice.h" +#include +#include "audio_output/mmdevice.h" static LARGE_INTEGER freq; /* performance counters frequency */ @@ -74,7 +75,7 @@ typedef struct aout_stream_sys vlc_fourcc_t format; /**< Sample format */ unsigned rate; /**< Sample rate */ unsigned bytes_per_frame; - UINT32 written; /**< Frames written to the buffer */ + UINT64 written; /**< Frames written to the buffer */ UINT32 frames; /**< Total buffer size (frames) */ } aout_stream_sys_t; @@ -84,36 +85,38 @@ static HRESULT TimeGet(aout_stream_t *s, mtime_t *restrict delay) { aout_stream_sys_t *sys = s->sys; void *pv; - UINT64 pos, qpcpos; + UINT64 pos, qpcpos, freq; HRESULT hr; hr = IAudioClient_GetService(sys->client, &IID_IAudioClock, &pv); - if (SUCCEEDED(hr)) + if (FAILED(hr)) { - IAudioClock *clock = pv; - - hr = IAudioClock_GetPosition(clock, &pos, &qpcpos); - if (FAILED(hr)) - msg_Err(s, "cannot get position (error 0x%lx)", hr); - IAudioClock_Release(clock); - } - else msg_Err(s, "cannot get clock (error 0x%lx)", hr); + return hr; + } + + IAudioClock *clock = pv; + hr = IAudioClock_GetPosition(clock, &pos, &qpcpos); if (SUCCEEDED(hr)) + hr = IAudioClock_GetFrequency(clock, &freq); + IAudioClock_Release(clock); + if (FAILED(hr)) { - if (pos != 0) - { - *delay = ((GetQPC() - qpcpos) / (10000000 / CLOCK_FREQ)); - static_assert((10000000 % CLOCK_FREQ) == 0, - "Frequency conversion broken"); - } - else - { - *delay = sys->written * CLOCK_FREQ / sys->rate; - msg_Dbg(s, "extrapolating position: still propagating buffers"); - } + msg_Err(s, "cannot get position (error 0x%lx)", hr); + return hr; } + + lldiv_t w = lldiv(sys->written, sys->rate); + lldiv_t r = lldiv(pos, freq); + + static_assert((10000000 % CLOCK_FREQ) == 0, "Frequency conversion broken"); + + *delay = ((w.quot - r.quot) * CLOCK_FREQ) + + ((w.rem * CLOCK_FREQ) / sys->rate) + - ((r.rem * CLOCK_FREQ) / freq) + - ((GetQPC() - qpcpos) / (10000000 / CLOCK_FREQ)); + return hr; } @@ -177,8 +180,7 @@ static HRESULT Play(aout_stream_t *s, block_t *block) break; /* done */ /* Out of buffer space, sleep */ - msleep(AOUT_MIN_PREPARE_TIME - + block->i_nb_samples * CLOCK_FREQ / sys->rate); + msleep(sys->frames * (CLOCK_FREQ / 2) / sys->rate); } IAudioRenderClient_Release(render); out: @@ -210,10 +212,13 @@ static HRESULT Flush(aout_stream_t *s) IAudioClient_Stop(sys->client); hr = IAudioClient_Reset(sys->client); - if (FAILED(hr)) - msg_Warn(s, "cannot reset stream (error 0x%lx)", hr); - else + if (SUCCEEDED(hr)) + { + msg_Dbg(s, "reset"); sys->written = 0; + } + else + msg_Warn(s, "cannot reset stream (error 0x%lx)", hr); return hr; } @@ -282,10 +287,44 @@ static int vlc_FromWave(const WAVEFORMATEX *restrict wf, { const WAVEFORMATEXTENSIBLE *wfe = (void *)wf; + if (IsEqualIID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + switch (wf->wBitsPerSample) + { + case 64: + audio->i_format = VLC_CODEC_FL64; + break; + case 32: + audio->i_format = VLC_CODEC_FL32; + break; + default: + return -1; + } + } + else if (IsEqualIID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + { + switch (wf->wBitsPerSample) + { + case 32: + audio->i_format = VLC_CODEC_S32N; + break; + case 16: + audio->i_format = VLC_CODEC_S16N; + break; + default: + return -1; + } + } + + if (wfe->Samples.wValidBitsPerSample != wf->wBitsPerSample) + return -1; + for (unsigned i = 0; chans_in[i]; i++) if (wfe->dwChannelMask & chans_in[i]) audio->i_physical_channels |= pi_vlc_chan_order_wg4[i]; } + else + return -1; audio->i_original_channels = audio->i_physical_channels; aout_FormatPrepare (audio); @@ -312,6 +351,10 @@ static unsigned vlc_CheckWaveOrder (const WAVEFORMATEX *restrict wf, static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict fmt, const GUID *sid) { + if (!s->b_force && var_InheritBool(s, "spdif") && AOUT_FMT_SPDIF(fmt)) + /* Fallback to other plugin until pass-through is implemented */ + return E_NOTIMPL; + aout_stream_sys_t *sys = malloc(sizeof (*sys)); if (unlikely(sys == NULL)) return E_OUTOFMEMORY; @@ -374,6 +417,16 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict fmt, msg_Err(s, "cannot get buffer size (error 0x%lx)", hr); goto error; } + msg_Dbg(s, "buffer size : %"PRIu32" frames", sys->frames); + + REFERENCE_TIME latT, defT, minT; + if (SUCCEEDED(IAudioClient_GetStreamLatency(sys->client, &latT)) + && SUCCEEDED(IAudioClient_GetDevicePeriod(sys->client, &defT, &minT))) + { + msg_Dbg(s, "maximum latency: %"PRIu64"00 ns", latT); + msg_Dbg(s, "default period : %"PRIu64"00 ns", defT); + msg_Dbg(s, "minimum period : %"PRIu64"00 ns", minT); + } sys->rate = fmt->i_rate; sys->bytes_per_frame = fmt->i_bytes_per_frame; @@ -397,15 +450,15 @@ static void Stop(aout_stream_t *s) IAudioClient_Stop(sys->client); /* should not be needed */ IAudioClient_Release(sys->client); -} -HRESULT aout_stream_Start(aout_stream_t *s, - audio_sample_format_t *restrict fmt, const GUID *sid) -{ - return Start(s, fmt, sid); + free(sys); } -void aout_stream_Stop(aout_stream_t *s) -{ - Stop(s); -} +vlc_module_begin() + set_shortname("WASAPI") + set_description(N_("Windows Audio Session API output")) + set_capability("aout stream", 50) + set_category(CAT_AUDIO) + set_subcategory(SUBCAT_AUDIO_AOUT) + set_callbacks(Start, Stop) +vlc_module_end()