1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "btm_sco.h"
17 
18 #include <securec.h>
19 
20 #include "btstack.h"
21 #include "hci/hci.h"
22 #include "hci/hci_error.h"
23 #include "platform/include/allocator.h"
24 #include "platform/include/list.h"
25 #include "platform/include/mutex.h"
26 
27 #include "btm.h"
28 #include "btm_acl.h"
29 #include "btm_controller.h"
30 #include "btm_sco_def.h"
31 
32 #define SCO_CONNECTION_TYPE_SCO 1
33 #define SCO_CONNECTION_TYPE_ESCO 2
34 
35 #define SCO_CONNECTION_STATUS_CONNECTING 1
36 #define SCO_CONNECTION_STATUS_CONNECTED 2
37 #define SCO_CONNECTION_STATUS_DISCONNECTING 3
38 #define SCO_CONNECTION_STATUS_DISCONNECTED 0
39 
40 #define FOREACH_CALLBACKS_START(x)                         \
41     MutexLock(g_scoCallbackListLock);                      \
42     ListNode *node_ = ListGetFirstNode(g_scoCallbackList); \
43     while (node_ != NULL) {                                \
44         x = ListGetNodeData(node_);                        \
45         if ((x) != NULL) {
46 
47 #define FOREACH_CALLBACKS_END       \
48     }                               \
49     node_ = ListGetNextNode(node_); \
50     }                               \
51     MutexUnlock(g_scoCallbackListLock);
52 
53 #define STATUS_NONE 0
54 #define STATUS_INITIALIZED 1
55 
56 #define IS_INITIALIZED() (g_status == STATUS_INITIALIZED)
57 
58 #define INVALID_HANDLE 0xFFFF
59 
60 #define LINEAR_PCM_BIT_POS_BIT_INDEX 2
61 
62 #define INPUT_SAMPLE_SIZE_16_BIT 16
63 
64 typedef struct {
65     BtAddr addr;
66     uint16_t scoHandle;
67     uint16_t aclHandle;
68     uint8_t type;
69     uint8_t status;
70 } BtmScoConnection;
71 
72 typedef struct {
73     const BtmScoCallbacks *callbacks;
74     void *context;
75 } BtmScoCallbacksBlock;
76 
77 static List *g_scoList = NULL;
78 static Mutex *g_scoListLock = NULL;
79 
80 static List *g_scoCallbackList = NULL;
81 static Mutex *g_scoCallbackListLock = NULL;
82 
83 static HciEventCallbacks g_hciEventCallbacks;
84 
85 static uint8_t g_status = STATUS_NONE;
86 
BtmAllocScoConnection(const BtAddr * addr,uint16_t aclHandle)87 static BtmScoConnection *BtmAllocScoConnection(const BtAddr *addr, uint16_t aclHandle)
88 {
89     BtmScoConnection *connection = MEM_MALLOC.alloc(sizeof(BtmScoConnection));
90     if (connection != NULL) {
91         connection->addr = *addr;
92         connection->aclHandle = aclHandle;
93         connection->scoHandle = INVALID_HANDLE;
94     }
95     return connection;
96 }
97 
BtmFreeScoConnection(void * connection)98 static void BtmFreeScoConnection(void *connection)
99 {
100     MEM_CALLOC.free(connection);
101 }
102 
BtmAllocScoCallbacksBlock(const BtmScoCallbacks * callbacks,void * context)103 static BtmScoCallbacksBlock *BtmAllocScoCallbacksBlock(const BtmScoCallbacks *callbacks, void *context)
104 {
105     BtmScoCallbacksBlock *block = MEM_MALLOC.alloc(sizeof(BtmScoCallbacksBlock));
106     if (block != NULL) {
107         block->callbacks = callbacks;
108         block->context = context;
109     }
110     return block;
111 }
112 
BtmFreeScoCallbacksBlock(void * block)113 static void BtmFreeScoCallbacksBlock(void *block)
114 {
115     MEM_MALLOC.free(block);
116 }
117 
BtmInitSco()118 void BtmInitSco()
119 {
120     g_scoList = ListCreate(BtmFreeScoConnection);
121     g_scoListLock = MutexCreate();
122 
123     g_scoCallbackList = ListCreate(BtmFreeScoCallbacksBlock);
124     g_scoCallbackListLock = MutexCreate();
125 
126     g_status = STATUS_INITIALIZED;
127 }
128 
BtmCloseSco()129 void BtmCloseSco()
130 {
131     g_status = STATUS_NONE;
132 
133     if (g_scoCallbackList != NULL) {
134         ListDelete(g_scoCallbackList);
135         g_scoCallbackList = NULL;
136     }
137     if (g_scoCallbackListLock != NULL) {
138         MutexDelete(g_scoCallbackListLock);
139         g_scoCallbackListLock = NULL;
140     }
141 
142     if (g_scoList != NULL) {
143         ListDelete(g_scoList);
144         g_scoList = NULL;
145     }
146     if (g_scoListLock != NULL) {
147         MutexDelete(g_scoListLock);
148         g_scoListLock = NULL;
149     }
150 }
151 
BtmStartSco()152 void BtmStartSco()
153 {
154     HCI_RegisterEventCallbacks(&g_hciEventCallbacks);
155 }
156 
BtmStopSco()157 void BtmStopSco()
158 {
159     HCI_DeregisterEventCallbacks(&g_hciEventCallbacks);
160 
161     MutexLock(g_scoListLock);
162     ListClear(g_scoList);
163     MutexUnlock(g_scoListLock);
164 
165     MutexLock(g_scoCallbackListLock);
166     ListClear(g_scoCallbackList);
167     MutexUnlock(g_scoCallbackListLock);
168 }
169 
BTM_RegisterScoCallbacks(const BtmScoCallbacks * callbacks,void * context)170 int BTM_RegisterScoCallbacks(const BtmScoCallbacks *callbacks, void *context)
171 {
172     if (callbacks == NULL) {
173         return BT_BAD_PARAM;
174     }
175 
176     if (!IS_INITIALIZED()) {
177         return BT_BAD_STATUS;
178     }
179 
180     BtmScoCallbacksBlock *block = BtmAllocScoCallbacksBlock(callbacks, context);
181     if (block == NULL) {
182         return BT_NO_MEMORY;
183     }
184 
185     MutexLock(g_scoCallbackListLock);
186     ListAddLast(g_scoCallbackList, block);
187     MutexUnlock(g_scoCallbackListLock);
188     return BT_SUCCESS;
189 }
190 
BTM_DeregisterScoCallbacks(const BtmScoCallbacks * callbacks)191 int BTM_DeregisterScoCallbacks(const BtmScoCallbacks *callbacks)
192 {
193     if (callbacks == NULL) {
194         return BT_BAD_PARAM;
195     }
196 
197     if (!IS_INITIALIZED()) {
198         return BT_BAD_STATUS;
199     }
200 
201     BtmScoCallbacksBlock *block = NULL;
202     FOREACH_CALLBACKS_START(block);
203     if (block->callbacks == callbacks) {
204         ListRemoveNode(g_scoCallbackList, block);
205         break;
206     }
207     FOREACH_CALLBACKS_END;
208     return BT_SUCCESS;
209 }
210 
BTM_WriteVoiceSetting(uint16_t voiceSetting)211 int BTM_WriteVoiceSetting(uint16_t voiceSetting)
212 {
213     if (!IS_INITIALIZED()) {
214         return BT_BAD_STATUS;
215     }
216 
217     HciWriteVoiceSettingParam param = {
218         .voiceSetting = voiceSetting,
219     };
220     return HCI_WriteVoiceSetting(&param);
221 }
222 
IsSameAddress(const BtAddr * addr1,const BtAddr * addr2)223 static bool IsSameAddress(const BtAddr *addr1, const BtAddr *addr2)
224 {
225     bool isSame = true;
226     for (int i = 0; i < BT_ADDRESS_SIZE; i++) {
227         if (addr1->addr[i] != addr2->addr[i]) {
228             isSame = false;
229         }
230     }
231     return isSame;
232 }
233 
BtmScoFindScoConnectionByAddress(const BtAddr * addr,uint8_t status)234 static BtmScoConnection *BtmScoFindScoConnectionByAddress(const BtAddr *addr, uint8_t status)
235 {
236     BtmScoConnection *scoConnection = NULL;
237 
238     BtmScoConnection *item = NULL;
239 
240     ListNode *node = ListGetFirstNode(g_scoList);
241     while (node != NULL) {
242         item = ListGetNodeData(node);
243         if (item != NULL) {
244             if (item->status == status && IsSameAddress(&item->addr, addr)) {
245                 scoConnection = item;
246                 break;
247             }
248             item = NULL;
249         }
250         node = ListGetNextNode(node);
251     }
252 
253     return scoConnection;
254 }
255 
BtmScoFindScoConnectionByScoHandle(uint16_t scoHandle,uint8_t status)256 static BtmScoConnection *BtmScoFindScoConnectionByScoHandle(uint16_t scoHandle, uint8_t status)
257 {
258     BtmScoConnection *scoConnection = NULL;
259 
260     BtmScoConnection *item = NULL;
261 
262     ListNode *node = ListGetFirstNode(g_scoList);
263     while (node != NULL) {
264         item = ListGetNodeData(node);
265         if (item != NULL) {
266             if (item->status == status && scoHandle == item->scoHandle) {
267                 scoConnection = item;
268                 break;
269             }
270             item = NULL;
271         }
272         node = ListGetNextNode(node);
273     }
274 
275     return scoConnection;
276 }
277 
BTM_CreateScoConnection(const BtmCreateScoConnectionParam * param)278 int BTM_CreateScoConnection(const BtmCreateScoConnectionParam *param)
279 {
280     if (param == NULL) {
281         return BT_BAD_PARAM;
282     }
283 
284     if (!IS_INITIALIZED()) {
285         return BT_BAD_STATUS;
286     }
287 
288     uint16_t aclHandle = 0xffff;
289     int result = BtmGetAclHandleByAddress(&param->addr, &aclHandle);
290     if (result != BT_SUCCESS) {
291         return result;
292     }
293 
294     MutexLock(g_scoListLock);
295     if (ListGetSize(g_scoList) >= BTM_MAX_SCO) {
296         MutexUnlock(g_scoListLock);
297         return BT_CONNECT_NUM_MAX;
298     } else {
299         BtmScoConnection *scoConnection = BtmAllocScoConnection(&param->addr, aclHandle);
300         if (scoConnection != NULL) {
301             scoConnection->status = SCO_CONNECTION_STATUS_CONNECTING;
302 
303             ListAddLast(g_scoList, scoConnection);
304             MutexUnlock(g_scoListLock);
305         } else {
306             MutexUnlock(g_scoListLock);
307             return BT_NO_MEMORY;
308         }
309 
310         BTM_ExitSniffMode(&param->addr);
311 
312         HciSetupSynchronousConnectionParam setupSCOParam = {
313             .connectionHandle = aclHandle,
314             .transmitBandwidth = param->transmitBandwidth,
315             .receiveBandwidth = param->receiveBandwidth,
316             .maxLatency = param->maxLatency,
317             .voiceSetting = param->voiceSetting,
318             .retransmissionEffort = param->retransmissionEffort,
319             .packetType = param->packetType,
320         };
321         result = HCI_SetupSynchronousConnection(&setupSCOParam);
322         if (result != BT_SUCCESS) {
323             MutexLock(g_scoListLock);
324             ListRemoveNode(g_scoList, scoConnection);
325             MutexUnlock(g_scoListLock);
326         }
327     }
328 
329     return result;
330 }
331 
BTM_AcceptScoConnectionRequest(const BtmAcceptScoConnectionRequestParam * param)332 int BTM_AcceptScoConnectionRequest(const BtmAcceptScoConnectionRequestParam *param)
333 {
334     if (param == NULL) {
335         return BT_BAD_PARAM;
336     }
337 
338     if (!IS_INITIALIZED()) {
339         return BT_BAD_STATUS;
340     }
341 
342     uint16_t aclHandle = 0xffff;
343     int result = BtmGetAclHandleByAddress(&param->addr, &aclHandle);
344     if (result != BT_SUCCESS) {
345         return result;
346     }
347 
348     MutexLock(g_scoListLock);
349     if (ListGetSize(g_scoList) >= BTM_MAX_SCO) {
350         MutexUnlock(g_scoListLock);
351         result = BT_CONNECT_NUM_MAX;
352     } else {
353         BtmScoConnection *scoConnection = BtmAllocScoConnection(&param->addr, aclHandle);
354         if (scoConnection != NULL) {
355             scoConnection->status = SCO_CONNECTION_STATUS_CONNECTING;
356 
357             ListAddLast(g_scoList, scoConnection);
358             MutexUnlock(g_scoListLock);
359         } else {
360             MutexUnlock(g_scoListLock);
361             return BT_NO_MEMORY;
362         }
363 
364         HciAcceptSynchronousConnectionRequestParam acceptParam = {
365             .addr =
366                 {
367                     .raw = {0},
368                 },
369             .transmitBandwidth = param->transmitBandwidth,
370             .receiveBandwidth = param->receiveBandwidth,
371             .maxLatency = param->maxLatency,
372             .voiceSetting = param->voiceSetting,
373             .retransmissionEffort = param->retransmissionEffort,
374             .packetType = param->packetType,
375         };
376         (void)memcpy_s(acceptParam.addr.raw, BT_ADDRESS_SIZE, param->addr.addr, BT_ADDRESS_SIZE);
377         result = HCI_AcceptSynchronousConnectionRequest(&acceptParam);
378     }
379 
380     return result;
381 }
382 
BTM_ModifyScoConnection(const BtmModifyScoConnectionParam * param)383 int BTM_ModifyScoConnection(const BtmModifyScoConnectionParam *param)
384 {
385     if (param == NULL) {
386         return BT_BAD_PARAM;
387     }
388 
389     if (!IS_INITIALIZED()) {
390         return BT_BAD_STATUS;
391     }
392 
393     int result;
394 
395     MutexLock(g_scoListLock);
396     BtmScoConnection *scoConnection =
397         BtmScoFindScoConnectionByScoHandle(param->connectionHandle, SCO_CONNECTION_STATUS_CONNECTED);
398     if (scoConnection != NULL) {
399         MutexUnlock(g_scoListLock);
400 
401         HciSetupSynchronousConnectionParam setupParam = {
402             .connectionHandle = param->connectionHandle,
403             .transmitBandwidth = param->transmitBandwidth,
404             .receiveBandwidth = param->receiveBandwidth,
405             .maxLatency = param->maxLatency,
406             .voiceSetting = param->voiceSetting,
407             .retransmissionEffort = param->retransmissionEffort,
408             .packetType = param->packetType,
409         };
410         result = HCI_SetupSynchronousConnection(&setupParam);
411     } else {
412         MutexUnlock(g_scoListLock);
413         result = BT_BAD_STATUS;
414     }
415 
416     return result;
417 }
418 
BtmEscoParamToVoiceSetting(const BtmEscoParameters * escoParam)419 static uint16_t BtmEscoParamToVoiceSetting(const BtmEscoParameters *escoParam)
420 {
421     uint16_t voiceSetting = 0;
422 
423     if (escoParam->inputCodingFormat.codingFormat == HCI_CODING_FORMAT_U_LAW_LOG) {
424         voiceSetting |= HCI_VOICE_SETTING_INPUT_CODING_ULAW;
425     } else if (escoParam->inputCodingFormat.codingFormat == HCI_CODING_FORMAT_A_LAW_LOG) {
426         voiceSetting |= HCI_VOICE_SETTING_INPUT_CODING_ALAW;
427     } else {
428         voiceSetting |= HCI_VOICE_SETTING_INPUT_CODING_LINEAR;
429     }
430 
431     if (escoParam->inputPCMDataFormat == HCI_PCM_DATA_FORMAT_1_COMPLEMENT) {
432         voiceSetting |= HCI_VOICE_SETTING_INPUT_DATA_FORMAT_1S_COMPLEMENT;
433     } else if (escoParam->inputPCMDataFormat == HCI_PCM_DATA_FORMAT_SIGN_MAGNITUDE) {
434         voiceSetting |= HCI_VOICE_SETTING_INPUT_DATA_FORMAT_SIGN_MAGNITUDE;
435     } else if (escoParam->inputPCMDataFormat == HCI_PCM_DATA_FORMAT_UNSIGNED) {
436         voiceSetting |= HCI_VOICE_SETTING_INPUT_DATA_FORMAT_UNSIGNED;
437     } else {
438         voiceSetting |= HCI_VOICE_SETTING_INPUT_DATA_FORMAT_2S_COMPLEMENT;
439     }
440 
441     if (escoParam->transmitCodingFormat.codingFormat == HCI_CODING_FORMAT_U_LAW_LOG) {
442         voiceSetting |= HCI_VOICE_SETTING_AIR_CODING_FORMAT_ULAW;
443     } else if (escoParam->transmitCodingFormat.codingFormat == HCI_CODING_FORMAT_A_LAW_LOG) {
444         voiceSetting |= HCI_VOICE_SETTING_AIR_CODING_FORMAT_ALAW;
445     } else if (escoParam->transmitCodingFormat.codingFormat == HCI_CODING_FORMAT_MSBC) {
446         voiceSetting |= HCI_VOICE_SETTING_AIR_CODING_FORMAT_TRANSPARENT_DATA;
447     } else {
448         voiceSetting |= HCI_VOICE_SETTING_AIR_CODING_FORMAT_CVSD;
449     }
450 
451     voiceSetting |= ((escoParam->inputPCMSamplePayloadMSBPosition & 0x7) << LINEAR_PCM_BIT_POS_BIT_INDEX);
452 
453     if (escoParam->inputCodedDataSize == INPUT_SAMPLE_SIZE_16_BIT) {
454         voiceSetting |= HCI_VOICE_SETTING_INPUT_SAMPLE_SIZE_16_BIT;
455     } else {
456         voiceSetting |= HCI_VOICE_SETTING_INPUT_SAMPLE_SIZE_8_BIT;
457     }
458 
459     return voiceSetting;
460 }
461 
BtmEnhancedCreateEscoConnection(uint16_t connectionHandle,const BtmCreateEscoConnectionParam * param,const BtmEscoParameters * escoParam)462 static int BtmEnhancedCreateEscoConnection(
463     uint16_t connectionHandle, const BtmCreateEscoConnectionParam *param, const BtmEscoParameters *escoParam)
464 {
465     HciEnhancedSetupSynchronousConnectionParam setupParam = {
466         .connectionHandle = connectionHandle,
467         .transmitBandwidth = param->transmitBandwidth,
468         .receiveBandwidth = param->receiveBandwidth,
469         .transmitCodingFormat =
470             {
471                 .codingFormat = escoParam->transmitCodingFormat.codingFormat,
472                 .companyID = escoParam->transmitCodingFormat.companyID,
473                 .vendorSpecificCodecID = escoParam->transmitCodingFormat.vendorSpecificCodecID,
474             },
475         .receiveCodingFormat =
476             {
477                 .codingFormat = escoParam->receiveCodingFormat.codingFormat,
478                 .companyID = escoParam->receiveCodingFormat.companyID,
479                 .vendorSpecificCodecID = escoParam->receiveCodingFormat.vendorSpecificCodecID,
480             },
481         .transmitCodecFrameSize = escoParam->transmitCodecFrameSize,
482         .receiveCodecFrameSize = escoParam->receiveCodecFrameSize,
483         .inputBandwidth = escoParam->inputBandwidth,
484         .outputBandwidth = escoParam->outputBandwidth,
485         .inputCodingFormat =
486             {
487                 .codingFormat = escoParam->inputCodingFormat.codingFormat,
488                 .companyID = escoParam->inputCodingFormat.companyID,
489                 .vendorSpecificCodecID = escoParam->inputCodingFormat.vendorSpecificCodecID,
490             },
491         .outputCodingFormat =
492             {
493                 .codingFormat = escoParam->outputCodingFormat.codingFormat,
494                 .companyID = escoParam->outputCodingFormat.companyID,
495                 .vendorSpecificCodecID = escoParam->outputCodingFormat.vendorSpecificCodecID,
496             },
497         .inputCodedDataSize = escoParam->inputCodedDataSize,
498         .outputCodedDataSize = escoParam->outputCodedDataSize,
499         .inputPCMDataFormat = escoParam->inputPCMDataFormat,
500         .outputPCMDataFormat = escoParam->outputPCMDataFormat,
501         .inputPCMSamplePayloadMSBPosition = escoParam->inputPCMSamplePayloadMSBPosition,
502         .outputPCMSamplePaylandMSBPosition = escoParam->outputPCMSamplePayloadMSBPosition,
503         .inputDataPath = escoParam->inputDataPath,
504         .outputDataPath = escoParam->outputDataPath,
505         .inputTransportUnitSize = escoParam->inputTransportUnitSize,
506         .outputTransportUnitSize = escoParam->outputTransportUnitSize,
507         .maxLatency = param->maxLatency,
508         .packetType = param->packetType,
509         .retransmissionEffort = param->retransmissionEffort,
510     };
511     return HCI_EnhancedSetupSynchronousConnection(&setupParam);
512 }
513 
BTM_CreateEscoConnection(const BtmCreateEscoConnectionParam * param)514 int BTM_CreateEscoConnection(const BtmCreateEscoConnectionParam *param)
515 {
516     if (param == NULL) {
517         return BT_BAD_PARAM;
518     }
519 
520     if (!IS_INITIALIZED()) {
521         return BT_BAD_STATUS;
522     }
523 
524     uint16_t aclHandle = 0xffff;
525     int result = BtmGetAclHandleByAddress(&param->addr, &aclHandle);
526     if (result != BT_SUCCESS) {
527         return result;
528     }
529 
530     const BtmEscoParameters *escoParam = BtmGetEscoParameters(param->codec);
531     if (escoParam == NULL) {
532         return BT_BAD_PARAM;
533     }
534 
535     MutexLock(g_scoListLock);
536     if (ListGetSize(g_scoList) >= BTM_MAX_SCO) {
537         MutexUnlock(g_scoListLock);
538         return BT_CONNECT_NUM_MAX;
539     }
540 
541     BtmScoConnection *scoConnection = BtmAllocScoConnection(&param->addr, aclHandle);
542     if (scoConnection != NULL) {
543         scoConnection->status = SCO_CONNECTION_STATUS_CONNECTING;
544 
545         ListAddLast(g_scoList, scoConnection);
546         MutexUnlock(g_scoListLock);
547     } else {
548         MutexUnlock(g_scoListLock);
549         return BT_NO_MEMORY;
550     }
551 
552     BTM_ExitSniffMode(&param->addr);
553 
554     if (BtmIsControllerSupportedEnhancedSetupSynchronousConnection()) {
555         result = BtmEnhancedCreateEscoConnection(aclHandle, param, escoParam);
556     } else {
557         uint16_t voiceSetting = BtmEscoParamToVoiceSetting(escoParam);
558         HciSetupSynchronousConnectionParam setupParam = {
559             .connectionHandle = aclHandle,
560             .transmitBandwidth = param->transmitBandwidth,
561             .receiveBandwidth = param->receiveBandwidth,
562             .maxLatency = param->maxLatency,
563             .voiceSetting = voiceSetting,
564             .retransmissionEffort = param->retransmissionEffort,
565             .packetType = param->packetType,
566         };
567         result = HCI_SetupSynchronousConnection(&setupParam);
568     }
569 
570     return result;
571 }
572 
BtmEnhancedModifyEscoConnection(const BtmModifyEscoConnectionParam * param,const BtmEscoParameters * escoParam)573 static int BtmEnhancedModifyEscoConnection(
574     const BtmModifyEscoConnectionParam *param, const BtmEscoParameters *escoParam)
575 {
576     HciEnhancedSetupSynchronousConnectionParam setupParam = {
577         .connectionHandle = param->connectionHandle,
578         .transmitBandwidth = param->transmitBandwidth,
579         .receiveBandwidth = param->receiveBandwidth,
580         .transmitCodingFormat =
581             {
582                 .codingFormat = escoParam->transmitCodingFormat.codingFormat,
583                 .companyID = escoParam->transmitCodingFormat.companyID,
584                 .vendorSpecificCodecID = escoParam->transmitCodingFormat.vendorSpecificCodecID,
585             },
586         .receiveCodingFormat =
587             {
588                 .codingFormat = escoParam->receiveCodingFormat.codingFormat,
589                 .companyID = escoParam->receiveCodingFormat.companyID,
590                 .vendorSpecificCodecID = escoParam->receiveCodingFormat.vendorSpecificCodecID,
591             },
592         .transmitCodecFrameSize = escoParam->transmitCodecFrameSize,
593         .receiveCodecFrameSize = escoParam->receiveCodecFrameSize,
594         .inputBandwidth = escoParam->inputBandwidth,
595         .outputBandwidth = escoParam->outputBandwidth,
596         .inputCodingFormat =
597             {
598                 .codingFormat = escoParam->inputCodingFormat.codingFormat,
599                 .companyID = escoParam->inputCodingFormat.companyID,
600                 .vendorSpecificCodecID = escoParam->inputCodingFormat.vendorSpecificCodecID,
601             },
602         .outputCodingFormat =
603             {
604                 .codingFormat = escoParam->outputCodingFormat.codingFormat,
605                 .companyID = escoParam->outputCodingFormat.companyID,
606                 .vendorSpecificCodecID = escoParam->outputCodingFormat.vendorSpecificCodecID,
607             },
608         .inputCodedDataSize = escoParam->inputCodedDataSize,
609         .outputCodedDataSize = escoParam->outputCodedDataSize,
610         .inputPCMDataFormat = escoParam->inputPCMDataFormat,
611         .outputPCMDataFormat = escoParam->outputPCMDataFormat,
612         .inputPCMSamplePayloadMSBPosition = escoParam->inputPCMSamplePayloadMSBPosition,
613         .outputPCMSamplePaylandMSBPosition = escoParam->outputPCMSamplePayloadMSBPosition,
614         .inputDataPath = escoParam->inputDataPath,
615         .outputDataPath = escoParam->outputDataPath,
616         .inputTransportUnitSize = escoParam->inputTransportUnitSize,
617         .outputTransportUnitSize = escoParam->outputTransportUnitSize,
618         .maxLatency = param->maxLatency,
619         .packetType = param->packetType,
620         .retransmissionEffort = param->retransmissionEffort,
621     };
622     return HCI_EnhancedSetupSynchronousConnection(&setupParam);
623 }
624 
BTM_ModifyEscoConnection(const BtmModifyEscoConnectionParam * param)625 int BTM_ModifyEscoConnection(const BtmModifyEscoConnectionParam *param)
626 {
627     if (param == NULL) {
628         return BT_BAD_PARAM;
629     }
630 
631     if (!IS_INITIALIZED()) {
632         return BT_BAD_STATUS;
633     }
634 
635     const BtmEscoParameters *escoParam = BtmGetEscoParameters(param->codec);
636     if (escoParam == NULL) {
637         return BT_BAD_PARAM;
638     }
639 
640     int result;
641 
642     MutexLock(g_scoListLock);
643     BtmScoConnection *scoConnection =
644         BtmScoFindScoConnectionByScoHandle(param->connectionHandle, SCO_CONNECTION_STATUS_CONNECTED);
645     if (scoConnection != NULL) {
646         MutexUnlock(g_scoListLock);
647 
648         if (BtmIsControllerSupportedEnhancedSetupSynchronousConnection()) {
649             result = BtmEnhancedModifyEscoConnection(param, escoParam);
650         } else {
651             uint16_t voiceSetting = BtmEscoParamToVoiceSetting(escoParam);
652             HciSetupSynchronousConnectionParam setupParam = {
653                 .connectionHandle = param->connectionHandle,
654                 .transmitBandwidth = param->transmitBandwidth,
655                 .receiveBandwidth = param->receiveBandwidth,
656                 .maxLatency = param->maxLatency,
657                 .voiceSetting = voiceSetting,
658                 .retransmissionEffort = param->retransmissionEffort,
659                 .packetType = param->packetType,
660             };
661             result = HCI_SetupSynchronousConnection(&setupParam);
662         }
663     } else {
664         MutexUnlock(g_scoListLock);
665         result = BT_BAD_STATUS;
666     }
667 
668     return result;
669 }
670 
BtmEnhancedAcceptEscoConnection(const BtmAcceptEscoConnectionRequestParam * param,const BtmEscoParameters * escoParam)671 static int BtmEnhancedAcceptEscoConnection(
672     const BtmAcceptEscoConnectionRequestParam *param, const BtmEscoParameters *escoParam)
673 {
674     HciEnhancedAcceptSynchronousConnectionRequestParam acceptParam = {
675         .bdAddr = {.raw = {0}},
676         .transmitBandwidth = param->transmitBandwidth,
677         .receiveBandwidth = param->receiveBandwidth,
678         .transmitCodingFormat =
679             {
680                 .codingFormat = escoParam->transmitCodingFormat.codingFormat,
681                 .companyID = escoParam->transmitCodingFormat.companyID,
682                 .vendorSpecificCodecID = escoParam->transmitCodingFormat.vendorSpecificCodecID,
683             },
684         .receiveCodingFormat =
685             {
686                 .codingFormat = escoParam->receiveCodingFormat.codingFormat,
687                 .companyID = escoParam->receiveCodingFormat.companyID,
688                 .vendorSpecificCodecID = escoParam->receiveCodingFormat.vendorSpecificCodecID,
689             },
690         .transmitCodecFrameSize = escoParam->transmitCodecFrameSize,
691         .receiveCodecFrameSize = escoParam->receiveCodecFrameSize,
692         .inputBandwidth = escoParam->inputBandwidth,
693         .outputBandwidth = escoParam->outputBandwidth,
694         .inputCodingFormat =
695             {
696                 .codingFormat = escoParam->inputCodingFormat.codingFormat,
697                 .companyID = escoParam->inputCodingFormat.companyID,
698                 .vendorSpecificCodecID = escoParam->inputCodingFormat.vendorSpecificCodecID,
699             },
700         .outputCodingFormat =
701             {
702                 .codingFormat = escoParam->outputCodingFormat.codingFormat,
703                 .companyID = escoParam->outputCodingFormat.companyID,
704                 .vendorSpecificCodecID = escoParam->outputCodingFormat.vendorSpecificCodecID,
705             },
706         .inputCodedDataSize = escoParam->inputCodedDataSize,
707         .outputCodedDataSize = escoParam->outputCodedDataSize,
708         .inputPCMDataFormat = escoParam->inputPCMDataFormat,
709         .outputPCMDataFormat = escoParam->outputPCMDataFormat,
710         .inputPCMSamplePayloadMSBPosition = escoParam->inputPCMSamplePayloadMSBPosition,
711         .outputPCMSamplePaylandMSBPosition = escoParam->outputPCMSamplePayloadMSBPosition,
712         .inputDataPath = escoParam->inputDataPath,
713         .outputDataPath = escoParam->outputDataPath,
714         .inputTransportUnitSize = escoParam->inputTransportUnitSize,
715         .outputTransportUnitSize = escoParam->outputTransportUnitSize,
716         .maxLatency = param->maxLatency,
717         .packetType = param->packetType,
718         .retransmissionEffort = param->retransmissionEffort,
719     };
720     (void)memcpy_s(acceptParam.bdAddr.raw, BT_ADDRESS_SIZE, param->addr.addr, BT_ADDRESS_SIZE);
721     return HCI_EnhancedAcceptSynchronousConnectionRequest(&acceptParam);
722 }
723 
BtmAcceptEscoConnection(const BtmAcceptEscoConnectionRequestParam * param,const BtmEscoParameters * escoParam)724 static int BtmAcceptEscoConnection(const BtmAcceptEscoConnectionRequestParam *param, const BtmEscoParameters *escoParam)
725 {
726     uint16_t voiceSetting = BtmEscoParamToVoiceSetting(escoParam);
727     HciAcceptSynchronousConnectionRequestParam acceptParam = {
728         .addr =
729             {
730                 .raw = {0},
731             },
732         .transmitBandwidth = param->transmitBandwidth,
733         .receiveBandwidth = param->receiveBandwidth,
734         .maxLatency = param->maxLatency,
735         .voiceSetting = voiceSetting,
736         .retransmissionEffort = param->retransmissionEffort,
737         .packetType = param->packetType,
738     };
739     (void)memcpy_s(acceptParam.addr.raw, BT_ADDRESS_SIZE, param->addr.addr, BT_ADDRESS_SIZE);
740     return HCI_AcceptSynchronousConnectionRequest(&acceptParam);
741 }
742 
BTM_AcceptEscoConnectionRequest(const BtmAcceptEscoConnectionRequestParam * param)743 int BTM_AcceptEscoConnectionRequest(const BtmAcceptEscoConnectionRequestParam *param)
744 {
745     if (param == NULL) {
746         return BT_BAD_PARAM;
747     }
748 
749     if (!IS_INITIALIZED()) {
750         return BT_BAD_STATUS;
751     }
752 
753     const BtmEscoParameters *escoParam = BtmGetEscoParameters(param->codec);
754     if (escoParam == NULL) {
755         return BT_BAD_PARAM;
756     }
757 
758     uint16_t aclHandle = 0xffff;
759     int result = BtmGetAclHandleByAddress(&param->addr, &aclHandle);
760     if (result != BT_SUCCESS) {
761         return result;
762     }
763 
764     MutexLock(g_scoListLock);
765     if (ListGetSize(g_scoList) >= BTM_MAX_SCO) {
766         MutexUnlock(g_scoListLock);
767         result = BT_CONNECT_NUM_MAX;
768     } else {
769         BtmScoConnection *scoConnection = BtmAllocScoConnection(&param->addr, aclHandle);
770         if (scoConnection != NULL) {
771             scoConnection->status = SCO_CONNECTION_STATUS_CONNECTING;
772 
773             ListAddLast(g_scoList, scoConnection);
774             MutexUnlock(g_scoListLock);
775         } else {
776             MutexUnlock(g_scoListLock);
777             return BT_NO_MEMORY;
778         }
779 
780         if (BtmIsControllerSupportedEnhancedAcceptSynchronousConnection()) {
781             result = BtmEnhancedAcceptEscoConnection(param, escoParam);
782         } else {
783             result = BtmAcceptEscoConnection(param, escoParam);
784         }
785     }
786 
787     return result;
788 }
789 
BtmScoOnConnectionComplete(const HciConnectionCompleteEventParam * eventParam)790 static void BtmScoOnConnectionComplete(const HciConnectionCompleteEventParam *eventParam)
791 {
792     if (eventParam->linkType != HCI_LINK_TYPE_SCO) {
793         return;
794     }
795 
796     BtAddr addr = {
797         .addr = {0},
798         .type = BT_PUBLIC_DEVICE_ADDRESS,
799     };
800     (void)memcpy_s(addr.addr, BT_ADDRESS_SIZE, eventParam->bdAddr.raw, BT_ADDRESS_SIZE);
801 
802     BtmScoConnection *scoConnection = NULL;
803     MutexLock(g_scoListLock);
804 
805     scoConnection = BtmScoFindScoConnectionByAddress(&addr, SCO_CONNECTION_STATUS_CONNECTING);
806     if (scoConnection != NULL) {
807         if (eventParam->status == HCI_SUCCESS) {
808             scoConnection->scoHandle = eventParam->connectionHandle;
809             scoConnection->type = SCO_CONNECTION_TYPE_SCO;
810             scoConnection->status = SCO_CONNECTION_STATUS_CONNECTED;
811         } else {
812             ListRemoveNode(g_scoList, scoConnection);
813         }
814     }
815     MutexUnlock(g_scoListLock);
816 
817     BtmScoConnectionCompleteParam param = {
818         .status = eventParam->status,
819         .connectionHandle = (eventParam->status == HCI_SUCCESS) ? eventParam->connectionHandle : INVALID_HANDLE,
820         .addr = &addr,
821     };
822 
823     BtmScoCallbacksBlock *block = NULL;
824     FOREACH_CALLBACKS_START(block);
825     if (block->callbacks->scoConnectionComplete != NULL) {
826         block->callbacks->scoConnectionComplete(&param, block->context);
827     }
828     FOREACH_CALLBACKS_END;
829 }
830 
BtmScoOnSynchronousConnectionComplete(const HciSynchronousConnectionCompleteEventParam * eventParam)831 static void BtmScoOnSynchronousConnectionComplete(const HciSynchronousConnectionCompleteEventParam *eventParam)
832 {
833     BtAddr addr = {
834         .addr = {0},
835         .type = BT_PUBLIC_DEVICE_ADDRESS,
836     };
837     (void)memcpy_s(addr.addr, BT_ADDRESS_SIZE, eventParam->bdAddr.raw, BT_ADDRESS_SIZE);
838 
839     BtmScoConnection *scoConnection = NULL;
840     uint8_t type = (eventParam->linkType == HCI_LINK_TYPE_ESCO) ? SCO_CONNECTION_TYPE_ESCO : SCO_CONNECTION_TYPE_SCO;
841     MutexLock(g_scoListLock);
842     scoConnection = BtmScoFindScoConnectionByAddress(&addr, SCO_CONNECTION_STATUS_CONNECTING);
843     if (scoConnection != NULL) {
844         if (eventParam->status == HCI_SUCCESS) {
845             scoConnection->scoHandle = eventParam->connectionHandle;
846             scoConnection->type = type;
847             scoConnection->status = SCO_CONNECTION_STATUS_CONNECTED;
848         } else {
849             ListRemoveNode(g_scoList, scoConnection);
850         }
851     }
852     MutexUnlock(g_scoListLock);
853 
854     BtmScoConnectionCompleteParam param = {
855         .status = eventParam->status,
856         .connectionHandle = (eventParam->status == HCI_SUCCESS) ? eventParam->connectionHandle : INVALID_HANDLE,
857         .addr = &addr,
858     };
859 
860     BtmScoCallbacksBlock *block = NULL;
861     FOREACH_CALLBACKS_START(block);
862     if (block->callbacks->scoConnectionComplete != NULL) {
863         block->callbacks->scoConnectionComplete(&param, block->context);
864     }
865     FOREACH_CALLBACKS_END;
866 }
867 
BTM_RejectScoConnectionRequest(const BtmRejectScoConnectionRequestParam * param)868 int BTM_RejectScoConnectionRequest(const BtmRejectScoConnectionRequestParam *param)
869 {
870     if (param == NULL) {
871         return BT_BAD_PARAM;
872     }
873 
874     if (!IS_INITIALIZED()) {
875         return BT_BAD_STATUS;
876     }
877 
878     HciRejectSynchronousConnectionRequestParam rejectParam = {
879         .bdAddr =
880             {
881                 .raw = {0},
882             },
883         .reason = param->reason,
884     };
885     (void)memcpy_s(rejectParam.bdAddr.raw, BT_ADDRESS_SIZE, param->addr.addr, BT_ADDRESS_SIZE);
886 
887     int result = HCI_RejectSynchronousConnectionRequest(&rejectParam);
888     return result;
889 }
890 
BTM_DisconnectScoConnection(uint16_t connectionHandle,uint8_t reason)891 int BTM_DisconnectScoConnection(uint16_t connectionHandle, uint8_t reason)
892 {
893     if (!IS_INITIALIZED()) {
894         return BT_BAD_STATUS;
895     }
896 
897     int result;
898 
899     MutexLock(g_scoListLock);
900     BtmScoConnection *scoConnection =
901         BtmScoFindScoConnectionByScoHandle(connectionHandle, SCO_CONNECTION_STATUS_CONNECTED);
902     if (scoConnection != NULL) {
903         scoConnection->status = SCO_CONNECTION_STATUS_DISCONNECTING;
904         MutexUnlock(g_scoListLock);
905 
906         HciDisconnectParam param = {
907             .connectionHandle = connectionHandle,
908             .reason = reason,
909         };
910         result = HCI_Disconnect(&param);
911     } else {
912         MutexUnlock(g_scoListLock);
913         result = BT_BAD_STATUS;
914     }
915 
916     return result;
917 }
918 
BtmScoOnSynchronousConnectionChanged(const HciSynchronousConnectionChangedEventParam * eventParam)919 static void BtmScoOnSynchronousConnectionChanged(const HciSynchronousConnectionChangedEventParam *eventParam)
920 {
921     if (eventParam->status != HCI_SUCCESS) {
922         return;
923     }
924 
925     BtmScoConnectionChangedParam param = {
926         .connectionHandle = eventParam->connectionHandle,
927         .transmissionInterval = eventParam->transmissionInterval,
928         .retransmissionWindow = eventParam->retransmissionWindow,
929         .rxPacketLength = eventParam->rxPacketLength,
930         .txPacketLength = eventParam->txPacketLength,
931     };
932 
933     BtmScoCallbacksBlock *block = NULL;
934     FOREACH_CALLBACKS_START(block);
935     if (block->callbacks->scoConnectionChanged != NULL) {
936         block->callbacks->scoConnectionChanged(&param, block->context);
937     }
938     FOREACH_CALLBACKS_END;
939 }
940 
BtmScoOnWriteVoiceSettingComplete(const HciWriteVoiceSettingParamReturnParam * returnParam)941 static void BtmScoOnWriteVoiceSettingComplete(const HciWriteVoiceSettingParamReturnParam *returnParam)
942 {
943     MutexLock(g_scoCallbackListLock);
944 
945     BtmScoCallbacksBlock *block = NULL;
946     ListNode *node = ListGetFirstNode(g_scoCallbackList);
947     while (node != NULL) {
948         block = ListGetNodeData(node);
949         if (block->callbacks->writeVoiceSettingComplete != NULL) {
950             block->callbacks->writeVoiceSettingComplete(returnParam->status, block->context);
951         }
952         node = ListGetNextNode(node);
953     }
954 
955     MutexUnlock(g_scoCallbackListLock);
956 }
957 
BtmScoOnConnectionRequest(const HciConnectionRequestEventParam * eventParam)958 static void BtmScoOnConnectionRequest(const HciConnectionRequestEventParam *eventParam)
959 {
960     if (eventParam->linkType != HCI_LINK_TYPE_SCO && eventParam->linkType != HCI_LINK_TYPE_ESCO) {
961         return;
962     }
963 
964     MutexLock(g_scoListLock);
965     if (ListGetSize(g_scoList) >= BTM_MAX_SCO) {
966         HciRejectSynchronousConnectionRequestParam rejectParam = {
967             .bdAddr = eventParam->bdAddr,
968             .reason = HCI_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES,
969         };
970         HCI_RejectSynchronousConnectionRequest(&rejectParam);
971 
972         MutexUnlock(g_scoListLock);
973     } else {
974         MutexUnlock(g_scoListLock);
975 
976         BtAddr addr = {
977             .addr = {0},
978             .type = BT_PUBLIC_DEVICE_ADDRESS,
979         };
980         (void)memcpy_s(addr.addr, BT_ADDRESS_SIZE, eventParam->bdAddr.raw, BT_ADDRESS_SIZE);
981 
982         BtmScoConnectionRequestParam param = {
983             .addr = &addr,
984             .linkType = eventParam->linkType,
985         };
986 
987         BtmScoCallbacksBlock *block = NULL;
988         FOREACH_CALLBACKS_START(block);
989         if (block->callbacks->scoConnectionRequest != NULL) {
990             block->callbacks->scoConnectionRequest(&param, block->context);
991         }
992         FOREACH_CALLBACKS_END;
993     }
994 }
995 
BtmScoOnDisconnectComplete(const HciDisconnectCompleteEventParam * param)996 NO_SANITIZE("cfi") static void BtmScoOnDisconnectComplete(const HciDisconnectCompleteEventParam *param)
997 {
998     MutexLock(g_scoListLock);
999     BtmScoConnection *scoConnection =
1000         BtmScoFindScoConnectionByScoHandle(param->connectionHandle, SCO_CONNECTION_STATUS_DISCONNECTING);
1001     if (scoConnection == NULL) {
1002         scoConnection = BtmScoFindScoConnectionByScoHandle(param->connectionHandle, SCO_CONNECTION_STATUS_CONNECTED);
1003     }
1004 
1005     if (scoConnection != NULL) {
1006         if (param->status == HCI_SUCCESS) {
1007             ListRemoveNode(g_scoList, scoConnection);
1008         }
1009     }
1010     MutexUnlock(g_scoListLock);
1011 
1012     BtmScoDisconnectionCompleteParam callbackParam = {
1013         .status = param->status,
1014         .connectionHandle = param->connectionHandle,
1015         .reason = param->reason,
1016     };
1017 
1018     BtmScoCallbacksBlock *block = NULL;
1019     FOREACH_CALLBACKS_START(block);
1020     block->callbacks->scoDisconnectionComplete(&callbackParam, block->context);
1021     FOREACH_CALLBACKS_END;
1022 }
1023 
1024 static HciEventCallbacks g_hciEventCallbacks = {
1025     .connectionComplete = BtmScoOnConnectionComplete,
1026     .synchronousConnectionComplete = BtmScoOnSynchronousConnectionComplete,
1027     .synchronousConnectionChanged = BtmScoOnSynchronousConnectionChanged,
1028 
1029     .connectionRequest = BtmScoOnConnectionRequest,
1030     .disconnectComplete = BtmScoOnDisconnectComplete,
1031 
1032     .writeVoiceSettingComplete = BtmScoOnWriteVoiceSettingComplete,
1033 };
1034