summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2018-01-31 03:51:47 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2018-01-31 14:58:21 +0530
commit538ccb60935cb93a7b711dde61f0cc40a854384b (patch)
tree369e68d3112d42ccfe29ab6021db46c1419582ec
parentec6a10ed0641cc18f9d1068f18c8882445c70dc0 (diff)
downloadgstreamer-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.c53
-rw-r--r--sys/wasapi/gstwasapisrc.c52
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)) {