mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-05 13:30:02 -05:00
media-session: use restore stream for routeless nodes
When a node does not have routes, treat it like a stream and use the restore-stream logic to restore the volumes. Rework some of the logic a little. Don't save empty strings. Wait for param updates to save/restore values. This makes volume restore work on virtual sinks/sources and sinks/sources without any routes. See #729
This commit is contained in:
parent
fc44013d17
commit
7ee52b396d
1 changed files with 63 additions and 48 deletions
|
|
@ -208,6 +208,11 @@ static char *serialize_props(struct stream *str, const struct spa_pod *param)
|
|||
|
||||
fprintf(f, " }");
|
||||
fclose(f);
|
||||
|
||||
if (strlen(ptr) < 5) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
|
@ -257,31 +262,42 @@ static int handle_props(struct stream *str, struct sm_param *p)
|
|||
const char *key;
|
||||
int changed = 0;
|
||||
|
||||
key = str->key;
|
||||
if (key == NULL)
|
||||
if ((key = str->key) == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
if (p->param) {
|
||||
char *val = serialize_props(str, p->param);
|
||||
pw_log_debug("stream %d: current props %s %s", str->id, key, val);
|
||||
if (val) {
|
||||
pw_log_info("stream %d: save props %s %s", str->id, key, val);
|
||||
changed += pw_properties_set(impl->props, key, val);
|
||||
free(val);
|
||||
add_idle_timeout(impl);
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
sync_metadata(impl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restore_stream(struct stream *str, const char *val)
|
||||
static int restore_stream(struct stream *str)
|
||||
{
|
||||
struct impl *impl = str->impl;
|
||||
struct spa_json it[3];
|
||||
const char *value;
|
||||
const char *val, *value;
|
||||
char buf[1024], key[128];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod *param;
|
||||
|
||||
if (str->key == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
val = pw_properties_get(impl->props, str->key);
|
||||
if (val == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
pw_log_info("stream %d: restore '%s' to %s", str->id, str->key, val);
|
||||
|
||||
spa_json_init(&it[0], val, strlen(val));
|
||||
|
||||
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
|
||||
|
|
@ -369,63 +385,8 @@ static int restore_stream(struct stream *str, const char *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void update_key(struct stream *str)
|
||||
static int save_stream(struct stream *str)
|
||||
{
|
||||
struct impl *impl = str->impl;
|
||||
uint32_t i;
|
||||
const char *p, *val;
|
||||
char *key;
|
||||
struct sm_object *obj = &str->obj->obj;
|
||||
bool changed;
|
||||
const char *keys[] = {
|
||||
PW_KEY_MEDIA_ROLE,
|
||||
PW_KEY_APP_ID,
|
||||
PW_KEY_APP_NAME,
|
||||
PW_KEY_MEDIA_NAME,
|
||||
};
|
||||
|
||||
key = NULL;
|
||||
for (i = 0; i < SPA_N_ELEMENTS(keys); i++) {
|
||||
if ((p = pw_properties_get(obj->props, keys[i]))) {
|
||||
key = spa_aprintf(PREFIX"%s.%s:%s", str->media_class, keys[i], p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (key == NULL)
|
||||
return;
|
||||
|
||||
pw_log_debug(NAME " %p: stream %p key '%s'", impl, str, key);
|
||||
changed = str->key == NULL || strcmp(str->key, key) != 0;
|
||||
free(str->key);
|
||||
str->key = key;
|
||||
if (!changed || str->restored)
|
||||
return;
|
||||
|
||||
val = pw_properties_get(impl->props, key);
|
||||
if (val != NULL) {
|
||||
pw_log_info("stream %d: restore '%s' to %s", str->id, key, val);
|
||||
restore_stream(str, val);
|
||||
str->restored = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void object_update(void *data)
|
||||
{
|
||||
struct stream *str = data;
|
||||
struct impl *impl = str->impl;
|
||||
bool rescan = false;
|
||||
|
||||
pw_log_debug(NAME" %p: stream %p %08x/%08x", impl, str,
|
||||
str->obj->obj.changed, str->obj->obj.avail);
|
||||
|
||||
if (str->obj->obj.changed & SM_OBJECT_CHANGE_MASK_PROPERTIES) {
|
||||
if (str->key == NULL)
|
||||
update_key(str);
|
||||
}
|
||||
if (str->obj->obj.changed & SM_NODE_CHANGE_MASK_PARAMS)
|
||||
rescan = true;
|
||||
|
||||
if (rescan) {
|
||||
struct sm_param *p;
|
||||
spa_list_for_each(p, &str->obj->param_list, link) {
|
||||
if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG))
|
||||
|
|
@ -439,7 +400,56 @@ static void object_update(void *data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_stream(struct stream *str)
|
||||
{
|
||||
struct impl *impl = str->impl;
|
||||
uint32_t i;
|
||||
const char *p;
|
||||
char *key;
|
||||
struct sm_object *obj = &str->obj->obj;
|
||||
const char *keys[] = {
|
||||
PW_KEY_MEDIA_ROLE,
|
||||
PW_KEY_APP_ID,
|
||||
PW_KEY_APP_NAME,
|
||||
PW_KEY_MEDIA_NAME,
|
||||
PW_KEY_NODE_NAME,
|
||||
};
|
||||
|
||||
key = NULL;
|
||||
for (i = 0; i < SPA_N_ELEMENTS(keys); i++) {
|
||||
if ((p = pw_properties_get(obj->props, keys[i]))) {
|
||||
key = spa_aprintf(PREFIX"%s.%s:%s", str->media_class, keys[i], p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (key == NULL)
|
||||
return;
|
||||
|
||||
pw_log_debug(NAME " %p: stream %p key '%s'", impl, str, key);
|
||||
free(str->key);
|
||||
str->key = key;
|
||||
|
||||
if (!str->restored) {
|
||||
restore_stream(str);
|
||||
str->restored = true;
|
||||
} else {
|
||||
save_stream(str);
|
||||
}
|
||||
}
|
||||
|
||||
static void object_update(void *data)
|
||||
{
|
||||
struct stream *str = data;
|
||||
struct impl *impl = str->impl;
|
||||
|
||||
pw_log_info(NAME" %p: stream %p %08x/%08x", impl, str,
|
||||
str->obj->obj.changed, str->obj->obj.avail);
|
||||
|
||||
if (str->obj->obj.changed & SM_NODE_CHANGE_MASK_PARAMS)
|
||||
update_stream(str);
|
||||
}
|
||||
|
||||
static const struct sm_object_events object_events = {
|
||||
|
|
@ -451,24 +461,29 @@ static void session_create(void *data, struct sm_object *object)
|
|||
{
|
||||
struct impl *impl = data;
|
||||
struct stream *str;
|
||||
const char *media_class;
|
||||
const char *media_class, *routes;
|
||||
|
||||
if (strcmp(object->type, PW_TYPE_INTERFACE_Node) != 0 ||
|
||||
object->props == NULL ||
|
||||
(media_class = pw_properties_get(object->props, PW_KEY_MEDIA_CLASS)) == NULL ||
|
||||
strstr(media_class, "Stream/") != media_class)
|
||||
(media_class = pw_properties_get(object->props, PW_KEY_MEDIA_CLASS)) == NULL)
|
||||
return;
|
||||
|
||||
if (strstr(media_class, "Stream/") == media_class) {
|
||||
media_class += strlen("Stream/");
|
||||
|
||||
pw_log_debug(NAME " %p: add stream '%d' %s", impl, object->id, media_class);
|
||||
} else if (strstr(media_class, "Audio/") == media_class &&
|
||||
((routes = pw_properties_get(object->props, "device.routes")) == NULL ||
|
||||
atoi(routes) == 0)) {
|
||||
pw_log_debug(NAME " %p: add node '%d' %s", impl, object->id, media_class);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
str = sm_object_add_data(object, SESSION_KEY, sizeof(struct stream));
|
||||
str->obj = (struct sm_node*)object;
|
||||
str->id = object->id;
|
||||
str->impl = impl;
|
||||
str->media_class = strdup(media_class);
|
||||
update_key(str);
|
||||
|
||||
str->obj->obj.mask |= SM_OBJECT_CHANGE_MASK_PROPERTIES | SM_NODE_CHANGE_MASK_PARAMS;
|
||||
sm_object_add_listener(&str->obj->obj, &str->listener, &object_events, str);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue