mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-16 08:56:45 -05:00
alsa: use absolute timers
Use absolute timers, together with the alsa timestamp they are potentially more accurate. fix some crashes
This commit is contained in:
parent
46928cbc04
commit
3f8123143d
2 changed files with 27 additions and 11 deletions
|
|
@ -378,7 +378,8 @@ do_flush_event (SpaSource *source,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
PinosContextImpl *impl = data;
|
PinosContextImpl *impl = data;
|
||||||
pinos_connection_flush (impl->connection);
|
if (impl->connection)
|
||||||
|
pinos_connection_flush (impl->connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -514,6 +515,8 @@ pinos_context_destroy (PinosContext *context)
|
||||||
pinos_log_debug ("context %p: destroy", context);
|
pinos_log_debug ("context %p: destroy", context);
|
||||||
pinos_signal_emit (&context->destroy_signal, context);
|
pinos_signal_emit (&context->destroy_signal, context);
|
||||||
|
|
||||||
|
pinos_loop_destroy_source (impl->this.loop, impl->flush_event);
|
||||||
|
|
||||||
if (context->state != PINOS_CONTEXT_STATE_UNCONNECTED)
|
if (context->state != PINOS_CONTEXT_STATE_UNCONNECTED)
|
||||||
pinos_context_disconnect (context);
|
pinos_context_disconnect (context);
|
||||||
|
|
||||||
|
|
@ -524,8 +527,6 @@ pinos_context_destroy (PinosContext *context)
|
||||||
|
|
||||||
pinos_map_clear (&context->objects);
|
pinos_map_clear (&context->objects);
|
||||||
|
|
||||||
pinos_loop_destroy_source (impl->this.loop, impl->flush_event);
|
|
||||||
|
|
||||||
free (context->name);
|
free (context->name);
|
||||||
if (context->properties)
|
if (context->properties)
|
||||||
pinos_properties_free (context->properties);
|
pinos_properties_free (context->properties);
|
||||||
|
|
|
||||||
|
|
@ -626,17 +626,19 @@ static inline void
|
||||||
calc_timeout (size_t frames,
|
calc_timeout (size_t frames,
|
||||||
size_t cb_threshold,
|
size_t cb_threshold,
|
||||||
size_t rate,
|
size_t rate,
|
||||||
|
snd_htimestamp_t *now,
|
||||||
struct timespec *ts)
|
struct timespec *ts)
|
||||||
{
|
{
|
||||||
size_t to_play_usec;
|
size_t to_play_usec;
|
||||||
|
|
||||||
ts->tv_sec = 0;
|
ts->tv_sec = now->tv_sec;
|
||||||
/* adjust sleep time to target our callback threshold */
|
/* adjust sleep time to target our callback threshold */
|
||||||
if (frames > cb_threshold)
|
if (frames > cb_threshold)
|
||||||
to_play_usec = (frames - cb_threshold) * 1000000 / rate;
|
to_play_usec = (frames - cb_threshold) * 1000000 / rate;
|
||||||
else
|
else
|
||||||
to_play_usec = 0;
|
to_play_usec = 0;
|
||||||
ts->tv_nsec = to_play_usec * 1000 + 1;
|
|
||||||
|
ts->tv_nsec = to_play_usec * 1000 + now->tv_nsec;
|
||||||
|
|
||||||
while (ts->tv_nsec > 1000000000L) {
|
while (ts->tv_nsec > 1000000000L) {
|
||||||
ts->tv_sec++;
|
ts->tv_sec++;
|
||||||
|
|
@ -651,22 +653,34 @@ alsa_on_timeout_event (SpaSource *source)
|
||||||
int res;
|
int res;
|
||||||
SpaALSAState *state = source->data;
|
SpaALSAState *state = source->data;
|
||||||
snd_pcm_t *hndl = state->hndl;
|
snd_pcm_t *hndl = state->hndl;
|
||||||
snd_pcm_sframes_t avail;
|
snd_pcm_sframes_t avail, delay;
|
||||||
struct itimerspec ts;
|
struct itimerspec ts;
|
||||||
snd_pcm_uframes_t total_written = 0, filled;
|
snd_pcm_uframes_t total_written = 0, filled;
|
||||||
const snd_pcm_channel_area_t *my_areas;
|
const snd_pcm_channel_area_t *my_areas;
|
||||||
|
snd_pcm_status_t *status;
|
||||||
|
snd_htimestamp_t htstamp;
|
||||||
|
|
||||||
read (state->timerfd, &exp, sizeof (uint64_t));
|
read (state->timerfd, &exp, sizeof (uint64_t));
|
||||||
|
|
||||||
if ((avail = snd_pcm_avail (hndl)) < 0) {
|
snd_pcm_status_alloca(&status);
|
||||||
spa_log_error (state->log, "snd_pcm_avail_update error: %s", snd_strerror (avail));
|
|
||||||
|
if ((res = snd_pcm_status (hndl, status)) < 0) {
|
||||||
|
spa_log_error (state->log, "snd_pcm_status error: %s", snd_strerror (res));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avail = snd_pcm_status_get_avail (status);
|
||||||
|
delay = snd_pcm_status_get_delay (status);
|
||||||
|
snd_pcm_status_get_htstamp (status, &htstamp);
|
||||||
|
|
||||||
|
state->last_ticks = state->sample_count - delay;
|
||||||
|
state->last_monotonic = (int64_t)htstamp.tv_sec * SPA_NSEC_PER_SEC + (int64_t)htstamp.tv_nsec;
|
||||||
|
|
||||||
if (avail > state->buffer_frames)
|
if (avail > state->buffer_frames)
|
||||||
avail = state->buffer_frames;
|
avail = state->buffer_frames;
|
||||||
|
|
||||||
filled = state->buffer_frames - avail;
|
filled = state->buffer_frames - avail;
|
||||||
if (filled > state->threshold) {
|
if (filled > state->threshold + 10) {
|
||||||
if (snd_pcm_state (hndl) == SND_PCM_STATE_SUSPENDED) {
|
if (snd_pcm_state (hndl) == SND_PCM_STATE_SUSPENDED) {
|
||||||
spa_log_error (state->log, "suspended: try resume");
|
spa_log_error (state->log, "suspended: try resume");
|
||||||
if ((res = alsa_try_resume (state)) < 0)
|
if ((res = alsa_try_resume (state)) < 0)
|
||||||
|
|
@ -700,6 +714,7 @@ alsa_on_timeout_event (SpaSource *source)
|
||||||
}
|
}
|
||||||
total_written += written;
|
total_written += written;
|
||||||
}
|
}
|
||||||
|
state->sample_count += total_written;
|
||||||
}
|
}
|
||||||
if (!state->alsa_started && total_written > 0) {
|
if (!state->alsa_started && total_written > 0) {
|
||||||
spa_log_trace (state->log, "snd_pcm_start");
|
spa_log_trace (state->log, "snd_pcm_start");
|
||||||
|
|
@ -710,13 +725,13 @@ alsa_on_timeout_event (SpaSource *source)
|
||||||
state->alsa_started = true;
|
state->alsa_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
calc_timeout (total_written + filled, state->threshold, state->rate, &ts.it_value);
|
calc_timeout (total_written + filled, state->threshold, state->rate, &htstamp, &ts.it_value);
|
||||||
|
|
||||||
// printf ("timeout %ld %ld %ld %ld\n", total_written, filled, ts.it_value.tv_sec, ts.it_value.tv_nsec);
|
// printf ("timeout %ld %ld %ld %ld\n", total_written, filled, ts.it_value.tv_sec, ts.it_value.tv_nsec);
|
||||||
|
|
||||||
ts.it_interval.tv_sec = 0;
|
ts.it_interval.tv_sec = 0;
|
||||||
ts.it_interval.tv_nsec = 0;
|
ts.it_interval.tv_nsec = 0;
|
||||||
timerfd_settime (state->timerfd, 0, &ts, NULL);
|
timerfd_settime (state->timerfd, TFD_TIMER_ABSTIME, &ts, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaResult
|
SpaResult
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue