Skip to content

Commit 354a63f

Browse files
lylezhu2012jhedberg
authored andcommitted
bluetooth: classic: HFP_AG: Fix early SCO connection req sending
When creating the audio connection, the SCO connection request will be sent before the response "OK" to AT command "AT+BCS" is issued. It causes the issue that the HFP HF cannot response the SCO connection request with the correct codec. Then the SCO connection cannot be established properly. Put all processing into the same context, thus avoiding non-sequential execution caused by the different priorities of different threads. Add a flag `BT_HFP_AG_AT_PROCESS` to flag the AT command is being processed. When the flag `BT_HFP_AG_AT_PROCESS` is set, put the pending executions into temp list `tx_submit_pending`. After the AT response `OK` or `ERROR` has been sent, move the pending executions from `tx_submit_pending` to `tx_pending`. Signed-off-by: Lyle Zhu <[email protected]>
1 parent 7e74b83 commit 354a63f

File tree

3 files changed

+155
-93
lines changed

3 files changed

+155
-93
lines changed

subsys/bluetooth/host/classic/Kconfig

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -328,17 +328,6 @@ config BT_HFP_AG_TX_BUF_COUNT
328328
sending buf. Normally this can be left to the default value, which
329329
is equal to the number of session in the stack-internal pool.
330330

331-
config BT_HFP_AG_THREAD_STACK_SIZE
332-
int "Size of the HFP AG thread stack [EXPERIMENTAL]"
333-
default 1024
334-
help
335-
Stack size needed for executing thread for HFP AG.
336-
337-
config BT_HFP_AG_THREAD_PRIO
338-
# Hidden option for HFP AG thread priority
339-
int
340-
default 6
341-
342331
config BT_HFP_AG_OUTGOING_TIMEOUT
343332
int "Call outgoing timeout value for HFP AG [EXPERIMENTAL]"
344333
default 3

subsys/bluetooth/host/classic/hfp_ag.c

Lines changed: 153 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,15 @@ static int hfp_ag_next_step(struct bt_hfp_ag *ag, bt_hfp_ag_tx_cb_t cb, void *us
367367
tx->user_data = user_data;
368368
tx->err = 0;
369369

370-
k_fifo_put(&ag_tx_notify, tx);
370+
hfp_ag_lock(ag);
371+
if (atomic_test_bit(ag->flags, BT_HFP_AG_AT_PROCESS)) {
372+
sys_slist_append(&ag->tx_submit_pending, &tx->node);
373+
} else {
374+
sys_slist_append(&ag->tx_pending, &tx->node);
375+
/* Always active tx work */
376+
k_work_reschedule(&ag->tx_work, K_NO_WAIT);
377+
}
378+
hfp_ag_unlock(ag);
371379

372380
return 0;
373381
}
@@ -835,6 +843,70 @@ static int hfp_ag_send(struct bt_hfp_ag *ag, struct bt_ag_tx *tx)
835843
return err;
836844
}
837845

846+
static void bt_ag_notify_work(struct k_work *work);
847+
848+
struct k_work ag_notify_work = Z_WORK_INITIALIZER(bt_ag_notify_work);
849+
850+
static void bt_ag_notify_work(struct k_work *work)
851+
{
852+
struct bt_ag_tx *tx;
853+
bt_hfp_ag_tx_cb_t cb;
854+
struct bt_hfp_ag *ag;
855+
void *user_data;
856+
bt_hfp_state_t state;
857+
int err;
858+
859+
tx = (struct bt_ag_tx *)k_fifo_get(&ag_tx_notify, K_NO_WAIT);
860+
861+
if (tx == NULL) {
862+
return;
863+
}
864+
865+
cb = tx->cb;
866+
ag = tx->ag;
867+
user_data = tx->user_data;
868+
err = tx->err;
869+
870+
bt_ag_tx_free(tx);
871+
872+
if (err < 0) {
873+
state = ag->state;
874+
if ((state != BT_HFP_DISCONNECTED) && (state != BT_HFP_DISCONNECTING)) {
875+
bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTING);
876+
bt_rfcomm_dlc_disconnect(&ag->rfcomm_dlc);
877+
}
878+
}
879+
880+
if (cb != NULL) {
881+
cb(ag, user_data);
882+
}
883+
884+
if (!k_fifo_is_empty(&ag_tx_notify)) {
885+
/* Submit worker if the fifo ag_tx_notify is not empty. */
886+
k_work_submit(&ag_notify_work);
887+
}
888+
}
889+
890+
static void bt_ag_tx_notify(struct bt_ag_tx *tx)
891+
{
892+
k_fifo_put(&ag_tx_notify, tx);
893+
894+
k_work_submit(&ag_notify_work);
895+
}
896+
897+
static void bt_ag_tx_done_with_err(struct bt_hfp_ag *ag, struct bt_ag_tx *tx, int err)
898+
{
899+
sys_slist_find_and_remove(&ag->tx_pending, &tx->node);
900+
tx->err = err;
901+
bt_ag_tx_notify(tx);
902+
/* Clear the tx ongoing flag */
903+
if (!atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_TX_ONGOING)) {
904+
LOG_WRN("tx ongoing flag is not set");
905+
}
906+
/* Due to the work is done, restart the tx work */
907+
k_work_reschedule(&ag->tx_work, K_NO_WAIT);
908+
}
909+
838910
static void bt_ag_tx_work(struct k_work *work)
839911
{
840912
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
@@ -859,20 +931,21 @@ static void bt_ag_tx_work(struct k_work *work)
859931
tx = CONTAINER_OF(node, struct bt_ag_tx, node);
860932

861933
if (!atomic_test_and_set_bit(ag->flags, BT_HFP_AG_TX_ONGOING)) {
934+
int err;
935+
862936
LOG_DBG("AG %p sending tx %p", ag, tx);
863-
int err = hfp_ag_send(ag, tx);
937+
938+
if (tx->buf == NULL) {
939+
/* Goto next state and remove the current tx */
940+
bt_ag_tx_done_with_err(ag, tx, 0);
941+
goto unlock;
942+
}
943+
944+
err = hfp_ag_send(ag, tx);
864945

865946
if (err < 0) {
866947
LOG_ERR("Rfcomm send error :(%d)", err);
867-
sys_slist_find_and_remove(&ag->tx_pending, &tx->node);
868-
tx->err = err;
869-
k_fifo_put(&ag_tx_notify, tx);
870-
/* Clear the tx ongoing flag */
871-
if (!atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_TX_ONGOING)) {
872-
LOG_WRN("tx ongoing flag is not set");
873-
}
874-
/* Due to the work is failed, restart the tx work */
875-
k_work_reschedule(&ag->tx_work, K_NO_WAIT);
948+
bt_ag_tx_done_with_err(ag, tx, err);
876949
}
877950
}
878951

@@ -3458,29 +3531,47 @@ static void hfp_ag_connected(struct bt_rfcomm_dlc *dlc)
34583531
LOG_DBG("AG %p", ag);
34593532
}
34603533

3534+
static struct bt_ag_tx *ag_get_tx(struct bt_hfp_ag *ag, sys_slist_t *list)
3535+
{
3536+
sys_snode_t *node;
3537+
3538+
hfp_ag_lock(ag);
3539+
node = sys_slist_get(list);
3540+
hfp_ag_unlock(ag);
3541+
if (node == NULL) {
3542+
return NULL;
3543+
}
3544+
3545+
return CONTAINER_OF(node, struct bt_ag_tx, node);
3546+
}
3547+
34613548
static void hfp_ag_disconnected(struct bt_rfcomm_dlc *dlc)
34623549
{
34633550
struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc);
3464-
sys_snode_t *node;
34653551
struct bt_ag_tx *tx;
34663552
struct bt_hfp_ag_call *call;
34673553

34683554
k_work_cancel_delayable(&ag->tx_work);
34693555

3470-
hfp_ag_lock(ag);
3471-
node = sys_slist_get(&ag->tx_pending);
3472-
hfp_ag_unlock(ag);
3473-
tx = CONTAINER_OF(node, struct bt_ag_tx, node);
3474-
while (tx) {
3475-
if (tx->buf && !atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_TX_ONGOING)) {
3556+
tx = ag_get_tx(ag, &ag->tx_pending);
3557+
while (tx != NULL) {
3558+
if ((tx->buf != NULL) &&
3559+
!atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_TX_ONGOING)) {
34763560
net_buf_unref(tx->buf);
34773561
}
34783562
tx->err = -ESHUTDOWN;
3479-
k_fifo_put(&ag_tx_notify, tx);
3480-
hfp_ag_lock(ag);
3481-
node = sys_slist_get(&ag->tx_pending);
3482-
hfp_ag_unlock(ag);
3483-
tx = CONTAINER_OF(node, struct bt_ag_tx, node);
3563+
bt_ag_tx_notify(tx);
3564+
tx = ag_get_tx(ag, &ag->tx_pending);
3565+
}
3566+
3567+
tx = ag_get_tx(ag, &ag->tx_submit_pending);
3568+
while (tx != NULL) {
3569+
if (tx->buf != NULL) {
3570+
net_buf_unref(tx->buf);
3571+
}
3572+
tx->err = -ESHUTDOWN;
3573+
bt_ag_tx_notify(tx);
3574+
tx = ag_get_tx(ag, &ag->tx_submit_pending);
34843575
}
34853576

34863577
bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTED);
@@ -3502,6 +3593,31 @@ static void hfp_ag_disconnected(struct bt_rfcomm_dlc *dlc)
35023593
LOG_DBG("AG %p", ag);
35033594
}
35043595

3596+
static void hfp_ag_preprocess_at_cmd(struct bt_hfp_ag *ag)
3597+
{
3598+
atomic_set_bit(ag->flags, BT_HFP_AG_AT_PROCESS);
3599+
}
3600+
3601+
static void hfp_ag_postprocess_at_cmd(struct bt_hfp_ag *ag)
3602+
{
3603+
sys_snode_t *node;
3604+
3605+
if (!atomic_test_and_clear_bit(ag->flags, BT_HFP_AG_AT_PROCESS)) {
3606+
LOG_WRN("No AT CMD is processing");
3607+
}
3608+
3609+
hfp_ag_lock(ag);
3610+
node = sys_slist_get(&ag->tx_submit_pending);
3611+
while (node != NULL) {
3612+
sys_slist_append(&ag->tx_pending, node);
3613+
node = sys_slist_get(&ag->tx_submit_pending);
3614+
}
3615+
hfp_ag_unlock(ag);
3616+
3617+
/* Always active tx work */
3618+
k_work_reschedule(&ag->tx_work, K_NO_WAIT);
3619+
}
3620+
35053621
static void hfp_ag_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
35063622
{
35073623
struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc);
@@ -3512,6 +3628,8 @@ static void hfp_ag_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
35123628

35133629
LOG_HEXDUMP_DBG(data, len, "Received:");
35143630

3631+
hfp_ag_preprocess_at_cmd(ag);
3632+
35153633
for (uint32_t index = 0; index < ARRAY_SIZE(cmd_handlers); index++) {
35163634
if (strlen(cmd_handlers[index].cmd) > len) {
35173635
continue;
@@ -3545,48 +3663,13 @@ static void hfp_ag_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
35453663
err = hfp_ag_send_data(ag, cb, NULL, "\r\n%s\r\n", (err == 0) ? "OK" : "ERROR");
35463664
}
35473665

3666+
hfp_ag_postprocess_at_cmd(ag);
3667+
35483668
if (err != 0) {
35493669
LOG_ERR("HFP AG send response err :(%d)", err);
35503670
}
35513671
}
35523672

3553-
static void bt_hfp_ag_thread(void *p1, void *p2, void *p3)
3554-
{
3555-
struct bt_ag_tx *tx;
3556-
bt_hfp_ag_tx_cb_t cb;
3557-
struct bt_hfp_ag *ag;
3558-
void *user_data;
3559-
bt_hfp_state_t state;
3560-
int err;
3561-
3562-
while (true) {
3563-
tx = (struct bt_ag_tx *)k_fifo_get(&ag_tx_notify, K_FOREVER);
3564-
3565-
if (tx == NULL) {
3566-
continue;
3567-
}
3568-
3569-
cb = tx->cb;
3570-
ag = tx->ag;
3571-
user_data = tx->user_data;
3572-
err = tx->err;
3573-
3574-
bt_ag_tx_free(tx);
3575-
3576-
if (err < 0) {
3577-
state = ag->state;
3578-
if ((state != BT_HFP_DISCONNECTED) && (state != BT_HFP_DISCONNECTING)) {
3579-
bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTING);
3580-
bt_rfcomm_dlc_disconnect(&ag->rfcomm_dlc);
3581-
}
3582-
}
3583-
3584-
if (cb) {
3585-
cb(ag, user_data);
3586-
}
3587-
}
3588-
}
3589-
35903673
static void hfp_ag_sent(struct bt_rfcomm_dlc *dlc, int err)
35913674
{
35923675
struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc);
@@ -3615,7 +3698,7 @@ static void hfp_ag_sent(struct bt_rfcomm_dlc *dlc, int err)
36153698
k_work_reschedule(&ag->tx_work, K_NO_WAIT);
36163699

36173700
tx->err = err;
3618-
k_fifo_put(&ag_tx_notify, tx);
3701+
bt_ag_tx_notify(tx);
36193702
}
36203703

