mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-05-23 02:38:16 +00:00
Merge branch 'audioringbuffer-segdone-overflow' into 'main'
audioringbuffer: Avoid overflows of segment done counter See merge request gstreamer/gstreamer!6740
This commit is contained in:
commit
c9c6e19dee
|
@ -1199,8 +1199,8 @@ static guint64
|
|||
gst_audio_base_sink_get_offset (GstAudioBaseSink * sink)
|
||||
{
|
||||
guint64 sample, sps;
|
||||
gint writeseg, segdone;
|
||||
gint diff;
|
||||
guint64 writeseg, segdone;
|
||||
gint64 diff;
|
||||
|
||||
/* assume we can append to the previous sample */
|
||||
sample = sink->next_sample;
|
||||
|
@ -1215,8 +1215,8 @@ gst_audio_base_sink_get_offset (GstAudioBaseSink * sink)
|
|||
writeseg = sample / sps;
|
||||
|
||||
/* get the currently processed segment */
|
||||
segdone = g_atomic_int_get (&sink->ringbuffer->segdone)
|
||||
- sink->ringbuffer->segbase;
|
||||
segdone = gst_audio_ring_buffer_get_segdone (sink->ringbuffer)
|
||||
- gst_audio_ring_buffer_get_segbase (sink->ringbuffer);
|
||||
|
||||
/* see how far away it is from the write segment */
|
||||
diff = writeseg - segdone;
|
||||
|
@ -1728,7 +1728,8 @@ gst_audio_base_sink_get_alignment (GstAudioBaseSink * sink,
|
|||
gint64 align;
|
||||
gint64 sample_diff;
|
||||
gint64 max_sample_diff;
|
||||
gint segdone = g_atomic_int_get (&ringbuf->segdone) - ringbuf->segbase;
|
||||
guint64 segdone = gst_audio_ring_buffer_get_segdone (sink->ringbuffer)
|
||||
- gst_audio_ring_buffer_get_segbase (sink->ringbuffer);
|
||||
gint64 samples_done = segdone * (gint64) ringbuf->samples_per_seg;
|
||||
gint64 headroom = sample_offset - samples_done;
|
||||
gboolean allow_align = TRUE;
|
||||
|
|
|
@ -700,8 +700,9 @@ static guint64
|
|||
gst_audio_base_src_get_offset (GstAudioBaseSrc * src)
|
||||
{
|
||||
guint64 sample;
|
||||
gint readseg, segdone, segtotal, sps;
|
||||
gint diff;
|
||||
guint64 readseg, segdone;
|
||||
gint segtotal, sps;
|
||||
gint64 diff;
|
||||
|
||||
/* assume we can append to the previous sample */
|
||||
sample = src->next_sample;
|
||||
|
@ -710,11 +711,12 @@ gst_audio_base_src_get_offset (GstAudioBaseSrc * src)
|
|||
segtotal = src->ringbuffer->spec.segtotal;
|
||||
|
||||
/* get the currently processed segment */
|
||||
segdone = g_atomic_int_get (&src->ringbuffer->segdone)
|
||||
- src->ringbuffer->segbase;
|
||||
segdone = gst_audio_ring_buffer_get_segdone (src->ringbuffer)
|
||||
- gst_audio_ring_buffer_get_segbase (src->ringbuffer);
|
||||
|
||||
if (sample != -1) {
|
||||
GST_DEBUG_OBJECT (src, "at segment %d and sample %" G_GUINT64_FORMAT,
|
||||
GST_DEBUG_OBJECT (src,
|
||||
"at segment %" G_GUINT64_FORMAT " and sample %" G_GUINT64_FORMAT,
|
||||
segdone, sample);
|
||||
/* figure out the segment and the offset inside the segment where
|
||||
* the sample should be read from. */
|
||||
|
@ -725,20 +727,22 @@ gst_audio_base_src_get_offset (GstAudioBaseSrc * src)
|
|||
* (where we are reading). */
|
||||
diff = segdone - readseg;
|
||||
if (diff >= segtotal) {
|
||||
GST_DEBUG_OBJECT (src, "dropped, align to segment %d", segdone);
|
||||
GST_DEBUG_OBJECT (src, "dropped, align to segment %" G_GUINT64_FORMAT,
|
||||
segdone);
|
||||
/* sample would be dropped, position to next playable position */
|
||||
sample = ((guint64) (segdone)) * sps;
|
||||
}
|
||||
} else {
|
||||
/* no previous sample, go to the current position */
|
||||
GST_DEBUG_OBJECT (src, "first sample, align to current %d", segdone);
|
||||
sample = ((guint64) (segdone)) * sps;
|
||||
GST_DEBUG_OBJECT (src, "first sample, align to current %" G_GUINT64_FORMAT,
|
||||
segdone);
|
||||
sample = segdone * sps;
|
||||
readseg = segdone;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (src,
|
||||
"reading from %d, we are at %d, sample %" G_GUINT64_FORMAT, readseg,
|
||||
segdone, sample);
|
||||
"reading from %" G_GUINT64_FORMAT ", we are at %" G_GUINT64_FORMAT
|
||||
", sample %" G_GUINT64_FORMAT, readseg, segdone, sample);
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
@ -876,20 +880,22 @@ gst_audio_base_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
|||
GstClockTime base_time;
|
||||
GstClockTime current_time;
|
||||
guint64 running_time_sample;
|
||||
gint running_time_segment;
|
||||
gint last_read_segment;
|
||||
gint segment_skew;
|
||||
guint64 running_time_segment;
|
||||
guint64 last_read_segment;
|
||||
gint64 segment_skew;
|
||||
gint sps;
|
||||
gint segments_written;
|
||||
gint last_written_segment;
|
||||
guint64 segments_written;
|
||||
guint64 last_written_segment;
|
||||
|
||||
/* get the amount of segments written from the device by now */
|
||||
segments_written = g_atomic_int_get (&ringbuffer->segdone);
|
||||
segments_written = gst_audio_ring_buffer_get_segdone (src->ringbuffer);
|
||||
|
||||
/* subtract the base to segments_written to get the number of the
|
||||
* last written segment in the ringbuffer
|
||||
* (one segment written = segment 0) */
|
||||
last_written_segment = segments_written - ringbuffer->segbase - 1;
|
||||
last_written_segment =
|
||||
segments_written - gst_audio_ring_buffer_get_segbase (ringbuffer) -
|
||||
1;
|
||||
|
||||
/* samples per segment */
|
||||
sps = ringbuffer->samples_per_seg;
|
||||
|
@ -923,13 +929,16 @@ gst_audio_base_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
|||
GST_TIME_FORMAT
|
||||
"\n timestamp = %"
|
||||
GST_TIME_FORMAT
|
||||
"\n running_time_segment = %d"
|
||||
"\n last_written_segment = %d"
|
||||
"\n segment_skew (running time segment - last_written_segment) = %d"
|
||||
"\n last_read_segment = %d",
|
||||
GST_TIME_ARGS (running_time), GST_TIME_ARGS (timestamp),
|
||||
running_time_segment, last_written_segment, segment_skew,
|
||||
last_read_segment);
|
||||
"\n running_time_segment = %"
|
||||
G_GUINT64_FORMAT
|
||||
"\n last_written_segment = %"
|
||||
G_GUINT64_FORMAT
|
||||
"\n segment_skew (running time segment - last_written_segment) = %"
|
||||
G_GINT64_FORMAT
|
||||
"\n last_read_segment = %"
|
||||
G_GUINT64_FORMAT, GST_TIME_ARGS (running_time),
|
||||
GST_TIME_ARGS (timestamp), running_time_segment,
|
||||
last_written_segment, segment_skew, last_read_segment);
|
||||
|
||||
/* Resync the ringbuffer if:
|
||||
*
|
||||
|
@ -943,8 +952,8 @@ gst_audio_base_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
|||
*/
|
||||
if ((segment_skew >= ringbuffer->spec.segtotal) ||
|
||||
(last_read_segment == 0) || first_sample) {
|
||||
gint new_read_segment;
|
||||
gint segment_diff;
|
||||
guint64 new_read_segment;
|
||||
guint64 segment_diff;
|
||||
guint64 new_sample;
|
||||
|
||||
/* the difference between running_time and the last written segment */
|
||||
|
@ -954,11 +963,11 @@ gst_audio_base_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
|||
gst_audio_ring_buffer_advance (ringbuffer, segment_diff);
|
||||
|
||||
/* we move the new read segment to the last known written segment */
|
||||
new_read_segment =
|
||||
g_atomic_int_get (&ringbuffer->segdone) - ringbuffer->segbase;
|
||||
new_read_segment = gst_audio_ring_buffer_get_segdone (src->ringbuffer)
|
||||
- gst_audio_ring_buffer_get_segbase (src->ringbuffer);
|
||||
|
||||
/* we calculate the new sample value */
|
||||
new_sample = ((guint64) new_read_segment) * sps;
|
||||
new_sample = new_read_segment * sps;
|
||||
|
||||
/* and get the relative time to this -> our new timestamp */
|
||||
timestamp = gst_util_uint64_scale_int (new_sample, GST_SECOND, rate);
|
||||
|
@ -967,7 +976,7 @@ gst_audio_base_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
|
|||
src->next_sample = new_sample + samples;
|
||||
|
||||
GST_DEBUG_OBJECT (bsrc,
|
||||
"Timeshifted the ringbuffer with %d segments: "
|
||||
"Timeshifted the ringbuffer with %" G_GINT64_FORMAT " segments: "
|
||||
"Updating the timestamp to %" GST_TIME_FORMAT ", "
|
||||
"and src->next_sample to %" G_GUINT64_FORMAT, segment_diff,
|
||||
GST_TIME_ARGS (timestamp), src->next_sample);
|
||||
|
|
|
@ -46,6 +46,104 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (gst_audio_ring_buffer_debug);
|
||||
#define GST_CAT_DEFAULT gst_audio_ring_buffer_debug
|
||||
|
||||
/* TODO: use GLib's once https://gitlab.gnome.org/GNOME/glib/issues/1076 lands, or
|
||||
* use C11 atomics once MS arrives in this century.
|
||||
*
|
||||
* We also assume that signed overflow just wraps around because unfortunately
|
||||
* there are no unsigned versions in MSVC. */
|
||||
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
|
||||
static inline guint64
|
||||
gst_atomic_uint64_add (guint64 * atomic, guint64 n)
|
||||
{
|
||||
return __sync_fetch_and_add (atomic, n);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_atomic_uint64_set (guint64 * atomic, guint64 n)
|
||||
{
|
||||
__sync_synchronize ();
|
||||
__asm__ __volatile__ ("":::"memory");
|
||||
*atomic = n;
|
||||
}
|
||||
|
||||
static inline guint64
|
||||
gst_atomic_uint64_get (guint64 * atomic)
|
||||
{
|
||||
gint64 ret = *atomic;
|
||||
__sync_synchronize ();
|
||||
__asm__ __volatile__ ("":::"memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif defined (G_PLATFORM_WIN32)
|
||||
#include <windows.h>
|
||||
static inline guint64
|
||||
gst_atomic_uint64_add (guint64 * atomic, guint64 n)
|
||||
{
|
||||
return InterlockedExchangeAdd64 ((gint64 *) atomic, (gint64) n);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_atomic_uint64_set (guint64 * atomic, guint64 n)
|
||||
{
|
||||
*atomic = n;
|
||||
MemoryBarrier ();
|
||||
}
|
||||
|
||||
static inline guint64
|
||||
gst_atomic_uint64_get (guint64 * atomic)
|
||||
{
|
||||
MemoryBarrier ();
|
||||
return *atomic;
|
||||
}
|
||||
#else
|
||||
#define STR_TOKEN(s) #s
|
||||
#define STR(s) STR_TOKEN(s)
|
||||
#pragma message "No 64-bit atomic int defined for this " STR(TARGET_CPU) " platform/toolchain!"
|
||||
|
||||
#define NO_64BIT_ATOMIC_INT_FOR_PLATFORM
|
||||
G_LOCK_DEFINE_STATIC (atomic_lock);
|
||||
static inline guint64
|
||||
gst_atomic_uint64_add (guint64 * atomic, guint64 n)
|
||||
{
|
||||
guint64 ret;
|
||||
|
||||
G_LOCK (atomic_lock);
|
||||
*atomic += n;
|
||||
ret = *atomic;
|
||||
G_UNLOCK (atomic_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_atomic_uint64_set (guint64 * atomic, guint64 n)
|
||||
{
|
||||
G_LOCK (atomic_lock);
|
||||
*atomic = n;
|
||||
G_UNLOCK (atomic_lock);
|
||||
}
|
||||
|
||||
static inline guint64
|
||||
gst_atomic_uint64_get (gint64 * atomic)
|
||||
{
|
||||
guint64 ret;
|
||||
|
||||
G_LOCK (atomic_lock);
|
||||
ret = *atomic;
|
||||
G_UNLOCK (atomic_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct _GstAudioRingBufferPrivate
|
||||
{
|
||||
/* ATOMIC */
|
||||
guint64 segdone;
|
||||
guint64 segbase;
|
||||
};
|
||||
|
||||
static void gst_audio_ring_buffer_dispose (GObject * object);
|
||||
static void gst_audio_ring_buffer_finalize (GObject * object);
|
||||
|
||||
|
@ -55,7 +153,7 @@ static guint default_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
|||
guint8 * data, gint in_samples, gint out_samples, gint * accum);
|
||||
|
||||
/* ringbuffer abstract base class */
|
||||
G_DEFINE_ABSTRACT_TYPE (GstAudioRingBuffer, gst_audio_ring_buffer,
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstAudioRingBuffer, gst_audio_ring_buffer,
|
||||
GST_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
|
@ -80,6 +178,7 @@ gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass)
|
|||
static void
|
||||
gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer)
|
||||
{
|
||||
ringbuffer->priv = gst_audio_ring_buffer_get_instance_private (ringbuffer);
|
||||
ringbuffer->open = FALSE;
|
||||
ringbuffer->acquired = FALSE;
|
||||
g_atomic_int_set (&ringbuffer->state, GST_AUDIO_RING_BUFFER_STATE_STOPPED);
|
||||
|
@ -89,6 +188,8 @@ gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer)
|
|||
ringbuffer->flushing = TRUE;
|
||||
ringbuffer->segbase = 0;
|
||||
ringbuffer->segdone = 0;
|
||||
ringbuffer->priv->segbase = 0;
|
||||
ringbuffer->priv->segdone = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -813,7 +914,9 @@ gst_audio_ring_buffer_release (GstAudioRingBuffer * buf)
|
|||
if (G_UNLIKELY (!res))
|
||||
goto release_failed;
|
||||
|
||||
gst_atomic_uint64_set (&buf->priv->segdone, 0);
|
||||
g_atomic_int_set (&buf->segdone, 0);
|
||||
buf->priv->segbase = 0;
|
||||
buf->segbase = 0;
|
||||
g_free (buf->empty_seg);
|
||||
buf->empty_seg = NULL;
|
||||
|
@ -1348,16 +1451,16 @@ not_acquired:
|
|||
guint64
|
||||
gst_audio_ring_buffer_samples_done (GstAudioRingBuffer * buf)
|
||||
{
|
||||
gint segdone;
|
||||
guint64 segdone;
|
||||
guint64 samples;
|
||||
|
||||
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), 0);
|
||||
|
||||
/* get the amount of segments we processed */
|
||||
segdone = g_atomic_int_get (&buf->segdone);
|
||||
segdone = gst_atomic_uint64_get (&buf->priv->segdone);
|
||||
|
||||
/* convert to samples */
|
||||
samples = ((guint64) segdone) * buf->samples_per_seg;
|
||||
samples = segdone * buf->samples_per_seg;
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
@ -1379,6 +1482,8 @@ gst_audio_ring_buffer_samples_done (GstAudioRingBuffer * buf)
|
|||
void
|
||||
gst_audio_ring_buffer_set_sample (GstAudioRingBuffer * buf, guint64 sample)
|
||||
{
|
||||
guint64 segdone;
|
||||
|
||||
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
||||
|
||||
if (sample == -1)
|
||||
|
@ -1390,12 +1495,69 @@ gst_audio_ring_buffer_set_sample (GstAudioRingBuffer * buf, guint64 sample)
|
|||
/* FIXME, we assume the ringbuffer can restart at a random
|
||||
* position, round down to the beginning and keep track of
|
||||
* offset when calculating the processed samples. */
|
||||
buf->segbase = buf->segdone - sample / buf->samples_per_seg;
|
||||
segdone = gst_atomic_uint64_get (&buf->priv->segdone);
|
||||
buf->priv->segbase = segdone - sample / buf->samples_per_seg;
|
||||
buf->segbase = buf->priv->segbase;
|
||||
|
||||
gst_audio_ring_buffer_clear_all (buf);
|
||||
|
||||
GST_DEBUG_OBJECT (buf, "set sample to %" G_GUINT64_FORMAT ", segbase %d",
|
||||
sample, buf->segbase);
|
||||
GST_DEBUG_OBJECT (buf,
|
||||
"set sample to %" G_GUINT64_FORMAT ", segbase %" G_GUINT64_FORMAT, sample,
|
||||
buf->priv->segbase);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_audio_ring_buffer_set_segdone:
|
||||
* @buf: the #GstAudioRingBuffer to use
|
||||
* @segdone: the segment number to set
|
||||
*
|
||||
* Sets the current segment number of the ringbuffer.
|
||||
*
|
||||
* MT safe.
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
void
|
||||
gst_audio_ring_buffer_set_segdone (GstAudioRingBuffer * buf, guint64 segdone)
|
||||
{
|
||||
gst_atomic_uint64_set (&buf->priv->segdone, segdone);
|
||||
g_atomic_int_set (&buf->segdone, segdone);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_audio_ring_buffer_get_segdone:
|
||||
* @buf: the #GstAudioRingBuffer to use
|
||||
*
|
||||
* Gets the current segment number of the ringbuffer.
|
||||
*
|
||||
* MT safe.
|
||||
*
|
||||
* Returns: Current segment number of the ringbuffer.
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
guint64
|
||||
gst_audio_ring_buffer_get_segdone (GstAudioRingBuffer * buf)
|
||||
{
|
||||
return gst_atomic_uint64_get (&buf->priv->segdone);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_audio_ring_buffer_get_segbase:
|
||||
* @buf: the #GstAudioRingBuffer to use
|
||||
*
|
||||
* Gets the current segment base number of the ringbuffer.
|
||||
*
|
||||
* MT safe.
|
||||
*
|
||||
* Returns: Current segment base number of the ringbuffer.
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
guint64
|
||||
gst_audio_ring_buffer_get_segbase (GstAudioRingBuffer * buf)
|
||||
{
|
||||
return gst_atomic_uint64_get (&buf->priv->segbase);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1445,7 +1607,7 @@ gst_audio_ring_buffer_clear_all (GstAudioRingBuffer * buf)
|
|||
static gboolean
|
||||
wait_segment (GstAudioRingBuffer * buf)
|
||||
{
|
||||
gint segments;
|
||||
guint64 segments;
|
||||
gboolean wait = TRUE;
|
||||
|
||||
/* buffer must be started now or we deadlock since nobody is reading */
|
||||
|
@ -1456,12 +1618,12 @@ wait_segment (GstAudioRingBuffer * buf)
|
|||
goto no_start;
|
||||
|
||||
GST_DEBUG_OBJECT (buf, "start!");
|
||||
segments = g_atomic_int_get (&buf->segdone);
|
||||
segments = gst_atomic_uint64_get (&buf->priv->segdone);
|
||||
gst_audio_ring_buffer_start (buf);
|
||||
|
||||
/* After starting, the writer may have wrote segments already and then we
|
||||
* don't need to wait anymore */
|
||||
if (G_LIKELY (g_atomic_int_get (&buf->segdone) != segments))
|
||||
if (G_LIKELY (gst_atomic_uint64_get (&buf->priv->segdone) != segments))
|
||||
wait = FALSE;
|
||||
}
|
||||
|
||||
|
@ -1625,10 +1787,10 @@ static guint
|
|||
default_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
||||
guint8 * data, gint in_samples, gint out_samples, gint * accum)
|
||||
{
|
||||
gint segdone;
|
||||
guint64 segdone;
|
||||
gint segsize, segtotal, channels, bps, bpf, sps;
|
||||
guint8 *dest, *data_end;
|
||||
gint writeseg, sampleoff;
|
||||
guint64 writeseg, sampleoff;
|
||||
gint *toprocess;
|
||||
gint inr, outr;
|
||||
gboolean reverse;
|
||||
|
@ -1677,17 +1839,20 @@ default_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
|||
gboolean skip;
|
||||
|
||||
while (TRUE) {
|
||||
gint diff;
|
||||
gint64 diff;
|
||||
|
||||
/* get the currently processed segment */
|
||||
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
||||
segdone =
|
||||
gst_atomic_uint64_get (&buf->priv->segdone) - buf->priv->segbase;
|
||||
|
||||
/* see how far away it is from the write segment */
|
||||
diff = writeseg - segdone;
|
||||
|
||||
GST_DEBUG_OBJECT (buf,
|
||||
"pointer at %d, write to %d-%d, diff %d, segtotal %d, segsize %d, base %d",
|
||||
segdone, writeseg, sampleoff, diff, segtotal, segsize, buf->segbase);
|
||||
"pointer at %" G_GUINT64_FORMAT ", write to %" G_GUINT64_FORMAT "-%"
|
||||
G_GUINT64_FORMAT ", diff %" G_GINT64_FORMAT
|
||||
", segtotal %d, segsize %d, base %" G_GUINT64_FORMAT, segdone,
|
||||
writeseg, sampleoff, diff, segtotal, segsize, buf->priv->segbase);
|
||||
|
||||
/* segment too far ahead, writer too slow, we need to drop, hopefully UNLIKELY */
|
||||
if (G_UNLIKELY (diff < 0)) {
|
||||
|
@ -1716,7 +1881,8 @@ default_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
|||
d_end = d + avail;
|
||||
*sample += avail / bpf;
|
||||
|
||||
GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d",
|
||||
GST_DEBUG_OBJECT (buf,
|
||||
"write @%p seg %d, sps %d, off %" G_GUINT64_FORMAT ", avail %d",
|
||||
dest + ws * segsize, ws, sps, sampleoff, avail);
|
||||
|
||||
if (need_reorder) {
|
||||
|
@ -1859,8 +2025,8 @@ guint
|
|||
gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
|
||||
guint8 * data, guint len, GstClockTime * timestamp)
|
||||
{
|
||||
gint segdone;
|
||||
gint segsize, segtotal, channels, bps, bpf, sps, readseg = 0;
|
||||
guint64 segdone, readseg = 0;
|
||||
gint segsize, segtotal, channels, bps, bpf, sps;
|
||||
guint8 *dest;
|
||||
guint to_read;
|
||||
gboolean need_reorder;
|
||||
|
@ -1890,10 +2056,11 @@ gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
|
|||
sampleoff = (sample % sps);
|
||||
|
||||
while (TRUE) {
|
||||
gint diff;
|
||||
gint64 diff;
|
||||
|
||||
/* get the currently processed segment */
|
||||
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
||||
segdone =
|
||||
gst_atomic_uint64_get (&buf->priv->segdone) - buf->priv->segbase;
|
||||
|
||||
/* see how far away it is from the read segment, normally segdone (where
|
||||
* the hardware is writing) is bigger than readseg (where software is
|
||||
|
@ -1901,10 +2068,10 @@ gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
|
|||
diff = segdone - readseg;
|
||||
|
||||
GST_DEBUG_OBJECT
|
||||
(buf, "pointer at %d, sample %" G_GUINT64_FORMAT
|
||||
", read from %d-%d, to_read %d, diff %d, segtotal %d, segsize %d",
|
||||
segdone, sample, readseg, sampleoff, to_read, diff, segtotal,
|
||||
segsize);
|
||||
(buf, "pointer at %" G_GUINT64_FORMAT ", sample %" G_GUINT64_FORMAT
|
||||
", read from %" G_GUINT64_FORMAT "-%d, to_read %d, diff %"
|
||||
G_GINT64_FORMAT ", segtotal %d, segsize %d", segdone, sample, readseg,
|
||||
sampleoff, to_read, diff, segtotal, segsize);
|
||||
|
||||
/* segment too far ahead, reader too slow */
|
||||
if (G_UNLIKELY (diff >= segtotal)) {
|
||||
|
@ -1928,7 +2095,8 @@ gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
|
|||
readseg = readseg % segtotal;
|
||||
sampleslen = MIN (sps - sampleoff, to_read);
|
||||
|
||||
GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d",
|
||||
GST_DEBUG_OBJECT (buf,
|
||||
"read @%p seg %" G_GUINT64_FORMAT ", off %d, sampleslen %d",
|
||||
dest + readseg * segsize, readseg, sampleoff, sampleslen);
|
||||
|
||||
if (need_reorder) {
|
||||
|
@ -1957,7 +2125,8 @@ gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
|
|||
if (buf->timestamps && timestamp) {
|
||||
*timestamp = buf->timestamps[readseg % segtotal];
|
||||
GST_DEBUG_OBJECT (buf, "Retrieved timestamp %" GST_TIME_FORMAT
|
||||
" @ %d", GST_TIME_ARGS (*timestamp), readseg % segtotal);
|
||||
" @ %" G_GUINT64_FORMAT, GST_TIME_ARGS (*timestamp),
|
||||
readseg % segtotal);
|
||||
}
|
||||
|
||||
return len - to_read;
|
||||
|
@ -1990,7 +2159,7 @@ gst_audio_ring_buffer_prepare_read (GstAudioRingBuffer * buf, gint * segment,
|
|||
guint8 ** readptr, gint * len)
|
||||
{
|
||||
guint8 *data;
|
||||
gint segdone;
|
||||
guint64 segdone;
|
||||
|
||||
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
||||
|
||||
|
@ -2008,14 +2177,15 @@ gst_audio_ring_buffer_prepare_read (GstAudioRingBuffer * buf, gint * segment,
|
|||
data = buf->memory;
|
||||
|
||||
/* get the position of the pointer */
|
||||
segdone = g_atomic_int_get (&buf->segdone);
|
||||
segdone = gst_atomic_uint64_get (&buf->priv->segdone);
|
||||
|
||||
*segment = segdone % buf->spec.segtotal;
|
||||
*len = buf->spec.segsize;
|
||||
*readptr = data + *segment * *len;
|
||||
|
||||
GST_LOG_OBJECT (buf, "prepare read from segment %d (real %d) @%p",
|
||||
*segment, segdone, *readptr);
|
||||
GST_LOG_OBJECT (buf,
|
||||
"prepare read from segment %d (real %" G_GUINT64_FORMAT ") @%p", *segment,
|
||||
segdone, *readptr);
|
||||
|
||||
/* callback to fill the memory with data, for pull based
|
||||
* scheduling. */
|
||||
|
@ -2041,6 +2211,7 @@ gst_audio_ring_buffer_advance (GstAudioRingBuffer * buf, guint advance)
|
|||
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
||||
|
||||
/* update counter */
|
||||
gst_atomic_uint64_add (&buf->priv->segdone, advance);
|
||||
g_atomic_int_add (&buf->segdone, advance);
|
||||
|
||||
/* the lock is already taken when the waiting flag is set,
|
||||
|
|
|
@ -42,6 +42,7 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstAudioRingBuffer GstAudioRingBuffer;
|
||||
typedef struct _GstAudioRingBufferClass GstAudioRingBufferClass;
|
||||
typedef struct _GstAudioRingBufferSpec GstAudioRingBufferSpec;
|
||||
typedef struct _GstAudioRingBufferPrivate GstAudioRingBufferPrivate;
|
||||
|
||||
/**
|
||||
* GstAudioRingBufferCallback:
|
||||
|
@ -241,7 +242,8 @@ struct _GstAudioRingBuffer {
|
|||
GDestroyNotify cb_data_notify;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING - 1];
|
||||
GstAudioRingBufferPrivate *priv;
|
||||
gpointer _gst_reserved[GST_PADDING - 2];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -435,6 +437,15 @@ void gst_audio_ring_buffer_advance (GstAudioRingBuffer *buf,
|
|||
GST_AUDIO_API
|
||||
void gst_audio_ring_buffer_may_start (GstAudioRingBuffer *buf, gboolean allowed);
|
||||
|
||||
GST_AUDIO_API
|
||||
void gst_audio_ring_buffer_set_segdone (GstAudioRingBuffer *buf, guint64 segdone);
|
||||
|
||||
GST_AUDIO_API
|
||||
guint64 gst_audio_ring_buffer_get_segdone (GstAudioRingBuffer *buf);
|
||||
|
||||
GST_AUDIO_API
|
||||
guint64 gst_audio_ring_buffer_get_segbase (GstAudioRingBuffer *buf);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstAudioRingBuffer, gst_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
|
|
@ -744,8 +744,8 @@ gst_pulsering_stream_latency_cb (pa_stream * s, void *userdata)
|
|||
* less. One concern here is that latency updates happen every 100ms, which
|
||||
* means segdone is not updated very often, but increasing the update
|
||||
* frequency would mean more communication overhead. */
|
||||
g_atomic_int_set (&ringbuf->segdone,
|
||||
(int) gst_util_uint64_scale_ceil (info->read_index, 1,
|
||||
gst_audio_ring_buffer_set_segdone (ringbuf,
|
||||
gst_util_uint64_scale_ceil (info->read_index, 1,
|
||||
ringbuf->spec.segsize));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue