1 /*
2  * Copyright (c) 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 #ifndef LOG_TAG
17 #define LOG_TAG "AudioVolume"
18 #endif
19 
20 #include "audio_volume.h"
21 #include "audio_volume_c.h"
22 #include "audio_service_log.h"
23 #include "audio_utils.h"
24 #include "audio_stream_info.h"
25 #include "media_monitor_manager.h"
26 #include "event_bean.h"
27 
28 namespace OHOS {
29 namespace AudioStandard {
30 static const std::unordered_map<std::string, AudioStreamType> STREAM_TYPE_STRING_ENUM_MAP = {
31     {"voice_call", STREAM_VOICE_CALL},
32     {"voice_call_assistant", STREAM_VOICE_CALL_ASSISTANT},
33     {"music", STREAM_MUSIC},
34     {"ring", STREAM_RING},
35     {"media", STREAM_MEDIA},
36     {"voice_assistant", STREAM_VOICE_ASSISTANT},
37     {"system", STREAM_SYSTEM},
38     {"alarm", STREAM_ALARM},
39     {"notification", STREAM_NOTIFICATION},
40     {"bluetooth_sco", STREAM_BLUETOOTH_SCO},
41     {"enforced_audible", STREAM_ENFORCED_AUDIBLE},
42     {"dtmf", STREAM_DTMF},
43     {"tts", STREAM_TTS},
44     {"accessibility", STREAM_ACCESSIBILITY},
45     {"recording", STREAM_RECORDING},
46     {"movie", STREAM_MOVIE},
47     {"game", STREAM_GAME},
48     {"speech", STREAM_SPEECH},
49     {"system_enforced", STREAM_SYSTEM_ENFORCED},
50     {"ultrasonic", STREAM_ULTRASONIC},
51     {"wakeup", STREAM_WAKEUP},
52     {"voice_message", STREAM_VOICE_MESSAGE},
53     {"navigation", STREAM_NAVIGATION}
54 };
55 
GetInstance()56 AudioVolume *AudioVolume::GetInstance()
57 {
58     static AudioVolume instance;
59     return &instance;
60 }
61 
AudioVolume()62 AudioVolume::AudioVolume()
63 {
64     AUDIO_INFO_LOG("AudioVolume construct");
65 }
66 
~AudioVolume()67 AudioVolume::~AudioVolume()
68 {
69     streamVolume_.clear();
70     systemVolume_.clear();
71     historyVolume_.clear();
72     monitorVolume_.clear();
73 }
74 
GetVolume(uint32_t sessionId, int32_t volumeType, const std::string &deviceClass)75 float AudioVolume::GetVolume(uint32_t sessionId, int32_t volumeType, const std::string &deviceClass)
76 {
77     Trace trace("AudioVolume::GetVolume sessionId:" + std::to_string(sessionId));
78     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
79     float volumeStream = 1.0f;
80     auto it = streamVolume_.find(sessionId);
81     if (it != streamVolume_.end()) {
82         volumeStream =
83             it->second.isMuted_ ? 0.0f : it->second.volume_ * it->second.duckFactor_ * it->second.lowPowerFactor_;
84         AUDIO_DEBUG_LOG("stream volume, sessionId:%{public}u, volume:%{public}f, duck:%{public}f, lowPower:%{public}f,"
85             " isMuted:%{public}d, streamVolumeSize:%{public}zu",
86             sessionId, it->second.volume_, it->second.duckFactor_, it->second.lowPowerFactor_, it->second.isMuted_,
87             streamVolume_.size());
88     } else {
89         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u, streamVolumeSize:%{public}zu",
90             sessionId, streamVolume_.size());
91     }
92 
93     int32_t volumeLevel = 0;
94     float volumeSystem = 1.0f;
95     std::string key = std::to_string(volumeType) + deviceClass;
96     auto itSV = systemVolume_.find(key);
97     if (itSV != systemVolume_.end()) {
98         volumeLevel = itSV->second.volumeLevel_;
99         volumeSystem = itSV->second.isMuted_ ? 0.0f : itSV->second.volume_;
100         AUDIO_DEBUG_LOG("system volume, volumeType:%{public}d, deviceClass:%{public}s,"
101             " volume:%{public}f, isMuted:%{public}d, systemVolumeSize:%{public}zu",
102             volumeType, deviceClass.c_str(), itSV->second.volume_, itSV->second.isMuted_, systemVolume_.size());
103     } else {
104         AUDIO_ERR_LOG("system volume not exist, volumeType:%{public}d, deviceClass:%{public}s,"
105             " systemVolumeSize:%{public}zu", volumeType, deviceClass.c_str(), systemVolume_.size());
106     }
107     float volumeFloat = volumeStream * volumeSystem;
108     if (monitorVolume_.find(sessionId) != monitorVolume_.end()) {
109         monitorVolume_[sessionId] = {volumeFloat, volumeLevel};
110     }
111     return volumeFloat;
112 }
113 
GetHistoryVolume(uint32_t sessionId)114 float AudioVolume::GetHistoryVolume(uint32_t sessionId)
115 {
116     Trace trace("AudioVolume::GetHistoryVolume sessionId:" + std::to_string(sessionId));
117     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
118     auto it = historyVolume_.find(sessionId);
119     if (it != historyVolume_.end()) {
120         return it->second;
121     }
122     return 0.0f;
123 }
124 
SetHistoryVolume(uint32_t sessionId, float volume)125 void AudioVolume::SetHistoryVolume(uint32_t sessionId, float volume)
126 {
127     AUDIO_INFO_LOG("history volume, sessionId:%{public}u, volume:%{public}f", sessionId, volume);
128     Trace trace("AudioVolume::SetHistoryVolume sessionId:" + std::to_string(sessionId));
129     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
130     auto it = historyVolume_.find(sessionId);
131     if (it != historyVolume_.end()) {
132         it->second = volume;
133     }
134 }
135 
AddStreamVolume(uint32_t sessionId, int32_t streamType, int32_t streamUsage, int32_t uid, int32_t pid)136 void AudioVolume::AddStreamVolume(uint32_t sessionId, int32_t streamType, int32_t streamUsage,
137     int32_t uid, int32_t pid)
138 {
139     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u", sessionId);
140     std::unique_lock<std::shared_mutex> lock(volumeMutex_);
141     auto it = streamVolume_.find(sessionId);
142     if (it == streamVolume_.end()) {
143         streamVolume_.insert(std::make_pair(sessionId, StreamVolume(sessionId, streamType, streamUsage, uid, pid)));
144         historyVolume_.insert(std::make_pair(sessionId, 0.0f));
145         monitorVolume_.insert(std::make_pair(sessionId, std::make_pair(0.0f, 0)));
146     } else {
147         AUDIO_ERR_LOG("stream volume already exist, sessionId:%{public}u", sessionId);
148     }
149 }
150 
RemoveStreamVolume(uint32_t sessionId)151 void AudioVolume::RemoveStreamVolume(uint32_t sessionId)
152 {
153     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u", sessionId);
154     std::unique_lock<std::shared_mutex> lock(volumeMutex_);
155     auto it = streamVolume_.find(sessionId);
156     if (it != streamVolume_.end()) {
157         streamVolume_.erase(sessionId);
158     } else {
159         AUDIO_ERR_LOG("stream volume already delete, sessionId:%{public}u", sessionId);
160     }
161     auto itHistory = historyVolume_.find(sessionId);
162     if (itHistory != historyVolume_.end()) {
163         historyVolume_.erase(sessionId);
164     }
165     auto itMonitor = monitorVolume_.find(sessionId);
166     if (itMonitor != monitorVolume_.end()) {
167         monitorVolume_.erase(sessionId);
168     }
169 }
170 
SetStreamVolume(uint32_t sessionId, float volume)171 void AudioVolume::SetStreamVolume(uint32_t sessionId, float volume)
172 {
173     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u, volume:%{public}f", sessionId, volume);
174     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
175     auto it = streamVolume_.find(sessionId);
176     if (it != streamVolume_.end()) {
177         it->second.volume_ = volume;
178     } else {
179         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u", sessionId);
180     }
181 }
182 
SetStreamVolumeDuckFactor(uint32_t sessionId, float duckFactor)183 void AudioVolume::SetStreamVolumeDuckFactor(uint32_t sessionId, float duckFactor)
184 {
185     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u, duckFactor:%{public}f", sessionId, duckFactor);
186     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
187     auto it = streamVolume_.find(sessionId);
188     if (it != streamVolume_.end()) {
189         it->second.duckFactor_ = duckFactor;
190     } else {
191         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u", sessionId);
192     }
193 }
194 
SetStreamVolumeLowPowerFactor(uint32_t sessionId, float lowPowerFactor)195 void AudioVolume::SetStreamVolumeLowPowerFactor(uint32_t sessionId, float lowPowerFactor)
196 {
197     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u, lowPowerFactor:%{public}f", sessionId, lowPowerFactor);
198     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
199     auto it = streamVolume_.find(sessionId);
200     if (it != streamVolume_.end()) {
201         it->second.lowPowerFactor_ = lowPowerFactor;
202     } else {
203         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u", sessionId);
204     }
205 }
206 
SetStreamVolumeMute(uint32_t sessionId, bool isMuted)207 void AudioVolume::SetStreamVolumeMute(uint32_t sessionId, bool isMuted)
208 {
209     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u, isMuted:%{public}d", sessionId, isMuted);
210     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
211     auto it = streamVolume_.find(sessionId);
212     if (it != streamVolume_.end()) {
213         it->second.isMuted_ = isMuted;
214     }
215 }
216 
SetStreamVolumeFade(uint32_t sessionId, float fadeBegin, float fadeEnd)217 void AudioVolume::SetStreamVolumeFade(uint32_t sessionId, float fadeBegin, float fadeEnd)
218 {
219     AUDIO_INFO_LOG("stream volume, sessionId:%{public}u, fadeBegin:%{public}f, fadeEnd:%{public}f",
220         sessionId, fadeBegin, fadeEnd);
221     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
222     auto it = streamVolume_.find(sessionId);
223     if (it != streamVolume_.end()) {
224         it->second.fadeBegin_ = fadeBegin;
225         it->second.fadeEnd_ = fadeEnd;
226     } else {
227         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u", sessionId);
228     }
229 }
230 
GetStreamVolumeFade(uint32_t sessionId)231 std::pair<float, float> AudioVolume::GetStreamVolumeFade(uint32_t sessionId)
232 {
233     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
234     auto it = streamVolume_.find(sessionId);
235     if (it != streamVolume_.end()) {
236         return {it->second.fadeBegin_, it->second.fadeEnd_};
237     } else {
238         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u", sessionId);
239     }
240     return {1.0f, 1.0f};
241 }
242 
SetSystemVolume(SystemVolume &systemVolume)243 void AudioVolume::SetSystemVolume(SystemVolume &systemVolume)
244 {
245     auto volumeType = systemVolume.GetVolumeType();
246     auto deviceClass = systemVolume.GetDeviceClass();
247     std::string key = std::to_string(volumeType) + deviceClass;
248     auto it = systemVolume_.find(key);
249     if (it != systemVolume_.end()) {
250         it->second.volume_ = systemVolume.volume_;
251         it->second.volumeLevel_ = systemVolume.volumeLevel_;
252         it->second.isMuted_ = systemVolume.isMuted_;
253     } else {
254         systemVolume_.insert(std::make_pair(key, systemVolume));
255     }
256     AUDIO_INFO_LOG("system volume, volumeType:%{public}d, deviceClass:%{public}s,"
257         " volume:%{public}f, volumeLevel:%{public}d, isMuted:%{public}d, systemVolumeSize:%{public}zu",
258         volumeType, deviceClass.c_str(), systemVolume.volume_, systemVolume.volumeLevel_, systemVolume.isMuted_,
259         systemVolume_.size());
260 }
261 
SetSystemVolume(int32_t volumeType, const std::string &deviceClass, float volume, int32_t volumeLevel)262 void AudioVolume::SetSystemVolume(int32_t volumeType, const std::string &deviceClass, float volume, int32_t volumeLevel)
263 {
264     std::string key = std::to_string(volumeType) + deviceClass;
265     auto it = systemVolume_.find(key);
266     if (it != systemVolume_.end()) {
267         it->second.volume_ = volume;
268         it->second.volumeLevel_ = volumeLevel;
269     } else {
270         SystemVolume systemVolume(volumeType, deviceClass);
271         systemVolume.volume_ = volume;
272         systemVolume.volumeLevel_ = volumeLevel;
273         systemVolume_.insert(std::make_pair(key, systemVolume));
274     }
275     AUDIO_INFO_LOG("system volume, volumeType:%{public}d, deviceClass:%{public}s,"
276         " volume:%{public}f, volumeLevel:%{public}d, systemVolumeSize:%{public}zu",
277         volumeType, deviceClass.c_str(), volume, volumeLevel, systemVolume_.size());
278 }
279 
SetSystemVolumeMute(int32_t volumeType, const std::string &deviceClass, bool isMuted)280 void AudioVolume::SetSystemVolumeMute(int32_t volumeType, const std::string &deviceClass, bool isMuted)
281 {
282     AUDIO_INFO_LOG("system volume, volumeType:%{public}d, deviceClass:%{public}s, isMuted:%{public}d",
283         volumeType, deviceClass.c_str(), isMuted);
284     std::string key = std::to_string(volumeType) + deviceClass;
285     auto it = systemVolume_.find(key);
286     if (it != systemVolume_.end()) {
287         it->second.isMuted_ = isMuted;
288     } else {
289         SystemVolume systemVolume(volumeType, deviceClass);
290         systemVolume.isMuted_ = isMuted;
291         systemVolume_.insert(std::make_pair(key, systemVolume));
292     }
293 }
294 
ConvertStreamTypeStrToInt(const std::string &streamType)295 int32_t AudioVolume::ConvertStreamTypeStrToInt(const std::string &streamType)
296 {
297     AudioStreamType stream = STREAM_MUSIC;
298     if (STREAM_TYPE_STRING_ENUM_MAP.find(streamType) != STREAM_TYPE_STRING_ENUM_MAP.end()) {
299         stream = STREAM_TYPE_STRING_ENUM_MAP.at(streamType);
300     } else {
301         AUDIO_WARNING_LOG("Invalid stream type [%{public}s]. Use default type", streamType.c_str());
302     }
303     return stream;
304 }
305 
IsSameVolume(float x, float y)306 bool AudioVolume::IsSameVolume(float x, float y)
307 {
308     return (std::abs((x) - (y)) <= std::abs(FLOAT_EPS));
309 }
310 
Dump(std::string &dumpString)311 void AudioVolume::Dump(std::string &dumpString)
312 {
313     AUDIO_INFO_LOG("AudioVolume dump begin");
314     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
315     // dump system volume
316     std::vector<SystemVolume> systemVolumeList;
317     for (auto &systemVolume : systemVolume_) {
318         systemVolumeList.push_back(systemVolume.second);
319     }
320     std::sort(systemVolumeList.begin(), systemVolumeList.end(), [](SystemVolume &a, SystemVolume &b) {
321         return a.GetVolumeType() < b.GetVolumeType();
322     });
323     AppendFormat(dumpString, "\n  - audio system volume size: %zu\n", systemVolumeList.size());
324     for (auto &systemVolume : systemVolumeList) {
325         AppendFormat(dumpString, "  streamtype: %d ", systemVolume.GetVolumeType());
326         AppendFormat(dumpString, "  isMute: %s ", (systemVolume.isMuted_ ? "true" : "false"));
327         AppendFormat(dumpString, "  volFloat: %f ", systemVolume.volume_);
328         AppendFormat(dumpString, "  volInt: %d ", systemVolume.volumeLevel_);
329         AppendFormat(dumpString, "  device class: %s \n", systemVolume.GetDeviceClass().c_str());
330     }
331 
332     // dump stream volume
333     std::vector<StreamVolume> streamVolumeList;
334     for (auto &streamVolume : streamVolume_) {
335         streamVolumeList.push_back(streamVolume.second);
336     }
337     std::sort(streamVolumeList.begin(), streamVolumeList.end(), [](StreamVolume &a, StreamVolume &b) {
338         return a.GetSessionId() < b.GetSessionId();
339     });
340     AppendFormat(dumpString, "\n  - audio stream volume size: %zu, his volume size: %zu, mon volume size: %zu\n",
341         streamVolumeList.size(), historyVolume_.size(), monitorVolume_.size());
342     for (auto &streamVolume : streamVolumeList) {
343         auto monVol = monitorVolume_.find(streamVolume.GetSessionId());
344         AppendFormat(dumpString, "  sessionId: %u ", streamVolume.GetSessionId());
345         AppendFormat(dumpString, "  streamType: %d ", streamVolume.GetStreamType());
346         AppendFormat(dumpString, "  streamUsage: %d ", streamVolume.GetStreamUsage());
347         AppendFormat(dumpString, "  appUid: %d ", streamVolume.GetAppUid());
348         AppendFormat(dumpString, "  appPid: %d ", streamVolume.GetAppPid());
349         AppendFormat(dumpString, "  volume: %f ", monVol != monitorVolume_.end() ? monVol->second.first : 0.0f);
350         AppendFormat(dumpString, "  volumeLevel: %d ",  monVol != monitorVolume_.end() ? monVol->second.second : 0);
351         AppendFormat(dumpString, "  volFactor: %f ", streamVolume.volume_);
352         AppendFormat(dumpString, "  duckFactor: %f ", streamVolume.duckFactor_);
353         AppendFormat(dumpString, "  powerFactor: %f ", streamVolume.lowPowerFactor_);
354         AppendFormat(dumpString, "  fadeBegin: %f ", streamVolume.fadeBegin_);
355         AppendFormat(dumpString, "  fadeEnd: %f \n", streamVolume.fadeEnd_);
356     }
357 }
358 
Monitor(uint32_t sessionId, bool isOutput)359 void AudioVolume::Monitor(uint32_t sessionId, bool isOutput)
360 {
361     std::shared_lock<std::shared_mutex> lock(volumeMutex_);
362     auto streamVolume = streamVolume_.find(sessionId);
363     if (streamVolume != streamVolume_.end()) {
364         auto monVol = monitorVolume_.find(sessionId);
365         std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
366             Media::MediaMonitor::AUDIO, Media::MediaMonitor::VOLUME_CHANGE,
367             Media::MediaMonitor::BEHAVIOR_EVENT);
368         bean->Add("ISOUTPUT", isOutput ? 1 : 0);
369         bean->Add("STREAMID", static_cast<int32_t>(sessionId));
370         bean->Add("APP_UID", streamVolume->second.GetAppUid());
371         bean->Add("APP_PID", streamVolume->second.GetAppPid());
372         bean->Add("STREAMTYPE", streamVolume->second.GetStreamType());
373         bean->Add("STREAM_TYPE", streamVolume->second.GetStreamUsage());
374         bean->Add("VOLUME", monVol != monitorVolume_.end() ? monVol->second.first : 0.0f);
375         bean->Add("SYSVOLUME", monVol != monitorVolume_.end() ? monVol->second.second : 0);
376         bean->Add("VOLUMEFACTOR", streamVolume->second.volume_);
377         bean->Add("POWERVOLUMEFACTOR", streamVolume->second.lowPowerFactor_);
378         Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
379     } else {
380         AUDIO_ERR_LOG("stream volume not exist, sessionId:%{public}u", sessionId);
381     }
382 }
383 } // namespace AudioStandard
384 } // namespace OHOS
385 
386 #ifdef __cplusplus
387 extern "C" {
388 #endif
389 using namespace OHOS::AudioStandard;
390 
GetCurVolume(uint32_t sessionId, const char *streamType, const char *deviceClass)391 float GetCurVolume(uint32_t sessionId, const char *streamType, const char *deviceClass)
392 {
393     CHECK_AND_RETURN_RET_LOG(streamType != nullptr, 1.0f, "streamType is nullptr");
394     CHECK_AND_RETURN_RET_LOG(deviceClass != nullptr, 1.0f, "deviceClass is nullptr");
395     int32_t stream = AudioVolume::GetInstance()->ConvertStreamTypeStrToInt(streamType);
396     AudioStreamType volumeType = VolumeUtils::GetVolumeTypeFromStreamType(static_cast<AudioStreamType>(stream));
397     return AudioVolume::GetInstance()->GetVolume(sessionId, volumeType, deviceClass);
398 }
399 
GetPreVolume(uint32_t sessionId)400 float GetPreVolume(uint32_t sessionId)
401 {
402     return AudioVolume::GetInstance()->GetHistoryVolume(sessionId);
403 }
404 
SetPreVolume(uint32_t sessionId, float volume)405 void SetPreVolume(uint32_t sessionId, float volume)
406 {
407     AudioVolume::GetInstance()->SetHistoryVolume(sessionId, volume);
408 }
409 
GetStreamVolumeFade(uint32_t sessionId, float *fadeBegin, float *fadeEnd)410 void GetStreamVolumeFade(uint32_t sessionId, float *fadeBegin, float *fadeEnd)
411 {
412     auto fade = AudioVolume::GetInstance()->GetStreamVolumeFade(sessionId);
413     *fadeBegin = fade.first;
414     *fadeEnd = fade.second;
415 }
416 
SetStreamVolumeFade(uint32_t sessionId, float fadeBegin, float fadeEnd)417 void SetStreamVolumeFade(uint32_t sessionId, float fadeBegin, float fadeEnd)
418 {
419     AudioVolume::GetInstance()->SetStreamVolumeFade(sessionId, fadeBegin, fadeEnd);
420 }
421 
IsSameVolume(float x, float y)422 bool IsSameVolume(float x, float y)
423 {
424     return AudioVolume::GetInstance()->IsSameVolume(x, y);
425 }
426 
MonitorVolume(uint32_t sessionId, bool isOutput)427 void MonitorVolume(uint32_t sessionId, bool isOutput)
428 {
429     AudioVolume::GetInstance()->Monitor(sessionId, isOutput);
430 }
431 #ifdef __cplusplus
432 }
433 #endif