From 7d7be9be9801e1d2ccb440643011e25a5f684b7b Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Mon, 8 May 2017 15:22:00 +0000 Subject: [PATCH] directsoundsink: Use GstClock API instead of Sleep() for waiting It's more accurate and allows cancellation. https://bugzilla.gnome.org/show_bug.cgi?id=773681 --- sys/directsound/gstdirectsoundsink.c | 54 ++++++++++++++++++++++++++++++++---- sys/directsound/gstdirectsoundsink.h | 4 +++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c index d9cefbd..73c7758 100644 --- a/sys/directsound/gstdirectsoundsink.c +++ b/sys/directsound/gstdirectsoundsink.c @@ -148,6 +148,10 @@ gst_directsound_sink_finalize (GObject * object) dsoundsink->device_id = NULL; g_mutex_clear (&dsoundsink->dsound_lock); + gst_object_unref (dsoundsink->system_clock); + if (dsoundsink->write_wait_clock_id != NULL) { + gst_clock_id_unref (dsoundsink->write_wait_clock_id); + } G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -227,6 +231,8 @@ gst_directsound_sink_init (GstDirectSoundSink * dsoundsink) dsoundsink->buffer_size = DSBSIZE_MIN; dsoundsink->volume = 100; g_mutex_init (&dsoundsink->dsound_lock); + dsoundsink->system_clock = gst_system_clock_obtain (); + dsoundsink->write_wait_clock_id = NULL; dsoundsink->first_buffer_after_reset = FALSE; } @@ -624,7 +630,8 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length) if (SUCCEEDED (hRes) && SUCCEEDED (hRes2) && (dwStatus & DSBSTATUS_PLAYING)) { DWORD dwFreeBufferSize = 0; - guint64 sleep_time_ms = 0; + GstClockTime sleep_time_ms = 0, sleep_until; + GstClockID clock_id; calculate_freesize: /* Calculate the free space in the circular buffer */ @@ -649,11 +656,44 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length) 1000, dsoundsink->bytes_per_sample * rate); /* Make sure we don't run in a tight loop unnecessarily */ sleep_time_ms = MAX (sleep_time_ms, 10); + sleep_until = gst_clock_get_time (dsoundsink->system_clock) + + sleep_time_ms * GST_MSECOND; + GST_DEBUG_OBJECT (dsoundsink, "length: %u, FreeBufSiz: %ld, sleep_time_ms: %" G_GUINT64_FORMAT ", bps: %i, rate: %i", length, dwFreeBufferSize, sleep_time_ms, dsoundsink->bytes_per_sample, rate); - Sleep (sleep_time_ms); + + if (G_UNLIKELY (dsoundsink->write_wait_clock_id == NULL || + gst_clock_single_shot_id_reinit (dsoundsink->system_clock, + dsoundsink->write_wait_clock_id, sleep_until) == FALSE)) { + + if (dsoundsink->write_wait_clock_id != NULL) { + gst_clock_id_unref (dsoundsink->write_wait_clock_id); + } + + dsoundsink->write_wait_clock_id = + gst_clock_new_single_shot_id (dsoundsink->system_clock, + sleep_until); + } + + clock_id = dsoundsink->write_wait_clock_id; + dsoundsink->reset_while_sleeping = FALSE; + + GST_DSOUND_UNLOCK (dsoundsink); + + /* don't bother with the return value as we'll detect reset separately, + as reset could happen between when this returns and we obtain the lock + again -- so we can't use UNSCHEDULED here */ + gst_clock_id_wait (clock_id, NULL); + + GST_DSOUND_LOCK (dsoundsink); + + /* if a reset occurs, exit now */ + if (dsoundsink->reset_while_sleeping == TRUE) { + GST_DSOUND_UNLOCK (dsoundsink); + return -1; + } /* May we send out? */ hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary, @@ -698,12 +738,12 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length) if (pLockedBuffer2 != NULL) memcpy (pLockedBuffer2, (LPBYTE) data + dwSizeBuffer1, dwSizeBuffer2); + hRes = IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer1, + dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2); + // Update where the buffer will lock (for next time) dsoundsink->current_circular_offset += dwSizeBuffer1 + dwSizeBuffer2; dsoundsink->current_circular_offset %= dsoundsink->buffer_size; /* Circular buffer */ - - hRes = IDirectSoundBuffer_Unlock (dsoundsink->pDSBSecondary, pLockedBuffer1, - dwSizeBuffer1, pLockedBuffer2, dwSizeBuffer2); } /* if the buffer was not in playing state yet, call play on the buffer @@ -790,7 +830,11 @@ gst_directsound_sink_reset (GstAudioSink * asink) } } + dsoundsink->reset_while_sleeping = TRUE; dsoundsink->first_buffer_after_reset = TRUE; + if (dsoundsink->write_wait_clock_id != NULL) { + gst_clock_id_unschedule (dsoundsink->write_wait_clock_id); + } GST_DSOUND_UNLOCK (dsoundsink); } diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h index 51f7648..eb27efd 100644 --- a/sys/directsound/gstdirectsoundsink.h +++ b/sys/directsound/gstdirectsoundsink.h @@ -81,6 +81,10 @@ struct _GstDirectSoundSink /* lock used to protect writes and resets */ GMutex dsound_lock; + GstClock *system_clock; + GstClockID write_wait_clock_id; + gboolean reset_while_sleeping; + gboolean first_buffer_after_reset; GstAudioRingBufferFormatType type; -- 2.7.4