1 /*
2 * Copyright (C) 2024-2024 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 "distributed_sink_switch_controller.h"
17
18 #include <chrono>
19 #include "distributed_communication_manager.h"
20 #include "audio_device_manager.h"
21 #include "audio_control_manager.h"
22 #include "bluetooth_connection.h"
23 #ifdef ABILITY_BLUETOOTH_SUPPORT
24 #include "bluetooth_device.h"
25 #endif
26
27 namespace OHOS {
28 namespace Telephony {
29 using namespace std::chrono;
OnDeviceOnline(const std::string & devId,const std::string & devName,AudioDeviceType devType)30 void DistributedSinkSwitchController::OnDeviceOnline(const std::string &devId, const std::string &devName,
31 AudioDeviceType devType)
32 {
33 #ifdef ABILITY_BLUETOOTH_SUPPORT
34 std::lock_guard<ffrt::mutex> lock(mutex_);
35 if (hfpListener_ == nullptr) {
36 hfpListener_ = std::make_shared<DcCallHfpListener>();
37 Bluetooth::HandsFreeAudioGateway::GetProfile()->RegisterObserver(hfpListener_);
38 }
39 #endif
40 }
41
OnDeviceOffline(const std::string & devId,const std::string & devName,AudioDeviceType devType)42 void DistributedSinkSwitchController::OnDeviceOffline(const std::string &devId, const std::string &devName,
43 AudioDeviceType devType)
44 {
45 #ifdef ABILITY_BLUETOOTH_SUPPORT
46 std::lock_guard<ffrt::mutex> lock(mutex_);
47 if (hfpListener_ != nullptr) {
48 Bluetooth::HandsFreeAudioGateway::GetProfile()->DeregisterObserver(hfpListener_);
49 hfpListener_ = nullptr;
50 }
51 #endif
52 }
53
OnDistributedAudioDeviceChange(const std::string & devId,const std::string & devName,AudioDeviceType devType,int32_t devRole)54 void DistributedSinkSwitchController::OnDistributedAudioDeviceChange(const std::string &devId,
55 const std::string &devName, AudioDeviceType devType, int32_t devRole)
56 {
57 {
58 std::lock_guard<ffrt::mutex> lock(mutex_);
59 isAudioOnSink_ = (devRole == static_cast<int32_t>(DistributedRole::SINK));
60 TELEPHONY_LOGI("OnDistributedAudioDeviceChange isAudioOnSink[%{public}d]", isAudioOnSink_);
61 }
62 if (devRole == static_cast<int32_t>(DistributedRole::SINK)) {
63 TrySwitchToBtHeadset();
64 #ifdef ABILITY_BLUETOOTH_SUPPORT
65 if (hfpListener_ != nullptr &&
66 !DelayedSingleton<BluetoothConnection>::GetInstance()->GetWearBtHeadsetAddress().empty()) {
67 hfpListener_->SetPreAction(WEAR_ACTION);
68 }
69 #endif
70 }
71 }
72
OnRemoveSystemAbility()73 void DistributedSinkSwitchController::OnRemoveSystemAbility()
74 {
75 std::lock_guard<ffrt::mutex> lock(mutex_);
76 isAudioOnSink_ = false;
77 #ifdef ABILITY_BLUETOOTH_SUPPORT
78 if (hfpListener_ != nullptr) {
79 Bluetooth::HandsFreeAudioGateway::GetProfile()->DeregisterObserver(hfpListener_);
80 hfpListener_ = nullptr;
81 }
82 #endif
83 }
84
TrySwitchToBtHeadset()85 void DistributedSinkSwitchController::TrySwitchToBtHeadset()
86 {
87 #ifdef ABILITY_BLUETOOTH_SUPPORT
88 auto address = DelayedSingleton<BluetoothConnection>::GetInstance()->GetWearBtHeadsetAddress();
89 if (address.empty()) {
90 return;
91 }
92
93 AudioDevice audioDevice;
94 audioDevice.deviceType = AudioDeviceType::DEVICE_BLUETOOTH_SCO;
95 if (memcpy_s(audioDevice.address, kMaxAddressLen, address.c_str(), address.length()) != EOK) {
96 TELEPHONY_LOGE("memcpy_s fail");
97 return;
98 }
99 auto ret = DelayedSingleton<AudioControlManager>::GetInstance()->SetAudioDevice(audioDevice);
100 TELEPHONY_LOGI("set bt headset ret[%{public}d]", ret);
101 #endif
102 }
103
104 #ifdef ABILITY_BLUETOOTH_SUPPORT
OnHfpStackChanged(const Bluetooth::BluetoothRemoteDevice & device,int32_t action)105 void DcCallHfpListener::OnHfpStackChanged(const Bluetooth::BluetoothRemoteDevice &device, int32_t action)
106 {
107 TELEPHONY_LOGI("dc call hfp stack changed, action[%{public}d], preAction_[%{public}d]", action, preAction_);
108 int32_t cod = DEFAULT_HFP_FLAG_VALUE;
109 int32_t majorClass = DEFAULT_HFP_FLAG_VALUE;
110 int32_t majorMinorClass = DEFAULT_HFP_FLAG_VALUE;
111 device.GetDeviceProductType(cod, majorClass, majorMinorClass);
112 bool isBtHeadset = (majorClass == Bluetooth::BluetoothDevice::MAJOR_AUDIO_VIDEO &&
113 (majorMinorClass == Bluetooth::BluetoothDevice::AUDIO_VIDEO_HEADPHONES ||
114 majorMinorClass == Bluetooth::BluetoothDevice::AUDIO_VIDEO_WEARABLE_HEADSET));
115 if (!isBtHeadset) {
116 return;
117 }
118 if (!DelayedSingleton<DistributedCommunicationManager>::GetInstance()->IsConnected() ||
119 !DelayedSingleton<DistributedCommunicationManager>::GetInstance()->IsAudioOnSink()) {
120 TELEPHONY_LOGI("dc not connected or audio not on sink");
121 preAction_ = action;
122 return;
123 }
124 if ((action == WEAR_ACTION) || (action == DISABLE_FROM_REMOTE_ACTION && preAction_ == WEAR_ACTION)) {
125 // Forcibly switch to the bt headset in either of the following situations:
126 // case 1: At the moment, the user wears the headset
127 // case 2: The headset is preempted by the peer device when the user wears the headset
128 SwitchToBtHeadset(device);
129 }
130 preAction_ = action;
131 }
132
SetPreAction(int32_t action)133 void DcCallHfpListener::SetPreAction(int32_t action)
134 {
135 preAction_ = action;
136 }
137
SwitchToBtHeadset(const Bluetooth::BluetoothRemoteDevice & device)138 void DcCallHfpListener::SwitchToBtHeadset(const Bluetooth::BluetoothRemoteDevice &device)
139 {
140 AudioDevice audioDevice;
141 audioDevice.deviceType = AudioDeviceType::DEVICE_BLUETOOTH_SCO;
142 if (memcpy_s(audioDevice.address, kMaxAddressLen, device.GetDeviceAddr().c_str(),
143 device.GetDeviceAddr().length()) != EOK) {
144 TELEPHONY_LOGE("memcpy_s address fail");
145 return;
146 }
147 auto ret = DelayedSingleton<AudioControlManager>::GetInstance()->SetAudioDevice(audioDevice);
148 TELEPHONY_LOGI("switch to bt headset, ret[%{public}d]", ret);
149 }
150 #endif
151
152 } // namespace Telephony
153 } // namespace OHOS
154