Skip to content

Commit 2fcb45e

Browse files
bluetooth: a2dp: implement the get_all_capabilities
From avdtp spec, the get_all_capablities should be used if the avdtp version is v1.3, otherwise the get_capabilities should be used. Signed-off-by: Mark Wang <yichang.wang@nxp.com>
1 parent e480bef commit 2fcb45e

File tree

7 files changed

+315
-32
lines changed

7 files changed

+315
-32
lines changed

include/zephyr/bluetooth/classic/a2dp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,12 @@ struct bt_a2dp_discover_param {
389389
* it save endpoint info internally.
390390
*/
391391
struct bt_avdtp_sep_info *seps_info;
392+
/** The AVDTP version of the peer's A2DP sdp service.
393+
* It is the same value of the avdtp sepcificaiton's version value.
394+
* For example: 0x0103 means version 1.3
395+
* value 0 means that it is unknown.
396+
*/
397+
uint16_t avdtp_version;
392398
/** The max count of seps (stream endpoint) that can be got in this call route */
393399
uint8_t sep_count;
394400
};

include/zephyr/bluetooth/classic/avdtp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
extern "C" {
1616
#endif
1717

18+
#define AVDTP_VERSION_1_3 0x0103 /**< AVDTP version 1.3 value */
19+
20+
#define AVDTP_VERSION AVDTP_VERSION_1_3 /**< AVDTP version used by Zephyr */
21+
1822
/**
1923
* @brief AVDTP error code
2024
*/

subsys/bluetooth/host/classic/a2dp.c

Lines changed: 171 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <zephyr/bluetooth/classic/avdtp.h>
2424
#include <zephyr/bluetooth/classic/a2dp_codec_sbc.h>
2525
#include <zephyr/bluetooth/classic/a2dp.h>
26+
#include <zephyr/bluetooth/classic/sdp.h>
2627

2728
#include "common/assert.h"
2829

@@ -65,6 +66,7 @@ struct bt_a2dp {
6566
struct bt_avdtp_get_capabilities_params get_capabilities_param;
6667
struct bt_avdtp_set_configuration_params set_config_param;
6768
struct bt_avdtp_ctrl_params ctrl_param;
69+
uint16_t avdtp_version;
6870
uint8_t get_cap_index;
6971
enum bt_a2dp_internal_state a2dp_state;
7072
uint8_t peer_seps_count;
@@ -125,8 +127,13 @@ static int a2dp_discovery_ind(struct bt_avdtp *session, uint8_t *errcode)
125127
}
126128

127129
static int a2dp_get_capabilities_ind(struct bt_avdtp *session, struct bt_avdtp_sep *sep,
128-
struct net_buf *rsp_buf, uint8_t *errcode)
130+
struct net_buf *rsp_buf, bool get_all_caps, uint8_t *errcode)
129131
{
132+
/* The Reporting, Recovery, Content Protection, Header Compression, Multiplexing and
133+
* Delay Reporting services are not supported, so the same response is replied as
134+
* get_capabilities.
135+
*/
136+
ARG_UNUSED(get_all_caps);
130137
struct bt_a2dp_ep *ep;
131138

132139
__ASSERT(sep, "Invalid sep");
@@ -505,6 +512,19 @@ static int bt_a2dp_get_sep_caps(struct bt_a2dp *a2dp)
505512
a2dp->get_capabilities_param.req.func = bt_a2dp_get_capabilities_cb;
506513
a2dp->get_capabilities_param.stream_endpoint_id =
507514
a2dp->discover_cb_param->seps_info[a2dp->get_cap_index].id;
515+
516+
/* The legacy Get Capabilities procedure is deprecated in cases
517+
* where backwards compatibility with AVDTP 1.2 and earlier is irrelevant.
518+
*/
519+
#if (AVDTP_VERSION >= AVDTP_VERSION_1_3)
520+
if (a2dp->avdtp_version >= AVDTP_VERSION_1_3) {
521+
a2dp->get_capabilities_param.get_all_caps = true;
522+
} else {
523+
#endif /* AVDTP_VERSION >= AVDTP_VERSION_1_3 */
524+
a2dp->get_capabilities_param.get_all_caps = false;
525+
#if (AVDTP_VERSION >= AVDTP_VERSION_1_3)
526+
}
527+
#endif /* AVDTP_VERSION >= AVDTP_VERSION_1_3 */
508528
err = bt_avdtp_get_capabilities(&a2dp->session,
509529
&a2dp->get_capabilities_param);
510530

@@ -575,6 +595,145 @@ static int bt_a2dp_discover_cb(struct bt_avdtp_req *req, struct net_buf *buf)
575595
return 0;
576596
}
577597

598+
static void bt_a2dp_end_discover(struct bt_a2dp *a2dp)
599+
{
600+
if (a2dp->discover_cb_param != NULL) {
601+
if (a2dp->discover_cb_param->cb != NULL) {
602+
a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
603+
}
604+
a2dp->discover_cb_param = NULL;
605+
}
606+
}
607+
608+
static int bt_a2dp_trigger_discover(struct bt_a2dp *a2dp)
609+
{
610+
int err;
611+
612+
if (a2dp->discover_cb_param == NULL) {
613+
return -EINVAL;
614+
}
615+
616+
a2dp->discover_param.req.func = bt_a2dp_discover_cb;
617+
618+
err = bt_avdtp_discover(&a2dp->session, &a2dp->discover_param);
619+
if (err != 0) {
620+
bt_a2dp_end_discover(a2dp);
621+
}
622+
623+
return err;
624+
}
625+
626+
#if defined(CONFIG_BT_A2DP_SOURCE) || defined(CONFIG_BT_A2DP_SINK)
627+
#define A2DP_SERVICE_LEN 512
628+
NET_BUF_POOL_FIXED_DEFINE(find_avdtp_version_pool, 1, A2DP_SERVICE_LEN,
629+
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
630+
631+
static const struct bt_uuid *a2dp_snk_uuid = BT_UUID_DECLARE_16(BT_SDP_AUDIO_SINK_SVCLASS);
632+
static const struct bt_uuid *a2dp_src_uuid = BT_UUID_DECLARE_16(BT_SDP_AUDIO_SOURCE_SVCLASS);
633+
static struct bt_sdp_discover_params discov_a2dp = {
634+
.type = BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
635+
.pool = &find_avdtp_version_pool,
636+
};
637+
#endif
638+
639+
#if defined(CONFIG_BT_A2DP_SINK)
640+
static uint8_t sdp_discover_audio_src_func(struct bt_conn *conn,
641+
struct bt_sdp_client_result *result,
642+
const struct bt_sdp_discover_params *params)
643+
{
644+
int err;
645+
uint16_t version;
646+
struct bt_a2dp *a2dp = &connection[bt_conn_index(conn)];
647+
648+
if ((result == NULL) || (result->resp_buf == NULL) || (result->resp_buf->len == 0)) {
649+
bt_a2dp_end_discover(a2dp);
650+
651+
return BT_SDP_DISCOVER_UUID_STOP;
652+
}
653+
654+
err = bt_sdp_get_proto_param(result->resp_buf, BT_SDP_PROTO_AVDTP, &version);
655+
if (err != 0) {
656+
bt_a2dp_end_discover(a2dp);
657+
} else {
658+
a2dp->avdtp_version = version;
659+
660+
(void)bt_a2dp_trigger_discover(a2dp);
661+
}
662+
663+
return BT_SDP_DISCOVER_UUID_STOP;
664+
}
665+
666+
static int bt_a2dp_find_audio_src_sdp_service(struct bt_a2dp *a2dp)
667+
{
668+
int err;
669+
struct bt_conn *conn;
670+
671+
conn = bt_a2dp_get_conn(a2dp);
672+
if (conn == NULL) {
673+
return -ENOTCONN;
674+
}
675+
676+
discov_a2dp.uuid = a2dp_src_uuid;
677+
discov_a2dp.func = sdp_discover_audio_src_func;
678+
err = bt_sdp_discover(conn, &discov_a2dp);
679+
bt_conn_unref(conn);
680+
681+
return err;
682+
}
683+
#endif
684+
685+
#if defined(CONFIG_BT_A2DP_SOURCE)
686+
static uint8_t sdp_discover_audio_snk_func(struct bt_conn *conn,
687+
struct bt_sdp_client_result *result,
688+
const struct bt_sdp_discover_params *params)
689+
{
690+
int err;
691+
uint16_t version;
692+
struct bt_a2dp *a2dp = &connection[bt_conn_index(conn)];
693+
694+
if ((result == NULL) || (result->resp_buf == NULL) || (result->resp_buf->len == 0)) {
695+
#if defined(CONFIG_BT_A2DP_SINK)
696+
err = bt_a2dp_find_audio_src_sdp_service(a2dp);
697+
if (err != 0) {
698+
bt_a2dp_end_discover(a2dp);
699+
}
700+
#else
701+
bt_a2dp_end_discover(a2dp);
702+
#endif
703+
return BT_SDP_DISCOVER_UUID_STOP;
704+
}
705+
706+
err = bt_sdp_get_proto_param(result->resp_buf, BT_SDP_PROTO_AVDTP, &version);
707+
if (err != 0) {
708+
bt_a2dp_end_discover(a2dp);
709+
} else {
710+
a2dp->avdtp_version = version;
711+
712+
(void)bt_a2dp_trigger_discover(a2dp);
713+
}
714+
715+
return BT_SDP_DISCOVER_UUID_STOP;
716+
}
717+
718+
static int bt_a2dp_find_audio_snk_sdp_service(struct bt_a2dp *a2dp)
719+
{
720+
int err;
721+
struct bt_conn *conn;
722+
723+
conn = bt_a2dp_get_conn(a2dp);
724+
if (conn == NULL) {
725+
return -ENOTCONN;
726+
}
727+
728+
discov_a2dp.uuid = a2dp_snk_uuid;
729+
discov_a2dp.func = sdp_discover_audio_snk_func;
730+
err = bt_sdp_discover(conn, &discov_a2dp);
731+
bt_conn_unref(conn);
732+
733+
return err;
734+
}
735+
#endif
736+
578737
int bt_a2dp_discover(struct bt_a2dp *a2dp, struct bt_a2dp_discover_param *param)
579738
{
580739
int err;
@@ -591,17 +750,20 @@ int bt_a2dp_discover(struct bt_a2dp *a2dp, struct bt_a2dp_discover_param *param)
591750
return -EBUSY;
592751
}
593752

594-
memset(&a2dp->discover_cb_param, 0U, sizeof(a2dp->discover_cb_param));
595753
a2dp->discover_cb_param = param;
596-
a2dp->discover_param.req.func = bt_a2dp_discover_cb;
597-
598-
err = bt_avdtp_discover(&a2dp->session, &a2dp->discover_param);
599-
if (err) {
600-
if (a2dp->discover_cb_param->cb != NULL) {
601-
a2dp->discover_cb_param->cb(a2dp, NULL, NULL);
754+
if (param->avdtp_version == 0 && a2dp->avdtp_version == 0) {
755+
/* try to get the peer's sdp a2dp service's avdtp version */
756+
#if defined(CONFIG_BT_A2DP_SOURCE)
757+
err = bt_a2dp_find_audio_snk_sdp_service(a2dp);
758+
#elif defined(CONFIG_BT_A2DP_SINK)
759+
err = bt_a2dp_find_audio_src_sdp_service(a2dp);
760+
#endif
761+
} else {
762+
if (param->avdtp_version != 0) {
763+
a2dp->avdtp_version = param->avdtp_version;
602764
}
603765

604-
a2dp->discover_cb_param = NULL;
766+
err = bt_a2dp_trigger_discover(a2dp);
605767
}
606768

607769
return err;

subsys/bluetooth/host/classic/avdtp.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@ static struct bt_avdtp_sep *avdtp_get_cmd_sep(struct net_buf *buf, uint8_t *erro
356356
return sep;
357357
}
358358

359-
static void avdtp_get_capabilities_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t tid)
359+
static void avdtp_get_caps_cmd_internal(struct bt_avdtp *session, struct net_buf *buf, uint8_t tid,
360+
bool get_all_caps)
360361
{
361362
int err = 0;
362363
struct net_buf *rsp_buf;
@@ -369,19 +370,22 @@ static void avdtp_get_capabilities_cmd(struct bt_avdtp *session, struct net_buf
369370
err = -ENOTSUP;
370371
} else {
371372
rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_ACCEPT, BT_AVDTP_PACKET_TYPE_SINGLE,
373+
get_all_caps ? BT_AVDTP_GET_ALL_CAPABILITIES :
372374
BT_AVDTP_GET_CAPABILITIES, tid);
373375
if (!rsp_buf) {
374376
return;
375377
}
376378

377-
err = session->ops->get_capabilities_ind(session, sep, rsp_buf, &error_code);
379+
err = session->ops->get_capabilities_ind(session, sep, rsp_buf, get_all_caps,
380+
&error_code);
378381
if (err) {
379382
net_buf_unref(rsp_buf);
380383
}
381384
}
382385

383386
if (err) {
384387
rsp_buf = avdtp_create_reply_pdu(BT_AVDTP_REJECT, BT_AVDTP_PACKET_TYPE_SINGLE,
388+
get_all_caps ? BT_AVDTP_GET_ALL_CAPABILITIES :
385389
BT_AVDTP_GET_CAPABILITIES, tid);
386390
if (!rsp_buf) {
387391
return;
@@ -403,6 +407,17 @@ static void avdtp_get_capabilities_cmd(struct bt_avdtp *session, struct net_buf
403407
}
404408
}
405409

410+
static void avdtp_get_capabilities_cmd(struct bt_avdtp *session, struct net_buf *buf, uint8_t tid)
411+
{
412+
avdtp_get_caps_cmd_internal(session, buf, tid, false);
413+
}
414+
415+
static void avdtp_get_all_capabilities_cmd(struct bt_avdtp *session,
416+
struct net_buf *buf, uint8_t tid)
417+
{
418+
avdtp_get_caps_cmd_internal(session, buf, tid, true);
419+
}
420+
406421
static void avdtp_get_capabilities_rsp(struct bt_avdtp *session, struct net_buf *buf,
407422
uint8_t msg_type)
408423
{
@@ -1103,19 +1118,19 @@ void bt_avdtp_l2cap_disconnected(struct bt_l2cap_chan *chan)
11031118
}
11041119

11051120
void (*cmd_handler[])(struct bt_avdtp *session, struct net_buf *buf, uint8_t tid) = {
1106-
avdtp_discover_cmd, /* BT_AVDTP_DISCOVER */
1107-
avdtp_get_capabilities_cmd, /* BT_AVDTP_GET_CAPABILITIES */
1108-
avdtp_set_configuration_cmd, /* BT_AVDTP_SET_CONFIGURATION */
1109-
NULL, /* BT_AVDTP_GET_CONFIGURATION */
1110-
avdtp_re_configure_cmd, /* BT_AVDTP_RECONFIGURE */
1111-
avdtp_open_cmd, /* BT_AVDTP_OPEN */
1112-
avdtp_start_cmd, /* BT_AVDTP_START */
1113-
avdtp_close_cmd, /* BT_AVDTP_CLOSE */
1114-
avdtp_suspend_cmd, /* BT_AVDTP_SUSPEND */
1115-
avdtp_abort_cmd, /* BT_AVDTP_ABORT */
1116-
NULL, /* BT_AVDTP_SECURITY_CONTROL */
1117-
NULL, /* BT_AVDTP_GET_ALL_CAPABILITIES */
1118-
NULL, /* BT_AVDTP_DELAYREPORT */
1121+
avdtp_discover_cmd, /* BT_AVDTP_DISCOVER */
1122+
avdtp_get_capabilities_cmd, /* BT_AVDTP_GET_CAPABILITIES */
1123+
avdtp_set_configuration_cmd, /* BT_AVDTP_SET_CONFIGURATION */
1124+
NULL, /* BT_AVDTP_GET_CONFIGURATION */
1125+
avdtp_re_configure_cmd, /* BT_AVDTP_RECONFIGURE */
1126+
avdtp_open_cmd, /* BT_AVDTP_OPEN */
1127+
avdtp_start_cmd, /* BT_AVDTP_START */
1128+
avdtp_close_cmd, /* BT_AVDTP_CLOSE */
1129+
avdtp_suspend_cmd, /* BT_AVDTP_SUSPEND */
1130+
avdtp_abort_cmd, /* BT_AVDTP_ABORT */
1131+
NULL, /* BT_AVDTP_SECURITY_CONTROL */
1132+
avdtp_get_all_capabilities_cmd, /* BT_AVDTP_GET_ALL_CAPABILITIES */
1133+
NULL, /* BT_AVDTP_DELAYREPORT */
11191134
};
11201135

11211136
void (*rsp_handler[])(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg_type) = {
@@ -1130,7 +1145,7 @@ void (*rsp_handler[])(struct bt_avdtp *session, struct net_buf *buf, uint8_t msg
11301145
avdtp_suspend_rsp, /* BT_AVDTP_SUSPEND */
11311146
avdtp_abort_rsp, /* BT_AVDTP_ABORT */
11321147
NULL, /* BT_AVDTP_SECURITY_CONTROL */
1133-
NULL, /* BT_AVDTP_GET_ALL_CAPABILITIES */
1148+
avdtp_get_capabilities_rsp, /* BT_AVDTP_GET_ALL_CAPABILITIES */
11341149
NULL, /* BT_AVDTP_DELAYREPORT */
11351150
};
11361151

@@ -1436,6 +1451,7 @@ int bt_avdtp_get_capabilities(struct bt_avdtp *session,
14361451
}
14371452

14381453
buf = avdtp_create_pdu(BT_AVDTP_CMD, BT_AVDTP_PACKET_TYPE_SINGLE,
1454+
param->get_all_caps ? BT_AVDTP_GET_ALL_CAPABILITIES :
14391455
BT_AVDTP_GET_CAPABILITIES);
14401456
if (!buf) {
14411457
LOG_ERR("Error: No Buff available");

subsys/bluetooth/host/classic/avdtp_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ struct bt_avdtp_discover_params {
153153
struct bt_avdtp_get_capabilities_params {
154154
struct bt_avdtp_req req;
155155
uint8_t stream_endpoint_id;
156+
bool get_all_caps;
156157
};
157158

158159
struct bt_avdtp_set_configuration_params {
@@ -183,7 +184,7 @@ struct bt_avdtp_ops_cb {
183184
int (*discovery_ind)(struct bt_avdtp *session, uint8_t *errcode);
184185

185186
int (*get_capabilities_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep,
186-
struct net_buf *rsp_buf, uint8_t *errcode);
187+
struct net_buf *rsp_buf, bool get_all_caps, uint8_t *errcode);
187188

188189
int (*set_configuration_ind)(struct bt_avdtp *session, struct bt_avdtp_sep *sep,
189190
uint8_t int_seid, struct net_buf *buf, uint8_t *errcode);

0 commit comments

Comments
 (0)