Commit 2aea47cf authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

PulseAudio: sync at start

parent dd2f4469
...@@ -203,9 +203,12 @@ static void stream_suspended_cb(pa_stream *s, void *userdata) ...@@ -203,9 +203,12 @@ static void stream_suspended_cb(pa_stream *s, void *userdata)
static void stream_underflow_cb(pa_stream *s, void *userdata) static void stream_underflow_cb(pa_stream *s, void *userdata)
{ {
aout_instance_t *aout = userdata; aout_instance_t *aout = userdata;
pa_operation *op;
msg_Dbg(aout, "underflow"); msg_Warn(aout, "underflow");
(void) s; op = pa_stream_cork(s, 1, NULL, NULL);
if (op != NULL)
pa_operation_unref(op);
} }
static int stream_wait(pa_threaded_mainloop *mainloop, pa_stream *stream) static int stream_wait(pa_threaded_mainloop *mainloop, pa_stream *stream)
...@@ -252,6 +255,17 @@ static void Play(aout_instance_t *aout) ...@@ -252,6 +255,17 @@ static void Play(aout_instance_t *aout)
aout_sys_t *sys = aout->output.p_sys; aout_sys_t *sys = aout->output.p_sys;
pa_stream *s = sys->stream; pa_stream *s = sys->stream;
/* This function is called exactly once per block in the output FIFO. */
block_t *block = aout_FifoPop(&aout->output.fifo);
assert (block != NULL);
const void *ptr = data_convert(&block);
if (unlikely(ptr == NULL))
return;
size_t len = block->i_buffer;
mtime_t pts = block->i_pts + block->i_length;
/* Note: The core already holds the output FIFO lock at this point. /* Note: The core already holds the output FIFO lock at this point.
* Therefore we must not under any circumstances (try to) acquire the * Therefore we must not under any circumstances (try to) acquire the
* output FIFO lock while the PulseAudio threaded main loop lock is held * output FIFO lock while the PulseAudio threaded main loop lock is held
...@@ -260,7 +274,41 @@ static void Play(aout_instance_t *aout) ...@@ -260,7 +274,41 @@ static void Play(aout_instance_t *aout)
pa_threaded_mainloop_lock(sys->mainloop); pa_threaded_mainloop_lock(sys->mainloop);
if (pa_stream_is_corked(s) > 0) { if (pa_stream_is_corked(s) > 0) {
pa_operation *op = pa_stream_cork(s, 0, NULL, NULL); /* Start or resume the stream. Zeroes are prepended to sync.
* This does not really work because PulseAudio latency measurement is
* garbage at start. */
pa_operation *op;
pa_usec_t latency;
int negative;
if (pa_stream_get_latency(s, &latency, &negative) == 0)
msg_Dbg(aout, "starting with %c%"PRIu64" us latency",
negative ? '-' : '+', latency);
else
latency = negative = 0;
mtime_t advance = block->i_pts - mdate();
if (negative)
advance += latency;
else
advance -= latency;
if (advance > 0) {
size_t nb = (advance * aout->output.output.i_rate) / CLOCK_FREQ;
size_t size = aout->output.output.i_bytes_per_frame;
float *zeroes = calloc (nb, size);
msg_Dbg(aout, "prepending %zu zeroes", nb);
if (likely(zeroes != NULL))
if (pa_stream_write(s, zeroes, nb * size, free, 0,
PA_SEEK_RELATIVE) < 0)
free(zeroes);
}
op = pa_stream_cork(s, 0, NULL, NULL);
if (op != NULL)
pa_operation_unref(op);
op = pa_stream_trigger(s, NULL, NULL);
if (op != NULL) if (op != NULL)
pa_operation_unref(op); pa_operation_unref(op);
msg_Dbg(aout, "uncorking"); msg_Dbg(aout, "uncorking");
...@@ -274,28 +322,10 @@ static void Play(aout_instance_t *aout) ...@@ -274,28 +322,10 @@ static void Play(aout_instance_t *aout)
} }
#endif #endif
/* This function is called exactly once per block in the output FIFO, so if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0) {
* this for-loop is not necessary.
* If this function is changed to not always dequeue blocks, be sure to
* limit the queue size to a reasonable limit to avoid huge leaks. */
for (;;) {
block_t *block = aout_FifoPop(&aout->output.fifo);
if (block == NULL)
break;
const void *ptr = data_convert(&block);
if (unlikely(ptr == NULL))
break;
size_t len = block->i_buffer;
//mtime_t pts = block->i_pts, duration = block->i_length;
if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0)
{
error(aout, "cannot write", sys->context); error(aout, "cannot write", sys->context);
block_Release(block); block_Release(block);
} }
}
pa_threaded_mainloop_unlock(sys->mainloop); pa_threaded_mainloop_unlock(sys->mainloop);
} }
...@@ -308,14 +338,12 @@ static void Pause(aout_instance_t *aout, bool b_paused, mtime_t i_date) ...@@ -308,14 +338,12 @@ static void Pause(aout_instance_t *aout, bool b_paused, mtime_t i_date)
aout_sys_t *sys = aout->output.p_sys; aout_sys_t *sys = aout->output.p_sys;
pa_stream *s = sys->stream; pa_stream *s = sys->stream;
/* Note: The core already holds the output FIFO lock at this point. if (!b_paused)
* Therefore we must not under any circumstances (try to) acquire the return; /* nothing to do - yet */
* output FIFO lock while the PulseAudio threaded main loop lock is held
* (including from PulseAudio stream callbacks). Otherwise lock inversion
* will take place, and sooner or later a deadlock. */
pa_threaded_mainloop_lock(sys->mainloop); pa_threaded_mainloop_lock(sys->mainloop);
pa_operation *op = pa_stream_cork(s, b_paused ? 1 : 0, NULL, NULL); pa_operation *op = pa_stream_cork(s, 1, NULL, NULL);
if (op != NULL) if (op != NULL)
pa_operation_unref(op); pa_operation_unref(op);
...@@ -490,15 +518,15 @@ static int Open(vlc_object_t *obj) ...@@ -490,15 +518,15 @@ static int Open(vlc_object_t *obj)
} }
/* Stream parameters */ /* Stream parameters */
const pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING const pa_stream_flags_t flags = PA_STREAM_START_CORKED
| PA_STREAM_AUTO_TIMING_UPDATE //| PA_STREAM_INTERPOLATE_TIMING
| PA_STREAM_START_CORKED; | PA_STREAM_AUTO_TIMING_UPDATE;
const uint32_t byterate = pa_bytes_per_second(&ss); const uint32_t byterate = pa_bytes_per_second(&ss);
struct pa_buffer_attr attr; struct pa_buffer_attr attr;
attr.maxlength = -1; attr.maxlength = -1;
attr.tlength = byterate * AOUT_MAX_PREPARE_TIME / CLOCK_FREQ; attr.tlength = byterate * AOUT_MAX_PREPARE_TIME / CLOCK_FREQ;
attr.prebuf = -1; attr.prebuf = 0; /* trigger manually */
attr.minreq = -1; attr.minreq = -1;
attr.fragsize = 0; /* not used for output */ attr.fragsize = 0; /* not used for output */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment