"restore_muted=<Save/restore muted states?> "
"on_hotplug=<When new device becomes available, recheck streams?> "
"on_rescue=<When device becomes unavailable, recheck streams?> "
- "fallback_table=<filename>");
+ "fallback_table=<filename>"
+ "preferred_stream_group=<prefer certain stream group in restore?> ");
#define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
#define IDENTIFICATION_PROPERTY "module-stream-restore.id"
"on_hotplug",
"on_rescue",
"fallback_table",
+ "preferred_stream_group",
NULL
};
pa_bool_t restore_muted:1;
pa_bool_t on_hotplug:1;
pa_bool_t on_rescue:1;
+ char *preferred_stream_group;
pa_native_protocol *protocol;
pa_idxset *subscribed;
if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx)))
return;
- if (!(name = pa_proplist_get_stream_group(sink_input->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(sink_input->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
return;
if ((old = entry_read(u, name))) {
if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx)))
return;
- if (!(name = pa_proplist_get_stream_group(source_output->proplist, "source-output", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(source_output->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
return;
if ((old = entry_read(u, name))) {
pa_assert(u);
pa_assert(u->restore_device);
- if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
return PA_HOOK_OK;
if (new_data->sink)
pa_assert(u);
pa_assert(u->restore_volume || u->restore_muted);
- if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
return PA_HOOK_OK;
if ((e = entry_read(u, name))) {
if (new_data->direct_on_input)
return PA_HOOK_OK;
- if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
return PA_HOOK_OK;
if (new_data->source)
pa_assert(u);
pa_assert(u->restore_volume || u->restore_muted);
- if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
return PA_HOOK_OK;
if ((e = entry_read(u, name))) {
if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
continue;
- if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(si->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
continue;
if ((e = entry_read(u, name))) {
if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
continue;
- if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(so->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
continue;
if ((e = entry_read(u, name))) {
if (!si->sink)
continue;
- if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(si->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
continue;
if ((e = entry_read(u, name))) {
if (!so->source)
continue;
- if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
+ if (!(name = pa_proplist_get_stream_group_extended(so->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
continue;
if ((e = entry_read(u, name))) {
char *n;
pa_sink *s;
- if (!(n = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
+ if (!(n = pa_proplist_get_stream_group_extended(si->proplist, "sink-input", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
continue;
if (!pa_streq(name, n)) {
char *n;
pa_source *s;
- if (!(n = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
+ if (!(n = pa_proplist_get_stream_group_extended(so->proplist, "source-output", IDENTIFICATION_PROPERTY, u->preferred_stream_group)))
continue;
if (!pa_streq(name, n)) {
pa_datum key;
pa_bool_t done;
#endif
+ const char *n;
pa_assert(m);
u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
+ u->preferred_stream_group = pa_xstrdup(pa_modargs_get_value(ma, "preferred_stream_group", NULL));
+
if (restore_device) {
/* A little bit earlier than module-intended-roles ... */
u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_hook_callback, u);
if (u->subscribed)
pa_idxset_free(u->subscribed, NULL);
+ if (u->preferred_stream_group)
+ pa_xfree(u->preferred_stream_group);
+
pa_xfree(u);
}
return t;
}
+
+char *pa_proplist_get_stream_group_extended(pa_proplist *p, const char *prefix, const char *cache, const char *preferred_stream_group) {
+ const char *r = NULL;
+ const char *q = NULL;
+ char *t;
+
+ if (!p)
+ return NULL;
+
+ if (cache && (r = pa_proplist_gets(p, cache)))
+ return pa_xstrdup(r);
+
+ if (!prefix)
+ prefix = "stream";
+
+ /* try first to get the preferred stream group, then fallback to hard coded order */
+ if (preferred_stream_group) {
+ if (!strcmp(preferred_stream_group, "media.role.within.application.name")) {
+ if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME)) &&
+ (q = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE))) {
+ t = pa_sprintf_malloc("%s-by-media-role-within-application-name:%s-%s", prefix, q, r);
+ } else {
+ /* make r NULL to be able to fallback to "standard" stream restore code */
+ r = NULL;
+ }
+ }
+ else if (r = pa_proplist_gets(p, preferred_stream_group)) {
+ if (!strcmp(preferred_stream_group, PA_PROP_MEDIA_ROLE))
+ t = pa_sprintf_malloc("%s-by-media-role:%s", prefix, r);
+ else if (!strcmp(preferred_stream_group, PA_PROP_APPLICATION_ID))
+ t = pa_sprintf_malloc("%s-by-application-id:%s", prefix, r);
+ else if (!strcmp(preferred_stream_group, PA_PROP_APPLICATION_NAME))
+ t = pa_sprintf_malloc("%s-by-application-name:%s", prefix, r);
+ else if (!strcmp(preferred_stream_group, PA_PROP_MEDIA_NAME))
+ t = pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
+ else
+ t = pa_sprintf_malloc("%s-fallback:%s", prefix, r);
+ }
+ }
+
+ if (!r) {
+ if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE)))
+ t = pa_sprintf_malloc("%s-by-media-role:%s", prefix, r);
+ else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_ID)))
+ t = pa_sprintf_malloc("%s-by-application-id:%s", prefix, r);
+ else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME)))
+ t = pa_sprintf_malloc("%s-by-application-name:%s", prefix, r);
+ else if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_NAME)))
+ t = pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
+ else
+ t = pa_sprintf_malloc("%s-fallback:%s", prefix, r);
+ }
+
+ if (cache)
+ pa_proplist_sets(p, cache, t);
+
+ return t;
+}