Rearrange code to stop all client
[platform/core/uifw/tts.git] / server / BackgroundVolume.cpp
1 /*
2 *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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 *  http://www.apache.org/licenses/LICENSE-2.0
7 *  Unless required by applicable law or agreed to in writing, software
8 *  distributed under the License is distributed on an "AS IS" BASIS,
9 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 *  See the License for the specific language governing permissions and
11 *  limitations under the License.
12 */
13
14 #include "ttsd_main.h"
15
16 #include "BackgroundVolume.h"
17
18
19 using namespace std;
20
21 static const char* __get_ducking_stream(sound_stream_type_e stream_type)
22 {
23         switch (stream_type)
24         {
25         case SOUND_STREAM_TYPE_MEDIA:
26                 return "Media stream";
27         case SOUND_STREAM_TYPE_NOTIFICATION:
28                 return "Notification stream";
29         case SOUND_STREAM_TYPE_ALARM:
30                 return "Alarm stream";
31
32         default:
33                 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] Type is not handled. type(%d)", stream_type);
34                 break;
35         }
36
37         return "Non matched stream";
38 }
39
40 static void __sound_stream_ducking_state_changed_cb(sound_stream_ducking_h stream_ducking, bool is_ducked, void *user_data)
41 {
42         SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] is ducked : %d", is_ducked);
43         return;
44 }
45
46 BackgroundVolume::BackgroundVolume(long long int duckingDuration):
47                 __duckingDuration(duckingDuration), __mediaStream(nullptr), __notificationStream(nullptr), __alarmStream(nullptr),
48                 __postponedRecoverTimer(nullptr), __postponedModifyTimer(nullptr)
49 {
50         int ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_MEDIA, __sound_stream_ducking_state_changed_cb, nullptr, &__mediaStream);
51         if (SOUND_MANAGER_ERROR_NONE != ret)
52                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to create stream ducking for type media, ret(%d)", ret);
53
54         ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_NOTIFICATION, __sound_stream_ducking_state_changed_cb, nullptr, &__notificationStream);
55         if (SOUND_MANAGER_ERROR_NONE != ret)
56                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to create stream ducking for notification type, ret(%d)", ret);
57
58         ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_ALARM, __sound_stream_ducking_state_changed_cb, nullptr, &__alarmStream);
59         if (SOUND_MANAGER_ERROR_NONE != ret)
60                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to create stream ducking for alarm type, ret(%d)", ret);
61
62         __isVolumeDucked = false;
63         __volumeRatio = 0.0;
64 }
65
66 BackgroundVolume::~BackgroundVolume()
67 {
68         long long int diff = getDurationAfterDucking();
69         if (diff < __duckingDuration) {
70                 usleep(__duckingDuration * 1000);
71         }
72
73         deactivateDuckingAll();
74
75         if (nullptr != __postponedModifyTimer) {
76                 void* result = ecore_timer_del(__postponedModifyTimer);
77                 __postponedModifyTimer = nullptr;
78                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove modification timer. result(%p)", result);
79         }
80
81         if (nullptr != __postponedRecoverTimer) {
82                 void* result = ecore_timer_del(__postponedRecoverTimer);
83                 __postponedRecoverTimer = nullptr;
84                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove recover timer. result(%p)", result);
85         }
86
87         if (__mediaStream) {
88                 int ret = sound_manager_destroy_stream_ducking(__mediaStream);
89                 if (SOUND_MANAGER_ERROR_NONE != ret)
90                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to destroy media stream ducking, ret(%d)", ret);
91                 __mediaStream = nullptr;
92         } else {
93                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for media stream is already destroyed");
94         }
95
96         if (__notificationStream) {
97                 int ret = sound_manager_destroy_stream_ducking(__notificationStream);
98                 if (SOUND_MANAGER_ERROR_NONE != ret)
99                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to destroy notification stream ducking, ret(%d)", ret);
100                 __notificationStream = nullptr;
101         } else {
102                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for notification stream is already destroyed");
103         }
104
105         if (__alarmStream) {
106                 int ret = sound_manager_destroy_stream_ducking(__alarmStream);
107                 if (SOUND_MANAGER_ERROR_NONE != ret)
108                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to destroy alarm stream ducking, ret(%d)", ret);
109                 __alarmStream = nullptr;
110         } else {
111                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for alarm stream is already destroyed");
112         }
113 }
114
115 void BackgroundVolume::setVolumeRatio(double ratio)
116 {
117         if (__volumeRatio.load() == ratio) {
118                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume is not changed (%lf).", ratio);
119                 return;
120         }
121
122         __volumeRatio = ratio;
123         ecore_main_loop_thread_safe_call_async(modifyVolumeOnMainThread, static_cast<void*>(this));
124 }
125
126 void BackgroundVolume::modifyVolumeOnMainThread(void* data)
127 {
128         if (nullptr == data) {
129                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
130                 return;
131         }
132
133         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
134         if (!backgroundVolume->__isVolumeDucked.load()) {
135                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume is not changed yet.");
136                 return;
137         }
138
139         if (backgroundVolume->__postponedModifyTimer != nullptr) {
140                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Reserved volume modification exist. (%p)", backgroundVolume->__postponedModifyTimer);
141                 return;
142         }
143
144         long long int diff = backgroundVolume->getDurationAfterDucking();
145         if (diff >= backgroundVolume->__duckingDuration) {
146                 double ratio = backgroundVolume->__volumeRatio.load();
147                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Modify volume ratio(%lf) directly", ratio);
148
149                 backgroundVolume->deactivateDuckingAll();
150                 backgroundVolume->activateDuckingAll(0, ratio);
151         } else {
152                 double delay = static_cast<double>(backgroundVolume->__duckingDuration - diff) / 1000.0;
153                 backgroundVolume->__postponedModifyTimer = ecore_timer_add(delay, postponedModifyTimerCb, data);
154                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delay volume modification (%p), delay(%lf)", backgroundVolume->__postponedModifyTimer, delay);
155         }
156 }
157
158 Eina_Bool BackgroundVolume::postponedModifyTimerCb(void* data)
159 {
160         if (nullptr == data) {
161                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
162                 return EINA_FALSE;
163         }
164
165         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
166         double ratio = backgroundVolume->__volumeRatio.load();
167         backgroundVolume->deactivateDuckingAll();
168         backgroundVolume->activateDuckingAll(0, ratio);
169
170         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delayed volume modification success. ratio(%lf)", ratio);
171         backgroundVolume->__postponedModifyTimer = nullptr;
172         return EINA_FALSE;
173 }
174
175 double BackgroundVolume::getVolumeRatio()
176 {
177         return __volumeRatio.load();
178 }
179
180 void BackgroundVolume::applyVolumeRatio()
181 {
182         __isVolumeDucked = true;
183         ecore_main_loop_thread_safe_call_async(changeVolumeOnMainThread, static_cast<void*>(this));
184 }
185
186 void BackgroundVolume::changeVolumeOnMainThread(void* data)
187 {
188         if (nullptr == data) {
189                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
190                 return;
191         }
192
193         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
194         if (nullptr != backgroundVolume->__postponedRecoverTimer) {
195                 void* result = ecore_timer_del(backgroundVolume->__postponedRecoverTimer);
196                 backgroundVolume->__postponedRecoverTimer = nullptr;
197                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove recover timer. result(%p)", result);
198         }
199
200         double ratio = backgroundVolume->__volumeRatio.load();
201         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume ratio(%lf)", ratio);
202         if (0.0 > ratio || 1.0 < ratio) {
203                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid ratio(%lf)", ratio);
204                 return;
205         }
206
207         backgroundVolume->activateDuckingAll(backgroundVolume->__duckingDuration, ratio);
208 }
209
210 void BackgroundVolume::activateDuckingAll(unsigned int duration, double ratio)
211 {
212         activateDucking(SOUND_STREAM_TYPE_MEDIA, duration, ratio);
213         activateDucking(SOUND_STREAM_TYPE_NOTIFICATION, duration, ratio);
214         activateDucking(SOUND_STREAM_TYPE_ALARM, duration, ratio);
215
216         __changeVolumeTime = chrono::steady_clock::now();
217 }
218
219 bool BackgroundVolume::activateDucking(sound_stream_type_e type, unsigned int duration, double ratio)
220 {
221         bool isDucked = false;
222         sound_stream_ducking_h handle = getStreamDuckingHandle(type);
223         sound_manager_is_ducked(handle, &isDucked);
224         if (isDucked) {
225                 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] The %s is already ducked", __get_ducking_stream(type));
226                 return false;
227         }
228
229         if (SOUND_MANAGER_ERROR_NONE != sound_manager_activate_ducking(handle, duration, ratio)) {
230                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to activate ducking for %s", __get_ducking_stream(type));
231                 return false;
232         }
233
234         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Activate ducking for %s", __get_ducking_stream(type));
235         return true;
236 }
237
238 void BackgroundVolume::recoverVolumeRatio()
239 {
240         __isVolumeDucked = false;
241         ecore_main_loop_thread_safe_call_async(recoverVolumeOnMainThread, static_cast<void*>(this));
242 }
243
244 void BackgroundVolume::recoverVolumeOnMainThread(void* data)
245 {
246         if (nullptr == data) {
247                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
248                 return;
249         }
250
251         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
252         if (nullptr != backgroundVolume->__postponedRecoverTimer) {
253                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Reserved volume recover exist. (%p)", backgroundVolume->__postponedRecoverTimer);
254                 return;
255         }
256
257         if (nullptr != backgroundVolume->__postponedModifyTimer) {
258                 void* result = ecore_timer_del(backgroundVolume->__postponedModifyTimer);
259                 backgroundVolume->__postponedModifyTimer = nullptr;
260                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove modification timer. result(%p)", result);
261         }
262
263         long long int diff = backgroundVolume->getDurationAfterDucking();
264         if (diff >= backgroundVolume->__duckingDuration) {
265                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Direct deactivate ducking");
266
267                 backgroundVolume->deactivateDuckingAll();
268         } else {
269                 double delay = static_cast<double>(backgroundVolume->__duckingDuration - diff) / 1000.0;
270                 backgroundVolume->__postponedRecoverTimer = ecore_timer_add(delay, postponedRecoverTimerCb, data);
271                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delay deactivate ducking (%p), delay(%f)", backgroundVolume->__postponedRecoverTimer, delay);
272         }
273 }
274
275 long long int BackgroundVolume::getDurationAfterDucking()
276 {
277         auto currentTime = chrono::steady_clock::now();
278         chrono::milliseconds diff = chrono::duration_cast<chrono::milliseconds>(currentTime - __changeVolumeTime);
279
280         return diff.count();
281 }
282
283 void BackgroundVolume::deactivateDuckingAll()
284 {
285         deactivateDucking(SOUND_STREAM_TYPE_MEDIA);
286         deactivateDucking(SOUND_STREAM_TYPE_NOTIFICATION);
287         deactivateDucking(SOUND_STREAM_TYPE_ALARM);
288 }
289
290 Eina_Bool BackgroundVolume::postponedRecoverTimerCb(void* data)
291 {
292         if (nullptr == data) {
293                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
294                 return EINA_FALSE;
295         }
296
297         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
298         backgroundVolume->deactivateDuckingAll();
299         backgroundVolume->__postponedRecoverTimer = nullptr;
300
301         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delayed unset policy success");
302         return EINA_FALSE;
303 }
304
305 void BackgroundVolume::deactivateDucking(sound_stream_type_e type)
306 {
307         bool isDucked = false;
308         sound_stream_ducking_h handle = getStreamDuckingHandle(type);
309         sound_manager_is_ducked(handle, &isDucked);
310         if (!isDucked) {
311                 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] The %s is already recovered from ducking", __get_ducking_stream(type));
312                 return;
313         }
314
315         if (SOUND_MANAGER_ERROR_NONE != sound_manager_deactivate_ducking(handle)) {
316                 SLOG(LOG_WARN, tts_tag(), "[BackgroundVolume] Fail to deactivate ducking for %s", __get_ducking_stream(type));
317         } else {
318                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Deactivate ducking for %s", __get_ducking_stream(type));
319         }
320 }
321
322 sound_stream_ducking_h BackgroundVolume::getStreamDuckingHandle(sound_stream_type_e type)
323 {
324         switch (type)
325         {
326         case SOUND_STREAM_TYPE_MEDIA:
327                 return __mediaStream;
328         case SOUND_STREAM_TYPE_NOTIFICATION:
329                 return __notificationStream;
330         case SOUND_STREAM_TYPE_ALARM:
331                 return __alarmStream;
332
333         default:
334                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid stream type (%d)", type);
335                 break;
336         }
337
338         return nullptr;
339 }