36213704
static const char *bt_ag_get_call_state_string(bt_hfp_call_state_t call_state)
@@ -3793,6 +3876,7 @@ static void bt_ag_send_ok_code(struct bt_hfp_ag *ag)
37933876
if (hfp_ag_send_data(ag, NULL, NULL, "\r\nOK\r\n") != 0) {
37943877
LOG_ERR("Failed to send OK code");
37953878
}
3879+
hfp_ag_postprocess_at_cmd(ag);
37963880
}
37973881

37983882
static void bt_ag_ongoing_call_work(struct k_work *work)
@@ -3811,8 +3895,6 @@ static void bt_ag_ongoing_call_work(struct k_work *work)
38113895
bt_ag_send_ok_code(ag);
38123896
}
38133897

3814-
static K_KERNEL_STACK_MEMBER(ag_thread_stack, CONFIG_BT_HFP_AG_THREAD_STACK_SIZE);
3815-
38163898
static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
38173899
{
38183900
static struct bt_rfcomm_dlc_ops ops = {
@@ -3821,30 +3903,11 @@ static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
38213903
.recv = hfp_ag_recv,
38223904
.sent = hfp_ag_sent,
38233905
};
3824-
static k_tid_t ag_thread_id;
3825-
static struct k_thread ag_thread;
38263906
size_t index;
38273907
struct bt_hfp_ag *ag;
38283908

38293909
LOG_DBG("conn %p", conn);
38303910

3831-
if (ag_thread_id == NULL) {
3832-
3833-
k_fifo_init(&ag_tx_free);
3834-
k_fifo_init(&ag_tx_notify);
3835-
3836-
for (index = 0; index < ARRAY_SIZE(ag_tx); index++) {
3837-
k_fifo_put(&ag_tx_free, &ag_tx[index]);
3838-
}
3839-
3840-
ag_thread_id = k_thread_create(
3841-
&ag_thread, ag_thread_stack, K_KERNEL_STACK_SIZEOF(ag_thread_stack),
3842-
bt_hfp_ag_thread, NULL, NULL, NULL,
3843-
K_PRIO_COOP(CONFIG_BT_HFP_AG_THREAD_PRIO), 0, K_NO_WAIT);
3844-
__ASSERT(ag_thread_id, "Cannot create thread for AG");
3845-
k_thread_name_set(ag_thread_id, "HFP AG");
3846-
}
3847-
38483911
index = (size_t)bt_conn_index(conn);
38493912
__ASSERT(index < ARRAY_SIZE(bt_hfp_ag_pool), "Conn index is out of bounds");
38503913

@@ -3857,6 +3920,7 @@ static struct bt_hfp_ag *hfp_ag_create(struct bt_conn *conn)
38573920
(void)memset(ag, 0, sizeof(struct bt_hfp_ag));
38583921

38593922
sys_slist_init(&ag->tx_pending);
3923+
sys_slist_init(&ag->tx_submit_pending);
38603924

38613925
k_sem_init(&ag->lock, 1, 1);
38623926

@@ -4053,6 +4117,13 @@ static void hfp_ag_init(void)
40534117
bt_sdp_register_service(&hfp_ag_rec);
40544118

40554119
bt_sco_conn_cb_register(&ag_sco_conn_cb);
4120+
4121+
k_fifo_init(&ag_tx_free);
4122+
k_fifo_init(&ag_tx_notify);
4123+
4124+
ARRAY_FOR_EACH(ag_tx, index) {
4125+
k_fifo_put(&ag_tx_free, &ag_tx[index]);
4126+
}
40564127
}
40574128

40584129
int bt_hfp_ag_register(struct bt_hfp_ag_cb *cb)

subsys/bluetooth/host/classic/hfp_ag_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ enum {
138138
BT_HFP_AG_VRE_R2A, /* HF is ready to accept audio */
139139
BT_HGP_AG_ONGOING_CALLS, /* Waiting ongoing calls */
140140
BT_HFP_AG_SLC_CONNECTED, /* SLC connected event needs to be notified */
141+
BT_HFP_AG_AT_PROCESS, /* AT command is in processing */
141142

142143
/* Total number of flags - must be at the end of the enum */
143144
BT_HFP_AG_NUM_FLAGS,
@@ -256,6 +257,7 @@ struct bt_hfp_ag {
256257

257258
/* HFP TX pending */
258259
sys_slist_t tx_pending;
260+
sys_slist_t tx_submit_pending;
259261

260262
/* Critical locker */
261263
struct k_sem lock;

0 commit comments

Comments
 (0)