From: Nirbheek Chauhan Date: Tue, 30 Jan 2018 22:21:47 +0000 (+0530) Subject: wasapi: Correctly set ringbuffer segsize/segtotal X-Git-Tag: 1.19.3~507^2~4523 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=538ccb60935cb93a7b711dde61f0cc40a854384b;p=platform%2Fupstream%2Fgstreamer.git 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 --- diff --git a/sys/wasapi/gstwasapisink.c b/sys/wasapi/gstwasapisink.c index 7a89cca..3dbb249 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 3825cf8..20d4df6 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)) {