1 /*
2 * Copyright (C) 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 <thread>
17 #include <pthread.h>
18
19 #include "distributed_call_manager.h"
20 #include "audio_control_manager.h"
21 #include "telephony_log_wrapper.h"
22 #include "nlohmann/json.hpp"
23
24 using json = nlohmann::json;
25
26 namespace OHOS {
27 namespace Telephony {
28 namespace {
29 const size_t INT32_MIN_ID_LENGTH = 3;
30 const size_t INT32_SHORT_ID_LENGTH = 20;
31 const size_t INT32_PLAINTEXT_LENGTH = 4;
32 const int32_t DCALL_SWITCH_DEVICE_TYPE_SOURCE = 0;
33 const int32_t DCALL_SWITCH_DEVICE_TYPE_SINK = 1;
34 const int32_t DISTRIBUTED_CALL_SOURCE_SA_ID = 9855;
35 const std::string CALLBACK_NAME = "telephony";
36 const std::string DISTRIBUTED_AUDIO_DEV_CAR = "dCar";
37 const std::string DISTRIBUTED_AUDIO_DEV_PHONE = "dPhone";
38 const std::string DISTRIBUTED_AUDIO_DEV_PAD = "dPad";
39 const std::string SWITCH_TO_DCALL_THREAD_NAME = "switch to dcall";
40
GetAnonyString(const std::string & value)41 std::string GetAnonyString(const std::string &value)
42 {
43 std::string res;
44 std::string tmpStr("******");
45 size_t strLen = value.length();
46 if (strLen < INT32_MIN_ID_LENGTH) {
47 return tmpStr;
48 }
49 if (strLen <= INT32_SHORT_ID_LENGTH) {
50 res += value[0];
51 res += tmpStr;
52 res += value[strLen - 1];
53 } else {
54 res.append(value, 0, INT32_PLAINTEXT_LENGTH);
55 res += tmpStr;
56 res.append(value, strLen - INT32_PLAINTEXT_LENGTH, INT32_PLAINTEXT_LENGTH);
57 }
58 return res;
59 }
60
IsDistributedAudioDevice(const AudioDevice & device)61 bool IsDistributedAudioDevice(const AudioDevice& device)
62 {
63 if ((device.deviceType == AudioDeviceType::DEVICE_DISTRIBUTED_PHONE) ||
64 (device.deviceType == AudioDeviceType::DEVICE_DISTRIBUTED_PAD) ||
65 (device.deviceType == AudioDeviceType::DEVICE_DISTRIBUTED_AUTOMOTIVE)) {
66 return true;
67 }
68 return false;
69 }
70 }
71
DistributedCallManager()72 DistributedCallManager::DistributedCallManager()
73 {
74 TELEPHONY_LOGI("DistributedCallManager constructed.");
75 }
76
~DistributedCallManager()77 DistributedCallManager::~DistributedCallManager()
78 {
79 TELEPHONY_LOGI("DistributedCallManager destructed.");
80 }
81
Init()82 void DistributedCallManager::Init()
83 {
84 TELEPHONY_LOGI("Init start.");
85 statusChangeListener_ = new (std::nothrow) DCallSystemAbilityListener();
86 if (statusChangeListener_ == nullptr) {
87 TELEPHONY_LOGE("failed to create statusChangeListener");
88 return;
89 }
90 auto managerPtr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
91 if (managerPtr == nullptr) {
92 TELEPHONY_LOGE("get system ability manager error");
93 return;
94 }
95 int32_t ret = managerPtr->SubscribeSystemAbility(DISTRIBUTED_CALL_SOURCE_SA_ID, statusChangeListener_);
96 if (ret != TELEPHONY_SUCCESS) {
97 TELEPHONY_LOGE("failed to subscribe dcall service SA: %{public}d", DISTRIBUTED_CALL_SOURCE_SA_ID);
98 return;
99 }
100 TELEPHONY_LOGI("Init end.");
101 }
102
CreateDAudioDevice(const std::string & devId,AudioDevice & device)103 bool DistributedCallManager::CreateDAudioDevice(const std::string& devId, AudioDevice& device)
104 {
105 if (!devId.length()) {
106 TELEPHONY_LOGE("dcall devId is invalid");
107 return false;
108 }
109 if (dcallProxy_ == nullptr) {
110 TELEPHONY_LOGE("dcallProxy_ is nullptr");
111 return false;
112 }
113 OHOS::DistributedHardware::DCallDeviceInfo devInfo;
114 int32_t ret = dcallProxy_->GetDCallDeviceInfo(devId, devInfo);
115 if (ret != TELEPHONY_SUCCESS) {
116 TELEPHONY_LOGI("get dcall device info failed.");
117 return false;
118 }
119 std::string devTypeName;
120 std::string devName = devInfo.devName;
121 if (devInfo.devType == OHOS::DistributedHardware::DCallDeviceType::DISTRIBUTED_DEVICE_PHONE) {
122 devTypeName = DISTRIBUTED_AUDIO_DEV_PHONE;
123 device.deviceType = AudioDeviceType::DEVICE_DISTRIBUTED_PHONE;
124 } else if (devInfo.devType == OHOS::DistributedHardware::DCallDeviceType::DISTRIBUTED_DEVICE_PAD) {
125 devTypeName = DISTRIBUTED_AUDIO_DEV_PAD;
126 device.deviceType = AudioDeviceType::DEVICE_DISTRIBUTED_PAD;
127 } else {
128 devTypeName = DISTRIBUTED_AUDIO_DEV_CAR;
129 device.deviceType = AudioDeviceType::DEVICE_DISTRIBUTED_AUTOMOTIVE;
130 }
131 json addressJson;
132 addressJson["devName"] = devName;
133 addressJson["devId"] = devId;
134 std::string addressStr = addressJson.dump();
135 if (memcpy_s(device.address, kMaxAddressLen, addressStr.c_str(), addressStr.length()) != EOK) {
136 TELEPHONY_LOGE("memcpy_s failed.");
137 return false;
138 }
139 TELEPHONY_LOGI("create distributed audio device succeed, type: %{public}s, addr: %{public}s",
140 devTypeName.c_str(), device.address);
141 return true;
142 }
143
GetDevIdFromAudioDevice(const AudioDevice & device)144 std::string DistributedCallManager::GetDevIdFromAudioDevice(const AudioDevice& device)
145 {
146 std::string devId = "";
147 if (!IsDistributedAudioDevice(device)) {
148 TELEPHONY_LOGE("not distributed audio device, device type: %{public}d", device.deviceType);
149 return devId;
150 }
151 std::string address = device.address;
152 if (!address.length()) {
153 TELEPHONY_LOGE("invalid address");
154 return devId;
155 }
156 json addressJson = json::parse(address, nullptr, false);
157 if (addressJson.is_null() || addressJson.is_discarded()) {
158 TELEPHONY_LOGE("json value is null or discarded, json string: %{public}s", address.c_str());
159 return devId;
160 }
161 if (!addressJson.contains("devId")) {
162 TELEPHONY_LOGE("json not contain devId, json string: %{public}s", address.c_str());
163 return devId;
164 }
165 if (!addressJson["devId"].is_string()) {
166 TELEPHONY_LOGE("json has no devId string, json string: %{public}s", address.c_str());
167 return devId;
168 }
169 devId = addressJson["devId"];
170 TELEPHONY_LOGI("devId: %{public}s", GetAnonyString(devId).c_str());
171 return devId;
172 }
173
AddDCallDevice(const std::string & devId)174 void DistributedCallManager::AddDCallDevice(const std::string& devId)
175 {
176 TELEPHONY_LOGI("add dcall device, devId: %{public}s.", GetAnonyString(devId).c_str());
177 std::lock_guard<std::mutex> lock(onlineDeviceMtx_);
178
179 auto iter = onlineDCallDevices_.find(devId);
180 if (iter != onlineDCallDevices_.end()) {
181 TELEPHONY_LOGI("device is already exist, devId: %{public}s", GetAnonyString(devId).c_str());
182 return;
183 }
184
185 AudioDevice device;
186 if (!CreateDAudioDevice(devId, device)) {
187 TELEPHONY_LOGE("failed to create distributed audio device, devId: %{public}s", GetAnonyString(devId).c_str());
188 return;
189 }
190
191 DelayedSingleton<AudioDeviceManager>::GetInstance()->AddAudioDeviceList(device.address, device.deviceType);
192 onlineDCallDevices_.emplace(devId, device);
193
194 if (!isConnected_.load() && isCallActived_.load()) {
195 if (device.deviceType == AudioDeviceType::DEVICE_DISTRIBUTED_AUTOMOTIVE) {
196 TELEPHONY_LOGI("switch call to auto motive as it is online");
197 SwitchDCallDeviceAsync(device);
198 }
199 }
200 }
201
RemoveDCallDevice(const std::string & devId)202 void DistributedCallManager::RemoveDCallDevice(const std::string& devId)
203 {
204 TELEPHONY_LOGI("remove dcall device, devId: %{public}s.", GetAnonyString(devId).c_str());
205 std::lock_guard<std::mutex> lock(onlineDeviceMtx_);
206 auto iter = onlineDCallDevices_.find(devId);
207 if (iter != onlineDCallDevices_.end()) {
208 std::string devId = GetDevIdFromAudioDevice(iter->second);
209 std::string curDevId = GetConnectedDCallDeviceId();
210 TELEPHONY_LOGI("removed devId: %{public}s, current devId: %{public}s",
211 GetAnonyString(devId).c_str(), GetAnonyString(curDevId).c_str());
212 DelayedSingleton<AudioDeviceManager>::GetInstance()->RemoveAudioDeviceList(
213 iter->second.address, iter->second.deviceType);
214 onlineDCallDevices_.erase(iter);
215 if (curDevId == devId) {
216 TELEPHONY_LOGI("current dcall device is removed, now reinit audio device.");
217 isConnected_.store(false);
218 ClearConnectedDAudioDevice();
219 DelayedSingleton<AudioDeviceManager>::GetInstance()->InitAudioDevice();
220 }
221 }
222 }
223
ClearDCallDevice()224 void DistributedCallManager::ClearDCallDevice()
225 {
226 TELEPHONY_LOGI("clear dcall device.");
227 std::lock_guard<std::mutex> lock(onlineDeviceMtx_);
228 onlineDCallDevices_.clear();
229 }
230
NotifyOnlineDCallDevices(std::vector<std::string> devices)231 void DistributedCallManager::NotifyOnlineDCallDevices(std::vector<std::string> devices)
232 {
233 TELEPHONY_LOGI("notify online dcall devices start, size: %{public}d", static_cast<int32_t>(devices.size()));
234 for (auto item : devices) {
235 AddDCallDevice(item);
236 TELEPHONY_LOGI("notify dcall device, devId: %{public}s", GetAnonyString(item).c_str());
237 }
238 TELEPHONY_LOGI("notify online dcall devices end.");
239 }
240
GetConnectedDCallAddr()241 std::string DistributedCallManager::GetConnectedDCallAddr()
242 {
243 std::lock_guard<std::mutex> lock(connectedDevMtx_);
244 std::string addr = connectedAudioDevice_.address;
245 return addr;
246 }
247
GetConnectedDCallType()248 AudioDeviceType DistributedCallManager::GetConnectedDCallType()
249 {
250 std::lock_guard<std::mutex> lock(connectedDevMtx_);
251 AudioDeviceType type = connectedAudioDevice_.deviceType;
252 return type;
253 }
254
GetConnectedDCallDeviceId()255 std::string DistributedCallManager::GetConnectedDCallDeviceId()
256 {
257 std::lock_guard<std::mutex> lock(connectedDevMtx_);
258 std::string devId = "";
259 if (isConnected_.load()) {
260 devId = GetDevIdFromAudioDevice(connectedAudioDevice_);
261 }
262 return devId;
263 }
264
GetConnectedAudioDevice(AudioDevice & device)265 void DistributedCallManager::GetConnectedAudioDevice(AudioDevice& device)
266 {
267 std::lock_guard<std::mutex> lock(connectedDevMtx_);
268 device.deviceType = connectedAudioDevice_.deviceType;
269 if (memcpy_s(device.address, kMaxAddressLen, connectedAudioDevice_.address, kMaxAddressLen) != EOK) {
270 TELEPHONY_LOGE("memcpy_s failed.");
271 }
272 }
273
SetConnectedAudioDevice(const AudioDevice & device)274 void DistributedCallManager::SetConnectedAudioDevice(const AudioDevice& device)
275 {
276 std::lock_guard<std::mutex> lock(connectedDevMtx_);
277 connectedAudioDevice_.deviceType = device.deviceType;
278 if (memcpy_s(connectedAudioDevice_.address, kMaxAddressLen, device.address, kMaxAddressLen) != EOK) {
279 TELEPHONY_LOGE("memcpy_s failed.");
280 }
281 }
282
ClearConnectedDAudioDevice()283 void DistributedCallManager::ClearConnectedDAudioDevice()
284 {
285 std::lock_guard<std::mutex> lock(connectedDevMtx_);
286 connectedAudioDevice_.deviceType = AudioDeviceType::DEVICE_UNKNOWN;
287 if (memset_s(connectedAudioDevice_.address, kMaxAddressLen, 0, kMaxAddressLen) != EOK) {
288 TELEPHONY_LOGE("memset_s failed.");
289 }
290 }
291
SwitchDCallDevice(const AudioDevice & device)292 bool DistributedCallManager::SwitchDCallDevice(const AudioDevice& device)
293 {
294 if (!IsDistributedAudioDevice(device)) {
295 TELEPHONY_LOGE("not distributed audio device, device type: %{public}d", device.deviceType);
296 return false;
297 }
298 std::string devId = GetDevIdFromAudioDevice(device);
299 if (!devId.length()) {
300 TELEPHONY_LOGE("dcall devId is invalid");
301 return false;
302 }
303 TELEPHONY_LOGI("switch dcall device start, devId: %{public}s", GetAnonyString(devId).c_str());
304 if (dcallProxy_ == nullptr) {
305 TELEPHONY_LOGE("dcallProxy_ is nullptr");
306 return false;
307 }
308 int32_t ret = dcallProxy_->SwitchDevice(devId, DCALL_SWITCH_DEVICE_TYPE_SINK);
309 if (ret == TELEPHONY_SUCCESS) {
310 isConnected_.store(true);
311 SetConnectedAudioDevice(device);
312 TELEPHONY_LOGI("switch dcall device succeed.");
313 return true;
314 }
315 TELEPHONY_LOGI("switch dcall device failed.");
316 return false;
317 }
318
SwitchToDistributedCallDevice(std::unique_ptr<AudioDevice> device)319 void DistributedCallManager::SwitchToDistributedCallDevice(std::unique_ptr<AudioDevice> device)
320 {
321 if (!IsDistributedAudioDevice(*device)) {
322 TELEPHONY_LOGE("not distributed audio device, device type: %{public}d", device->deviceType);
323 return;
324 }
325 std::string devId = GetDevIdFromAudioDevice(*device);
326 if (!devId.length()) {
327 TELEPHONY_LOGE("dcall devId is invalid");
328 return;
329 }
330 if (dcallProxy_ == nullptr) {
331 TELEPHONY_LOGE("dcallProxy_ is nullptr");
332 return;
333 }
334 TELEPHONY_LOGI("switch to distributed call device start, devId: %s", GetAnonyString(devId).c_str());
335 int32_t ret = dcallProxy_->SwitchDevice(devId, DCALL_SWITCH_DEVICE_TYPE_SINK);
336 if (ret == TELEPHONY_SUCCESS) {
337 isConnected_.store(true);
338 SetConnectedAudioDevice(*device);
339 DelayedSingleton<AudioDeviceManager>::GetInstance()->SetCurrentAudioDevice(
340 device->deviceType);
341 TELEPHONY_LOGI("switch to distributed call device succeed.");
342 } else {
343 TELEPHONY_LOGE("switch to distributed call device failed.");
344 }
345 }
346
SetCallState(bool isActive)347 void DistributedCallManager::SetCallState(bool isActive)
348 {
349 isCallActived_.store(isActive);
350 }
351
SwitchDCallDeviceAsync(const AudioDevice & device)352 void DistributedCallManager::SwitchDCallDeviceAsync(const AudioDevice& device)
353 {
354 std::unique_ptr<AudioDevice> dCallDevice = std::make_unique<AudioDevice>();
355 if (dCallDevice == nullptr) {
356 TELEPHONY_LOGE("fail to create AudioDevice obj");
357 return;
358 }
359 dCallDevice->deviceType = device.deviceType;
360 if (memset_s(dCallDevice->address, kMaxAddressLen + 1, 0, kMaxAddressLen + 1) != EOK) {
361 TELEPHONY_LOGE("failed to memset_s dCallDevice->address");
362 return;
363 }
364 if (memcpy_s(dCallDevice->address, kMaxAddressLen, device.address, kMaxAddressLen) != EOK) {
365 TELEPHONY_LOGE("failed to memcpy_s dCallDevice->address");
366 return;
367 }
368 std::thread switchThread(&DistributedCallManager::SwitchToDistributedCallDevice, this, std::move(dCallDevice));
369 pthread_setname_np(switchThread.native_handle(), SWITCH_TO_DCALL_THREAD_NAME.c_str());
370 switchThread.detach();
371 }
372
DisconnectDCallDevice()373 void DistributedCallManager::DisconnectDCallDevice()
374 {
375 if (!isConnected_.load()) {
376 TELEPHONY_LOGE("distributed audio device not connected.");
377 return;
378 }
379 std::string devId = GetConnectedDCallDeviceId();
380 if (!devId.length()) {
381 TELEPHONY_LOGE("dcall devId is invalid");
382 return;
383 }
384 TELEPHONY_LOGI("disconnect dcall device start, devId: %{public}s", GetAnonyString(devId).c_str());
385 if (dcallProxy_ == nullptr) {
386 TELEPHONY_LOGE("dcallProxy_ is nullptr");
387 return;
388 }
389 int32_t ret = dcallProxy_->SwitchDevice(devId, DCALL_SWITCH_DEVICE_TYPE_SOURCE);
390 if (ret == TELEPHONY_SUCCESS) {
391 isConnected_.store(false);
392 ClearConnectedDAudioDevice();
393 TELEPHONY_LOGI("disconnect dcall device succeed.");
394 } else {
395 TELEPHONY_LOGE("disconnect dcall device failed");
396 }
397 TELEPHONY_LOGI("disconnect dcall device end.");
398 }
399
IsDAudioDeviceConnected()400 bool DistributedCallManager::IsDAudioDeviceConnected()
401 {
402 return isConnected_.load();
403 }
404
OnDeviceOnline(const std::string & devId)405 void DistributedCallManager::OnDeviceOnline(const std::string &devId)
406 {
407 TELEPHONY_LOGI("dcall device is online, devId: %{public}s", GetAnonyString(devId).c_str());
408 AddDCallDevice(devId);
409 }
410
OnDeviceOffline(const std::string & devId)411 void DistributedCallManager::OnDeviceOffline(const std::string &devId)
412 {
413 TELEPHONY_LOGI("dcall device is offline, devId: %{public}s", GetAnonyString(devId).c_str());
414 RemoveDCallDevice(devId);
415 }
416
OnDeviceOnline(const std::string & devId)417 int32_t DistributedCallManager::DistributedCallDeviceListener::OnDeviceOnline(const std::string &devId)
418 {
419 TELEPHONY_LOGI("dcall device is online, devId: %{public}s", GetAnonyString(devId).c_str());
420 DelayedSingleton<DistributedCallManager>::GetInstance()->OnDeviceOnline(devId);
421 return TELEPHONY_SUCCESS;
422 }
423
OnDeviceOffline(const std::string & devId)424 int32_t DistributedCallManager::DistributedCallDeviceListener::OnDeviceOffline(const std::string &devId)
425 {
426 TELEPHONY_LOGI("dcall device is offline, devId: %{public}s", GetAnonyString(devId).c_str());
427 DelayedSingleton<DistributedCallManager>::GetInstance()->OnDeviceOffline(devId);
428 return TELEPHONY_SUCCESS;
429 }
430
OnDCallSystemAbilityAdded(const std::string & deviceId)431 void DistributedCallManager::OnDCallSystemAbilityAdded(const std::string &deviceId)
432 {
433 TELEPHONY_LOGI("dcall source service is added, deviceId: %{public}s", GetAnonyString(deviceId).c_str());
434 dcallProxy_ = std::make_shared<DistributedCallProxy>();
435 if (dcallProxy_ == nullptr) {
436 TELEPHONY_LOGE("fail to create dcall proxy obj");
437 return;
438 }
439 if (dcallProxy_->Init() != TELEPHONY_SUCCESS) {
440 TELEPHONY_LOGE("init dcall proxy failed");
441 return;
442 }
443 dcallDeviceListener_ = std::make_shared<DistributedCallDeviceListener>();
444 if (dcallDeviceListener_ == nullptr) {
445 TELEPHONY_LOGE("dcallDeviceListener_ is nullptr");
446 return;
447 }
448 if (dcallProxy_->RegisterDeviceCallback(CALLBACK_NAME, dcallDeviceListener_) != TELEPHONY_SUCCESS) {
449 TELEPHONY_LOGE("register dcall callback failed");
450 return;
451 }
452 std::vector<std::string> dcallDevices;
453 if (dcallProxy_->GetOnlineDeviceList(dcallDevices) != TELEPHONY_SUCCESS) {
454 TELEPHONY_LOGE("get dcall device list failed");
455 return;
456 }
457 if (dcallDevices.size() > 0) {
458 NotifyOnlineDCallDevices(dcallDevices);
459 }
460 TELEPHONY_LOGI("OnDCallSystemAbilityAdded end.");
461 }
462
OnDCallSystemAbilityRemoved(const std::string & deviceId)463 void DistributedCallManager::OnDCallSystemAbilityRemoved(const std::string &deviceId)
464 {
465 TELEPHONY_LOGI("dcall source service is removed, deviceId: %{public}s", GetAnonyString(deviceId).c_str());
466 dcallDeviceListener_ = nullptr;
467 dcallProxy_ = nullptr;
468 isConnected_.store(false);
469 ClearDCallDevice();
470 ClearConnectedDAudioDevice();
471 DelayedSingleton<AudioDeviceManager>::GetInstance()->ResetDistributedCallDevicesList();
472 DelayedSingleton<AudioDeviceManager>::GetInstance()->InitAudioDevice();
473 TELEPHONY_LOGI("OnDCallSystemAbilityRemoved end.");
474 }
475
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)476 void DCallSystemAbilityListener::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
477 {
478 TELEPHONY_LOGI("SA: %{public}d is added!", systemAbilityId);
479 if (!CheckInputSysAbilityId(systemAbilityId)) {
480 TELEPHONY_LOGE("added SA is invalid!");
481 return;
482 }
483 if (systemAbilityId != DISTRIBUTED_CALL_SOURCE_SA_ID) {
484 TELEPHONY_LOGE("added SA is not dcall source service, ignored.");
485 return;
486 }
487 TELEPHONY_LOGI("notify dcall source service added event to distributed call manager");
488 DelayedSingleton<DistributedCallManager>::GetInstance()->OnDCallSystemAbilityAdded(deviceId);
489 }
490
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)491 void DCallSystemAbilityListener::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
492 {
493 TELEPHONY_LOGI("SA: %{public}d is removed!", systemAbilityId);
494 if (!CheckInputSysAbilityId(systemAbilityId)) {
495 TELEPHONY_LOGE("removed SA is invalid!");
496 return;
497 }
498 if (systemAbilityId != DISTRIBUTED_CALL_SOURCE_SA_ID) {
499 TELEPHONY_LOGE("removed SA is not dcall source service, ignored.");
500 return;
501 }
502 TELEPHONY_LOGI("notify dcall source service removed event to distributed call manager");
503 DelayedSingleton<DistributedCallManager>::GetInstance()->OnDCallSystemAbilityRemoved(deviceId);
504 }
505 } // namespace Telephony
506 } // namespace OHOS