mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-23 20:24:21 +08:00
client/player: Add codec as parameter to endpoint.presets
This changes endpoint.presets command to take codec as parameter.
This commit is contained in:
parent
1707c35771
commit
f3977023f9
240
client/player.c
240
client/player.c
@ -78,6 +78,7 @@ struct endpoint {
|
||||
uint8_t cis;
|
||||
char *transport;
|
||||
DBusMessage *msg;
|
||||
struct preset *preset;
|
||||
};
|
||||
|
||||
static DBusConnection *dbus_conn;
|
||||
@ -1166,7 +1167,7 @@ struct codec_qos {
|
||||
};
|
||||
|
||||
struct codec_preset {
|
||||
const char *name;
|
||||
char *name;
|
||||
const struct iovec data;
|
||||
const struct codec_qos qos;
|
||||
uint8_t target_latency;
|
||||
@ -1410,9 +1411,10 @@ static struct codec_preset lc3_presets[] = {
|
||||
LC3_10_UNFRAMED(155u, 13u, 100u, 40000u)),
|
||||
};
|
||||
|
||||
#define PRESET(_uuid, _presets, _default_index) \
|
||||
#define PRESET(_uuid, _codec, _presets, _default_index) \
|
||||
{ \
|
||||
.uuid = _uuid, \
|
||||
.codec = _codec, \
|
||||
.custom = { .name = "custom" }, \
|
||||
.default_preset = &_presets[_default_index], \
|
||||
.presets = _presets, \
|
||||
@ -1421,46 +1423,142 @@ static struct codec_preset lc3_presets[] = {
|
||||
|
||||
static struct preset {
|
||||
const char *uuid;
|
||||
uint8_t codec;
|
||||
uint16_t cid;
|
||||
uint16_t vid;
|
||||
struct codec_preset custom;
|
||||
struct codec_preset *default_preset;
|
||||
struct codec_preset *presets;
|
||||
size_t num_presets;
|
||||
} presets[] = {
|
||||
PRESET(A2DP_SOURCE_UUID, sbc_presets, 6),
|
||||
PRESET(A2DP_SINK_UUID, sbc_presets, 6),
|
||||
PRESET(PAC_SINK_UUID, lc3_presets, 3),
|
||||
PRESET(PAC_SOURCE_UUID, lc3_presets, 3),
|
||||
PRESET(A2DP_SOURCE_UUID, A2DP_CODEC_SBC, sbc_presets, 6),
|
||||
PRESET(A2DP_SINK_UUID, A2DP_CODEC_SBC, sbc_presets, 6),
|
||||
PRESET(PAC_SINK_UUID, LC3_ID, lc3_presets, 3),
|
||||
PRESET(PAC_SOURCE_UUID, LC3_ID, lc3_presets, 3),
|
||||
};
|
||||
|
||||
static struct codec_preset *find_preset(const char *uuid, const char *name)
|
||||
static void parse_vendor_codec(const char *codec, uint16_t *vid, uint16_t *cid)
|
||||
{
|
||||
char **list;
|
||||
char *endptr = NULL;
|
||||
|
||||
if (!codec)
|
||||
return;
|
||||
|
||||
list = g_strsplit(codec, ":", 2);
|
||||
|
||||
if (vid)
|
||||
*vid = strtol(list[0], &endptr, 0);
|
||||
|
||||
if (cid)
|
||||
*cid = strtol(list[1], &endptr, 0);
|
||||
|
||||
g_strfreev(list);
|
||||
}
|
||||
|
||||
static struct preset *find_presets(const char *uuid, uint8_t codec,
|
||||
uint16_t vid, uint16_t cid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (codec == 0xff) {
|
||||
GList *l;
|
||||
|
||||
for (l = local_endpoints; l; l = g_list_next(l)) {
|
||||
struct endpoint *ep = l->data;
|
||||
|
||||
if (strcasecmp(ep->uuid, uuid) || ep->codec != codec)
|
||||
continue;
|
||||
|
||||
if (ep->codec == 0xff && (ep->vid != vid ||
|
||||
ep->cid != cid))
|
||||
continue;
|
||||
|
||||
return ep->preset;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(presets); i++) {
|
||||
struct preset *preset = &presets[i];
|
||||
|
||||
if (!strcasecmp(preset->uuid, uuid)) {
|
||||
size_t j;
|
||||
if (preset->codec != codec)
|
||||
continue;
|
||||
|
||||
if (!name)
|
||||
return preset->default_preset;
|
||||
else if (!strcmp(name, "custom"))
|
||||
return &preset->custom;
|
||||
|
||||
for (j = 0; j < preset->num_presets; j++) {
|
||||
struct codec_preset *p;
|
||||
|
||||
p = &preset->presets[j];
|
||||
|
||||
if (!strcmp(p->name, name))
|
||||
return p;
|
||||
}
|
||||
}
|
||||
if (!strcasecmp(preset->uuid, uuid))
|
||||
return preset;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct preset *find_vendor_presets(const char *uuid, const char *codec)
|
||||
{
|
||||
uint16_t cid;
|
||||
uint16_t vid;
|
||||
|
||||
if (!uuid || !codec)
|
||||
return NULL;
|
||||
|
||||
parse_vendor_codec(codec, &vid, &cid);
|
||||
|
||||
return find_presets(uuid, 0xff, vid, cid);
|
||||
}
|
||||
|
||||
static struct preset *find_presets_name(const char *uuid, const char *codec)
|
||||
{
|
||||
uint8_t id;
|
||||
char *endptr = NULL;
|
||||
|
||||
if (!uuid || !codec)
|
||||
return NULL;
|
||||
|
||||
if (strrchr(codec, ':'))
|
||||
return find_vendor_presets(uuid, codec);
|
||||
|
||||
id = strtol(codec, &endptr, 0);
|
||||
|
||||
return find_presets(uuid, id, 0x0000, 0x0000);
|
||||
}
|
||||
|
||||
static struct codec_preset *preset_find_name(struct preset *preset,
|
||||
const char *name)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!preset)
|
||||
return NULL;
|
||||
|
||||
if (!name)
|
||||
return preset->default_preset;
|
||||
else if (!strcmp(name, "custom"))
|
||||
return &preset->custom;
|
||||
|
||||
for (i = 0; i < preset->num_presets; i++) {
|
||||
struct codec_preset *p;
|
||||
|
||||
p = &preset->presets[i];
|
||||
|
||||
if (!strcmp(p->name, name))
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct codec_preset *find_preset(const char *uuid, const char *codec,
|
||||
const char *name)
|
||||
{
|
||||
struct preset *preset;
|
||||
|
||||
preset = find_presets_name(uuid, codec);
|
||||
if (!preset)
|
||||
return NULL;
|
||||
|
||||
return preset_find_name(preset, name);
|
||||
}
|
||||
|
||||
static DBusMessage *endpoint_select_config_reply(DBusMessage *msg,
|
||||
uint8_t *data, size_t len)
|
||||
{
|
||||
@ -1525,7 +1623,7 @@ static void select_config_response(const char *input, void *user_data)
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
|
||||
p = find_preset(ep->uuid, input);
|
||||
p = preset_find_name(ep->preset, input);
|
||||
if (p) {
|
||||
data = p->data.iov_base;
|
||||
len = p->data.iov_len;
|
||||
@ -1580,7 +1678,7 @@ static DBusMessage *endpoint_select_configuration(DBusConnection *conn,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = find_preset(ep->uuid, NULL);
|
||||
p = preset_find_name(ep->preset, NULL);
|
||||
if (!p) {
|
||||
reply = g_dbus_create_error(msg, "org.bluez.Error.Rejected",
|
||||
NULL);
|
||||
@ -1755,7 +1853,7 @@ static void select_properties_response(const char *input, void *user_data)
|
||||
struct codec_preset *p;
|
||||
DBusMessage *reply;
|
||||
|
||||
p = find_preset(ep->uuid, input);
|
||||
p = preset_find_name(ep->preset, input);
|
||||
if (p) {
|
||||
reply = endpoint_select_properties_reply(ep, ep->msg, p);
|
||||
goto done;
|
||||
@ -1797,9 +1895,9 @@ static DBusMessage *endpoint_select_properties(DBusConnection *conn,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = find_preset(ep->uuid, NULL);
|
||||
p = preset_find_name(ep->preset, NULL);
|
||||
if (!p)
|
||||
NULL;
|
||||
return NULL;
|
||||
|
||||
reply = endpoint_select_properties_reply(ep, msg, p);
|
||||
if (!reply)
|
||||
@ -1903,6 +2001,11 @@ static void endpoint_free(void *data)
|
||||
if (ep->msg)
|
||||
dbus_message_unref(ep->msg);
|
||||
|
||||
if (ep->codec == 0xff) {
|
||||
free(ep->preset->custom.name);
|
||||
free(ep->preset);
|
||||
}
|
||||
|
||||
g_free(ep->path);
|
||||
g_free(ep->uuid);
|
||||
g_free(ep);
|
||||
@ -2312,7 +2415,6 @@ static void cmd_register_endpoint(int argc, char *argv[])
|
||||
{
|
||||
struct endpoint *ep;
|
||||
char *endptr = NULL;
|
||||
char **list;
|
||||
|
||||
ep = g_new0(struct endpoint, 1);
|
||||
ep->uuid = g_strdup(argv[1]);
|
||||
@ -2324,12 +2426,13 @@ static void cmd_register_endpoint(int argc, char *argv[])
|
||||
local_endpoints = g_list_append(local_endpoints, ep);
|
||||
|
||||
if (strrchr(argv[2], ':')) {
|
||||
list = g_strsplit(argv[2], ":", 2);
|
||||
|
||||
ep->codec = 0xff;
|
||||
ep->vid = strtol(list[0], &endptr, 0);
|
||||
endptr = NULL;
|
||||
ep->cid = strtol(list[1], &endptr, 0);
|
||||
parse_vendor_codec(argv[2], &ep->cid, &ep->vid);
|
||||
ep->preset = new0(struct preset, 1);
|
||||
ep->preset->custom.name = strdup("custom");
|
||||
ep->preset->default_preset = &ep->preset->custom;
|
||||
} else {
|
||||
ep->preset = find_presets_name(ep->uuid, argv[2]);
|
||||
}
|
||||
|
||||
if (argc > 3)
|
||||
@ -2489,7 +2592,7 @@ static void cmd_config_endpoint(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
preset = find_preset(cfg->ep->uuid, argv[3]);
|
||||
preset = preset_find_name(cfg->ep->preset, argv[3]);
|
||||
if (!preset) {
|
||||
bt_shell_printf("Preset %s not found\n", argv[3]);
|
||||
goto fail;
|
||||
@ -2835,46 +2938,50 @@ static void custom_frequency(const char *input, void *user_data)
|
||||
custom_duration, user_data);
|
||||
}
|
||||
|
||||
static void cmd_presets_endpoint(int argc, char *argv[])
|
||||
static void print_presets(struct preset *preset)
|
||||
{
|
||||
size_t i;
|
||||
struct codec_preset *p;
|
||||
|
||||
p = &preset->custom;
|
||||
|
||||
bt_shell_printf("%s%s\n", p == preset->default_preset ? "*" : "",
|
||||
p->name);
|
||||
|
||||
for (i = 0; i < preset->num_presets; i++) {
|
||||
p = &preset->presets[i];
|
||||
bt_shell_printf("%s%s\n", p == preset->default_preset ?
|
||||
"*" : "", p->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_presets_endpoint(int argc, char *argv[])
|
||||
{
|
||||
struct preset *preset;
|
||||
struct codec_preset *default_preset = NULL;
|
||||
|
||||
if (argc > 2) {
|
||||
default_preset = find_preset(argv[1], argv[2]);
|
||||
if (argc > 3) {
|
||||
default_preset = find_preset(argv[1], argv[2], argv[3]);
|
||||
if (!default_preset) {
|
||||
bt_shell_printf("Preset %s not found\n", argv[2]);
|
||||
bt_shell_printf("Preset %s not found\n", argv[3]);
|
||||
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(presets); i++) {
|
||||
struct preset *preset = &presets[i];
|
||||
|
||||
if (!strcasecmp(preset->uuid, argv[1])) {
|
||||
size_t j;
|
||||
struct codec_preset *p;
|
||||
|
||||
if (default_preset) {
|
||||
preset->default_preset = default_preset;
|
||||
break;
|
||||
}
|
||||
|
||||
p = &preset->custom;
|
||||
|
||||
bt_shell_printf("%s%s\n", p == preset->default_preset ?
|
||||
"*" : "", p->name);
|
||||
|
||||
for (j = 0; j < preset->num_presets; j++) {
|
||||
p = &preset->presets[j];
|
||||
|
||||
bt_shell_printf("%s%s\n",
|
||||
p == preset->default_preset ?
|
||||
"*" : "", p->name);
|
||||
}
|
||||
}
|
||||
preset = find_presets_name(argv[1], argv[2]);
|
||||
if (!preset) {
|
||||
bt_shell_printf("No preset found\n");
|
||||
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (default_preset) {
|
||||
preset->default_preset = default_preset;
|
||||
goto done;
|
||||
}
|
||||
|
||||
print_presets(preset);
|
||||
|
||||
done:
|
||||
if (default_preset && !strcmp(default_preset->name, "custom")) {
|
||||
bt_shell_prompt_input("Codec", "Enter frequency (Khz):",
|
||||
custom_frequency, default_preset);
|
||||
@ -2904,7 +3011,8 @@ static const struct bt_shell_menu endpoint_menu = {
|
||||
cmd_config_endpoint,
|
||||
"Configure Endpoint",
|
||||
endpoint_generator },
|
||||
{ "presets", "<UUID> [default]", cmd_presets_endpoint,
|
||||
{ "presets", "<UUID> <codec[:company]> [default]",
|
||||
cmd_presets_endpoint,
|
||||
"List available presets",
|
||||
uuid_generator },
|
||||
{} },
|
||||
@ -2938,6 +3046,8 @@ static void register_endpoints(GDBusProxy *proxy)
|
||||
continue;
|
||||
|
||||
ep = endpoint_new(cap);
|
||||
ep->preset = find_presets(ep->uuid, ep->codec, ep->vid,
|
||||
ep->cid);
|
||||
ep->max_transports = UINT8_MAX;
|
||||
ep->auto_accept = true;
|
||||
ep->cig = BT_ISO_QOS_CIG_UNSET;
|
||||
|
Loading…
Reference in New Issue
Block a user