mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-23 06:59:58 -05:00
bluez5: add codec_data for codec-private configuration data
With BAP codec configuration selection goes via multiple functions, which will need to maintain some private state. Adjust media_codec to allow for that. Use it for get_qos().
This commit is contained in:
parent
914e8c6c7a
commit
ff6db3e08e
12 changed files with 95 additions and 44 deletions
|
|
@ -139,7 +139,8 @@ static int get_valid_aac_bitrate(a2dp_aac_t *conf)
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_aac_t conf;
|
a2dp_aac_t conf;
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,8 @@ aptx_frequencies[] = {
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_aptx_t conf;
|
a2dp_aptx_t conf;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -146,7 +147,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
static int codec_select_config_ll(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config_ll(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_aptx_ll_ext_t conf = { 0 };
|
a2dp_aptx_ll_ext_t conf = { 0 };
|
||||||
size_t actual_conf_size;
|
size_t actual_conf_size;
|
||||||
|
|
@ -166,7 +168,7 @@ static int codec_select_config_ll(const struct media_codec *codec, uint32_t flag
|
||||||
if (codec->duplex_codec && !conf.base.bidirect_link)
|
if (codec->duplex_codec && !conf.base.bidirect_link)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|
||||||
if ((res = codec_select_config(codec, flags, caps, caps_size, info, settings, config)) < 0)
|
if ((res = codec_select_config(codec, flags, caps, caps_size, info, settings, config, NULL)) < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
memcpy(&conf.base.aptx, config, sizeof(conf.base.aptx));
|
memcpy(&conf.base.aptx, config, sizeof(conf.base.aptx));
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,8 @@ duplex_frequencies[] = {
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_faststream_t conf;
|
a2dp_faststream_t conf;
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,8 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags,
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_lc3plus_hr_t conf;
|
a2dp_lc3plus_hr_t conf;
|
||||||
|
|
||||||
|
|
@ -137,8 +138,8 @@ static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t f
|
||||||
int a, b;
|
int a, b;
|
||||||
|
|
||||||
/* Order selected configurations by preference */
|
/* Order selected configurations by preference */
|
||||||
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1);
|
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1, NULL);
|
||||||
res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2);
|
res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2, NULL);
|
||||||
|
|
||||||
#define PREFER_EXPR(expr) \
|
#define PREFER_EXPR(expr) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,8 @@ ldac_channel_modes[] = {
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_ldac_t conf;
|
a2dp_ldac_t conf;
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,8 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags,
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_opus_g_t conf;
|
a2dp_opus_g_t conf;
|
||||||
int frequency, duration, channels;
|
int frequency, duration, channels;
|
||||||
|
|
@ -126,8 +127,8 @@ static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t f
|
||||||
int a, b;
|
int a, b;
|
||||||
|
|
||||||
/* Order selected configurations by preference */
|
/* Order selected configurations by preference */
|
||||||
res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1);
|
res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1, NULL);
|
||||||
res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2);
|
res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2, NULL);
|
||||||
|
|
||||||
#define PREFER_EXPR(expr) \
|
#define PREFER_EXPR(expr) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
||||||
|
|
@ -590,7 +590,8 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags,
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
struct props props;
|
struct props props;
|
||||||
a2dp_opus_05_t conf;
|
a2dp_opus_05_t conf;
|
||||||
|
|
@ -699,8 +700,8 @@ static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t f
|
||||||
int a, b;
|
int a, b;
|
||||||
|
|
||||||
/* Order selected configurations by preference */
|
/* Order selected configurations by preference */
|
||||||
res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1);
|
res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1, NULL);
|
||||||
res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2);
|
res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2, NULL);
|
||||||
|
|
||||||
#define PREFER_EXPR(expr) \
|
#define PREFER_EXPR(expr) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,8 @@ sbc_xq_channel_modes[] = {
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
a2dp_sbc_t conf;
|
a2dp_sbc_t conf;
|
||||||
int bitpool, i;
|
int bitpool, i;
|
||||||
|
|
@ -221,8 +222,8 @@ static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t f
|
||||||
bool xq = (spa_streq(codec->name, "sbc_xq"));
|
bool xq = (spa_streq(codec->name, "sbc_xq"));
|
||||||
|
|
||||||
/* Order selected configurations by preference */
|
/* Order selected configurations by preference */
|
||||||
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1);
|
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1, NULL);
|
||||||
res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2);
|
res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2, NULL);
|
||||||
|
|
||||||
#define PREFER_EXPR(expr) \
|
#define PREFER_EXPR(expr) \
|
||||||
do { \
|
do { \
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include <spa/param/audio/format-utils.h>
|
#include <spa/param/audio/format-utils.h>
|
||||||
#include <spa/utils/string.h>
|
#include <spa/utils/string.h>
|
||||||
#include <spa/utils/json.h>
|
#include <spa/utils/json.h>
|
||||||
|
#include <spa/utils/cleanup.h>
|
||||||
#include <spa/debug/log.h>
|
#include <spa/debug/log.h>
|
||||||
|
|
||||||
#include <lc3.h>
|
#include <lc3.h>
|
||||||
|
|
@ -47,13 +48,17 @@ struct settings {
|
||||||
uint32_t channel_allocation;
|
uint32_t channel_allocation;
|
||||||
bool sink;
|
bool sink;
|
||||||
bool duplex;
|
bool duplex;
|
||||||
const char *qos_name;
|
char *qos_name;
|
||||||
int retransmission;
|
int retransmission;
|
||||||
int latency;
|
int latency;
|
||||||
int64_t delay;
|
int64_t delay;
|
||||||
int framing;
|
int framing;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct config_data {
|
||||||
|
struct settings settings;
|
||||||
|
};
|
||||||
|
|
||||||
struct pac_data {
|
struct pac_data {
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
@ -771,7 +776,7 @@ static void parse_settings(struct settings *s, const struct spa_dict *settings,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((str = spa_dict_lookup(settings, "bluez5.bap.preset")))
|
if ((str = spa_dict_lookup(settings, "bluez5.bap.preset")))
|
||||||
s->qos_name = str;
|
s->qos_name = strdup(str);
|
||||||
|
|
||||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.rtn"), &value, 0))
|
if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.rtn"), &value, 0))
|
||||||
s->retransmission = value;
|
s->retransmission = value;
|
||||||
|
|
@ -811,23 +816,38 @@ static void parse_settings(struct settings *s, const struct spa_dict *settings,
|
||||||
(int)s->sink, (int)s->duplex);
|
(int)s->sink, (int)s->duplex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_config_data(struct config_data *d)
|
||||||
|
{
|
||||||
|
if (!d)
|
||||||
|
return;
|
||||||
|
free(d->settings.qos_name);
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPA_DEFINE_AUTOPTR_CLEANUP(config_data, struct config_data, { spa_clear_ptr(*thing, free_config_data); });
|
||||||
|
|
||||||
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE])
|
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data)
|
||||||
{
|
{
|
||||||
struct pac_data pacs[MAX_PACS];
|
struct pac_data pacs[MAX_PACS];
|
||||||
int npacs;
|
int npacs;
|
||||||
bap_lc3_t conf;
|
bap_lc3_t conf;
|
||||||
struct spa_debug_log_ctx debug_ctx;
|
struct spa_debug_log_ctx debug_ctx;
|
||||||
struct settings s;
|
spa_autoptr(config_data) d = NULL;
|
||||||
int i;
|
int i, ret;
|
||||||
struct ltv_writer writer = LTV_WRITER(config, A2DP_MAX_CAPS_SIZE);
|
struct ltv_writer writer = LTV_WRITER(config, A2DP_MAX_CAPS_SIZE);
|
||||||
|
|
||||||
if (caps == NULL)
|
if (caps == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
parse_settings(&s, settings, &debug_ctx);
|
d = calloc(1, sizeof(*d));
|
||||||
|
if (!d)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
parse_settings(&d->settings, settings, &debug_ctx);
|
||||||
|
|
||||||
/* Select best conf from those possible */
|
/* Select best conf from those possible */
|
||||||
npacs = parse_bluez_pacs(caps, caps_size, pacs, &debug_ctx.ctx);
|
npacs = parse_bluez_pacs(caps, caps_size, pacs, &debug_ctx.ctx);
|
||||||
|
|
@ -840,7 +860,7 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < npacs; ++i)
|
for (i = 0; i < npacs; ++i)
|
||||||
pacs[i].settings = &s;
|
pacs[i].settings = &d->settings;
|
||||||
|
|
||||||
qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp);
|
qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp);
|
||||||
|
|
||||||
|
|
@ -859,7 +879,12 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags,
|
||||||
ltv_writer_uint16(&writer, LC3_TYPE_FRAMELEN, conf.framelen);
|
ltv_writer_uint16(&writer, LC3_TYPE_FRAMELEN, conf.framelen);
|
||||||
ltv_writer_uint8(&writer, LC3_TYPE_BLKS, conf.n_blks);
|
ltv_writer_uint8(&writer, LC3_TYPE_BLKS, conf.n_blks);
|
||||||
|
|
||||||
return ltv_writer_end(&writer);
|
ret = ltv_writer_end(&writer);
|
||||||
|
|
||||||
|
if (ret >= 0 && config_data)
|
||||||
|
*config_data = spa_steal_ptr(d);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size,
|
static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size,
|
||||||
|
|
@ -869,8 +894,8 @@ static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t f
|
||||||
int res1, res2;
|
int res1, res2;
|
||||||
|
|
||||||
/* Order selected configurations by preference */
|
/* Order selected configurations by preference */
|
||||||
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1);
|
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1, NULL);
|
||||||
res2 = codec->select_config(codec, 0, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2);
|
res2 = codec->select_config(codec, 0, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2, NULL);
|
||||||
|
|
||||||
return conf_cmp(&conf1, res1, &conf2, res2);
|
return conf_cmp(&conf1, res1, &conf2, res2);
|
||||||
}
|
}
|
||||||
|
|
@ -1038,22 +1063,22 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags
|
||||||
static int codec_get_qos(const struct media_codec *codec,
|
static int codec_get_qos(const struct media_codec *codec,
|
||||||
const void *config, size_t config_size,
|
const void *config, size_t config_size,
|
||||||
const struct bap_endpoint_qos *endpoint_qos,
|
const struct bap_endpoint_qos *endpoint_qos,
|
||||||
struct bap_codec_qos *qos, const struct spa_dict *settings)
|
const void *config_data,
|
||||||
|
struct bap_codec_qos *qos)
|
||||||
{
|
{
|
||||||
struct bap_qos bap_qos;
|
struct bap_qos bap_qos;
|
||||||
bap_lc3_t conf;
|
bap_lc3_t conf;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
struct settings s;
|
const struct config_data *d = config_data;
|
||||||
struct spa_debug_log_ctx debug_ctx;
|
|
||||||
|
|
||||||
spa_zero(*qos);
|
spa_zero(*qos);
|
||||||
|
|
||||||
|
if (!d)
|
||||||
|
return -EINVAL;
|
||||||
if (!parse_conf(&conf, config, config_size))
|
if (!parse_conf(&conf, config, config_size))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
parse_settings(&s, settings, &debug_ctx);
|
found = select_bap_qos(&bap_qos, &d->settings, get_rate_mask(conf.rate), get_duration_mask(conf.frame_duration),
|
||||||
|
|
||||||
found = select_bap_qos(&bap_qos, &s, get_rate_mask(conf.rate), get_duration_mask(conf.frame_duration),
|
|
||||||
conf.framelen, conf.framelen);
|
conf.framelen, conf.framelen);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
/* shouldn't happen: select_config should pick existing one */
|
/* shouldn't happen: select_config should pick existing one */
|
||||||
|
|
@ -1096,6 +1121,11 @@ static int codec_get_qos(const struct media_codec *codec,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void codec_free_config_data(const struct media_codec *codec, void *config_data)
|
||||||
|
{
|
||||||
|
free_config_data(config_data);
|
||||||
|
}
|
||||||
|
|
||||||
static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
||||||
void *config, size_t config_len, const struct spa_audio_info *info,
|
void *config, size_t config_len, const struct spa_audio_info *info,
|
||||||
void *props, size_t mtu)
|
void *props, size_t mtu)
|
||||||
|
|
@ -1419,6 +1449,7 @@ const struct media_codec bap_codec_lc3 = {
|
||||||
.enum_config = codec_enum_config,
|
.enum_config = codec_enum_config,
|
||||||
.validate_config = codec_validate_config,
|
.validate_config = codec_validate_config,
|
||||||
.get_qos = codec_get_qos,
|
.get_qos = codec_get_qos,
|
||||||
|
.free_config_data = codec_free_config_data,
|
||||||
.caps_preference_cmp = codec_caps_preference_cmp,
|
.caps_preference_cmp = codec_caps_preference_cmp,
|
||||||
.init = codec_init,
|
.init = codec_init,
|
||||||
.deinit = codec_deinit,
|
.deinit = codec_deinit,
|
||||||
|
|
|
||||||
|
|
@ -695,7 +695,7 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu
|
||||||
* by codec switching.
|
* by codec switching.
|
||||||
*/
|
*/
|
||||||
res = codec->select_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info,
|
res = codec->select_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info,
|
||||||
&monitor->global_settings, config);
|
&monitor->global_settings, config, NULL);
|
||||||
else
|
else
|
||||||
res = -ENOTSUP;
|
res = -ENOTSUP;
|
||||||
|
|
||||||
|
|
@ -1032,6 +1032,7 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe
|
||||||
|
|
||||||
const char *endpoint_path = NULL;
|
const char *endpoint_path = NULL;
|
||||||
uint8_t config[A2DP_MAX_CAPS_SIZE];
|
uint8_t config[A2DP_MAX_CAPS_SIZE];
|
||||||
|
void *config_data = NULL;
|
||||||
char locations[64] = {0};
|
char locations[64] = {0};
|
||||||
char channel_allocation[64] = {0};
|
char channel_allocation[64] = {0};
|
||||||
int conf_size;
|
int conf_size;
|
||||||
|
|
@ -1048,6 +1049,9 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe
|
||||||
|
|
||||||
path = dbus_message_get_path(m);
|
path = dbus_message_get_path(m);
|
||||||
|
|
||||||
|
if ((r = dbus_message_new_method_return(m)) == NULL)
|
||||||
|
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||||
|
|
||||||
/* TODO: for codecs with shared endpoint, this currently always picks the default
|
/* TODO: for codecs with shared endpoint, this currently always picks the default
|
||||||
* one. However, currently we don't have BAP codecs with shared endpoint, so
|
* one. However, currently we don't have BAP codecs with shared endpoint, so
|
||||||
* this does not matter, but in case they are needed later we should pick the
|
* this does not matter, but in case they are needed later we should pick the
|
||||||
|
|
@ -1105,7 +1109,7 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe
|
||||||
settings = SPA_DICT_INIT(setting_items, i);
|
settings = SPA_DICT_INIT(setting_items, i);
|
||||||
|
|
||||||
conf_size = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len,
|
conf_size = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len,
|
||||||
&monitor->default_audio_info, &settings, config);
|
&monitor->default_audio_info, &settings, config, &config_data);
|
||||||
if (conf_size < 0) {
|
if (conf_size < 0) {
|
||||||
spa_log_error(monitor->log, "can't select config: %d (%s)",
|
spa_log_error(monitor->log, "can't select config: %d (%s)",
|
||||||
conf_size, spa_strerror(conf_size));
|
conf_size, spa_strerror(conf_size));
|
||||||
|
|
@ -1114,8 +1118,6 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe
|
||||||
spa_log_info(monitor->log, "%p: selected conf %d", monitor, conf_size);
|
spa_log_info(monitor->log, "%p: selected conf %d", monitor, conf_size);
|
||||||
spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', (uint8_t *)config, (size_t)conf_size);
|
spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', (uint8_t *)config, (size_t)conf_size);
|
||||||
|
|
||||||
if ((r = dbus_message_new_method_return(m)) == NULL)
|
|
||||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
|
||||||
dbus_message_iter_init_append(r, &iter);
|
dbus_message_iter_init_append(r, &iter);
|
||||||
|
|
||||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||||
|
|
@ -1134,7 +1136,7 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe
|
||||||
|
|
||||||
spa_zero(qos);
|
spa_zero(qos);
|
||||||
|
|
||||||
res = codec->get_qos(codec, config, conf_size, &ep->qos, &qos, &settings);
|
res = codec->get_qos(codec, config, conf_size, &ep->qos, config_data, &qos);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
spa_log_error(monitor->log, "can't select QOS config: %d (%s)",
|
spa_log_error(monitor->log, "can't select QOS config: %d (%s)",
|
||||||
res, spa_strerror(res));
|
res, spa_strerror(res));
|
||||||
|
|
@ -1184,6 +1186,9 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe
|
||||||
|
|
||||||
dbus_message_iter_close_container(&iter, &dict);
|
dbus_message_iter_close_container(&iter, &dict);
|
||||||
|
|
||||||
|
if (config_data && codec->free_config_data)
|
||||||
|
codec->free_config_data(codec, config_data);
|
||||||
|
|
||||||
if (!dbus_connection_send(conn, r, NULL))
|
if (!dbus_connection_send(conn, r, NULL))
|
||||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||||
|
|
||||||
|
|
@ -1194,6 +1199,9 @@ error_invalid:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
if (config_data && codec->free_config_data)
|
||||||
|
codec->free_config_data(codec, config_data);
|
||||||
|
|
||||||
if (!reply_with_error(conn, m, "org.bluez.Error.InvalidArguments", err_msg))
|
if (!reply_with_error(conn, m, "org.bluez.Error.InvalidArguments", err_msg))
|
||||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||||
return DBUS_HANDLER_RESULT_HANDLED;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
|
|
@ -4506,7 +4514,7 @@ static bool codec_switch_configure_a2dp(struct spa_bt_codec_switch *sw, const ch
|
||||||
}
|
}
|
||||||
|
|
||||||
res = codec->select_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len,
|
res = codec->select_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len,
|
||||||
&monitor->default_audio_info, &monitor->global_settings, config);
|
&monitor->default_audio_info, &monitor->global_settings, config, NULL);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
spa_log_error(monitor->log, "media codec switch %p: incompatible capabilities (%d)",
|
spa_log_error(monitor->log, "media codec switch %p: incompatible capabilities (%d)",
|
||||||
sw, res);
|
sw, res);
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ bool media_codec_check_caps(const struct media_codec *codec, unsigned int codec_
|
||||||
if (caps == NULL)
|
if (caps == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config);
|
res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config, NULL);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#define SPA_TYPE_INTERFACE_Bluez5CodecMedia SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:Media:Private"
|
#define SPA_TYPE_INTERFACE_Bluez5CodecMedia SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:Media:Private"
|
||||||
|
|
||||||
#define SPA_VERSION_BLUEZ5_CODEC_MEDIA 15
|
#define SPA_VERSION_BLUEZ5_CODEC_MEDIA 16
|
||||||
|
|
||||||
struct spa_bluez5_codec_a2dp {
|
struct spa_bluez5_codec_a2dp {
|
||||||
struct spa_interface iface;
|
struct spa_interface iface;
|
||||||
|
|
@ -103,7 +103,8 @@ struct media_codec {
|
||||||
int (*select_config) (const struct media_codec *codec, uint32_t flags,
|
int (*select_config) (const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size,
|
const void *caps, size_t caps_size,
|
||||||
const struct media_codec_audio_info *info,
|
const struct media_codec_audio_info *info,
|
||||||
const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE]);
|
const struct spa_dict *global_settings, uint8_t config[A2DP_MAX_CAPS_SIZE],
|
||||||
|
void **config_data);
|
||||||
int (*enum_config) (const struct media_codec *codec, uint32_t flags,
|
int (*enum_config) (const struct media_codec *codec, uint32_t flags,
|
||||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||||
struct spa_pod_builder *builder, struct spa_pod **param);
|
struct spa_pod_builder *builder, struct spa_pod **param);
|
||||||
|
|
@ -113,7 +114,9 @@ struct media_codec {
|
||||||
int (*get_qos)(const struct media_codec *codec,
|
int (*get_qos)(const struct media_codec *codec,
|
||||||
const void *config, size_t config_size,
|
const void *config, size_t config_size,
|
||||||
const struct bap_endpoint_qos *endpoint_qos,
|
const struct bap_endpoint_qos *endpoint_qos,
|
||||||
struct bap_codec_qos *qos, const struct spa_dict *settings);
|
const void *config_data,
|
||||||
|
struct bap_codec_qos *qos);
|
||||||
|
void (*free_config_data)(const struct media_codec *codec, void *config_data);
|
||||||
|
|
||||||
/** qsort comparison sorting caps in order of preference for the codec.
|
/** qsort comparison sorting caps in order of preference for the codec.
|
||||||
* Used in codec switching to select best remote endpoints.
|
* Used in codec switching to select best remote endpoints.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue