1 /*
2 * Copyright (c) 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 #undef LOG_TAG
16 #define LOG_TAG "AudioZone"
17
18 #include "audio_info.h"
19 #include "audio_zone.h"
20 #include "audio_log.h"
21 #include "audio_errors.h"
22
23 namespace OHOS {
24 namespace AudioStandard {
GenerateZoneId()25 static int32_t GenerateZoneId()
26 {
27 static int32_t genId = 1;
28 static std::mutex genLock;
29 std::unique_lock<std::mutex> lock(genLock);
30 int32_t id = genId;
31 genId++;
32 if (genId <= 0) {
33 genId = 1;
34 }
35 return id;
36 }
37
AudioZoneBindKey(int32_t uid)38 AudioZoneBindKey::AudioZoneBindKey(int32_t uid)
39 : uid_(uid)
40 {
41 }
42
AudioZoneBindKey(int32_t uid,const std::string & deviceTag)43 AudioZoneBindKey::AudioZoneBindKey(int32_t uid, const std::string &deviceTag)
44 : uid_(uid),
45 deviceTag_(deviceTag)
46 {
47 }
48
AudioZoneBindKey(int32_t uid,const std::string & deviceTag,const std::string & streamTag)49 AudioZoneBindKey::AudioZoneBindKey(int32_t uid, const std::string &deviceTag, const std::string &streamTag)
50 : uid_(uid),
51 deviceTag_(deviceTag),
52 streamTag_(streamTag)
53 {
54 }
55
AudioZoneBindKey(int32_t uid,const std::string & deviceTag,const std::string & streamTag,const StreamUsage & usage)56 AudioZoneBindKey::AudioZoneBindKey(int32_t uid, const std::string &deviceTag, const std::string &streamTag,
57 const StreamUsage &usage)
58 : uid_(uid),
59 deviceTag_(deviceTag),
60 streamTag_(streamTag),
61 usage_(usage)
62 {
63 }
64
AudioZoneBindKey(const AudioZoneBindKey & other)65 AudioZoneBindKey::AudioZoneBindKey(const AudioZoneBindKey &other)
66 {
67 Assign(other);
68 }
69
AudioZoneBindKey(AudioZoneBindKey && other)70 AudioZoneBindKey::AudioZoneBindKey(AudioZoneBindKey &&other)
71 {
72 Swap(std::move(other));
73 }
74
operator =(const AudioZoneBindKey & other)75 AudioZoneBindKey &AudioZoneBindKey::operator=(const AudioZoneBindKey &other)
76 {
77 Assign(other);
78 return *this;
79 }
80
operator =(AudioZoneBindKey && other)81 AudioZoneBindKey &AudioZoneBindKey::operator=(AudioZoneBindKey &&other)
82 {
83 Swap(std::move(other));
84 return *this;
85 }
86
operator ==(const AudioZoneBindKey & other) const87 bool AudioZoneBindKey::operator==(const AudioZoneBindKey &other) const
88 {
89 return this->uid_ == other.uid_ &&
90 this->deviceTag_ == other.deviceTag_ &&
91 this->streamTag_ == other.streamTag_ &&
92 this->usage_ == other.usage_;
93 }
94
operator !=(const AudioZoneBindKey & other) const95 bool AudioZoneBindKey::operator!=(const AudioZoneBindKey &other) const
96 {
97 return !(*this == other);
98 }
99
Assign(const AudioZoneBindKey & other)100 void AudioZoneBindKey::Assign(const AudioZoneBindKey &other)
101 {
102 this->uid_ = other.uid_;
103 this->deviceTag_ = other.deviceTag_;
104 this->streamTag_ = other.streamTag_;
105 this->usage_ = other.usage_;
106 }
107
Swap(AudioZoneBindKey && other)108 void AudioZoneBindKey::Swap(AudioZoneBindKey &&other)
109 {
110 this->uid_ = other.uid_;
111 this->deviceTag_ = other.deviceTag_;
112 this->streamTag_ = std::move(other.streamTag_);
113 this->usage_ = other.usage_;
114 }
115
GetUid() const116 int32_t AudioZoneBindKey::GetUid() const
117 {
118 return uid_;
119 }
120
GetString() const121 const std::string AudioZoneBindKey::GetString() const
122 {
123 std::string str = "uid=";
124 str += std::to_string(uid_);
125 str += ",deviceTag=";
126 str += deviceTag_;
127 str += ",streamTag=";
128 str += streamTag_;
129 str += ",usage_=";
130 str += std::to_string(usage_);
131 return str;
132 }
133
IsContain(const AudioZoneBindKey & other) const134 bool AudioZoneBindKey::IsContain(const AudioZoneBindKey &other) const
135 {
136 std::vector<AudioZoneBindKey> supportKeys = GetSupportKeys(other);
137 int32_t index = -1;
138 int32_t otherIndex = -1;
139 for (int32_t i = 0; i < static_cast<int32_t>(supportKeys.size()); i++) {
140 if (supportKeys[i] == *this) {
141 index = i;
142 }
143
144 if (supportKeys[i] == other) {
145 otherIndex = i;
146 }
147 }
148 CHECK_AND_RETURN_RET(index != -1, false);
149 return index >= otherIndex;
150 }
151
GetSupportKeys(int32_t uid,const std::string & deviceTag,const std::string & streamTag,const StreamUsage & usage)152 const std::vector<AudioZoneBindKey> AudioZoneBindKey::GetSupportKeys(int32_t uid, const std::string &deviceTag,
153 const std::string &streamTag, const StreamUsage &usage)
154 {
155 std::vector<AudioZoneBindKey> keys;
156 keys.push_back(AudioZoneBindKey(uid, deviceTag, streamTag, StreamUsage::STREAM_USAGE_INVALID));
157 auto pushBack = [&keys](const AudioZoneBindKey &temp) {
158 for (auto &key : keys) {
159 CHECK_AND_RETURN(key != temp);
160 }
161 keys.push_back(temp);
162 };
163 pushBack(AudioZoneBindKey(uid, "", streamTag));
164 pushBack(AudioZoneBindKey(uid));
165 pushBack(AudioZoneBindKey(uid, deviceTag));
166 pushBack(AudioZoneBindKey(INVALID_UID, "", "", usage));
167 return keys;
168 }
169
GetSupportKeys(const AudioZoneBindKey & key)170 const std::vector<AudioZoneBindKey> AudioZoneBindKey::GetSupportKeys(const AudioZoneBindKey &key)
171 {
172 int32_t uid = key.uid_;
173 std::string deviceTag = key.deviceTag_;
174 std::string streamTag = key.streamTag_;
175 StreamUsage usage = key.usage_;
176 return GetSupportKeys(uid, deviceTag, streamTag, usage);
177 }
178
AudioZone(std::shared_ptr<AudioZoneClientManager> manager,const std::string & name,const AudioZoneContext & context,pid_t clientPid)179 AudioZone::AudioZone(std::shared_ptr<AudioZoneClientManager> manager,
180 const std::string &name, const AudioZoneContext &context, pid_t clientPid)
181 : zoneId_(GenerateZoneId()),
182 name_(name),
183 clientManager_(manager),
184 zoneClientPid_(clientPid)
185 {
186 }
187
GetId()188 int32_t AudioZone::GetId()
189 {
190 return zoneId_;
191 }
192
IsVolumeProxyEnable()193 bool AudioZone::IsVolumeProxyEnable()
194 {
195 std::lock_guard<std::mutex> lock(zoneMutex_);
196 return isVolumeProxyEnabled_;
197 }
198
GetDescriptor()199 const std::shared_ptr<AudioZoneDescriptor> AudioZone::GetDescriptor()
200 {
201 std::lock_guard<std::mutex> lock(zoneMutex_);
202 return GetDescriptorNoLock();
203 }
204
GetStringDescriptor()205 const std::string AudioZone::GetStringDescriptor()
206 {
207 std::lock_guard<std::mutex> lock(zoneMutex_);
208 std::string str;
209 str += "zone name is";
210 str += name_;
211 str += "\n";
212 for (auto &key : keys_) {
213 str += "bing key ";
214 str += key.GetString();
215 str += "\n";
216 }
217 str += "zone vloume proxy is";
218 str += isVolumeProxyEnabled_ ? "enabled" : "disabled";
219 str += "\n";
220 return str;
221 }
222
GetName()223 const std::string AudioZone::GetName()
224 {
225 return name_;
226 }
227
GetDescriptorNoLock()228 const std::shared_ptr<AudioZoneDescriptor> AudioZone::GetDescriptorNoLock()
229 {
230 std::shared_ptr<AudioZoneDescriptor> descriptor = std::make_shared<AudioZoneDescriptor>();
231 CHECK_AND_RETURN_RET_LOG(descriptor != nullptr, nullptr, "descriptor is nullptr");
232
233 descriptor->zoneId_ = zoneId_;
234 descriptor->name_ = name_;
235 for (const auto &key : keys_) {
236 descriptor->uids_.insert(key.GetUid());
237 }
238 for (const auto &it : devices_) {
239 descriptor->devices_.emplace_back(it.first);
240 }
241 return descriptor;
242 }
243
BindByKey(const AudioZoneBindKey & key)244 void AudioZone::BindByKey(const AudioZoneBindKey &key)
245 {
246 std::lock_guard<std::mutex> lock(zoneMutex_);
247 for (auto itKey = keys_.begin(); itKey != keys_.end();) {
248 CHECK_AND_RETURN_LOG(!itKey->IsContain(key), "exist low key %{public}s to %{public}s for zone %{public}d",
249 itKey->GetString().c_str(), key.GetString().c_str(), zoneId_);
250 if (key.IsContain(*itKey)) {
251 AUDIO_INFO_LOG("erase high key %{public}s to %{public}s for zone %{public}d",
252 itKey->GetString().c_str(), key.GetString().c_str(), zoneId_);
253 keys_.erase(itKey++);
254 } else {
255 ++itKey;
256 }
257 }
258 keys_.emplace_back(key);
259 AUDIO_INFO_LOG("bind key %{public}s to zone %{public}d", key.GetString().c_str(), zoneId_);
260 for (auto &temp : keys_) {
261 AUDIO_DEBUG_LOG("zone %{public}d bind key %{public}s", zoneId_, temp.GetString().c_str());
262 }
263 SendZoneChangeEvent(AudioZoneChangeReason::BIND_NEW_APP);
264 }
265
RemoveKey(const AudioZoneBindKey & key)266 void AudioZone::RemoveKey(const AudioZoneBindKey &key)
267 {
268 std::lock_guard<std::mutex> lock(zoneMutex_);
269 auto itKey = std::find(keys_.begin(), keys_.end(), key);
270 CHECK_AND_RETURN_LOG(itKey != keys_.end(), "key %{public}s not exist for zone %{public}d",
271 key.GetString().c_str(), zoneId_);
272
273 AUDIO_INFO_LOG("remove key %{public}s for zone %{public}d", key.GetString().c_str(), zoneId_);
274 keys_.erase(itKey);
275 for (auto &temp : keys_) {
276 AUDIO_DEBUG_LOG("zone %{public}d bind key %{public}s", zoneId_, temp.GetString().c_str());
277 }
278 SendZoneChangeEvent(AudioZoneChangeReason::UNBIND_APP);
279 }
280
IsContainKey(const AudioZoneBindKey & key)281 bool AudioZone::IsContainKey(const AudioZoneBindKey &key)
282 {
283 std::lock_guard<std::mutex> lock(zoneMutex_);
284 for (const auto &it : keys_) {
285 if (it == key) {
286 return true;
287 }
288 }
289 return false;
290 }
291
AddDeviceDescriptor(const std::vector<std::shared_ptr<AudioDeviceDescriptor>> & devices)292 int32_t AudioZone::AddDeviceDescriptor(const std::vector<std::shared_ptr<AudioDeviceDescriptor>> &devices)
293 {
294 std::lock_guard<std::mutex> lock(zoneMutex_);
295 for (const auto &device : devices) {
296 CHECK_AND_RETURN_RET_LOG(device != nullptr, ERR_INVALID_PARAM, "device is nullptr");
297 auto findDevice = [&device] (const std::pair<std::shared_ptr<AudioDeviceDescriptor>, bool> &item) {
298 return device->IsSameDeviceDesc(*(item.first));
299 };
300
301 auto itDev = std::find_if(devices_.begin(), devices_.end(), findDevice);
302 if (itDev != devices_.end()) {
303 AUDIO_WARNING_LOG("add duplicate device %{public}d,%{public}d,%{public}s to zone %{public}d",
304 device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
305 } else {
306 std::vector<std::shared_ptr<AudioDeviceDescriptor>> connectDevices;
307 AudioConnectedDevice::GetInstance().GetAllConnectedDeviceByType(device->networkId_,
308 device->deviceType_, device->macAddress_, device->deviceRole_, connectDevices);
309 devices_.emplace_back(std::make_pair(device, connectDevices.size() != 0));
310 AUDIO_INFO_LOG("add device %{public}d,%{public}d,%{public}s to zone %{public}d",
311 device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
312 }
313 }
314 return SUCCESS;
315 }
316
RemoveDeviceDescriptor(const std::vector<std::shared_ptr<AudioDeviceDescriptor>> & devices)317 int32_t AudioZone::RemoveDeviceDescriptor(const std::vector<std::shared_ptr<AudioDeviceDescriptor>> &devices)
318 {
319 std::lock_guard<std::mutex> lock(zoneMutex_);
320 for (const auto &device : devices) {
321 CHECK_AND_RETURN_RET_LOG(device != nullptr, ERR_INVALID_PARAM, "device is nullptr");
322 auto findDevice = [device] (const std::pair<std::shared_ptr<AudioDeviceDescriptor>, bool> &item) {
323 return device->IsSameDeviceDesc(*(item.first));
324 };
325
326 auto itDev = std::find_if(devices_.begin(), devices_.end(), findDevice);
327 CHECK_AND_CONTINUE(itDev != devices_.end());
328
329 devices_.erase(itDev);
330 AUDIO_INFO_LOG("remove device %{public}d,%{public}d,%{public}s from zone %{public}d",
331 device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
332 }
333 return SUCCESS;
334 }
335
UpdateDeviceDescriptor(const std::shared_ptr<AudioDeviceDescriptor> device)336 int32_t AudioZone::UpdateDeviceDescriptor(const std::shared_ptr<AudioDeviceDescriptor> device)
337 {
338 std::lock_guard<std::mutex> lock(zoneMutex_);
339 CHECK_AND_RETURN_RET_LOG(device != nullptr, ERR_INVALID_PARAM, "device is nullptr");
340 auto findDevice = [&device] (const std::pair<std::shared_ptr<AudioDeviceDescriptor>, bool> &item) {
341 return device->IsSameDeviceDesc(*(item.first));
342 };
343 auto itDev = std::find_if(devices_.begin(), devices_.end(), findDevice);
344 CHECK_AND_RETURN_RET_LOG(itDev != devices_.end(), ERROR,
345 "update device %{public}d,%{public}d,%{public}s not exist for zone %{public}d",
346 device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
347
348 devices_.erase(itDev);
349 std::vector<std::shared_ptr<AudioDeviceDescriptor>> connectDevices;
350 AudioConnectedDevice::GetInstance().GetAllConnectedDeviceByType(device->networkId_,
351 device->deviceType_, device->macAddress_, device->deviceRole_, connectDevices);
352 devices_.emplace_back(std::make_pair(device, connectDevices.size() != 0));
353 AUDIO_INFO_LOG("add device %{public}d,%{public}d,%{public}s to zone %{public}d",
354 device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
355 return SUCCESS;
356 }
357
EnableDeviceDescriptor(std::shared_ptr<AudioDeviceDescriptor> device)358 int32_t AudioZone::EnableDeviceDescriptor(std::shared_ptr<AudioDeviceDescriptor> device)
359 {
360 return SetDeviceDescriptorState(device, true);
361 }
362
DisableDeviceDescriptor(std::shared_ptr<AudioDeviceDescriptor> device)363 int32_t AudioZone::DisableDeviceDescriptor(std::shared_ptr<AudioDeviceDescriptor> device)
364 {
365 return SetDeviceDescriptorState(device, false);
366 }
367
SetDeviceDescriptorState(const std::shared_ptr<AudioDeviceDescriptor> device,const bool enable)368 int32_t AudioZone::SetDeviceDescriptorState(const std::shared_ptr<AudioDeviceDescriptor> device, const bool enable)
369 {
370 std::lock_guard<std::mutex> lock(zoneMutex_);
371 CHECK_AND_RETURN_RET_LOG(device != nullptr, ERROR, "device is nullptr");
372 auto findDevice = [device] (const std::pair<std::shared_ptr<AudioDeviceDescriptor>, bool> &item) {
373 return device->IsSameDeviceDesc(*(item.first));
374 };
375
376 auto itDev = std::find_if(devices_.begin(), devices_.end(), findDevice);
377 CHECK_AND_RETURN_RET_LOG(itDev != devices_.end(), ERROR,
378 "device %{public}d,%{public}d,%{public}s not exist for zone %{public}d",
379 device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
380
381 itDev->second = enable;
382 AUDIO_INFO_LOG("%{public}s device %{public}d,%{public}d,%{public}s of zone %{public}d",
383 enable ? "enable" : "disable", device->deviceType_, device->deviceId_, device->deviceName_.c_str(), zoneId_);
384 return SUCCESS;
385 }
386
IsDeviceConnect(std::shared_ptr<AudioDeviceDescriptor> device)387 bool AudioZone::IsDeviceConnect(std::shared_ptr<AudioDeviceDescriptor> device)
388 {
389 std::lock_guard<std::mutex> lock(zoneMutex_);
390 CHECK_AND_RETURN_RET_LOG(device != nullptr, false, "device is nullptr");
391 auto findDevice = [device] (const std::pair<std::shared_ptr<AudioDeviceDescriptor>, bool> &item) {
392 return device->IsSameDeviceDesc(*(item.first));
393 };
394 auto itDev = std::find_if(devices_.begin(), devices_.end(), findDevice);
395 CHECK_AND_RETURN_RET(itDev != devices_.end(), false);
396
397 return itDev->second;
398 }
399
FetchOutputDevices(StreamUsage streamUsage,int32_t clientUid,const RouterType & bypassType)400 std::vector<std::shared_ptr<AudioDeviceDescriptor>> AudioZone::FetchOutputDevices(StreamUsage streamUsage,
401 int32_t clientUid, const RouterType &bypassType)
402 {
403 std::lock_guard<std::mutex> lock(zoneMutex_);
404 std::vector<std::shared_ptr<AudioDeviceDescriptor>> descs;
405 for (const auto &device : devices_) {
406 if (device.second && device.first->deviceRole_ == OUTPUT_DEVICE) {
407 descs.emplace_back(device.first);
408 return descs;
409 }
410 }
411 return descs;
412 }
413
FetchInputDevice(SourceType sourceType,int32_t clientUid)414 std::shared_ptr<AudioDeviceDescriptor> AudioZone::FetchInputDevice(SourceType sourceType, int32_t clientUid)
415 {
416 std::lock_guard<std::mutex> lock(zoneMutex_);
417 for (const auto &device : devices_) {
418 if (device.second && device.first->deviceRole_ == INPUT_DEVICE) {
419 return device.first;
420 }
421 }
422 return nullptr;
423 }
424
EnableChangeReport(pid_t clientPid,bool enable)425 int32_t AudioZone::EnableChangeReport(pid_t clientPid, bool enable)
426 {
427 std::lock_guard<std::mutex> lock(zoneMutex_);
428 if (enable) {
429 changeReportClientList_.insert(clientPid);
430 } else {
431 changeReportClientList_.erase(clientPid);
432 }
433 AUDIO_INFO_LOG(" %{public}s zone %{public}d change report to client %{public}d",
434 enable ? "enable" : "disable", zoneId_, clientPid);
435 return SUCCESS;
436 }
437
SendZoneChangeEvent(AudioZoneChangeReason reason)438 void AudioZone::SendZoneChangeEvent(AudioZoneChangeReason reason)
439 {
440 CHECK_AND_RETURN_LOG(clientManager_ != nullptr, "clientManager is nullptr");
441 for (auto &pid : changeReportClientList_) {
442 clientManager_->SendZoneChangeEvent(pid, this->GetDescriptorNoLock(), reason);
443 }
444 }
445
EnableSystemVolumeProxy(pid_t clientPid,bool enable)446 int32_t AudioZone::EnableSystemVolumeProxy(pid_t clientPid, bool enable)
447 {
448 std::lock_guard<std::mutex> lock(zoneMutex_);
449 volumeProxyClientPid_ = clientPid;
450 isVolumeProxyEnabled_ = enable;
451 AUDIO_INFO_LOG("volume proxy is %{public}s by %{public}d",
452 enable ? "enable" : "disable", clientPid);
453 return SUCCESS;
454 }
455
SetSystemVolumeLevel(AudioVolumeType volumeType,int32_t volumeLevel,int32_t volumeFlag)456 int32_t AudioZone::SetSystemVolumeLevel(AudioVolumeType volumeType,
457 int32_t volumeLevel, int32_t volumeFlag)
458 {
459 std::shared_ptr<AudioZoneClientManager> mgr;
460 {
461 std::lock_guard<std::mutex> lock(zoneMutex_);
462 CHECK_AND_RETURN_RET_LOG(clientManager_ != nullptr, ERROR, "clientManager is nullptr");
463 CHECK_AND_RETURN_RET_LOG(isVolumeProxyEnabled_, ERROR, "volume proxy is not enable");
464
465 mgr = clientManager_;
466 }
467 return mgr->SetSystemVolumeLevel(volumeProxyClientPid_, zoneId_,
468 volumeType, volumeLevel, volumeFlag);
469 }
470
GetSystemVolumeLevel(AudioVolumeType volumeType)471 int32_t AudioZone::GetSystemVolumeLevel(AudioVolumeType volumeType)
472 {
473 std::shared_ptr<AudioZoneClientManager> mgr;
474 {
475 std::lock_guard<std::mutex> lock(zoneMutex_);
476 CHECK_AND_RETURN_RET_LOG(clientManager_ != nullptr, ERROR, "clientManager is nullptr");
477 CHECK_AND_RETURN_RET_LOG(isVolumeProxyEnabled_, ERROR, "volume proxy is not enable");
478
479 mgr = clientManager_;
480 }
481 return mgr->GetSystemVolumeLevel(volumeProxyClientPid_, zoneId_, volumeType);
482 }
483
GetClientPid()484 pid_t AudioZone::GetClientPid()
485 {
486 return zoneClientPid_;
487 }
488 } // namespace AudioStandard
489 } // namespace OHOS