mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Rework profile/route handling
Add save property to Profile and Route params to notify the session manager that they should be saved. Let the session manager only save the Profile and Routes with the save flag. Make pulse-server set the save flag on Profile and Route changes. The result is that we can make a difference between user requested changes and automatical changes and only remember the user preferences. When a port changes availability, first check if we need to perform a profile switch, if not select the new best port.
This commit is contained in:
parent
5ae92fd643
commit
8414092763
9 changed files with 176 additions and 105 deletions
|
|
@ -119,6 +119,7 @@ enum spa_param_profile {
|
|||
* String : property (eg. "card.profile.devices"),
|
||||
* Array of Int: device indexes
|
||||
* )*)) */
|
||||
SPA_PARAM_PROFILE_save, /**< If profile should be saved (Bool) */
|
||||
};
|
||||
|
||||
enum spa_param_port_config_mode {
|
||||
|
|
@ -159,6 +160,7 @@ enum spa_param_route {
|
|||
SPA_PARAM_ROUTE_props, /**< properties SPA_TYPE_OBJECT_Props */
|
||||
SPA_PARAM_ROUTE_devices, /**< associated device indexes (Array of Int) */
|
||||
SPA_PARAM_ROUTE_profile, /**< profile id (Int) */
|
||||
SPA_PARAM_ROUTE_save, /**< If route should be saved (Bool) */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ static const struct spa_type_info spa_type_param_profile[] = {
|
|||
{ SPA_PARAM_PROFILE_available, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_PROFILE_BASE "available", spa_type_param_availability, },
|
||||
{ SPA_PARAM_PROFILE_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "info", NULL, },
|
||||
{ SPA_PARAM_PROFILE_classes, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_PROFILE_BASE "classes", NULL, },
|
||||
{ SPA_PARAM_PROFILE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_PROFILE_BASE "save", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
|
|
@ -357,6 +358,7 @@ static const struct spa_type_info spa_type_param_route[] = {
|
|||
{ SPA_PARAM_ROUTE_props, SPA_TYPE_OBJECT_Props, SPA_TYPE_INFO_PARAM_ROUTE_BASE "props", NULL, },
|
||||
{ SPA_PARAM_ROUTE_devices, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "devices", NULL, },
|
||||
{ SPA_PARAM_ROUTE_profile, SPA_TYPE_Int, SPA_TYPE_INFO_PARAM_ROUTE_BASE "profile", NULL, },
|
||||
{ SPA_PARAM_ROUTE_save, SPA_TYPE_Bool, SPA_TYPE_INFO_PARAM_ROUTE_BASE "save", NULL, },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ static int cmd_set_profile(struct data *data, const struct command *cmd, int arg
|
|||
else
|
||||
index = card->active_profile_index;
|
||||
|
||||
return acp_card_set_profile(card, index);
|
||||
return acp_card_set_profile(card, index, 0);
|
||||
}
|
||||
|
||||
static int cmd_list_ports(struct data *data, const struct command *cmd, int argc, char *argv[])
|
||||
|
|
@ -355,7 +355,7 @@ static int cmd_set_port(struct data *data, const struct command *cmd, int argc,
|
|||
if (dev_id >= card->n_devices)
|
||||
return -EINVAL;
|
||||
|
||||
return acp_device_set_port(card->devices[dev_id], port_id);
|
||||
return acp_device_set_port(card->devices[dev_id], port_id, 0);
|
||||
}
|
||||
|
||||
static int cmd_list_devices(struct data *data, const struct command *cmd, int argc, char *argv[])
|
||||
|
|
|
|||
|
|
@ -1328,7 +1328,7 @@ static int device_enable(pa_card *impl, pa_alsa_mapping *mapping, pa_alsa_device
|
|||
return 0;
|
||||
}
|
||||
|
||||
int acp_card_set_profile(struct acp_card *card, uint32_t new_index)
|
||||
int acp_card_set_profile(struct acp_card *card, uint32_t new_index, uint32_t flags)
|
||||
{
|
||||
pa_card *impl = (pa_card *)card;
|
||||
pa_alsa_mapping *am;
|
||||
|
|
@ -1397,8 +1397,8 @@ int acp_card_set_profile(struct acp_card *card, uint32_t new_index)
|
|||
}
|
||||
}
|
||||
if (op)
|
||||
op->profile.flags &= ~ACP_PROFILE_ACTIVE;
|
||||
np->profile.flags |= ACP_PROFILE_ACTIVE;
|
||||
op->profile.flags &= ~(ACP_PROFILE_ACTIVE | ACP_PROFILE_SAVE);
|
||||
np->profile.flags |= ACP_PROFILE_ACTIVE | flags;
|
||||
impl->card.active_profile_index = new_index;
|
||||
|
||||
if (impl->events && impl->events->profile_changed)
|
||||
|
|
@ -1566,7 +1566,7 @@ struct acp_card *acp_card_new(uint32_t index, const struct acp_dict *props)
|
|||
profile = "off";
|
||||
|
||||
profile_index = acp_card_find_best_profile_index(&impl->card, profile);
|
||||
acp_card_set_profile(&impl->card, profile_index);
|
||||
acp_card_set_profile(&impl->card, profile_index, 0);
|
||||
|
||||
init_eld_ctls(impl);
|
||||
|
||||
|
|
@ -1744,7 +1744,7 @@ uint32_t acp_device_find_best_port_index(struct acp_device *dev, const char *nam
|
|||
return ACP_INVALID_INDEX;
|
||||
}
|
||||
|
||||
int acp_device_set_port(struct acp_device *dev, uint32_t port_index)
|
||||
int acp_device_set_port(struct acp_device *dev, uint32_t port_index, uint32_t flags)
|
||||
{
|
||||
pa_alsa_device *d = (pa_alsa_device*)dev;
|
||||
pa_card *impl = d->card;
|
||||
|
|
@ -1762,9 +1762,9 @@ int acp_device_set_port(struct acp_device *dev, uint32_t port_index)
|
|||
return -EINVAL;
|
||||
|
||||
if (old)
|
||||
old->port.flags &= ~ACP_PORT_ACTIVE;
|
||||
old->port.flags &= ~(ACP_PORT_ACTIVE | ACP_PORT_SAVE);
|
||||
d->active_port = p;
|
||||
p->port.flags |= ACP_PORT_ACTIVE;
|
||||
p->port.flags |= ACP_PORT_ACTIVE | flags;
|
||||
|
||||
if (impl->use_ucm) {
|
||||
pa_alsa_ucm_port_data *data;
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ struct acp_card_events {
|
|||
struct acp_port {
|
||||
uint32_t index; /**< unique index for this port */
|
||||
#define ACP_PORT_ACTIVE (1<<0)
|
||||
#define ACP_PORT_SAVE (1<<1) /* if the port needs saving */
|
||||
uint32_t flags; /**< extra port flags */
|
||||
|
||||
const char *name; /**< Name of this port */
|
||||
|
|
@ -229,6 +230,7 @@ struct acp_card_profile {
|
|||
uint32_t index;
|
||||
#define ACP_PROFILE_ACTIVE (1<<0)
|
||||
#define ACP_PROFILE_OFF (1<<1) /* the Off profile */
|
||||
#define ACP_PROFILE_SAVE (1<<2) /* if the profile needs saving */
|
||||
uint32_t flags;
|
||||
|
||||
const char *name;
|
||||
|
|
@ -274,10 +276,10 @@ int acp_card_poll_descriptors_revents(struct acp_card *card, struct pollfd *pfds
|
|||
int acp_card_handle_events(struct acp_card *card);
|
||||
|
||||
uint32_t acp_card_find_best_profile_index(struct acp_card *card, const char *name);
|
||||
int acp_card_set_profile(struct acp_card *card, uint32_t profile_index);
|
||||
int acp_card_set_profile(struct acp_card *card, uint32_t profile_index, uint32_t flags);
|
||||
|
||||
uint32_t acp_device_find_best_port_index(struct acp_device *dev, const char *name);
|
||||
int acp_device_set_port(struct acp_device *dev, uint32_t port_index);
|
||||
int acp_device_set_port(struct acp_device *dev, uint32_t port_index, uint32_t flags);
|
||||
|
||||
int acp_device_set_volume(struct acp_device *dev, const float *volume, uint32_t n_volume);
|
||||
int acp_device_get_volume(struct acp_device *dev, float *volume, uint32_t n_volume);
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ static int impl_sync(void *object, int seq)
|
|||
}
|
||||
|
||||
static struct spa_pod *build_profile(struct spa_pod_builder *b, uint32_t id,
|
||||
struct acp_card_profile *pr)
|
||||
struct acp_card_profile *pr, bool current)
|
||||
{
|
||||
struct spa_pod_frame f[2];
|
||||
uint32_t i, n_classes, n_capture = 0, n_playback = 0;
|
||||
|
|
@ -345,6 +345,11 @@ static struct spa_pod *build_profile(struct spa_pod_builder *b, uint32_t id,
|
|||
n_playback, playback));
|
||||
}
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
if (current) {
|
||||
spa_pod_builder_prop(b, SPA_PARAM_PROFILE_save, 0);
|
||||
spa_pod_builder_bool(b, SPA_FLAG_IS_SET(pr->flags, ACP_PROFILE_SAVE));
|
||||
}
|
||||
|
||||
return spa_pod_builder_pop(b, &f[0]);
|
||||
}
|
||||
|
||||
|
|
@ -438,6 +443,8 @@ static struct spa_pod *build_route(struct spa_pod_builder *b, uint32_t id,
|
|||
if (profile != SPA_ID_INVALID) {
|
||||
spa_pod_builder_prop(b, SPA_PARAM_ROUTE_profile, 0);
|
||||
spa_pod_builder_int(b, profile);
|
||||
spa_pod_builder_prop(b, SPA_PARAM_ROUTE_save, 0);
|
||||
spa_pod_builder_bool(b, SPA_FLAG_IS_SET(p->flags, ACP_PORT_SAVE));
|
||||
}
|
||||
return spa_pod_builder_pop(b, &f[0]);
|
||||
}
|
||||
|
|
@ -486,7 +493,7 @@ static int impl_enum_params(void *object, int seq,
|
|||
return 0;
|
||||
|
||||
pr = card->profiles[result.index];
|
||||
param = build_profile(&b, id, pr);
|
||||
param = build_profile(&b, id, pr, false);
|
||||
break;
|
||||
|
||||
case SPA_PARAM_Profile:
|
||||
|
|
@ -494,7 +501,7 @@ static int impl_enum_params(void *object, int seq,
|
|||
return 0;
|
||||
|
||||
pr = card->profiles[card->active_profile_index];
|
||||
param = build_profile(&b, id, pr);
|
||||
param = build_profile(&b, id, pr, true);
|
||||
break;
|
||||
|
||||
case SPA_PARAM_EnumRoute:
|
||||
|
|
@ -600,16 +607,18 @@ static int impl_set_param(void *object,
|
|||
case SPA_PARAM_Profile:
|
||||
{
|
||||
uint32_t id;
|
||||
bool save = false;
|
||||
|
||||
if ((res = spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamProfile, NULL,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(&id))) < 0) {
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(&id),
|
||||
SPA_PARAM_PROFILE_save, SPA_POD_OPT_Bool(&save))) < 0) {
|
||||
spa_log_warn(this->log, "can't parse profile");
|
||||
spa_debug_pod(0, NULL, param);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = acp_card_set_profile(this->card, id);
|
||||
res = acp_card_set_profile(this->card, id, save ? ACP_PROFILE_SAVE : 0);
|
||||
emit_info(this, false);
|
||||
break;
|
||||
}
|
||||
|
|
@ -618,12 +627,14 @@ static int impl_set_param(void *object,
|
|||
uint32_t id, device;
|
||||
struct spa_pod *props = NULL;
|
||||
struct acp_device *dev;
|
||||
bool save = false;
|
||||
|
||||
if ((res = spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamRoute, NULL,
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(&id),
|
||||
SPA_PARAM_ROUTE_device, SPA_POD_Int(&device),
|
||||
SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props))) < 0) {
|
||||
SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&props),
|
||||
SPA_PARAM_ROUTE_save, SPA_POD_OPT_Bool(&save))) < 0) {
|
||||
spa_log_warn(this->log, "can't parse route");
|
||||
spa_debug_pod(0, NULL, param);
|
||||
return res;
|
||||
|
|
@ -632,7 +643,7 @@ static int impl_set_param(void *object,
|
|||
return -EINVAL;
|
||||
|
||||
dev = this->card->devices[device];
|
||||
res = acp_device_set_port(dev, id);
|
||||
res = acp_device_set_port(dev, id, save ? ACP_PORT_SAVE : 0);
|
||||
if (props)
|
||||
apply_device_props(this, dev, props);
|
||||
emit_info(this, false);
|
||||
|
|
@ -712,7 +723,7 @@ static void card_profile_available(void *data, uint32_t index,
|
|||
|
||||
if (this->props.auto_profile) {
|
||||
uint32_t best = acp_card_find_best_profile_index(card, NULL);
|
||||
acp_card_set_profile(card, best);
|
||||
acp_card_set_profile(card, best, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -755,7 +766,7 @@ static void card_port_available(void *data, uint32_t index,
|
|||
continue;
|
||||
|
||||
best = acp_device_find_best_port_index(d, NULL);
|
||||
acp_device_set_port(d, best);
|
||||
acp_device_set_port(d, best, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ struct profile {
|
|||
const char *name;
|
||||
uint32_t prio;
|
||||
uint32_t available;
|
||||
bool save;
|
||||
};
|
||||
|
||||
static int parse_profile(struct sm_param *p, struct profile *pr)
|
||||
|
|
@ -127,25 +128,14 @@ static int parse_profile(struct sm_param *p, struct profile *pr)
|
|||
pr->p = p;
|
||||
pr->prio = 0;
|
||||
pr->available = SPA_PARAM_AVAILABILITY_unknown;
|
||||
pr->save = false;
|
||||
return spa_pod_parse_object(p->param,
|
||||
SPA_TYPE_OBJECT_ParamProfile, NULL,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(&pr->index),
|
||||
SPA_PARAM_PROFILE_name, SPA_POD_String(&pr->name),
|
||||
SPA_PARAM_PROFILE_priority, SPA_POD_OPT_Int(&pr->prio),
|
||||
SPA_PARAM_PROFILE_available, SPA_POD_OPT_Id(&pr->available));
|
||||
}
|
||||
|
||||
static int find_profile(struct device *dev, uint32_t index, struct profile *pr)
|
||||
{
|
||||
struct sm_param *p;
|
||||
spa_list_for_each(p, &dev->obj->param_list, link) {
|
||||
if (p->id != SPA_PARAM_EnumProfile ||
|
||||
parse_profile(p, pr) < 0)
|
||||
continue;
|
||||
if (index == pr->index)
|
||||
return 0;
|
||||
}
|
||||
return -ENOENT;
|
||||
SPA_PARAM_PROFILE_available, SPA_POD_OPT_Id(&pr->available),
|
||||
SPA_PARAM_PROFILE_save, SPA_POD_OPT_Bool(&pr->save));
|
||||
}
|
||||
|
||||
static int find_current_profile(struct device *dev, struct profile *pr)
|
||||
|
|
@ -252,7 +242,8 @@ static int set_profile(struct device *dev, struct profile *pr)
|
|||
SPA_PARAM_Profile, 0,
|
||||
spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(pr->index)));
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(pr->index),
|
||||
SPA_PARAM_PROFILE_save, SPA_POD_Bool(pr->save)));
|
||||
|
||||
dev->active_profile = pr->index;
|
||||
|
||||
|
|
@ -265,33 +256,6 @@ static int handle_profile(struct device *dev)
|
|||
struct profile pr;
|
||||
int res;
|
||||
|
||||
if (dev->active_profile != SPA_ID_INVALID) {
|
||||
/* we have a profile, find it */
|
||||
res = find_profile(dev, dev->active_profile, &pr);
|
||||
if (res < 0 || pr.available == SPA_PARAM_AVAILABILITY_no) {
|
||||
/* we had a profile but it is now gone or not available,
|
||||
* try to restore a new profile */
|
||||
if (res < 0)
|
||||
pw_log_info("device '%s': active profile index %d removed",
|
||||
dev->name, dev->active_profile);
|
||||
else
|
||||
pw_log_info("device '%s': active profile '%s' unavailable",
|
||||
dev->name, pr.name);
|
||||
|
||||
dev->restored = false;
|
||||
} else if (dev->saved_profile != SPA_ID_INVALID && pr.index != dev->saved_profile) {
|
||||
struct profile saved;
|
||||
/* we had a saved profile but we're on some other profile,
|
||||
* see if the saved profile is available now and switch to it */
|
||||
res = find_saved_profile(dev, &saved);
|
||||
if (res >= 0 && saved.available != SPA_PARAM_AVAILABILITY_no) {
|
||||
pw_log_info("device '%s': restore saved profile '%s' index %d",
|
||||
dev->name, saved.name, saved.index);
|
||||
if (set_profile(dev, &saved) >= 0)
|
||||
dev->restored = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dev->restored) {
|
||||
/* first try to restore our saved profile */
|
||||
res = find_saved_profile(dev, &pr);
|
||||
|
|
@ -316,6 +280,8 @@ static int handle_profile(struct device *dev)
|
|||
pw_log_info("device '%s': found saved profile '%s'",
|
||||
dev->name, pr.name);
|
||||
dev->saved_profile = pr.index;
|
||||
/* make sure we save again */
|
||||
pr.save = true;
|
||||
}
|
||||
if (res >= 0) {
|
||||
pw_log_info("device '%s': restore profile '%s' index %d",
|
||||
|
|
@ -332,9 +298,13 @@ static int handle_profile(struct device *dev)
|
|||
if (dev->active_profile == pr.index)
|
||||
return 0;
|
||||
|
||||
/* we get here when had configured a profile but something
|
||||
* else changed it, in that case, save it. */
|
||||
/* we get here when we had configured a profile but something
|
||||
* else changed it, in that case, save it when asked. */
|
||||
dev->active_profile = pr.index;
|
||||
|
||||
if (!pr.save)
|
||||
return 0;
|
||||
|
||||
dev->saved_profile = pr.index;
|
||||
if (pw_properties_setf(impl->properties, dev->key, "{ \"name\": \"%s\" }", pr.name)) {
|
||||
pw_log_info("device '%s': active profile changed to '%s'", dev->name, pr.name);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ struct route {
|
|||
uint32_t priority;
|
||||
uint32_t available;
|
||||
struct spa_pod *props;
|
||||
bool save;
|
||||
};
|
||||
|
||||
#define ROUTE_INIT(__p) (struct route) { \
|
||||
|
|
@ -194,7 +195,8 @@ static int parse_route(struct sm_param *p, struct route *r)
|
|||
SPA_PARAM_ROUTE_name, SPA_POD_String(&r->name),
|
||||
SPA_PARAM_ROUTE_priority, SPA_POD_OPT_Int(&r->priority),
|
||||
SPA_PARAM_ROUTE_available, SPA_POD_OPT_Id(&r->available),
|
||||
SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&r->props));
|
||||
SPA_PARAM_ROUTE_props, SPA_POD_OPT_Pod(&r->props),
|
||||
SPA_PARAM_ROUTE_save, SPA_POD_OPT_Bool(&r->save));
|
||||
}
|
||||
|
||||
static bool array_contains(struct spa_pod *pod, uint32_t val)
|
||||
|
|
@ -316,7 +318,7 @@ static char *serialize_props(struct device *dev, const struct spa_pod *param)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static int restore_route_params(struct device *dev, const char *val, uint32_t index, uint32_t device_id)
|
||||
static int restore_route_params(struct device *dev, const char *val, struct route *r)
|
||||
{
|
||||
struct spa_json it[3];
|
||||
char buf[1024], key[128];
|
||||
|
|
@ -333,8 +335,8 @@ static int restore_route_params(struct device *dev, const char *val, uint32_t in
|
|||
spa_pod_builder_push_object(&b, &f[0],
|
||||
SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route);
|
||||
spa_pod_builder_add(&b,
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(index),
|
||||
SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id),
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(r->index),
|
||||
SPA_PARAM_ROUTE_device, SPA_POD_Int(r->device_id),
|
||||
0);
|
||||
spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0);
|
||||
spa_pod_builder_push_object(&b, &f[1],
|
||||
|
|
@ -405,6 +407,8 @@ static int restore_route_params(struct device *dev, const char *val, uint32_t in
|
|||
}
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_save, 0);
|
||||
spa_pod_builder_bool(&b, r->save);
|
||||
param = spa_pod_builder_pop(&b, &f[0]);
|
||||
|
||||
if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG))
|
||||
|
|
@ -418,6 +422,8 @@ static int restore_route_params(struct device *dev, const char *val, uint32_t in
|
|||
struct profile {
|
||||
uint32_t index;
|
||||
const char *name;
|
||||
uint32_t prio;
|
||||
uint32_t available;
|
||||
struct spa_pod *classes;
|
||||
};
|
||||
|
||||
|
|
@ -429,6 +435,8 @@ static int parse_profile(struct sm_param *p, struct profile *pr)
|
|||
SPA_TYPE_OBJECT_ParamProfile, NULL,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(&pr->index),
|
||||
SPA_PARAM_PROFILE_name, SPA_POD_String(&pr->name),
|
||||
SPA_PARAM_PROFILE_priority, SPA_POD_OPT_Int(&pr->prio),
|
||||
SPA_PARAM_PROFILE_available, SPA_POD_OPT_Id(&pr->available),
|
||||
SPA_PARAM_PROFILE_classes, SPA_POD_OPT_Pod(&pr->classes))) < 0)
|
||||
return res;
|
||||
return 0;
|
||||
|
|
@ -445,7 +453,50 @@ static int find_current_profile(struct device *dev, struct profile *pr)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int restore_route(struct device *dev, struct route *r, bool save)
|
||||
static int find_best_profile(struct device *dev, struct profile *pr)
|
||||
{
|
||||
struct sm_param *p;
|
||||
struct profile best, best_avail, best_unk, off;
|
||||
|
||||
spa_zero(best);
|
||||
spa_zero(best_avail);
|
||||
spa_zero(best_unk);
|
||||
spa_zero(off);
|
||||
|
||||
spa_list_for_each(p, &dev->obj->param_list, link) {
|
||||
struct profile t;
|
||||
|
||||
if (p->id != SPA_PARAM_EnumProfile ||
|
||||
parse_profile(p, &t) < 0)
|
||||
continue;
|
||||
|
||||
if (t.name && strcmp(t.name, "pro-audio") == 0)
|
||||
continue;
|
||||
|
||||
if (t.name && strcmp(t.name, "off") == 0) {
|
||||
off = t;
|
||||
}
|
||||
else if (t.available == SPA_PARAM_AVAILABILITY_yes) {
|
||||
if (best_avail.name == NULL || t.prio > best_avail.prio)
|
||||
best_avail = t;
|
||||
}
|
||||
else if (t.available != SPA_PARAM_AVAILABILITY_no) {
|
||||
if (best_unk.name == NULL || t.prio > best_unk.prio)
|
||||
best_unk = t;
|
||||
}
|
||||
}
|
||||
best = best_avail;
|
||||
if (best.name == NULL)
|
||||
best = best_unk;
|
||||
if (best.name == NULL)
|
||||
best = off;
|
||||
if (best.name == NULL)
|
||||
return -ENOENT;
|
||||
*pr = best;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restore_route(struct device *dev, struct route *r)
|
||||
{
|
||||
struct impl *impl = dev->impl;
|
||||
char key[1024];
|
||||
|
|
@ -464,10 +515,10 @@ static int restore_route(struct device *dev, struct route *r, bool save)
|
|||
|
||||
pw_log_info("device %d: restore route %d '%s' to %s", dev->id, r->index, key, val);
|
||||
|
||||
restore_route_params(dev, val, r->index, r->device_id);
|
||||
restore_route_params(dev, val, r);
|
||||
ri->generation = dev->generation;
|
||||
ri->restore = false;
|
||||
ri->save = save;
|
||||
ri->save = r->save;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -603,11 +654,24 @@ static int restore_device_route(struct device *dev, const char *val, uint32_t de
|
|||
{
|
||||
int res;
|
||||
struct route t;
|
||||
bool save = false;
|
||||
|
||||
pw_log_info("device %d: restoring device %u", dev->id, device_id);
|
||||
|
||||
res = find_saved_route(dev, val, device_id, &t);
|
||||
if (res >= 0) {
|
||||
/* we found a saved route */
|
||||
if (t.available == SPA_PARAM_AVAILABILITY_no) {
|
||||
pw_log_info("device %d: saved route '%s' not available", dev->id,
|
||||
t.name);
|
||||
/* not available, try to find next best port */
|
||||
res = -ENOENT;
|
||||
} else {
|
||||
pw_log_info("device %d: found saved route '%s'", dev->id,
|
||||
t.name);
|
||||
/* make sure we save it again */
|
||||
t.save = true;
|
||||
}
|
||||
}
|
||||
if (res < 0) {
|
||||
/* we could not find a saved route, try to find a new best */
|
||||
res = find_best_route(dev, device_id, &t);
|
||||
|
|
@ -617,16 +681,10 @@ static int restore_device_route(struct device *dev, const char *val, uint32_t de
|
|||
pw_log_info("device %d: found best route '%s'", dev->id,
|
||||
t.name);
|
||||
}
|
||||
} else {
|
||||
/* we found a saved route */
|
||||
pw_log_info("device %d: found saved route '%s'", dev->id,
|
||||
t.name);
|
||||
/* make sure we save it again */
|
||||
save = true;
|
||||
}
|
||||
if (res >= 0) {
|
||||
restore_route(dev, &t, save);
|
||||
}
|
||||
if (res >= 0)
|
||||
restore_route(dev, &t);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -702,15 +760,31 @@ static void prune_route_info(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static int set_profile(struct device *dev, struct profile *pr)
|
||||
{
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
|
||||
if (dev->active_profile == pr->index)
|
||||
return 0;
|
||||
|
||||
pw_device_set_param((struct pw_device*)dev->obj->obj.proxy,
|
||||
SPA_PARAM_Profile, 0,
|
||||
spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(pr->index),
|
||||
SPA_PARAM_PROFILE_save, SPA_POD_Bool(false)));
|
||||
|
||||
dev->active_profile = pr->index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_route(struct device *dev, struct route *r)
|
||||
{
|
||||
struct route_info *ri;
|
||||
bool restore = false;
|
||||
char key[1024];
|
||||
int res;
|
||||
bool save = false;
|
||||
|
||||
pw_log_info("device %d: route %s %p", dev->id, r->name, r->p);
|
||||
if ((ri = find_route_info(dev, r)) == NULL)
|
||||
return -errno;
|
||||
|
||||
|
|
@ -718,10 +792,27 @@ static int handle_route(struct device *dev, struct route *r)
|
|||
/* a new port has been found, restore the volume and make sure we
|
||||
* save this as a prefered port */
|
||||
pw_log_info("device %d: new port found '%s'", dev->id, r->name);
|
||||
save = true;
|
||||
restore = true;
|
||||
} else {
|
||||
if (r->available != SPA_PARAM_AVAILABILITY_yes && ri->available != r->available) {
|
||||
restore_route(dev, r);
|
||||
} else if (ri->available != r->available) {
|
||||
struct profile best;
|
||||
|
||||
ri->available = r->available;
|
||||
/* port availability changed, find new best profile and switch
|
||||
* to it when needed. */
|
||||
pw_log_info("device %d: route %s available changed %d -> %d",
|
||||
dev->id, r->name, ri->available, r->available);
|
||||
|
||||
if ((res = find_best_profile(dev, &best)) < 0) {
|
||||
pw_log_info("device %d: can't find best profile", dev->id);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (dev->active_profile != best.index) {
|
||||
pw_log_info("device %d: activating best profile %s",
|
||||
dev->id, best.name);
|
||||
/* we need to switch profiles */
|
||||
set_profile(dev, &best);
|
||||
} else if (r->available != SPA_PARAM_AVAILABILITY_yes) {
|
||||
struct route t;
|
||||
|
||||
/* an existing port has changed to unavailable */
|
||||
|
|
@ -734,25 +825,14 @@ static int handle_route(struct device *dev, struct route *r)
|
|||
} else {
|
||||
pw_log_info("device %d: found best route '%s'", dev->id,
|
||||
t.name);
|
||||
*r = t;
|
||||
restore = true;
|
||||
restore_route(dev, &t);
|
||||
}
|
||||
}
|
||||
ri->available = r->available;
|
||||
}
|
||||
ri->generation = dev->generation;
|
||||
|
||||
if (r == NULL)
|
||||
return -EIO;
|
||||
|
||||
snprintf(key, sizeof(key), PREFIX"%s:%s:%s", dev->name,
|
||||
r->direction == SPA_DIRECTION_INPUT ? "input" : "output", r->name);
|
||||
|
||||
if (restore) {
|
||||
restore_route(dev, r, save);
|
||||
} else if (r->props) {
|
||||
/* just save port properties */
|
||||
save_route(dev, r);
|
||||
}
|
||||
ri->generation = dev->generation;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2949,6 +2949,8 @@ static int set_card_volume_mute_delay(struct pw_manager_object *o, uint32_t id,
|
|||
spa_pod_builder_add(&b,
|
||||
SPA_PROP_latencyOffsetNsec, SPA_POD_Long(*latency_offset), 0);
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_save, 0);
|
||||
spa_pod_builder_bool(&b, true);
|
||||
param = spa_pod_builder_pop(&b, &f[0]);
|
||||
|
||||
pw_device_set_param((struct pw_device*)o->proxy,
|
||||
|
|
@ -2970,7 +2972,8 @@ static int set_card_port(struct pw_manager_object *o, uint32_t device_id,
|
|||
spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamRoute, SPA_PARAM_Route,
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(port_id),
|
||||
SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id)));
|
||||
SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id),
|
||||
SPA_PARAM_ROUTE_save, SPA_POD_Bool(true)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4693,7 +4696,8 @@ static int do_set_profile(struct client *client, uint32_t command, uint32_t tag,
|
|||
SPA_PARAM_Profile, 0,
|
||||
spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_id)));
|
||||
SPA_PARAM_PROFILE_index, SPA_POD_Int(profile_id),
|
||||
SPA_PARAM_PROFILE_save, SPA_POD_Bool(true)));
|
||||
|
||||
return reply_simple_ack(client, tag);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue