Skip to content

Commit 3723ba1

Browse files
lylezhu2012kartben
authored andcommitted
Bluetooth: HFP_AG: Support RFCOMM responder
Define SDP records for HFP AG. Register HFP AG SDP service records in AG initialization. Register HFP AG RFCOMM server in AG initialization. Register HFP AG SCO server in AG initialization. Signed-off-by: Lyle Zhu <[email protected]>
1 parent 4833f82 commit 3723ba1

File tree

1 file changed

+221
-70
lines changed

1 file changed

+221
-70
lines changed

subsys/bluetooth/host/classic/hfp_ag.c

Lines changed: 221 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <zephyr/bluetooth/classic/rfcomm.h>
1919
#include <zephyr/bluetooth/classic/hfp_ag.h>
20+
#include <zephyr/bluetooth/classic/sdp.h>
2021

2122
#include "host/hci_core.h"
2223
#include "host/conn_internal.h"
@@ -79,9 +80,78 @@ static struct bt_ag_tx ag_tx[CONFIG_BT_HFP_AG_TX_BUF_COUNT * 2];
7980
static K_FIFO_DEFINE(ag_tx_free);
8081
static K_FIFO_DEFINE(ag_tx_notify);
8182

82-
struct k_thread ag_thread;
83-
static K_KERNEL_STACK_MEMBER(ag_thread_stack, CONFIG_BT_HFP_AG_THREAD_STACK_SIZE);
84-
static k_tid_t ag_thread_id;
83+
/* HFP Gateway SDP record */
84+
static struct bt_sdp_attribute hfp_ag_attrs[] = {
85+
BT_SDP_NEW_SERVICE,
86+
BT_SDP_LIST(
87+
BT_SDP_ATTR_SVCLASS_ID_LIST,
88+
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
89+
BT_SDP_DATA_ELEM_LIST(
90+
{
91+
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
92+
BT_SDP_ARRAY_16(BT_SDP_HANDSFREE_AGW_SVCLASS)
93+
},
94+
{
95+
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
96+
BT_SDP_ARRAY_16(BT_SDP_GENERIC_AUDIO_SVCLASS)
97+
}
98+
)
99+
),
100+
BT_SDP_LIST(
101+
BT_SDP_ATTR_PROTO_DESC_LIST,
102+
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 12),
103+
BT_SDP_DATA_ELEM_LIST(
104+
{
105+
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
106+
BT_SDP_DATA_ELEM_LIST(
107+
{
108+
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
109+
BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
110+
},
111+
)
112+
},
113+
{
114+
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 5),
115+
BT_SDP_DATA_ELEM_LIST(
116+
{
117+
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
118+
BT_SDP_ARRAY_16(BT_SDP_PROTO_RFCOMM)
119+
},
120+
{
121+
BT_SDP_TYPE_SIZE(BT_SDP_UINT8),
122+
BT_SDP_ARRAY_8(BT_RFCOMM_CHAN_HFP_AG)
123+
},
124+
)
125+
},
126+
)
127+
),
128+
BT_SDP_LIST(
129+
BT_SDP_ATTR_PROFILE_DESC_LIST,
130+
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
131+
BT_SDP_DATA_ELEM_LIST(
132+
{
133+
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
134+
BT_SDP_ARRAY_16(BT_SDP_HANDSFREE_SVCLASS)
135+
},
136+
{
137+
BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
138+
BT_SDP_ARRAY_16(0x0109)
139+
},
140+
)
141+
),
142+
143+
BT_SDP_LIST(
144+
BT_SDP_ATTR_NETWORK,
145+
BT_SDP_TYPE_SIZE(BT_SDP_UINT8),
146+
BT_SDP_ARRAY_8(IS_ENABLED(CONFIG_BT_HFP_AG_REJECT_CALL))
147+
),
148+
/* The values of the “SupportedFeatures” bitmap shall be the same as the
149+
* values of the Bits 0 to 4 of the AT-command AT+BRSF (see Section 5.3).
150+
*/
151+
BT_SDP_SUPPORTED_FEATURES(BT_HFP_AG_SDP_SUPPORTED_FEATURES),
152+
};
153+
154+
static struct bt_sdp_record hfp_ag_rec = BT_SDP_RECORD(hfp_ag_attrs);
85155

86156
static enum at_cme bt_hfp_ag_get_cme_err(int err)
87157
{
@@ -3205,6 +3275,8 @@ static void hfp_ag_disconnected(struct bt_rfcomm_dlc *dlc)
32053275
}
32063276
}
32073277

3278+
ag->acl_conn = NULL;
3279+
32083280
LOG_DBG("AG %p", ag);
32093281
}
32103282

@@ -3481,121 +3553,133 @@ static void bt_ag_ringing_work(struct k_work *work)
34813553
(void)hfp_ag_next_step(call->ag, bt_ag_ringing_work_cb, call);
34823554
}
34833555

3484-
int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t channel)
3485-
{
3486-
int i;
3487-
int err;
3556+
static K_KERNEL_STACK_MEMBER(ag_thread_stack, CONFIG_BT_HFP_AG_THREAD_STACK_SIZE);
34883557

3558+
static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
3559+
{
34893560
static struct bt_rfcomm_dlc_ops ops = {
34903561
.connected = hfp_ag_connected,
34913562
.disconnected = hfp_ag_disconnected,
34923563
.recv = hfp_ag_recv,
34933564
.sent = hfp_ag_sent,
34943565
};
3566+
static k_tid_t ag_thread_id;
3567+
static struct k_thread ag_thread;
3568+
size_t index;
3569+
struct bt_hfp_ag *ag;
34953570

3496-
LOG_DBG("");
3497-
3498-
if (ag == NULL) {
3499-
return -EINVAL;
3500-
}
3501-
3502-
*ag = NULL;
3571+
LOG_DBG("conn %p", conn);
35033572

35043573
if (ag_thread_id == NULL) {
35053574

35063575
k_fifo_init(&ag_tx_free);
35073576
k_fifo_init(&ag_tx_notify);
35083577

3509-
for (i = 0; i < ARRAY_SIZE(ag_tx); i++) {
3510-
k_fifo_put(&ag_tx_free, &ag_tx[i]);
3578+
for (index = 0; index < ARRAY_SIZE(ag_tx); index++) {
3579+
k_fifo_put(&ag_tx_free, &ag_tx[index]);
35113580
}
35123581

35133582
ag_thread_id = k_thread_create(
35143583
&ag_thread, ag_thread_stack, K_KERNEL_STACK_SIZEOF(ag_thread_stack),
35153584
bt_hfp_ag_thread, NULL, NULL, NULL,
35163585
K_PRIO_COOP(CONFIG_BT_HFP_AG_THREAD_PRIO), 0, K_NO_WAIT);
3517-
if (ag_thread_id == NULL) {
3518-
return -ENOMEM;
3519-
}
3586+
__ASSERT(ag_thread_id, "Cannot create thread for AG");
35203587
k_thread_name_set(ag_thread_id, "HFP AG");
35213588
}
35223589

3523-
for (i = 0; i < ARRAY_SIZE(bt_hfp_ag_pool); i++) {
3524-
struct bt_hfp_ag *_ag = &bt_hfp_ag_pool[i];
3590+
index = (size_t)bt_conn_index(conn);
3591+
ag = &bt_hfp_ag_pool[index];
3592+
if (ag->acl_conn) {
3593+
LOG_ERR("AG connection (%p) is established", conn);
3594+
return NULL;
3595+
}
35253596

3526-
if (_ag->rfcomm_dlc.session) {
3527-
continue;
3528-
}
3597+
(void)memset(ag, 0, sizeof(struct bt_hfp_ag));
35293598

3530-
(void)memset(_ag, 0, sizeof(struct bt_hfp_ag));
3599+
sys_slist_init(&ag->tx_pending);
35313600

3532-
sys_slist_init(&_ag->tx_pending);
3601+
k_sem_init(&ag->lock, 1, 1);
35333602

3534-
k_sem_init(&_ag->lock, 1, 1);
3603+
ag->rfcomm_dlc.ops = &ops;
3604+
ag->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
35353605

3536-
_ag->rfcomm_dlc.ops = &ops;
3537-
_ag->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
3606+
/* Set the supported features*/
3607+
ag->ag_features = BT_HFP_AG_SUPPORTED_FEATURES;
35383608

3539-
/* Set the supported features*/
3540-
_ag->ag_features = BT_HFP_AG_SUPPORTED_FEATURES;
3609+
/* Support HF indicators */
3610+
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_ENH_SAFETY)) {
3611+
ag->hf_indicators_of_ag |= BIT(HFP_HF_ENHANCED_SAFETY_IND);
3612+
}
35413613

3542-
/* Support HF indicators */
3543-
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_ENH_SAFETY)) {
3544-
_ag->hf_indicators_of_ag |= BIT(HFP_HF_ENHANCED_SAFETY_IND);
3545-
}
3614+
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_BATTERY)) {
3615+
ag->hf_indicators_of_ag |= BIT(HFP_HF_BATTERY_LEVEL_IND);
3616+
}
35463617

3547-
if (IS_ENABLED(CONFIG_BT_HFP_AG_HF_INDICATOR_BATTERY)) {
3548-
_ag->hf_indicators_of_ag |= BIT(HFP_HF_BATTERY_LEVEL_IND);
3549-
}
3618+
ag->hf_indicators = ag->hf_indicators_of_ag;
35503619

3551-
_ag->hf_indicators = _ag->hf_indicators_of_ag;
3620+
/* If supported codec ids cannot be notified, disable codec negotiation. */
3621+
if (!(bt_ag && bt_ag->codec)) {
3622+
ag->ag_features &= ~BT_HFP_AG_FEATURE_CODEC_NEG;
3623+
}
35523624

3553-
/* If supported codec ids cannot be notified, disable codec negotiation. */
3554-
if (!(bt_ag && bt_ag->codec)) {
3555-
_ag->ag_features &= ~BT_HFP_AG_FEATURE_CODEC_NEG;
3556-
}
3625+
ag->hf_features = 0;
3626+
ag->hf_codec_ids = 0;
3627+
3628+
ag->acl_conn = conn;
3629+
3630+
/* Set AG indicator value */
3631+
ag->indicator_value[BT_HFP_AG_SERVICE_IND] = 0;
3632+
ag->indicator_value[BT_HFP_AG_CALL_IND] = 0;
3633+
ag->indicator_value[BT_HFP_AG_CALL_SETUP_IND] = 0;
3634+
ag->indicator_value[BT_HFP_AG_CALL_HELD_IND] = 0;
3635+
ag->indicator_value[BT_HFP_AG_SIGNAL_IND] = 0;
3636+
ag->indicator_value[BT_HFP_AG_ROAM_IND] = 0;
3637+
ag->indicator_value[BT_HFP_AG_BATTERY_IND] = 0;
3638+
3639+
/* Set AG indicator status */
3640+
ag->indicator = BIT(BT_HFP_AG_SERVICE_IND) | BIT(BT_HFP_AG_CALL_IND) |
3641+
BIT(BT_HFP_AG_CALL_SETUP_IND) | BIT(BT_HFP_AG_CALL_HELD_IND) |
3642+
BIT(BT_HFP_AG_SIGNAL_IND) | BIT(BT_HFP_AG_ROAM_IND) |
3643+
BIT(BT_HFP_AG_BATTERY_IND);
35573644

3558-
_ag->hf_features = 0;
3559-
_ag->hf_codec_ids = 0;
3645+
/* Set AG operator */
3646+
memcpy(ag->operator, "UNKNOWN", sizeof("UNKNOWN"));
35603647

3561-
_ag->acl_conn = conn;
3648+
/* Set Codec ID*/
3649+
ag->selected_codec_id = BT_HFP_AG_CODEC_CVSD;
35623650

3563-
/* Set AG indicator value */
3564-
_ag->indicator_value[BT_HFP_AG_SERVICE_IND] = 0;
3565-
_ag->indicator_value[BT_HFP_AG_CALL_IND] = 0;
3566-
_ag->indicator_value[BT_HFP_AG_CALL_SETUP_IND] = 0;
3567-
_ag->indicator_value[BT_HFP_AG_CALL_HELD_IND] = 0;
3568-
_ag->indicator_value[BT_HFP_AG_SIGNAL_IND] = 0;
3569-
_ag->indicator_value[BT_HFP_AG_ROAM_IND] = 0;
3570-
_ag->indicator_value[BT_HFP_AG_BATTERY_IND] = 0;
3651+
/* Init delay work */
3652+
k_work_init_delayable(&ag->tx_work, bt_ag_tx_work);
35713653

3572-
/* Set AG indicator status */
3573-
_ag->indicator = BIT(BT_HFP_AG_SERVICE_IND) | BIT(BT_HFP_AG_CALL_IND) |
3574-
BIT(BT_HFP_AG_CALL_SETUP_IND) | BIT(BT_HFP_AG_CALL_HELD_IND) |
3575-
BIT(BT_HFP_AG_SIGNAL_IND) | BIT(BT_HFP_AG_ROAM_IND) |
3576-
BIT(BT_HFP_AG_BATTERY_IND);
3654+
return ag;
3655+
}
35773656

