1 /*
2 * Copyright (c) 2023-2025 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 #ifndef LOG_TAG
16 #define LOG_TAG "BluetoothScoManager"
17 #endif
18
19 #include "bluetooth_sco_manager.h"
20 #include "audio_errors.h"
21 #include "audio_common_log.h"
22 #include "audio_utils.h"
23 #include "bluetooth_device_utils.h"
24
25 namespace OHOS {
26 namespace Bluetooth {
27 using namespace AudioStandard;
28
29 AudioScoState BluetoothScoManager::currentScoState_ = AudioScoState::DISCONNECTED;
30 AudioScoMode BluetoothScoManager::currentScoMode_ = AudioScoMode::DEFAULT_MODE;
31 AudioScoMode BluetoothScoManager::lastScoMode_ = AudioScoMode::DEFAULT_MODE;
32 HandsFreeAudioGateway *BluetoothScoManager::hfpInstance_ = HandsFreeAudioGateway::GetProfile();
33 std::mutex g_scoStateLock;
34
UpdateScoState(HfpScoConnectState scoState,const BluetoothRemoteDevice * device)35 void BluetoothScoManager::UpdateScoState(HfpScoConnectState scoState, const BluetoothRemoteDevice *device)
36 {
37 std::unique_lock<std::mutex> stateLock(g_scoStateLock);
38 AudioScoState lastScoState = currentScoState_;
39 AudioScoMode tmpMode = currentScoMode_;
40 AUDIO_INFO_LOG("Before UpdateScoState, lastScoState: %{public}d", lastScoState);
41 if (scoState == HfpScoConnectState::SCO_CONNECTED) {
42 currentScoState_ = AudioScoState::CONNECTED;
43 stateLock.unlock();
44 if (lastScoState == AudioScoState::DISCONNECT_AFTER_CONNECTED) {
45 BluetoothScoManager::HandleScoDisconnect(GetScoCategeryFromMode(currentScoMode_), device);
46 } else if (lastScoState == AudioScoState::CONNECT_AFTER_DISCONNECTED) {
47 BluetoothScoManager::HandleScoDisconnect(GetScoCategeryFromMode(lastScoMode_), device);
48 BluetoothScoManager::HandleScoConnect(GetScoCategeryFromMode(tmpMode), device);
49 }
50 } else if (scoState == HfpScoConnectState::SCO_DISCONNECTED) {
51 currentScoState_ = AudioScoState::DISCONNECTED;
52 stateLock.unlock();
53 if (lastScoState == AudioScoState::CONNECT_AFTER_DISCONNECTED) {
54 BluetoothScoManager::HandleScoConnect(GetScoCategeryFromMode(currentScoMode_), device);
55 } else if (lastScoState == AudioScoState::DISCONNECT_AFTER_CONNECTED) {
56 BluetoothScoManager::HandleScoConnect(GetScoCategeryFromMode(lastScoMode_), device);
57 BluetoothScoManager::HandleScoDisconnect(GetScoCategeryFromMode(tmpMode), device);
58 }
59 }
60 }
61
HandleScoConnect(ScoCategory scoCategory,const BluetoothRemoteDevice * device)62 int32_t BluetoothScoManager::HandleScoConnect(ScoCategory scoCategory, const BluetoothRemoteDevice *device)
63 {
64 CHECK_AND_RETURN_RET_LOG(hfpInstance_ != nullptr, ERROR, "HFP AG profile instance unavailable");
65 std::lock_guard<std::mutex> stateLock(g_scoStateLock);
66 AudioScoState lastScoState = currentScoState_;
67 lastScoMode_ = currentScoMode_;
68 currentScoMode_ = BluetoothScoManager::GetScoModeFromCategery(scoCategory);
69 AUDIO_INFO_LOG("HandleScoConnect, lastScoState: %{public}d, lastScoMode: %{public}d, currentScoMode: %{public}d",
70 lastScoState, lastScoMode_, currentScoMode_);
71 int32_t ret = ERROR;
72 if (lastScoState == AudioScoState::DISCONNECTED) {
73 if (currentScoMode_ == AudioScoMode::REC_MODE) {
74 CHECK_AND_RETURN_RET_LOG(device != nullptr, ERROR, "HandleScoConnect failed, device is nullptr");
75 ret = ((hfpInstance_->OpenVoiceRecognition(*device) == true) ? SUCCESS : ERROR);
76 } else {
77 ret = hfpInstance_->ConnectSco(static_cast<uint8_t> (scoCategory));
78 }
79 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "HandleScoConnect failed, result: %{public}d", ret);
80 currentScoState_ = AudioScoState::CONNECTING;
81 } else if (lastScoState == AudioScoState::DISCONNECT_AFTER_CONNECTED && lastScoMode_ == currentScoMode_) {
82 currentScoState_ = AudioScoState::CONNECTING;
83 } else if (lastScoState == AudioScoState::DISCONNECT_AFTER_CONNECTED && lastScoMode_ != currentScoMode_) {
84 currentScoState_ = AudioScoState::CONNECT_AFTER_DISCONNECTED;
85 } else if (lastScoState == AudioScoState::DISCONNECTING) {
86 currentScoState_ = AudioScoState::CONNECT_AFTER_DISCONNECTED;
87 }
88 return SUCCESS;
89 }
90
HandleScoDisconnect(ScoCategory scoCategory,const BluetoothRemoteDevice * device)91 int32_t BluetoothScoManager::HandleScoDisconnect(ScoCategory scoCategory, const BluetoothRemoteDevice *device)
92 {
93 CHECK_AND_RETURN_RET_LOG(hfpInstance_ != nullptr, ERROR, "HFP AG profile instance unavailable");
94 std::lock_guard<std::mutex> stateLock(g_scoStateLock);
95 AudioScoState lastScoState = currentScoState_;
96 lastScoMode_ = currentScoMode_;
97 currentScoMode_ = BluetoothScoManager::GetScoModeFromCategery(scoCategory);
98 AUDIO_INFO_LOG("HandleScoDisconnect, lastScoState: %{public}d, lastScoMode: %{public}d, currentScoMode: %{public}d",
99 lastScoState, lastScoMode_, currentScoMode_);
100 int32_t ret = ERROR;
101 if (lastScoState == AudioScoState::CONNECTED) {
102 if (currentScoMode_ == AudioScoMode::REC_MODE) {
103 CHECK_AND_RETURN_RET_LOG(device != nullptr, ERROR, "HandleScoDisconnect failed, device is nullptr");
104 ret = ((hfpInstance_->CloseVoiceRecognition(*device) == true) ? SUCCESS : ERROR);
105 } else {
106 ret = hfpInstance_->DisconnectSco(static_cast<uint8_t> (scoCategory));
107 }
108 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "HandleScoDisconnect failed, result: %{public}d", ret);
109 currentScoState_ = AudioScoState::DISCONNECTING;
110 } else if (lastScoState == AudioScoState::CONNECT_AFTER_DISCONNECTED) {
111 currentScoState_ = AudioScoState::DISCONNECTING;
112 } else if (lastScoState == AudioScoState::CONNECTING) {
113 currentScoState_ = AudioScoState::DISCONNECT_AFTER_CONNECTED;
114 }
115 return SUCCESS;
116 }
117
GetAudioScoState()118 AudioScoState BluetoothScoManager::GetAudioScoState()
119 {
120 return currentScoState_;
121 }
122
GetScoModeFromCategery(ScoCategory scoCategory)123 AudioScoMode BluetoothScoManager::GetScoModeFromCategery(ScoCategory scoCategory)
124 {
125 switch (scoCategory) {
126 case ScoCategory::SCO_CALLULAR:
127 return AudioScoMode::CALL_MODE;
128 case ScoCategory::SCO_VIRTUAL:
129 return AudioScoMode::VOIP_MODE;
130 case ScoCategory::SCO_RECOGNITION:
131 return AudioScoMode::REC_MODE;
132 default:
133 return AudioScoMode::DEFAULT_MODE;
134 }
135 }
136
GetScoCategeryFromMode(AudioScoMode scoMode)137 ScoCategory BluetoothScoManager::GetScoCategeryFromMode(AudioScoMode scoMode)
138 {
139 switch (scoMode) {
140 case AudioScoMode::CALL_MODE:
141 return ScoCategory::SCO_CALLULAR;
142 case AudioScoMode::VOIP_MODE:
143 return ScoCategory::SCO_VIRTUAL;
144 case AudioScoMode::REC_MODE:
145 return ScoCategory::SCO_RECOGNITION;
146 default:
147 return ScoCategory::SCO_DEFAULT;
148 }
149 }
150
151 }
152 }