mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: pause/resume when entering/exiting freewheel
When we start freewheeling, pause the device and resume when we finish freewheel. In freewheel mode, just discard samples in the sink and produce silence in the source.
This commit is contained in:
parent
a80ec36ad5
commit
02decd9fba
4 changed files with 62 additions and 16 deletions
|
|
@ -638,11 +638,13 @@ static int impl_node_process(void *object)
|
|||
spa_return_val_if_fail(input != NULL, -EIO);
|
||||
|
||||
spa_log_trace_fp(this->log, NAME " %p: process %d %d/%d", this, input->status,
|
||||
input->buffer_id,
|
||||
this->n_buffers);
|
||||
input->buffer_id, this->n_buffers);
|
||||
|
||||
if (this->position && this->position->clock.flags & SPA_IO_CLOCK_FLAG_FREEWHEEL) {
|
||||
input->status = SPA_STATUS_NEED_DATA;
|
||||
} else if (input->status == SPA_STATUS_HAVE_DATA &&
|
||||
return SPA_STATUS_HAVE_DATA;
|
||||
}
|
||||
if (input->status == SPA_STATUS_HAVE_DATA &&
|
||||
input->buffer_id < this->n_buffers) {
|
||||
struct buffer *b = &this->buffers[input->buffer_id];
|
||||
|
||||
|
|
|
|||
|
|
@ -666,16 +666,13 @@ static int impl_node_process(void *object)
|
|||
spa_alsa_recycle_buffer(this, io->buffer_id);
|
||||
io->buffer_id = SPA_ID_INVALID;
|
||||
}
|
||||
if (this->position && this->position->clock.flags & SPA_IO_CLOCK_FLAG_FREEWHEEL) {
|
||||
spa_log_info(this->log, NAME " %p:freewheel", this);
|
||||
io->status = SPA_STATUS_HAVE_DATA;
|
||||
io->buffer_id = 0;
|
||||
return SPA_STATUS_HAVE_DATA;
|
||||
|
||||
if (spa_list_is_empty(&this->ready) && this->following) {
|
||||
if (this->freewheel)
|
||||
spa_alsa_skip(this);
|
||||
else
|
||||
spa_alsa_read(this);
|
||||
}
|
||||
|
||||
if (spa_list_is_empty(&this->ready) && this->following)
|
||||
spa_alsa_read(this, 0);
|
||||
|
||||
if (spa_list_is_empty(&this->ready) || !this->following)
|
||||
return SPA_STATUS_OK;
|
||||
|
||||
|
|
|
|||
|
|
@ -1158,7 +1158,7 @@ push_frames(struct state *state,
|
|||
}
|
||||
|
||||
|
||||
int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence)
|
||||
int spa_alsa_read(struct state *state)
|
||||
{
|
||||
snd_pcm_t *hndl = state->hndl;
|
||||
snd_pcm_uframes_t total_read = 0, to_read;
|
||||
|
|
@ -1260,6 +1260,40 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int spa_alsa_skip(struct state *state)
|
||||
{
|
||||
struct buffer *b;
|
||||
struct spa_data *d;
|
||||
uint32_t i, avail, total_frames, n_bytes, frames;
|
||||
|
||||
if (spa_list_is_empty(&state->free)) {
|
||||
spa_log_warn(state->log, NAME" %s: no more buffers", state->props.device);
|
||||
return -EPIPE;
|
||||
}
|
||||
|
||||
frames = state->read_size;
|
||||
|
||||
b = spa_list_first(&state->free, struct buffer, link);
|
||||
spa_list_remove(&b->link);
|
||||
|
||||
d = b->buf->datas;
|
||||
|
||||
avail = d[0].maxsize / state->frame_size;
|
||||
total_frames = SPA_MIN(avail, frames);
|
||||
n_bytes = total_frames * state->frame_size;
|
||||
|
||||
for (i = 0; i < b->buf->n_datas; i++) {
|
||||
memset(d[i].data, 0, n_bytes);
|
||||
d[i].chunk->offset = 0;
|
||||
d[i].chunk->size = n_bytes;
|
||||
d[i].chunk->stride = state->frame_size;
|
||||
}
|
||||
spa_list_append(&state->ready, &b->link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int handle_play(struct state *state, uint64_t nsec,
|
||||
snd_pcm_uframes_t delay, snd_pcm_uframes_t target)
|
||||
{
|
||||
|
|
@ -1305,7 +1339,7 @@ static int handle_capture(struct state *state, uint64_t nsec,
|
|||
if (SPA_UNLIKELY(res = update_time(state, nsec, delay, target, false)) < 0)
|
||||
return res;
|
||||
|
||||
if ((res = spa_alsa_read(state, target)) < 0)
|
||||
if ((res = spa_alsa_read(state)) < 0)
|
||||
return res;
|
||||
|
||||
if (spa_list_is_empty(&state->ready))
|
||||
|
|
@ -1508,7 +1542,7 @@ static int do_reassign_follower(struct spa_loop *loop,
|
|||
|
||||
int spa_alsa_reassign_follower(struct state *state)
|
||||
{
|
||||
bool following;
|
||||
bool following, freewheel;
|
||||
|
||||
if (!state->started)
|
||||
return 0;
|
||||
|
|
@ -1520,6 +1554,17 @@ int spa_alsa_reassign_follower(struct state *state)
|
|||
spa_loop_invoke(state->data_loop, do_reassign_follower, 0, NULL, 0, true, state);
|
||||
}
|
||||
setup_matching(state);
|
||||
|
||||
freewheel = state->position &&
|
||||
SPA_FLAG_IS_SET(state->position->clock.flags, SPA_IO_CLOCK_FLAG_FREEWHEEL);
|
||||
|
||||
if (state->freewheel != freewheel) {
|
||||
state->freewheel = freewheel;
|
||||
if (freewheel)
|
||||
snd_pcm_pause(state->hndl, 1);
|
||||
else
|
||||
snd_pcm_pause(state->hndl, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ struct state {
|
|||
unsigned int resample:1;
|
||||
unsigned int use_mmap:1;
|
||||
unsigned int planar:1;
|
||||
unsigned int freewheel:1;
|
||||
|
||||
int64_t sample_count;
|
||||
|
||||
|
|
@ -195,7 +196,8 @@ int spa_alsa_pause(struct state *state);
|
|||
int spa_alsa_close(struct state *state);
|
||||
|
||||
int spa_alsa_write(struct state *state);
|
||||
int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence);
|
||||
int spa_alsa_read(struct state *state);
|
||||
int spa_alsa_skip(struct state *state);
|
||||
|
||||
void spa_alsa_recycle_buffer(struct state *state, uint32_t buffer_id);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue