diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2018-01-31 03:51:47 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek@centricular.com> | 2018-01-31 14:58:21 +0530 |
commit | 538ccb60935cb93a7b711dde61f0cc40a854384b (patch) | |
tree | 369e68d3112d42ccfe29ab6021db46c1419582ec | |
parent | ec6a10ed0641cc18f9d1068f18c8882445c70dc0 (diff) | |
download | gstreamer-plugins-bad-538ccb60935cb93a7b711dde61f0cc40a854384b.tar.gz |
wasapi: Correctly set ringbuffer segsize/segtotal
This will set the actual-latency-time and actual-buffer-time of the sink
and source.
We completely ignore the latency-time/buffer-time values set
on the element because WASAPI is happiest when it is reading/writing at
the default period. Improving this will likely require the use of the
IAudioClient3 interfaces which are not available in MinGW yet.
https://bugzilla.gnome.org/show_bug.cgi?id=792897
-rw-r--r-- | sys/wasapi/gstwasapisink.c | 53 | ||||
-rw-r--r-- | sys/wasapi/gstwasapisrc.c | 52 |
2 files changed, 77 insertions, 28 deletions
diff --git a/sys/wasapi/gstwasapisink.c b/sys/wasapi/gstwasapisink.c index 7a89cca2d..3dbb249b5 100644 --- a/sys/wasapi/gstwasapisink.c +++ b/sys/wasapi/gstwasapisink.c @@ -346,13 +346,29 @@ gst_wasapi_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) { GstWasapiSink *self = GST_WASAPI_SINK (asink); gboolean res = FALSE; - HRESULT hr; REFERENCE_TIME latency_rt; IAudioRenderClient *render_client = NULL; + gint64 default_period, min_period; + guint bpf, rate; + HRESULT hr; + hr = IAudioClient_GetDevicePeriod (self->client, &default_period, &min_period); + if (hr != S_OK) { + GST_ERROR_OBJECT (self, "IAudioClient::GetDevicePeriod failed"); + goto beach; + } + GST_INFO_OBJECT (self, "wasapi default period: %" G_GINT64_FORMAT + ", min period: %" G_GINT64_FORMAT, default_period, min_period); + + /* Set hnsBufferDuration to 0, which should, in theory, tell the device to + * create a buffer with the smallest latency possible. In practice, this is + * usually 2 * default_period. See: + * https://msdn.microsoft.com/en-us/library/windows/desktop/dd370871(v=vs.85).aspx + * + * NOTE: min_period is a lie, and I have never seen WASAPI use it as the + * current period */ hr = IAudioClient_Initialize (self->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - spec->buffer_time * 10, 0, self->mix_format, NULL); + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, self->mix_format, NULL); if (hr != S_OK) { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("IAudioClient::Initialize () failed: %s", @@ -360,6 +376,26 @@ gst_wasapi_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) goto beach; } + /* Total size of the allocated buffer that we will write to */ + hr = IAudioClient_GetBufferSize (self->client, &self->buffer_frame_count); + if (hr != S_OK) { + GST_ERROR_OBJECT (self, "IAudioClient::GetBufferSize failed"); + goto beach; + } + + bpf = GST_AUDIO_INFO_BPF (&spec->info); + rate = GST_AUDIO_INFO_RATE (&spec->info); + GST_INFO_OBJECT (self, "buffer size is %i frames, bpf is %i bytes, " + "rate is %i Hz", self->buffer_frame_count, bpf, rate); + + /* Actual latency-time/buffer-time are different now */ + spec->segsize = gst_util_uint64_scale_int_round (rate * bpf, + default_period * 100, GST_SECOND); + spec->segtotal = (self->buffer_frame_count * bpf) / spec->segsize; + + GST_INFO_OBJECT (self, "segsize is %i, segtotal is %i", spec->segsize, + spec->segtotal); + /* Get latency for logging */ hr = IAudioClient_GetStreamLatency (self->client, &latency_rt); if (hr != S_OK) { @@ -376,17 +412,6 @@ gst_wasapi_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec) goto beach; } - /* Total size of the allocated buffer that we will write to - * XXX: Will this ever change while playing? */ - hr = IAudioClient_GetBufferSize (self->client, &self->buffer_frame_count); - if (hr != S_OK) { - GST_ERROR_OBJECT (self, "IAudioClient::GetBufferSize failed"); - goto beach; - } - GST_INFO_OBJECT (self, "frame count is %i, blockAlign is %i, " - "buffer_time is %" G_GINT64_FORMAT, self->buffer_frame_count, - self->mix_format->nBlockAlign, spec->buffer_time); - /* Get render sink client and start it up */ if (!gst_wasapi_util_get_render_client (GST_ELEMENT (self), self->client, &render_client)) { diff --git a/sys/wasapi/gstwasapisrc.c b/sys/wasapi/gstwasapisrc.c index 3825cf87e..20d4df672 100644 --- a/sys/wasapi/gstwasapisrc.c +++ b/sys/wasapi/gstwasapisrc.c @@ -346,11 +346,27 @@ gst_wasapi_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) guint64 client_clock_freq = 0; IAudioCaptureClient *capture_client = NULL; REFERENCE_TIME latency_rt; + gint64 default_period, min_period; + guint bpf, rate, buffer_frames; HRESULT hr; + hr = IAudioClient_GetDevicePeriod (self->client, &default_period, &min_period); + if (hr != S_OK) { + GST_ERROR_OBJECT (self, "IAudioClient::GetDevicePeriod failed"); + goto beach; + } + GST_INFO_OBJECT (self, "wasapi default period: %" G_GINT64_FORMAT + ", min period: %" G_GINT64_FORMAT, default_period, min_period); + + /* Set hnsBufferDuration to 0, which should, in theory, tell the device to + * create a buffer with the smallest latency possible. In practice, this is + * usually 2 * default_period. See: + * https://msdn.microsoft.com/en-us/library/windows/desktop/dd370871(v=vs.85).aspx + * + * NOTE: min_period is a lie, and I have never seen WASAPI use it as the + * current period */ hr = IAudioClient_Initialize (self->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, spec->buffer_time * 10, 0, - self->mix_format, NULL); + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, self->mix_format, NULL); if (hr != S_OK) { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, (NULL), ("IAudioClient::Initialize failed: %s", @@ -358,7 +374,26 @@ gst_wasapi_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) goto beach; } - /* Get latency for logging */ + /* Total size in frames of the allocated buffer that we will read from */ + hr = IAudioClient_GetBufferSize (self->client, &buffer_frames); + if (hr != S_OK) { + GST_ERROR_OBJECT (self, "IAudioClient::GetBufferSize failed"); + goto beach; + } + + bpf = GST_AUDIO_INFO_BPF (&spec->info); + rate = GST_AUDIO_INFO_RATE (&spec->info); + GST_INFO_OBJECT (self, "buffer size is %i frames, bpf is %i bytes, " + "rate is %i Hz", buffer_frames, bpf, rate); + + spec->segsize = gst_util_uint64_scale_int_round (rate * bpf, + default_period * 100, GST_SECOND); + spec->segtotal = (buffer_frames * bpf) / spec->segsize; + + GST_INFO_OBJECT (self, "segsize is %i, segtotal is %i", spec->segsize, + spec->segtotal); + + /* Get WASAPI latency for logging */ hr = IAudioClient_GetStreamLatency (self->client, &latency_rt); if (hr != S_OK) { GST_ERROR_OBJECT (self, "IAudioClient::GetStreamLatency failed"); @@ -386,17 +421,6 @@ gst_wasapi_src_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) goto beach; } - /* Total size of the allocated buffer that we will read from - * XXX: Will this ever change while playing? */ - hr = IAudioClient_GetBufferSize (self->client, &self->buffer_frame_count); - if (hr != S_OK) { - GST_ERROR_OBJECT (self, "IAudioClient::GetBufferSize failed"); - goto beach; - } - GST_INFO_OBJECT (self, "frame count is %i, blockAlign is %i, " - "buffer_time is %" G_GINT64_FORMAT, self->buffer_frame_count, - self->mix_format->nBlockAlign, spec->buffer_time); - /* Get capture source client and start it up */ if (!gst_wasapi_util_get_capture_client (GST_ELEMENT (self), self->client, &capture_client)) { |