mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: tell the codec whether endpoint is sink or source
Add a flag A2DP_CODEC_FLAG_SINK to incidate a sink endpoint. Also enum_config and caps_preference_cmp may need to know whether the codec is being configured for SRC or SNK. Also add the flags argument to init_props. Bump codec API version.
This commit is contained in:
parent
8d66b2b2f7
commit
a8eb146d39
10 changed files with 63 additions and 34 deletions
|
|
@ -170,7 +170,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags,
|
|||
return sizeof(conf);
|
||||
}
|
||||
|
||||
static int codec_enum_config(const struct a2dp_codec *codec,
|
||||
static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
@ -289,7 +289,7 @@ static int codec_validate_config(const struct a2dp_codec *codec, uint32_t flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void *codec_init_props(const struct a2dp_codec *codec, const struct spa_dict *settings)
|
||||
static void *codec_init_props(const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings)
|
||||
{
|
||||
struct props *p = calloc(1, sizeof(struct props));
|
||||
const char *str;
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ static int codec_select_config_ll(const struct a2dp_codec *codec, uint32_t flags
|
|||
return actual_conf_size;
|
||||
}
|
||||
|
||||
static int codec_enum_config(const struct a2dp_codec *codec,
|
||||
static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
@ -458,7 +458,7 @@ static int codec_decode(void *data,
|
|||
* When connected as SRC to SNK, aptX-LL sink may send back mSBC data.
|
||||
*/
|
||||
|
||||
static int msbc_enum_config(const struct a2dp_codec *codec,
|
||||
static int msbc_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags,
|
|||
return sizeof(conf);
|
||||
}
|
||||
|
||||
static int codec_enum_config(const struct a2dp_codec *codec,
|
||||
static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
@ -372,7 +372,7 @@ static SPA_UNUSED int codec_decode(void *data,
|
|||
* When connected as SRC to SNK, FastStream sink may send back SBC data.
|
||||
*/
|
||||
|
||||
static int duplex_enum_config(const struct a2dp_codec *codec,
|
||||
static int duplex_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags,
|
|||
return sizeof(conf);
|
||||
}
|
||||
|
||||
static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void *caps1, size_t caps1_size,
|
||||
static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size,
|
||||
const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info)
|
||||
{
|
||||
a2dp_lc3plus_hr_t conf1, conf2;
|
||||
|
|
@ -160,7 +160,7 @@ static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void
|
|||
|
||||
/* Order selected configurations by preference */
|
||||
res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1);
|
||||
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);
|
||||
|
||||
#define PREFER_EXPR(expr) \
|
||||
do { \
|
||||
|
|
@ -190,7 +190,7 @@ static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void
|
|||
#undef PREFER_BOOL
|
||||
}
|
||||
|
||||
static int codec_enum_config(const struct a2dp_codec *codec,
|
||||
static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags,
|
|||
return sizeof(conf);
|
||||
}
|
||||
|
||||
static int codec_enum_config(const struct a2dp_codec *codec,
|
||||
static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
@ -284,7 +284,7 @@ static int string_to_eqmid(const char * eqmid)
|
|||
return LDACBT_EQMID_AUTO;
|
||||
}
|
||||
|
||||
static void *codec_init_props(const struct a2dp_codec *codec, const struct spa_dict *settings)
|
||||
static void *codec_init_props(const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings)
|
||||
{
|
||||
struct props *p = calloc(1, sizeof(struct props));
|
||||
const char *str;
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags,
|
|||
return sizeof(conf);
|
||||
}
|
||||
|
||||
static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void *caps1, size_t caps1_size,
|
||||
static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size,
|
||||
const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info)
|
||||
{
|
||||
a2dp_sbc_t conf1, conf2;
|
||||
|
|
@ -356,7 +356,7 @@ static int codec_set_bitpool(struct impl *this, int bitpool)
|
|||
return this->sbc.bitpool;
|
||||
}
|
||||
|
||||
static int codec_enum_config(const struct a2dp_codec *codec,
|
||||
static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#define SPA_TYPE_INTERFACE_Bluez5CodecA2DP SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:A2DP:Private"
|
||||
|
||||
#define SPA_VERSION_BLUEZ5_CODEC_A2DP 1
|
||||
#define SPA_VERSION_BLUEZ5_CODEC_A2DP 2
|
||||
|
||||
struct spa_bluez5_codec_a2dp {
|
||||
struct spa_interface iface;
|
||||
|
|
@ -62,6 +62,7 @@ extern const struct a2dp_codec * const * const codec_plugin_a2dp_codecs;
|
|||
extern const char *codec_plugin_factory_name;
|
||||
#endif
|
||||
|
||||
#define A2DP_CODEC_FLAG_SINK (1 << 0)
|
||||
|
||||
#define A2DP_CODEC_DEFAULT_RATE 48000
|
||||
#define A2DP_CODEC_DEFAULT_CHANNELS 2
|
||||
|
|
@ -97,7 +98,7 @@ struct a2dp_codec {
|
|||
const void *caps, size_t caps_size,
|
||||
const struct a2dp_codec_audio_info *info,
|
||||
const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]);
|
||||
int (*enum_config) (const struct a2dp_codec *codec,
|
||||
int (*enum_config) (const struct a2dp_codec *codec, uint32_t flags,
|
||||
const void *caps, size_t caps_size, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *builder, struct spa_pod **param);
|
||||
int (*validate_config) (const struct a2dp_codec *codec, uint32_t flags,
|
||||
|
|
@ -109,10 +110,10 @@ struct a2dp_codec {
|
|||
* The caps handed in correspond to this codec_id, but are
|
||||
* otherwise not checked beforehand.
|
||||
*/
|
||||
int (*caps_preference_cmp) (const struct a2dp_codec *codec, const void *caps1, size_t caps1_size,
|
||||
int (*caps_preference_cmp) (const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size,
|
||||
const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info);
|
||||
|
||||
void *(*init_props) (const struct a2dp_codec *codec, const struct spa_dict *settings);
|
||||
void *(*init_props) (const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings);
|
||||
void (*clear_props) (void *);
|
||||
int (*enum_props) (void *props, const struct spa_dict *settings, uint32_t id, uint32_t idx,
|
||||
struct spa_pod_builder *builder, struct spa_pod **param);
|
||||
|
|
|
|||
|
|
@ -910,7 +910,8 @@ static int do_start(struct impl *this)
|
|||
for (i = 0; i < size; i++)
|
||||
spa_log_debug(this->log, " %d: %02x", i, conf[i]);
|
||||
|
||||
this->codec_data = this->codec->init(this->codec, 0,
|
||||
this->codec_data = this->codec->init(this->codec,
|
||||
this->is_duplex ? A2DP_CODEC_FLAG_SINK : 0,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
&port->current_format,
|
||||
|
|
@ -1197,6 +1198,7 @@ impl_node_port_enum_params(void *object, int seq,
|
|||
return -EIO;
|
||||
|
||||
if ((res = this->codec->enum_config(this->codec,
|
||||
this->is_duplex ? A2DP_CODEC_FLAG_SINK : 0,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
id, result.index, &b, ¶m)) != 1)
|
||||
|
|
@ -1726,6 +1728,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
if (this->codec->init_props != NULL)
|
||||
this->codec_props = this->codec->init_props(this->codec,
|
||||
this->is_duplex ? A2DP_CODEC_FLAG_SINK : 0,
|
||||
this->transport->device->settings);
|
||||
|
||||
reset_props(this, &this->props);
|
||||
|
|
|
|||
|
|
@ -630,7 +630,8 @@ static int transport_start(struct impl *this)
|
|||
|
||||
this->transport_acquired = true;
|
||||
|
||||
this->codec_data = this->codec->init(this->codec, 0,
|
||||
this->codec_data = this->codec->init(this->codec,
|
||||
this->is_duplex ? 0 : A2DP_CODEC_FLAG_SINK,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
&port->current_format,
|
||||
|
|
@ -967,6 +968,7 @@ impl_node_port_enum_params(void *object, int seq,
|
|||
return -EIO;
|
||||
|
||||
if ((res = this->codec->enum_config(this->codec,
|
||||
this->is_duplex ? 0 : A2DP_CODEC_FLAG_SINK,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
id, result.index, &b, ¶m)) != 1)
|
||||
|
|
@ -1581,6 +1583,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
|
||||
if (this->codec->init_props != NULL)
|
||||
this->codec_props = this->codec->init_props(this->codec,
|
||||
this->is_duplex ? 0 : A2DP_CODEC_FLAG_SINK,
|
||||
this->transport->device->settings);
|
||||
|
||||
spa_bt_transport_add_listener(this->transport,
|
||||
|
|
|
|||
|
|
@ -437,18 +437,21 @@ static int a2dp_codec_to_endpoint(const struct a2dp_codec *codec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct a2dp_codec *a2dp_endpoint_to_codec(struct spa_bt_monitor *monitor, const char *endpoint)
|
||||
static const struct a2dp_codec *a2dp_endpoint_to_codec(struct spa_bt_monitor *monitor, const char *endpoint, bool *sink)
|
||||
{
|
||||
const char *ep_name;
|
||||
const struct a2dp_codec * const * const a2dp_codecs = monitor->a2dp_codecs;
|
||||
int i;
|
||||
|
||||
if (spa_strstartswith(endpoint, A2DP_SINK_ENDPOINT "/"))
|
||||
if (spa_strstartswith(endpoint, A2DP_SINK_ENDPOINT "/")) {
|
||||
ep_name = endpoint + strlen(A2DP_SINK_ENDPOINT "/");
|
||||
else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/"))
|
||||
*sink = true;
|
||||
} else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/")) {
|
||||
ep_name = endpoint + strlen(A2DP_SOURCE_ENDPOINT "/");
|
||||
else
|
||||
*sink = false;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; a2dp_codecs[i]; i++) {
|
||||
const struct a2dp_codec *codec = a2dp_codecs[i];
|
||||
|
|
@ -486,6 +489,7 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu
|
|||
DBusError err;
|
||||
int i, size, res;
|
||||
const struct a2dp_codec *codec;
|
||||
bool sink;
|
||||
|
||||
dbus_error_init(&err);
|
||||
|
||||
|
|
@ -501,14 +505,14 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu
|
|||
for (i = 0; i < size; i++)
|
||||
spa_log_debug(monitor->log, " %d: %02x", i, cap[i]);
|
||||
|
||||
codec = a2dp_endpoint_to_codec(monitor, path);
|
||||
codec = a2dp_endpoint_to_codec(monitor, path, &sink);
|
||||
if (codec != NULL)
|
||||
/* FIXME: We can't determine which device the SelectConfiguration()
|
||||
* call is associated with, therefore device settings are not passed.
|
||||
* This causes inconsistency with SelectConfiguration() triggered
|
||||
* by codec switching.
|
||||
*/
|
||||
res = codec->select_config(codec, 0, cap, size, &monitor->default_audio_info, NULL, config);
|
||||
res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info, NULL, config);
|
||||
else
|
||||
res = -ENOTSUP;
|
||||
|
||||
|
|
@ -2573,6 +2577,7 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s
|
|||
DBusMessage *m;
|
||||
DBusMessageIter iter, d;
|
||||
int i;
|
||||
bool sink;
|
||||
|
||||
/* Try setting configuration for current codec on current endpoint in list */
|
||||
|
||||
|
|
@ -2603,8 +2608,10 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s
|
|||
|
||||
if (sw->profile & SPA_BT_PROFILE_A2DP_SINK) {
|
||||
local_endpoint_base = A2DP_SOURCE_ENDPOINT;
|
||||
sink = false;
|
||||
} else if (sw->profile & SPA_BT_PROFILE_A2DP_SOURCE) {
|
||||
local_endpoint_base = A2DP_SINK_ENDPOINT;
|
||||
sink = true;
|
||||
} else {
|
||||
spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: bad profile (%d), try next",
|
||||
sw, sw->profile);
|
||||
|
|
@ -2630,7 +2637,7 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s
|
|||
}
|
||||
}
|
||||
|
||||
res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len,
|
||||
res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len,
|
||||
&sw->device->monitor->default_audio_info,
|
||||
sw->device->settings, config);
|
||||
if (res < 0) {
|
||||
|
|
@ -2878,6 +2885,7 @@ static int a2dp_codec_switch_cmp(const void *a, const void *b)
|
|||
const struct a2dp_codec *codec = *sw->codec_iter;
|
||||
const char *path1 = *(char **)a, *path2 = *(char **)b;
|
||||
struct spa_bt_remote_endpoint *ep1, *ep2;
|
||||
uint32_t flags;
|
||||
|
||||
ep1 = device_remote_endpoint_find(sw->device, path1);
|
||||
ep2 = device_remote_endpoint_find(sw->device, path2);
|
||||
|
|
@ -2886,6 +2894,10 @@ static int a2dp_codec_switch_cmp(const void *a, const void *b)
|
|||
ep1 = NULL;
|
||||
if (ep2 != NULL && (ep2->uuid == NULL || ep2->codec != codec->codec_id || ep2->capabilities == NULL))
|
||||
ep2 = NULL;
|
||||
if (ep1 && ep2 && !spa_streq(ep1->uuid, ep2->uuid)) {
|
||||
ep1 = NULL;
|
||||
ep2 = NULL;
|
||||
}
|
||||
|
||||
if (ep1 == NULL && ep2 == NULL)
|
||||
return 0;
|
||||
|
|
@ -2894,7 +2906,9 @@ static int a2dp_codec_switch_cmp(const void *a, const void *b)
|
|||
else if (ep2 == NULL)
|
||||
return -1;
|
||||
|
||||
return codec->caps_preference_cmp(codec, ep1->capabilities, ep1->capabilities_len,
|
||||
flags = spa_streq(ep1->uuid, SPA_BT_UUID_A2DP_SOURCE) ? A2DP_CODEC_FLAG_SINK : 0;
|
||||
|
||||
return codec->caps_preference_cmp(codec, flags, ep1->capabilities, ep1->capabilities_len,
|
||||
ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info);
|
||||
}
|
||||
|
||||
|
|
@ -3031,6 +3045,7 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
|
|||
struct spa_bt_transport *transport;
|
||||
const struct a2dp_codec *codec;
|
||||
int profile;
|
||||
bool sink;
|
||||
|
||||
if (!dbus_message_has_signature(m, "oa{sv}")) {
|
||||
spa_log_warn(monitor->log, "invalid SetConfiguration() signature");
|
||||
|
|
@ -3039,7 +3054,7 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
|
|||
endpoint = dbus_message_get_path(m);
|
||||
|
||||
profile = a2dp_endpoint_to_profile(endpoint);
|
||||
codec = a2dp_endpoint_to_codec(monitor, endpoint);
|
||||
codec = a2dp_endpoint_to_codec(monitor, endpoint, &sink);
|
||||
if (codec == NULL) {
|
||||
spa_log_warn(monitor->log, "unknown SetConfiguration() codec");
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
|
@ -3100,7 +3115,7 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
|
|||
|
||||
if (codec->validate_config) {
|
||||
struct spa_audio_info info;
|
||||
if (codec->validate_config(codec, 0,
|
||||
if (codec->validate_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0,
|
||||
transport->configuration, transport->configuration_len,
|
||||
&info) < 0) {
|
||||
spa_log_error(monitor->log, "invalid transport configuration");
|
||||
|
|
@ -3290,12 +3305,15 @@ static int bluez_register_endpoint(struct spa_bt_monitor *monitor,
|
|||
uint8_t caps[A2DP_MAX_CAPS_SIZE];
|
||||
int ret, caps_size;
|
||||
uint16_t codec_id = codec->codec_id;
|
||||
bool sink;
|
||||
|
||||
ret = a2dp_codec_to_endpoint(codec, endpoint, &object_path);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = caps_size = codec->fill_caps(codec, 0, caps);
|
||||
sink = spa_streq(endpoint, A2DP_SINK_ENDPOINT);
|
||||
|
||||
ret = caps_size = codec->fill_caps(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, caps);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
|
|
@ -3501,11 +3519,11 @@ static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *
|
|||
if (!is_a2dp_codec_enabled(monitor, codec))
|
||||
continue;
|
||||
|
||||
caps_size = codec->fill_caps(codec, 0, caps);
|
||||
if (caps_size < 0)
|
||||
continue;
|
||||
|
||||
if (codec->decode != NULL) {
|
||||
caps_size = codec->fill_caps(codec, A2DP_CODEC_FLAG_SINK, caps);
|
||||
if (caps_size < 0)
|
||||
continue;
|
||||
|
||||
ret = a2dp_codec_to_endpoint(codec, A2DP_SINK_ENDPOINT, &endpoint);
|
||||
if (ret == 0) {
|
||||
spa_log_info(monitor->log, "register A2DP sink codec %s: %s", a2dp_codecs[i]->name, endpoint);
|
||||
|
|
@ -3516,6 +3534,10 @@ static DBusHandlerResult object_manager_handler(DBusConnection *c, DBusMessage *
|
|||
}
|
||||
|
||||
if (codec->encode != NULL) {
|
||||
caps_size = codec->fill_caps(codec, 0, caps);
|
||||
if (caps_size < 0)
|
||||
continue;
|
||||
|
||||
ret = a2dp_codec_to_endpoint(codec, A2DP_SOURCE_ENDPOINT, &endpoint);
|
||||
if (ret == 0) {
|
||||
spa_log_info(monitor->log, "register A2DP source codec %s: %s", a2dp_codecs[i]->name, endpoint);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue