• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }