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(¶m);
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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m, 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(¶m, 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(¶m);
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(¶m, 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(¶m, 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