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 #ifndef LOG_TAG
16 #define LOG_TAG "VolumeRamp"
17 #endif
18 
19 #include "volume_ramp.h"
20 #include <cinttypes>
21 #include "audio_common_log.h"
22 
23 namespace OHOS {
24 namespace AudioStandard {
25 using namespace std;
26 constexpr float MIN_CURVE_TIME = 0.0f;
27 constexpr float MAX_CURVE_TIME = 1.0f;
28 constexpr int32_t MS_PER_S = 1000;
29 constexpr int32_t NS_PER_MS = 1000000;
30 constexpr unsigned long VOLUME_SIZE = 2;
31 
VolumeRamp()32 VolumeRamp::VolumeRamp()
33 {
34     initTime_ = -1;
35     isVolumeRampActive_ = false;
36     rampVolume_ = 1.0f;
37 }
38 
SetVolumeCurve(vector<float> & volumes)39 void VolumeRamp::SetVolumeCurve(vector<float> &volumes)
40 {
41     vector<float> times = {0.0f, 1.0f};
42     CHECK_AND_RETURN_LOG(volumes.size() == VOLUME_SIZE, "Array size must 2!");
43 
44     std::lock_guard<std::mutex> lock(curveMapMutex_);
45     curvePoints_.clear();
46     for (size_t i = 0; i < times.size(); i++) {
47         curvePoints_.emplace(times[i], volumes[i]);
48     }
49 }
50 
SetVolumeRampConfig(float targetVolume,float currStreamVolume,int32_t duration)51 void VolumeRamp::SetVolumeRampConfig(float targetVolume, float currStreamVolume, int32_t duration)
52 {
53     vector<float> volumes;
54 
55     isVolumeRampActive_ = true;
56     initTime_ = -1;
57     duration_ = duration;
58 
59     if (currStreamVolume > targetVolume) {
60         volumes.assign({targetVolume, currStreamVolume});
61         rampDirection_ = RAMP_DOWN;
62     } else {
63         volumes.assign({currStreamVolume, targetVolume});
64         rampDirection_ = RAMP_UP;
65     }
66     SetVolumeCurve(volumes);
67 }
68 
GetCurrentTimeMS()69 static int64_t GetCurrentTimeMS()
70 {
71     timespec tm {};
72     clock_gettime(CLOCK_MONOTONIC, &tm);
73     return tm.tv_sec * MS_PER_S + (tm.tv_nsec / NS_PER_MS);
74 }
75 
GetRampVolume()76 float VolumeRamp::GetRampVolume()
77 {
78     if (!isVolumeRampActive_) {
79         return rampVolume_;
80     }
81 
82     int64_t currentTime = GetCurrentTimeMS();
83 
84     if (initTime_ < 0) {
85         initTime_ = currentTime;
86         scale_ = 1.0 / duration_;
87     }
88 
89     float scaledTime = GetScaledTime(currentTime);
90     rampVolume_ = FindRampVolume(scaledTime);
91     return rampVolume_;
92 }
93 
GetScaledTime(int64_t currentTime)94 float VolumeRamp::GetScaledTime(int64_t currentTime)
95 {
96     float offset = scale_ * (currentTime - initTime_);
97     if (rampDirection_ == RAMP_DOWN) {
98         offset =  1 - offset;
99         if (offset < MIN_CURVE_TIME) {
100             offset = MIN_CURVE_TIME;
101             isVolumeRampActive_ = false;
102         } else if (offset > MAX_CURVE_TIME) {
103             offset = MAX_CURVE_TIME;
104         }
105     } else {
106         if (offset < MIN_CURVE_TIME) {
107             offset = MIN_CURVE_TIME;
108         } else if (offset > MAX_CURVE_TIME) {
109             offset = MAX_CURVE_TIME;
110             isVolumeRampActive_ = false;
111         }
112     }
113 
114     return offset;
115 }
116 
FindRampVolume(float time)117 float VolumeRamp::FindRampVolume(float time)
118 {
119     std::lock_guard<std::mutex> lock(curveMapMutex_);
120     CHECK_AND_RETURN_RET_LOG(!curvePoints_.empty(), 0.0f, "Curve points map is empty");
121 
122     auto lowPoint = curvePoints_.begin();
123     auto highPoint = curvePoints_.rbegin();
124 
125     float volume = lowPoint->second + ((time - lowPoint->first) / (highPoint->first - lowPoint->first))
126         * (highPoint->second - lowPoint->second);
127     return volume;
128 }
129 
IsActive()130 bool VolumeRamp::IsActive()
131 {
132     return isVolumeRampActive_;
133 }
134 
Terminate()135 void VolumeRamp::Terminate()
136 {
137     isVolumeRampActive_ = false;
138 }
139 } // namespace AudioStandard
140 } // namespace OHOS
141