1 /*
2 * Copyright (c) 2021-2023 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 "audio_bluetooth_manager.h"
17 #include "bluetooth_def.h"
18 #include "audio_errors.h"
19 #include "audio_log.h"
20 #include "bluetooth_device_manager.h"
21 #include "bluetooth_device_utils.h"
22
23 namespace OHOS {
24 namespace Bluetooth {
25 using namespace AudioStandard;
26
27 A2dpSource *AudioA2dpManager::a2dpInstance_ = nullptr;
28 std::shared_ptr<AudioA2dpListener> AudioA2dpManager::a2dpListener_ = std::make_shared<AudioA2dpListener>();
29 int AudioA2dpManager::connectionState_ = static_cast<int>(BTConnectState::DISCONNECTED);
30 BluetoothRemoteDevice AudioA2dpManager::activeA2dpDevice_;
31 std::mutex g_a2dpInstanceLock;
32 HandsFreeAudioGateway *AudioHfpManager::hfpInstance_ = nullptr;
33 std::shared_ptr<AudioHfpListener> AudioHfpManager::hfpListener_ = std::make_shared<AudioHfpListener>();
34 AudioScene AudioHfpManager::scene_ = AUDIO_SCENE_DEFAULT;
35 BluetoothRemoteDevice AudioHfpManager::activeHfpDevice_;
36 std::mutex g_activehfpDeviceLock;
37 std::mutex g_audioSceneLock;
38 std::mutex g_hfpInstanceLock;
39
GetAudioStreamInfo(A2dpCodecInfo codecInfo,AudioStreamInfo & audioStreamInfo)40 static bool GetAudioStreamInfo(A2dpCodecInfo codecInfo, AudioStreamInfo &audioStreamInfo)
41 {
42 switch (codecInfo.sampleRate) {
43 case A2DP_SBC_SAMPLE_RATE_48000_USER:
44 audioStreamInfo.samplingRate = SAMPLE_RATE_48000;
45 break;
46 case A2DP_SBC_SAMPLE_RATE_44100_USER:
47 audioStreamInfo.samplingRate = SAMPLE_RATE_44100;
48 break;
49 case A2DP_SBC_SAMPLE_RATE_32000_USER:
50 audioStreamInfo.samplingRate = SAMPLE_RATE_32000;
51 break;
52 case A2DP_SBC_SAMPLE_RATE_16000_USER:
53 audioStreamInfo.samplingRate = SAMPLE_RATE_16000;
54 break;
55 case A2DP_L2HCV2_SAMPLE_RATE_96000_USER:
56 audioStreamInfo.samplingRate = SAMPLE_RATE_96000;
57 break;
58 default:
59 return false;
60 }
61 switch (codecInfo.bitsPerSample) {
62 case A2DP_SAMPLE_BITS_16_USER:
63 audioStreamInfo.format = SAMPLE_S16LE;
64 break;
65 case A2DP_SAMPLE_BITS_24_USER:
66 audioStreamInfo.format = SAMPLE_S24LE;
67 break;
68 case A2DP_SAMPLE_BITS_32_USER:
69 audioStreamInfo.format = SAMPLE_S32LE;
70 break;
71 default:
72 return false;
73 }
74 switch (codecInfo.channelMode) {
75 case A2DP_SBC_CHANNEL_MODE_STEREO_USER:
76 audioStreamInfo.channels = STEREO;
77 break;
78 case A2DP_SBC_CHANNEL_MODE_MONO_USER:
79 audioStreamInfo.channels = MONO;
80 break;
81 default:
82 return false;
83 }
84 audioStreamInfo.encoding = ENCODING_PCM;
85 return true;
86 }
87
RegisterBluetoothA2dpListener()88 void AudioA2dpManager::RegisterBluetoothA2dpListener()
89 {
90 AUDIO_INFO_LOG("AudioA2dpManager::RegisterBluetoothA2dpListener");
91 std::lock_guard<std::mutex> a2dpLock(g_a2dpInstanceLock);
92 a2dpInstance_ = A2dpSource::GetProfile();
93 CHECK_AND_RETURN_LOG(a2dpInstance_ != nullptr, "Failed to obtain A2DP profile instance");
94 a2dpInstance_->RegisterObserver(a2dpListener_);
95 }
96
UnregisterBluetoothA2dpListener()97 void AudioA2dpManager::UnregisterBluetoothA2dpListener()
98 {
99 AUDIO_INFO_LOG("AudioA2dpManager::UnregisterBluetoothA2dpListener");
100 std::lock_guard<std::mutex> a2dpLock(g_a2dpInstanceLock);
101 CHECK_AND_RETURN_LOG(a2dpInstance_ != nullptr, "A2DP profile instance unavailable");
102 a2dpInstance_->DeregisterObserver(a2dpListener_);
103 a2dpInstance_ = nullptr;
104 }
105
DisconnectBluetoothA2dpSink()106 void AudioA2dpManager::DisconnectBluetoothA2dpSink()
107 {
108 int connectionState = static_cast<int>(BTConnectState::DISCONNECTED);
109 a2dpListener_->OnConnectionStateChanged(activeA2dpDevice_, connectionState);
110 MediaBluetoothDeviceManager::ClearAllA2dpBluetoothDevice();
111 }
112
SetActiveA2dpDevice(const std::string & macAddress)113 int32_t AudioA2dpManager::SetActiveA2dpDevice(const std::string& macAddress)
114 {
115 std::lock_guard<std::mutex> a2dpLock(g_a2dpInstanceLock);
116 a2dpInstance_ = A2dpSource::GetProfile();
117 CHECK_AND_RETURN_RET_LOG(a2dpInstance_ != nullptr, ERROR, "Failed to obtain A2DP profile instance");
118 BluetoothRemoteDevice device;
119 if (macAddress != "") {
120 int32_t tmp = MediaBluetoothDeviceManager::GetConnectedA2dpBluetoothDevice(macAddress, device);
121 CHECK_AND_RETURN_RET_LOG(tmp == SUCCESS, ERROR, "the configuring A2DP device doesn't exist.");
122 } else {
123 AUDIO_INFO_LOG("Deactive A2DP device");
124 }
125 int32_t ret = a2dpInstance_->SetActiveSinkDevice(device);
126 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "SetActiveA2dpDevice failed. result: %{public}d", ret);
127 activeA2dpDevice_ = device;
128 return SUCCESS;
129 }
130
GetActiveA2dpDevice()131 std::string AudioA2dpManager::GetActiveA2dpDevice()
132 {
133 std::lock_guard<std::mutex> a2dpLock(g_a2dpInstanceLock);
134 a2dpInstance_ = A2dpSource::GetProfile();
135 CHECK_AND_RETURN_RET_LOG(a2dpInstance_ != nullptr, "", "Failed to obtain A2DP profile instance");
136 BluetoothRemoteDevice device = a2dpInstance_->GetActiveSinkDevice();
137 return device.GetDeviceAddr();
138 }
139
SetDeviceAbsVolume(const std::string & macAddress,int32_t volume)140 int32_t AudioA2dpManager::SetDeviceAbsVolume(const std::string& macAddress, int32_t volume)
141 {
142 BluetoothRemoteDevice device;
143 int32_t ret = MediaBluetoothDeviceManager::GetConnectedA2dpBluetoothDevice(macAddress, device);
144 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR, "SetDeviceAbsVolume: the configuring A2DP device doesn't exist.");
145 return AvrcpTarget::GetProfile()->SetDeviceAbsoluteVolume(device, volume);
146 }
147
GetA2dpDeviceStreamInfo(const std::string & macAddress,AudioStreamInfo & streamInfo)148 int32_t AudioA2dpManager::GetA2dpDeviceStreamInfo(const std::string& macAddress,
149 AudioStreamInfo &streamInfo)
150 {
151 std::lock_guard<std::mutex> a2dpLock(g_a2dpInstanceLock);
152 a2dpInstance_ = A2dpSource::GetProfile();
153 CHECK_AND_RETURN_RET_LOG(a2dpInstance_ != nullptr, ERROR, "Failed to obtain A2DP profile instance");
154 BluetoothRemoteDevice device;
155 int32_t ret = MediaBluetoothDeviceManager::GetConnectedA2dpBluetoothDevice(macAddress, device);
156 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERROR,
157 "GetA2dpDeviceStreamInfo: the configuring A2DP device doesn't exist.");
158 A2dpCodecStatus codecStatus = a2dpInstance_->GetCodecStatus(device);
159 bool result = GetAudioStreamInfo(codecStatus.codecInfo, streamInfo);
160 CHECK_AND_RETURN_RET_LOG(result, ERROR, "GetA2dpDeviceStreamInfo: Unsupported a2dp codec info");
161 return SUCCESS;
162 }
163
HasA2dpDeviceConnected()164 bool AudioA2dpManager::HasA2dpDeviceConnected()
165 {
166 a2dpInstance_ = A2dpSource::GetProfile();
167 CHECK_AND_RETURN_RET(a2dpInstance_, false);
168 std::vector<int32_t> states {static_cast<int32_t>(BTConnectState::CONNECTED)};
169 std::vector<BluetoothRemoteDevice> devices;
170 a2dpInstance_->GetDevicesByStates(states, devices);
171
172 return !devices.empty();
173 }
174
A2dpOffloadSessionRequest(const std::vector<A2dpStreamInfo> & info)175 int32_t AudioA2dpManager::A2dpOffloadSessionRequest(const std::vector<A2dpStreamInfo> &info)
176 {
177 CHECK_AND_RETURN_RET_LOG(activeA2dpDevice_.GetDeviceAddr() != "00:00:00:00:00:00", A2DP_NOT_OFFLOAD,
178 "Invalid mac address, not request, return A2DP_NOT_OFFLOAD.");
179 int32_t ret = a2dpInstance_->A2dpOffloadSessionRequest(activeA2dpDevice_, info);
180 AUDIO_DEBUG_LOG("Request %{public}zu stream and return a2dp offload state %{public}d", info.size(), ret);
181 return ret;
182 }
183
OffloadStartPlaying(const std::vector<int32_t> & sessionsID)184 int32_t AudioA2dpManager::OffloadStartPlaying(const std::vector<int32_t> &sessionsID)
185 {
186 CHECK_AND_RETURN_RET_LOG(activeA2dpDevice_.GetDeviceAddr() != "00:00:00:00:00:00", ERROR,
187 "Invalid mac address, not start, return error.");
188 AUDIO_DEBUG_LOG("Start playing %{public}zu stream", sessionsID.size());
189 return a2dpInstance_->OffloadStartPlaying(activeA2dpDevice_, sessionsID);
190 }
191
OffloadStopPlaying(const std::vector<int32_t> & sessionsID)192 int32_t AudioA2dpManager::OffloadStopPlaying(const std::vector<int32_t> &sessionsID)
193 {
194 if (activeA2dpDevice_.GetDeviceAddr() == "00:00:00:00:00:00") {
195 AUDIO_DEBUG_LOG("Invalid mac address, not stop, return error.");
196 return ERROR;
197 }
198 AUDIO_DEBUG_LOG("Stop playing %{public}zu stream", sessionsID.size());
199 return a2dpInstance_->OffloadStopPlaying(activeA2dpDevice_, sessionsID);
200 }
201
OnConnectionStateChanged(const BluetoothRemoteDevice & device,int state)202 void AudioA2dpListener::OnConnectionStateChanged(const BluetoothRemoteDevice &device, int state)
203 {
204 AUDIO_INFO_LOG("AudioA2dpListener OnConnectionStateChanged: state: %{public}d", state);
205 // Record connection state and device for hdi start time to check
206 AudioA2dpManager::SetConnectionState(state);
207 if (state == static_cast<int>(BTConnectState::CONNECTED)) {
208 MediaBluetoothDeviceManager::SetMediaStack(device, BluetoothDeviceAction::CONNECT_ACTION);
209 }
210 if (state == static_cast<int>(BTConnectState::DISCONNECTED)) {
211 MediaBluetoothDeviceManager::SetMediaStack(device, BluetoothDeviceAction::DISCONNECT_ACTION);
212 }
213 }
214
OnConfigurationChanged(const BluetoothRemoteDevice & device,const A2dpCodecInfo & codecInfo,int error)215 void AudioA2dpListener::OnConfigurationChanged(const BluetoothRemoteDevice &device, const A2dpCodecInfo &codecInfo,
216 int error)
217 {
218 AUDIO_INFO_LOG("OnConfigurationChanged: sampleRate: %{public}d, channels: %{public}d, format: %{public}d",
219 codecInfo.sampleRate, codecInfo.channelMode, codecInfo.bitsPerSample);
220 AudioStreamInfo streamInfo = {};
221 bool result = GetAudioStreamInfo(codecInfo, streamInfo);
222 CHECK_AND_RETURN_LOG(result, "OnConfigurationChanged: Unsupported a2dp codec info");
223 MediaBluetoothDeviceManager::UpdateA2dpDeviceConfiguration(device, streamInfo);
224 }
225
OnPlayingStatusChanged(const BluetoothRemoteDevice & device,int playingState,int error)226 void AudioA2dpListener::OnPlayingStatusChanged(const BluetoothRemoteDevice &device, int playingState, int error)
227 {
228 AUDIO_INFO_LOG("OnPlayingStatusChanged, state: %{public}d, error: %{public}d", playingState, error);
229 }
230
OnMediaStackChanged(const BluetoothRemoteDevice & device,int action)231 void AudioA2dpListener::OnMediaStackChanged(const BluetoothRemoteDevice &device, int action)
232 {
233 AUDIO_INFO_LOG("OnMediaStackChanged, action: %{public}d", action);
234 MediaBluetoothDeviceManager::SetMediaStack(device, action);
235 }
236
RegisterBluetoothScoListener()237 void AudioHfpManager::RegisterBluetoothScoListener()
238 {
239 AUDIO_INFO_LOG("AudioHfpManager::RegisterBluetoothScoListener");
240 std::lock_guard<std::mutex> hfpLock(g_hfpInstanceLock);
241 hfpInstance_ = HandsFreeAudioGateway::GetProfile();
242 CHECK_AND_RETURN_LOG(hfpInstance_ != nullptr, "Failed to obtain HFP AG profile instance");
243
244 hfpInstance_->RegisterObserver(hfpListener_);
245 }
246
UnregisterBluetoothScoListener()247 void AudioHfpManager::UnregisterBluetoothScoListener()
248 {
249 AUDIO_INFO_LOG("AudioHfpManager::UnregisterBluetoothScoListene");
250 std::lock_guard<std::mutex> hfpLock(g_hfpInstanceLock);
251 CHECK_AND_RETURN_LOG(hfpInstance_ != nullptr, "HFP AG profile instance unavailable");
252
253 hfpInstance_->DeregisterObserver(hfpListener_);
254 hfpInstance_ = nullptr;
255 }
256
SetActiveHfpDevice(const std::string & macAddress)257 int32_t AudioHfpManager::SetActiveHfpDevice(const std::string &macAddress)
258 {
259 AUDIO_INFO_LOG("AudioHfpManager::SetActiveHfpDevice");
260 BluetoothRemoteDevice device;
261 if (HfpBluetoothDeviceManager::GetConnectedHfpBluetoothDevice(macAddress, device) != SUCCESS) {
262 AUDIO_ERR_LOG("SetActiveHfpDevice failed for the HFP device does not exist.");
263 return ERROR;
264 }
265 std::lock_guard<std::mutex> hfpDeviceLock(g_activehfpDeviceLock);
266 if (macAddress != activeHfpDevice_.GetDeviceAddr()) {
267 AUDIO_INFO_LOG("Active hfp device is changed, need to DisconnectSco for current activeHfpDevice.");
268 int32_t ret = DisconnectSco();
269 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "DisconnectSco failed, result: %{public}d", ret);
270 }
271 std::lock_guard<std::mutex> hfpLock(g_hfpInstanceLock);
272 CHECK_AND_RETURN_RET_LOG(hfpInstance_ != nullptr, ERROR, "HFP AG profile instance unavailable");
273 bool res = hfpInstance_->SetActiveDevice(device);
274 CHECK_AND_RETURN_RET_LOG(res == true, ERROR, "SetActiveHfpDevice failed, result: %{public}d", res);
275 activeHfpDevice_ = device;
276 return SUCCESS;
277 }
278
GetActiveHfpDevice()279 std::string AudioHfpManager::GetActiveHfpDevice()
280 {
281 std::lock_guard<std::mutex> hfpLock(g_hfpInstanceLock);
282 CHECK_AND_RETURN_RET_LOG(hfpInstance_ != nullptr, "", "HFP AG profile instance unavailable");
283 BluetoothRemoteDevice device = hfpInstance_->GetActiveDevice();
284 return device.GetDeviceAddr();
285 }
286
ConnectScoWithAudioScene(AudioScene scene)287 int32_t AudioHfpManager::ConnectScoWithAudioScene(AudioScene scene)
288 {
289 AUDIO_INFO_LOG("new audioScene is %{public}d, last audioScene is %{public}d", scene, scene_);
290 std::lock_guard<std::mutex> sceneLock(g_audioSceneLock);
291 int8_t lastScoCategory = GetScoCategoryFromScene(scene_);
292 int8_t newScoCategory = GetScoCategoryFromScene(scene);
293 if (lastScoCategory == newScoCategory) {
294 AUDIO_DEBUG_LOG("AudioScene category is not changed, ignore ConnectScoWithAudioScene operation.");
295 return SUCCESS;
296 }
297 std::lock_guard<std::mutex> hfpLock(g_hfpInstanceLock);
298 CHECK_AND_RETURN_RET_LOG(hfpInstance_ != nullptr, ERROR, "HFP AG profile instance unavailable");
299 bool isInbardingEnabled = false;
300 hfpInstance_->IsInbandRingingEnabled(isInbardingEnabled);
301 if (scene == AUDIO_SCENE_RINGING && !isInbardingEnabled) {
302 AUDIO_INFO_LOG("The inbarding switch is off, ignore the ring scene.");
303 return SUCCESS;
304 }
305 int32_t ret;
306 if (lastScoCategory != ScoCategory::SCO_DEFAULT) {
307 AUDIO_INFO_LOG("Entered to disConnectSco for last audioScene category.");
308 ret = hfpInstance_->DisconnectSco(static_cast<uint8_t>(lastScoCategory));
309 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR,
310 "ConnectScoWithAudioScene failed as the last SCO failed to be disconnected, result: %{public}d", ret);
311 }
312 if (newScoCategory != ScoCategory::SCO_DEFAULT) {
313 AUDIO_INFO_LOG("Entered to connectSco for new audioScene category.");
314 ret = hfpInstance_->ConnectSco(static_cast<uint8_t>(newScoCategory));
315 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "ConnectScoWithAudioScene failed, result: %{public}d", ret);
316 }
317 scene_ = scene;
318 return SUCCESS;
319 }
320
DisconnectSco()321 int32_t AudioHfpManager::DisconnectSco()
322 {
323 AUDIO_INFO_LOG("AudioHfpManager::DisconnectSco");
324 std::lock_guard<std::mutex> sceneLock(g_audioSceneLock);
325 int8_t currentScoCategory = GetScoCategoryFromScene(scene_);
326 if (currentScoCategory == ScoCategory::SCO_DEFAULT) {
327 AUDIO_INFO_LOG("Current audioScene is not need to disconnect sco.");
328 return SUCCESS;
329 }
330 std::lock_guard<std::mutex> hfpLock(g_hfpInstanceLock);
331 CHECK_AND_RETURN_RET_LOG(hfpInstance_ != nullptr, ERROR, "HFP AG profile instance unavailable");
332 int32_t ret = hfpInstance_->DisconnectSco(static_cast<uint8_t>(currentScoCategory));
333 CHECK_AND_RETURN_RET_LOG(ret == 0, ERROR, "DisconnectSco failed, result: %{public}d", ret);
334 scene_ = AUDIO_SCENE_DEFAULT;
335 return SUCCESS;
336 }
337
GetScoCategoryFromScene(AudioScene scene)338 int8_t AudioHfpManager::GetScoCategoryFromScene(AudioScene scene)
339 {
340 switch (scene) {
341 case AUDIO_SCENE_RINGING:
342 case AUDIO_SCENE_PHONE_CALL:
343 return ScoCategory::SCO_CALLULAR;
344 case AUDIO_SCENE_PHONE_CHAT:
345 return ScoCategory::SCO_VIRTUAL;
346 default:
347 return ScoCategory::SCO_DEFAULT;
348 }
349 }
350
DisconnectBluetoothHfpSink()351 void AudioHfpManager::DisconnectBluetoothHfpSink()
352 {
353 int connectionState = static_cast<int>(BTConnectState::DISCONNECTED);
354 hfpListener_->OnConnectionStateChanged(activeHfpDevice_, connectionState);
355 HfpBluetoothDeviceManager::ClearAllHfpBluetoothDevice();
356 }
357
UpdateCurrentActiveHfpDevice(const BluetoothRemoteDevice & device)358 void AudioHfpManager::UpdateCurrentActiveHfpDevice(const BluetoothRemoteDevice &device)
359 {
360 std::lock_guard<std::mutex> hfpDeviceLock(g_activehfpDeviceLock);
361 activeHfpDevice_ = device;
362 }
363
GetCurrentActiveHfpDevice()364 std::string AudioHfpManager::GetCurrentActiveHfpDevice()
365 {
366 std::lock_guard<std::mutex> hfpDeviceLock(g_activehfpDeviceLock);
367 return activeHfpDevice_.GetDeviceAddr();
368 }
369
UpdateAudioScene(AudioScene scene)370 void AudioHfpManager::UpdateAudioScene(AudioScene scene)
371 {
372 std::lock_guard<std::mutex> sceneLock(g_audioSceneLock);
373 scene_ = scene;
374 }
375
OnScoStateChanged(const BluetoothRemoteDevice & device,int state)376 void AudioHfpListener::OnScoStateChanged(const BluetoothRemoteDevice &device, int state)
377 {
378 AUDIO_INFO_LOG("AudioHfpListener::OnScoStateChanged: state: [%{public}d]", state);
379 HfpScoConnectState scoState = static_cast<HfpScoConnectState>(state);
380 if (scoState == HfpScoConnectState::SCO_CONNECTED || scoState == HfpScoConnectState::SCO_DISCONNECTED) {
381 if (device.GetDeviceAddr() == AudioHfpManager::GetCurrentActiveHfpDevice() &&
382 scoState == HfpScoConnectState::SCO_DISCONNECTED) {
383 AUDIO_INFO_LOG("Sco disconnect, need set audio scene as default.");
384 AudioHfpManager::UpdateAudioScene(AUDIO_SCENE_DEFAULT);
385 }
386 bool isConnected = (scoState == HfpScoConnectState::SCO_CONNECTED) ? true : false;
387 HfpBluetoothDeviceManager::OnScoStateChanged(device, isConnected);
388 }
389 }
390
OnConnectionStateChanged(const BluetoothRemoteDevice & device,int state)391 void AudioHfpListener::OnConnectionStateChanged(const BluetoothRemoteDevice &device, int state)
392 {
393 AUDIO_INFO_LOG("AudioHfpListener::OnConnectionStateChanged: state: %{public}d", state);
394 if (state == static_cast<int>(BTConnectState::CONNECTED)) {
395 HfpBluetoothDeviceManager::SetHfpStack(device, BluetoothDeviceAction::CONNECT_ACTION);
396 }
397 if (state == static_cast<int>(BTConnectState::DISCONNECTED)) {
398 if (device.GetDeviceAddr() == AudioHfpManager::GetCurrentActiveHfpDevice()) {
399 BluetoothRemoteDevice defaultDevice;
400 AudioHfpManager::UpdateCurrentActiveHfpDevice(defaultDevice);
401 AUDIO_INFO_LOG("Current active hfp device diconnect, need set audio scene as default.");
402 AudioHfpManager::UpdateAudioScene(AUDIO_SCENE_DEFAULT);
403 }
404 HfpBluetoothDeviceManager::SetHfpStack(device, BluetoothDeviceAction::DISCONNECT_ACTION);
405 }
406 }
407
OnHfpStackChanged(const BluetoothRemoteDevice & device,int action)408 void AudioHfpListener::OnHfpStackChanged(const BluetoothRemoteDevice &device, int action)
409 {
410 AUDIO_INFO_LOG("OnHfpStackChanged, action: %{public}d", action);
411 HfpBluetoothDeviceManager::SetHfpStack(device, action);
412 }
413 } // namespace Bluetooth
414 } // namespace OHOS
415