alsa: handle master/slave changes

This commit is contained in:
Wim Taymans 2019-04-24 15:38:06 +02:00
parent f2cdba1929
commit 24f6fc2a34
4 changed files with 65 additions and 29 deletions

View file

@ -170,6 +170,8 @@ static int impl_node_set_io(struct spa_node *node, uint32_t id, void *data, size
default: default:
return -ENOENT; return -ENOENT;
} }
spa_alsa_reslave(this);
return 0; return 0;
} }

View file

@ -166,6 +166,7 @@ static int impl_node_set_io(struct spa_node *node, uint32_t id, void *data, size
default: default:
return -ENOENT; return -ENOENT;
} }
spa_alsa_reslave(this);
return 0; return 0;
} }

View file

@ -1008,10 +1008,28 @@ static void reset_buffers(struct state *this)
} }
} }
static int set_timers(struct state *state)
{
struct itimerspec ts;
ts.it_value.tv_sec = 0;
if (state->slaved)
ts.it_value.tv_nsec = 0;
else
ts.it_value.tv_nsec = 1;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
timerfd_settime(state->timerfd, 0, &ts, NULL);
return 0;
}
static inline bool is_slaved(struct state *state)
{
return state->position && state->clock && state->position->clock.id != state->clock->id;
}
int spa_alsa_start(struct state *state) int spa_alsa_start(struct state *state)
{ {
int err; int err;
struct itimerspec ts;
if (state->started) if (state->started)
return 0; return 0;
@ -1021,11 +1039,7 @@ int spa_alsa_start(struct state *state)
else else
state->threshold = state->props.min_latency; state->threshold = state->props.min_latency;
state->slaved = false; state->slaved = is_slaved(state);
if (state->position && state->clock) {
if (state->position->clock.id != state->clock->id)
state->slaved = true;
}
init_loop(state); init_loop(state);
state->safety = 0.0; state->safety = 0.0;
@ -1040,14 +1054,12 @@ int spa_alsa_start(struct state *state)
return err; return err;
} }
if (!state->slaved) { state->source.func = alsa_on_timeout_event;
state->source.func = alsa_on_timeout_event; state->source.data = state;
state->source.data = state; state->source.fd = state->timerfd;
state->source.fd = state->timerfd; state->source.mask = SPA_IO_IN;
state->source.mask = SPA_IO_IN; state->source.rmask = 0;
state->source.rmask = 0; spa_loop_add_source(state->data_loop, &state->source);
spa_loop_add_source(state->data_loop, &state->source);
}
reset_buffers(state); reset_buffers(state);
state->alsa_sync = true; state->alsa_sync = true;
@ -1063,13 +1075,7 @@ int spa_alsa_start(struct state *state)
state->alsa_started = true; state->alsa_started = true;
} }
if (!state->slaved) { set_timers(state);
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 1;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
timerfd_settime(state->timerfd, 0, &ts, NULL);
}
state->io->status = SPA_STATUS_OK; state->io->status = SPA_STATUS_OK;
state->io->buffer_id = SPA_ID_INVALID; state->io->buffer_id = SPA_ID_INVALID;
@ -1079,6 +1085,34 @@ int spa_alsa_start(struct state *state)
return 0; return 0;
} }
static int do_reslave(struct spa_loop *loop,
bool async,
uint32_t seq,
const void *data,
size_t size,
void *user_data)
{
struct state *state = user_data;
set_timers(state);
return 0;
}
int spa_alsa_reslave(struct state *state)
{
bool slaved;
if (!state->started)
return 0;
slaved = is_slaved(state);
if (slaved != state->slaved) {
spa_log_debug(state->log, "alsa %p: reslave %d->%d", state, state->slaved, slaved);
state->slaved = slaved;
spa_loop_invoke(state->data_loop, do_reslave, 0, NULL, 0, true, state);
}
return 0;
}
static int do_remove_source(struct spa_loop *loop, static int do_remove_source(struct spa_loop *loop,
bool async, bool async,
uint32_t seq, uint32_t seq,
@ -1089,14 +1123,12 @@ static int do_remove_source(struct spa_loop *loop,
struct state *state = user_data; struct state *state = user_data;
struct itimerspec ts; struct itimerspec ts;
if (!state->slaved) { spa_loop_remove_source(state->data_loop, &state->source);
spa_loop_remove_source(state->data_loop, &state->source); ts.it_value.tv_sec = 0;
ts.it_value.tv_sec = 0; ts.it_value.tv_nsec = 0;
ts.it_value.tv_nsec = 0; 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, 0, &ts, NULL);
}
return 0; return 0;
} }

View file

@ -151,6 +151,7 @@ spa_alsa_enum_format(struct state *state, int seq,
int spa_alsa_set_format(struct state *state, struct spa_audio_info *info, uint32_t flags); int spa_alsa_set_format(struct state *state, struct spa_audio_info *info, uint32_t flags);
int spa_alsa_start(struct state *state); int spa_alsa_start(struct state *state);
int spa_alsa_reslave(struct state *state);
int spa_alsa_pause(struct state *state); int spa_alsa_pause(struct state *state);
int spa_alsa_close(struct state *state); int spa_alsa_close(struct state *state);