summaryrefslogtreecommitdiff
path: root/sys/directsound
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2017-05-03 23:23:10 +0530
committerSebastian Dröge <sebastian@centricular.com>2017-05-08 16:02:46 +0200
commit2d44b53ff664658ba9a4578b5b3231365c7c8e71 (patch)
tree16160805606fa8d257db6edab1535254b8381a1f /sys/directsound
parent0700b1f0b0dd6b986f232c993b20929cee69ed6a (diff)
downloadgstreamer-plugins-good-2d44b53ff664658ba9a4578b5b3231365c7c8e71.tar.gz
directsoundsink: Fix corner case causing large CPU usage
We were unnecessarily looping/goto-ing repeatedly when we had exactly the amount of data as the free space, and also when the free space was too small. This, as it turns out, is a very common scenario with Directsound on Windows. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=773681 We have to do polling here because the event notification API that Directsound exposes cannot be used with live playback since all events must be registered in advance with the capture buffer, you cannot add/remove them once playback has begun. Directsoundsrc had the same problem. See also: https://bugzilla.gnome.org/show_bug.cgi?id=781249
Diffstat (limited to 'sys/directsound')
-rw-r--r--sys/directsound/gstdirectsoundsink.c39
1 files changed, 23 insertions, 16 deletions
diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c
index b7ec9b4e9..cceeca545 100644
--- a/sys/directsound/gstdirectsoundsink.c
+++ b/sys/directsound/gstdirectsoundsink.c
@@ -621,10 +621,10 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
if (SUCCEEDED (hRes) && SUCCEEDED (hRes2) && (dwStatus & DSBSTATUS_PLAYING)) {
DWORD dwFreeBufferSize = 0;
- DWORD sleepTime = 0;
+ guint64 sleep_time_ms = 0;
calculate_freesize:
- /* calculate the free size of the circular buffer */
+ /* Calculate the free space in the circular buffer */
if (dwCurrentPlayCursor < dsoundsink->current_circular_offset)
dwFreeBufferSize =
dsoundsink->buffer_size - (dsoundsink->current_circular_offset -
@@ -633,21 +633,28 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
dwFreeBufferSize =
dwCurrentPlayCursor - dsoundsink->current_circular_offset;
- if (length >= dwFreeBufferSize) {
- sleepTime =
- ((length -
- dwFreeBufferSize) * 1000) / (dsoundsink->bytes_per_sample *
- GST_AUDIO_BASE_SINK (asink)->ringbuffer->spec.info.rate);
- if (sleepTime > 0) {
- GST_DEBUG_OBJECT (dsoundsink,
- "gst_directsound_sink_write: length:%i, FreeBufSiz: %ld, sleepTime: %ld, bps: %i, rate: %i",
- length, dwFreeBufferSize, sleepTime, dsoundsink->bytes_per_sample,
- GST_AUDIO_BASE_SINK (asink)->ringbuffer->spec.info.rate);
- Sleep (sleepTime);
- }
+ /* Not enough free space, wait for some samples to be played out. We could
+ * write out partial data, but that will result in a tight loop in the
+ * audioringbuffer write thread, and lead to high CPU usage. */
+ if (length > dwFreeBufferSize) {
+ gint rate = GST_AUDIO_BASE_SINK (asink)->ringbuffer->spec.info.rate;
+ /* Wait for a time proportional to the space needed. In reality, the
+ * directsound sink's position does not update frequently enough, so we
+ * will end up waiting for much longer. Note that Sleep() has millisecond
+ * resolution at best. */
+ sleep_time_ms = gst_util_uint64_scale_int ((length - dwFreeBufferSize),
+ 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);
+ 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);
+
+ /* May we send out? */
hRes = IDirectSoundBuffer_GetCurrentPosition (dsoundsink->pDSBSecondary,
&dwCurrentPlayCursor, NULL);
-
hRes2 =
IDirectSoundBuffer_GetStatus (dsoundsink->pDSBSecondary, &dwStatus);
if (SUCCEEDED (hRes) && SUCCEEDED (hRes2)
@@ -674,10 +681,10 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
if (dwStatus & DSBSTATUS_BUFFERLOST) {
hRes = IDirectSoundBuffer_Restore (dsoundsink->pDSBSecondary); /*need a loop waiting the buffer is restored?? */
-
dsoundsink->current_circular_offset = 0;
}
+ /* Lock a buffer of length @length for writing */
hRes = IDirectSoundBuffer_Lock (dsoundsink->pDSBSecondary,
dsoundsink->current_circular_offset, length, &pLockedBuffer1,
&dwSizeBuffer1, &pLockedBuffer2, &dwSizeBuffer2, 0L);