3578-
/* Set AG operator */
3579-
memcpy(_ag->operator, "UNKNOWN", sizeof("UNKNOWN"));
3657+
int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t channel)
3658+
{
3659+
struct bt_hfp_ag *new_ag;
3660+
int err;
35803661

3581-
/* Set Codec ID*/
3582-
_ag->selected_codec_id = BT_HFP_AG_CODEC_CVSD;
3662+
LOG_DBG("");
35833663

3584-
/* Init delay work */
3585-
k_work_init_delayable(&_ag->tx_work, bt_ag_tx_work);
3664+
if (!conn || !ag || !channel) {
3665+
return -EINVAL;
3666+
}
35863667

3587-
*ag = _ag;
3668+
if (!bt_ag) {
3669+
return -EFAULT;
35883670
}
35893671

3590-
if (*ag == NULL) {
3591-
return -ENOMEM;
3672+
new_ag = hfp_ag_create(conn);
3673+
if (!new_ag) {
3674+
return -ECONNREFUSED;
35923675
}
35933676

3594-
err = bt_rfcomm_dlc_connect(conn, &(*ag)->rfcomm_dlc, channel);
3677+
err = bt_rfcomm_dlc_connect(conn, &new_ag->rfcomm_dlc, channel);
35953678
if (err != 0) {
3596-
(void)memset(*ag, 0, sizeof(struct bt_hfp_ag));
3679+
(void)memset(new_ag, 0, sizeof(*new_ag));
35973680
*ag = NULL;
35983681
} else {
3682+
*ag = new_ag;
35993683
bt_hfp_ag_set_state(*ag, BT_HFP_CONNECTING);
36003684
}
36013685

@@ -3615,6 +3699,71 @@ int bt_hfp_ag_disconnect(struct bt_hfp_ag *ag)
36153699
return bt_rfcomm_dlc_disconnect(&ag->rfcomm_dlc);
36163700
}
36173701

3702+
static int hfp_ag_accept(struct bt_conn *conn, struct bt_rfcomm_server *server,
3703+
struct bt_rfcomm_dlc **dlc)
3704+
{
3705+
struct bt_hfp_ag *ag;
3706+
3707+
ag = hfp_ag_create(conn);
3708+
3709+
if (!ag) {
3710+
return -ECONNREFUSED;
3711+
}
3712+
3713+
*dlc = &ag->rfcomm_dlc;
3714+
3715+
return 0;
3716+
}
3717+
3718+
static int bt_hfp_ag_sco_accept(const struct bt_sco_accept_info *info,
3719+
struct bt_sco_chan **chan)
3720+
{
3721+
static struct bt_sco_chan_ops ops = {
3722+
.connected = hfp_ag_sco_connected,
3723+
.disconnected = hfp_ag_sco_disconnected,
3724+
};
3725+
size_t index;
3726+
struct bt_hfp_ag *ag;
3727+
3728+
LOG_DBG("conn %p", info->acl);
3729+
3730+
index = (size_t)bt_conn_index(info->acl);
3731+
ag = &bt_hfp_ag_pool[index];
3732+
if (ag->acl_conn != info->acl) {
3733+
LOG_ERR("ACL %p of AG is unaligned with SCO's %p", ag->acl_conn, info->acl);
3734+
return -EINVAL;
3735+
}
3736+
3737+
if (ag->sco_chan.sco) {
3738+
return -ECONNREFUSED;
3739+
}
3740+
3741+
ag->sco_chan.ops = &ops;
3742+
3743+
*chan = &ag->sco_chan;
3744+
3745+
return 0;
3746+
}
3747+
3748+
static void hfp_ag_init(void)
3749+
{
3750+
static struct bt_rfcomm_server chan = {
3751+
.channel = BT_RFCOMM_CHAN_HFP_AG,
3752+
.accept = hfp_ag_accept,
3753+
};
3754+
3755+
bt_rfcomm_server_register(&chan);
3756+
3757+
static struct bt_sco_server sco_server = {
3758+
.sec_level = BT_SECURITY_L0,
3759+
.accept = bt_hfp_ag_sco_accept,
3760+
};
3761+
3762+
bt_sco_server_register(&sco_server);
3763+
3764+
bt_sdp_register_service(&hfp_ag_rec);
3765+
}
3766+
36183767
int bt_hfp_ag_register(struct bt_hfp_ag_cb *cb)
36193768
{
36203769
if (!cb) {
@@ -3627,6 +3776,8 @@ int bt_hfp_ag_register(struct bt_hfp_ag_cb *cb)
36273776

36283777
bt_ag = cb;
36293778

3779+
hfp_ag_init();
3780+
36303781
return 0;
36313782
}
36323783

0 commit comments

Comments
 (0)