mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
module-stream-restore: don't fiddle with sinks/sources/streams that are not fully set up yet
This commit is contained in:
parent
0f2a4ed422
commit
7891f964e4
1 changed files with 86 additions and 26 deletions
|
|
@ -102,15 +102,16 @@ struct userdata {
|
||||||
pa_idxset *subscribed;
|
pa_idxset *subscribed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ENTRY_VERSION 2
|
#define ENTRY_VERSION 3
|
||||||
|
|
||||||
struct entry {
|
struct entry {
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
pa_bool_t muted_valid:1, volume_valid:1, device_valid:1;
|
pa_bool_t muted_valid:1, volume_valid:1, device_valid:1, card_valid:1;
|
||||||
pa_bool_t muted:1;
|
pa_bool_t muted:1;
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
pa_cvolume volume;
|
pa_cvolume volume;
|
||||||
char device[PA_NAME_MAX];
|
char device[PA_NAME_MAX];
|
||||||
|
char card[PA_NAME_MAX];
|
||||||
} PA_GCC_PACKED;
|
} PA_GCC_PACKED;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -196,11 +197,21 @@ static struct entry* read_entry(struct userdata *u, const char *name) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!memchr(e->card, 0, sizeof(e->card))) {
|
||||||
|
pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (e->device_valid && !pa_namereg_is_valid_name(e->device)) {
|
if (e->device_valid && !pa_namereg_is_valid_name(e->device)) {
|
||||||
pa_log_warn("Invalid device name stored in database for stream %s", name);
|
pa_log_warn("Invalid device name stored in database for stream %s", name);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e->card_valid && !pa_namereg_is_valid_name(e->card)) {
|
||||||
|
pa_log_warn("Invalid card name stored in database for stream %s", name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
|
if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
|
||||||
pa_log_warn("Invalid channel map stored in database for stream %s", name);
|
pa_log_warn("Invalid channel map stored in database for stream %s", name);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -252,6 +263,10 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
|
||||||
(a->device_valid && strncmp(a->device, b->device, sizeof(a->device))))
|
(a->device_valid && strncmp(a->device, b->device, sizeof(a->device))))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (a->card_valid != b->card_valid ||
|
||||||
|
(a->card_valid && strncmp(a->card, b->card, sizeof(a->card))))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (a->muted_valid != b->muted_valid ||
|
if (a->muted_valid != b->muted_valid ||
|
||||||
(a->muted_valid && (a->muted != b->muted)))
|
(a->muted_valid && (a->muted != b->muted)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
@ -308,6 +323,11 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
|
||||||
if (sink_input->save_sink) {
|
if (sink_input->save_sink) {
|
||||||
pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
|
pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
|
||||||
entry.device_valid = TRUE;
|
entry.device_valid = TRUE;
|
||||||
|
|
||||||
|
if (sink_input->sink->card) {
|
||||||
|
pa_strlcpy(entry.card, sink_input->sink->card->name, sizeof(entry.card));
|
||||||
|
entry.card_valid = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -327,6 +347,11 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
|
||||||
if (source_output->save_source) {
|
if (source_output->save_source) {
|
||||||
pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
|
pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
|
||||||
entry.device_valid = source_output->save_source;
|
entry.device_valid = source_output->save_source;
|
||||||
|
|
||||||
|
if (source_output->source->card) {
|
||||||
|
pa_strlcpy(entry.card, source_output->source->card->name, sizeof(entry.card));
|
||||||
|
entry.card_valid = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,19 +393,28 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
|
||||||
if (!(name = get_name(new_data->proplist, "sink-input")))
|
if (!(name = get_name(new_data->proplist, "sink-input")))
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
if ((e = read_entry(u, name))) {
|
if (new_data->sink)
|
||||||
|
pa_log_debug("Not restoring device for stream %s, because already set.", name);
|
||||||
|
else if ((e = read_entry(u, name))) {
|
||||||
|
pa_sink *s = NULL;
|
||||||
|
|
||||||
if (e->device_valid) {
|
if (e->device_valid)
|
||||||
pa_sink *s;
|
s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK);
|
||||||
|
|
||||||
if ((s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK))) {
|
if (!s && e->card_valid) {
|
||||||
if (!new_data->sink) {
|
pa_card *card;
|
||||||
pa_log_info("Restoring device for stream %s.", name);
|
|
||||||
new_data->sink = s;
|
if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
|
||||||
new_data->save_sink = TRUE;
|
s = pa_idxset_first(card->sinks, NULL);
|
||||||
} else
|
}
|
||||||
pa_log_debug("Not restoring device for stream %s, because already set.", name);
|
|
||||||
}
|
/* It might happen that a stream and a sink are set up at the
|
||||||
|
same time, in which case we want to make sure we don't
|
||||||
|
interfere with that */
|
||||||
|
if (s && PA_SINK_IS_LINKED(pa_sink_get_state(s))) {
|
||||||
|
pa_log_info("Restoring device for stream %s.", name);
|
||||||
|
new_data->sink = s;
|
||||||
|
new_data->save_sink = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_xfree(e);
|
pa_xfree(e);
|
||||||
|
|
@ -455,18 +489,28 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
|
||||||
if (!(name = get_name(new_data->proplist, "source-output")))
|
if (!(name = get_name(new_data->proplist, "source-output")))
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
if ((e = read_entry(u, name))) {
|
if (new_data->source)
|
||||||
pa_source *s;
|
pa_log_debug("Not restoring device for stream %s, because already set", name);
|
||||||
|
else if ((e = read_entry(u, name))) {
|
||||||
|
pa_source *s = NULL;
|
||||||
|
|
||||||
if (e->device_valid) {
|
if (e->device_valid)
|
||||||
if ((s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE))) {
|
s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE);
|
||||||
if (!new_data->source) {
|
|
||||||
pa_log_info("Restoring device for stream %s.", name);
|
if (!s && e->card_valid) {
|
||||||
new_data->source = s;
|
pa_card *card;
|
||||||
new_data->save_source = TRUE;
|
|
||||||
} else
|
if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
|
||||||
pa_log_debug("Not restoring device for stream %s, because already set", name);
|
s = pa_idxset_first(card->sources, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* It might happen that a stream and a sink are set up at the
|
||||||
|
same time, in which case we want to make sure we don't
|
||||||
|
interfere with that */
|
||||||
|
if (s && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) {
|
||||||
|
pa_log_info("Restoring device for stream %s.", name);
|
||||||
|
new_data->source = s;
|
||||||
|
new_data->save_source = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_xfree(e);
|
pa_xfree(e);
|
||||||
|
|
@ -496,6 +540,12 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct
|
||||||
if (si->save_sink)
|
if (si->save_sink)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* It might happen that a stream and a sink are set up at the
|
||||||
|
same time, in which case we want to make sure we don't
|
||||||
|
interfere with that */
|
||||||
|
if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(name = get_name(si->proplist, "sink-input")))
|
if (!(name = get_name(si->proplist, "sink-input")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -534,6 +584,12 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
|
||||||
if (so->direct_on_input)
|
if (so->direct_on_input)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* It might happen that a stream and a sink are set up at the
|
||||||
|
same time, in which case we want to make sure we don't
|
||||||
|
interfere with that */
|
||||||
|
if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(name = get_name(so->proplist, "source-input")))
|
if (!(name = get_name(so->proplist, "source-input")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -575,7 +631,9 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, str
|
||||||
if (e->device_valid) {
|
if (e->device_valid) {
|
||||||
pa_sink *d;
|
pa_sink *d;
|
||||||
|
|
||||||
if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && d != sink)
|
if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) &&
|
||||||
|
d != sink &&
|
||||||
|
PA_SINK_IS_LINKED(pa_sink_get_state(d)))
|
||||||
pa_sink_input_move_to(si, d, TRUE);
|
pa_sink_input_move_to(si, d, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -613,7 +671,9 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc
|
||||||
if (e->device_valid) {
|
if (e->device_valid) {
|
||||||
pa_source *d;
|
pa_source *d;
|
||||||
|
|
||||||
if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) && d != source)
|
if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) &&
|
||||||
|
d != source &&
|
||||||
|
PA_SOURCE_IS_LINKED(pa_source_get_state(d)))
|
||||||
pa_source_output_move_to(so, d, TRUE);
|
pa_source_output_move_to(so, d, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue