diff options
author | Dustin Spicuzza <dustin@virtualroadside.com> | 2017-05-08 15:22:00 +0000 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2017-05-08 17:33:38 +0200 |
commit | a303a7971c29db5599b34e82ef96565a1f58abee (patch) | |
tree | 4e3243021f284e43bd504e1b38c0de8701e23a76 | |
parent | 55c7e77d2c025ac91c6298b8cb06fded65031a11 (diff) |
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
-rw-r--r-- | sys/directsound/gstdirectsoundsink.c | 54 | ||||
-rw-r--r-- | 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 cceeca545..44145efbe 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; } @@ -621,7 +627,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 */ @@ -646,11 +653,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, @@ -695,12 +735,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 @@ -787,7 +827,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 51f7648e5..eb27efd3e 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; |