Check and try to recreate the handle if the handle is invalid
[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),
48         __mediaStream(nullptr),
49         __notificationStream(nullptr),
50         __alarmStream(nullptr),
51         __volumeRatio(0.0),
52         __isVolumeDucked(false),
53         __changeVolumeTime(chrono::steady_clock::now()),
54         __postponedRecoverTimer(nullptr),
55         __postponedModifyTimer(nullptr)
56 {
57         int ret = createHandles();
58         if (TTSD_ERROR_NONE != ret) {
59                 SLOG(LOG_WARN, tts_tag(), "[BackgroundVolume] Fail to create handles.");
60         }
61 }
62
63 BackgroundVolume::~BackgroundVolume()
64 {
65         long long int diff = getDurationAfterDucking();
66         if (diff < __duckingDuration) {
67                 usleep(__duckingDuration * 1000);
68         }
69
70         deactivateDuckingAll();
71
72         if (nullptr != __postponedModifyTimer) {
73                 void* result = ecore_timer_del(__postponedModifyTimer);
74                 __postponedModifyTimer = nullptr;
75                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove modification timer. result(%p)", result);
76         }
77
78         if (nullptr != __postponedRecoverTimer) {
79                 void* result = ecore_timer_del(__postponedRecoverTimer);
80                 __postponedRecoverTimer = nullptr;
81                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove recover timer. result(%p)", result);
82         }
83
84         if (__mediaStream) {
85                 int ret = sound_manager_destroy_stream_ducking(__mediaStream);
86                 if (SOUND_MANAGER_ERROR_NONE != ret)
87                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to destroy media stream ducking, ret(%d)", ret);
88                 __mediaStream = nullptr;
89         } else {
90                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for media stream is already destroyed");
91         }
92
93         if (__notificationStream) {
94                 int ret = sound_manager_destroy_stream_ducking(__notificationStream);
95                 if (SOUND_MANAGER_ERROR_NONE != ret)
96                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to destroy notification stream ducking, ret(%d)", ret);
97                 __notificationStream = nullptr;
98         } else {
99                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for notification stream is already destroyed");
100         }
101
102         if (__alarmStream) {
103                 int ret = sound_manager_destroy_stream_ducking(__alarmStream);
104                 if (SOUND_MANAGER_ERROR_NONE != ret)
105                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to destroy alarm stream ducking, ret(%d)", ret);
106                 __alarmStream = nullptr;
107         } else {
108                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for alarm stream is already destroyed");
109         }
110 }
111
112 void BackgroundVolume::setVolumeRatio(double ratio)
113 {
114         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume is changed from (%lf) to (%lf).", __volumeRatio.load(), ratio);
115         __volumeRatio = ratio;
116         ecore_main_loop_thread_safe_call_async(modifyVolumeOnMainThread, static_cast<void*>(this));
117 }
118
119 void BackgroundVolume::modifyVolumeOnMainThread(void* data)
120 {
121         if (nullptr == data) {
122                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
123                 return;
124         }
125
126         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
127         if (!backgroundVolume->__isVolumeDucked.load()) {
128                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume is not changed yet.");
129                 return;
130         }
131
132         if (backgroundVolume->__postponedModifyTimer != nullptr) {
133                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Reserved volume modification exist. (%p)", backgroundVolume->__postponedModifyTimer);
134                 return;
135         }
136
137         long long int diff = backgroundVolume->getDurationAfterDucking();
138         if (diff >= backgroundVolume->__duckingDuration) {
139                 double ratio = backgroundVolume->__volumeRatio.load();
140                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Modify volume ratio(%lf) directly", ratio);
141
142                 backgroundVolume->deactivateDuckingAll();
143                 backgroundVolume->activateDuckingAll(0, ratio);
144         } else {
145                 double delay = static_cast<double>(backgroundVolume->__duckingDuration - diff) / 1000.0;
146                 backgroundVolume->__postponedModifyTimer = ecore_timer_add(delay, postponedModifyTimerCb, data);
147                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delay volume modification (%p), delay(%lf)", backgroundVolume->__postponedModifyTimer, delay);
148         }
149 }
150
151 Eina_Bool BackgroundVolume::postponedModifyTimerCb(void* data)
152 {
153         if (nullptr == data) {
154                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
155                 return EINA_FALSE;
156         }
157
158         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
159         double ratio = backgroundVolume->__volumeRatio.load();
160         backgroundVolume->deactivateDuckingAll();
161         backgroundVolume->activateDuckingAll(0, ratio);
162
163         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delayed volume modification success. ratio(%lf)", ratio);
164         backgroundVolume->__postponedModifyTimer = nullptr;
165         return EINA_FALSE;
166 }
167
168 double BackgroundVolume::getVolumeRatio()
169 {
170         return __volumeRatio.load();
171 }
172
173 void BackgroundVolume::applyVolumeRatio()
174 {
175         __isVolumeDucked = true;
176         ecore_main_loop_thread_safe_call_async(changeVolumeOnMainThread, static_cast<void*>(this));
177 }
178
179 void BackgroundVolume::changeVolumeOnMainThread(void* data)
180 {
181         if (nullptr == data) {
182                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
183                 return;
184         }
185
186         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
187         if (nullptr != backgroundVolume->__postponedRecoverTimer) {
188                 void* result = ecore_timer_del(backgroundVolume->__postponedRecoverTimer);
189                 backgroundVolume->__postponedRecoverTimer = nullptr;
190                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove recover timer. result(%p)", result);
191         }
192
193         double ratio = backgroundVolume->__volumeRatio.load();
194         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume ratio(%lf)", ratio);
195         if (0.0 > ratio || 1.0 < ratio) {
196                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid ratio(%lf)", ratio);
197                 return;
198         }
199
200         backgroundVolume->activateDuckingAll(backgroundVolume->__duckingDuration, ratio);
201 }
202
203 void BackgroundVolume::activateDuckingAll(unsigned int duration, double ratio)
204 {
205         if (false == isDuckingHandleValid()) {
206                 SLOG(LOG_WARN, tts_tag(), "[BackgroundVolume] There are some invalid handles. Try to recreate the hnadles");
207                 int ret = createHandles();
208                 if (TTSD_ERROR_NONE != ret) {
209                         SLOG(LOG_WARN, tts_tag(), "[BackgroundVolume] Fail to create handles. Skip ducking activation.");
210                         return;
211                 }
212         }
213
214         activateDucking(SOUND_STREAM_TYPE_MEDIA, duration, ratio);
215         activateDucking(SOUND_STREAM_TYPE_NOTIFICATION, duration, ratio);
216         activateDucking(SOUND_STREAM_TYPE_ALARM, duration, ratio);
217
218         __changeVolumeTime = chrono::steady_clock::now();
219 }
220
221 bool BackgroundVolume::activateDucking(sound_stream_type_e type, unsigned int duration, double ratio)
222 {
223         bool isDucked = false;
224         sound_stream_ducking_h handle = getStreamDuckingHandle(type);
225         sound_manager_is_ducked(handle, &isDucked);
226         if (isDucked) {
227                 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] The %s is already ducked", __get_ducking_stream(type));
228                 return false;
229         }
230
231         if (SOUND_MANAGER_ERROR_NONE != sound_manager_activate_ducking(handle, duration, ratio)) {
232                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to activate ducking for %s", __get_ducking_stream(type));
233                 return false;
234         }
235
236         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Activate ducking for %s", __get_ducking_stream(type));
237         return true;
238 }
239
240 void BackgroundVolume::recoverVolumeRatio()
241 {
242         __isVolumeDucked = false;
243         ecore_main_loop_thread_safe_call_async(recoverVolumeOnMainThread, static_cast<void*>(this));
244 }
245
246 void BackgroundVolume::recoverVolumeOnMainThread(void* data)
247 {
248         if (nullptr == data) {
249                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
250                 return;
251         }
252
253         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
254         if (nullptr != backgroundVolume->__postponedRecoverTimer) {
255                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Reserved volume recover exist. (%p)", backgroundVolume->__postponedRecoverTimer);
256                 return;
257         }
258
259         if (nullptr != backgroundVolume->__postponedModifyTimer) {
260                 void* result = ecore_timer_del(backgroundVolume->__postponedModifyTimer);
261                 backgroundVolume->__postponedModifyTimer = nullptr;
262                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Remove modification timer. result(%p)", result);
263         }
264
265         long long int diff = backgroundVolume->getDurationAfterDucking();
266         if (diff >= backgroundVolume->__duckingDuration) {
267                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Direct deactivate ducking");
268
269                 backgroundVolume->deactivateDuckingAll();
270         } else {
271                 double delay = static_cast<double>(backgroundVolume->__duckingDuration - diff) / 1000.0;
272                 backgroundVolume->__postponedRecoverTimer = ecore_timer_add(delay, postponedRecoverTimerCb, data);
273                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delay deactivate ducking (%p), delay(%f)", backgroundVolume->__postponedRecoverTimer, delay);
274         }
275 }
276
277 long long int BackgroundVolume::getDurationAfterDucking()
278 {
279         auto currentTime = chrono::steady_clock::now();
280         chrono::milliseconds diff = chrono::duration_cast<chrono::milliseconds>(currentTime - __changeVolumeTime);
281
282         return diff.count();
283 }
284
285 void BackgroundVolume::deactivateDuckingAll()
286 {
287         if (false == isDuckingHandleValid()) {
288                 SLOG(LOG_WARN, tts_tag(), "[BackgroundVolume] There are some invalid handles. Skip ducking deactivation.");
289                 return;
290         }
291
292         deactivateDucking(SOUND_STREAM_TYPE_MEDIA);
293         deactivateDucking(SOUND_STREAM_TYPE_NOTIFICATION);
294         deactivateDucking(SOUND_STREAM_TYPE_ALARM);
295 }
296
297 Eina_Bool BackgroundVolume::postponedRecoverTimerCb(void* data)
298 {
299         if (nullptr == data) {
300                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
301                 return EINA_FALSE;
302         }
303
304         BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
305         backgroundVolume->deactivateDuckingAll();
306         backgroundVolume->__postponedRecoverTimer = nullptr;
307
308         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delayed unset policy success");
309         return EINA_FALSE;
310 }
311
312 void BackgroundVolume::deactivateDucking(sound_stream_type_e type)
313 {
314         bool isDucked = false;
315         sound_stream_ducking_h handle = getStreamDuckingHandle(type);
316         sound_manager_is_ducked(handle, &isDucked);
317         if (!isDucked) {
318                 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] The %s is already recovered from ducking", __get_ducking_stream(type));
319                 return;
320         }
321
322         if (SOUND_MANAGER_ERROR_NONE != sound_manager_deactivate_ducking(handle)) {
323                 SLOG(LOG_WARN, tts_tag(), "[BackgroundVolume] Fail to deactivate ducking for %s", __get_ducking_stream(type));
324         } else {
325                 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Deactivate ducking for %s", __get_ducking_stream(type));
326         }
327 }
328
329 int BackgroundVolume::createHandles()
330 {
331         SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Create ducking handles");
332
333         if (nullptr == __mediaStream) {
334                 int ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_MEDIA, __sound_stream_ducking_state_changed_cb, nullptr, &__mediaStream);
335                 if (SOUND_MANAGER_ERROR_NONE != ret) {
336                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to create stream ducking for type media, ret(%d/%s)", ret, get_error_message(ret));
337                         __mediaStream = nullptr;
338                         return TTSD_ERROR_OPERATION_FAILED;
339                 }
340         }
341
342         if (nullptr == __notificationStream) {
343                 int ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_NOTIFICATION, __sound_stream_ducking_state_changed_cb, nullptr, &__notificationStream);
344                 if (SOUND_MANAGER_ERROR_NONE != ret) {
345                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to create stream ducking for notification type, ret(%d/%s)", ret, get_error_message(ret));
346                         __notificationStream = nullptr;
347                         return TTSD_ERROR_OPERATION_FAILED;
348                 }
349         }
350
351         if (nullptr == __alarmStream) {
352                 int ret = sound_manager_create_stream_ducking(SOUND_STREAM_TYPE_ALARM, __sound_stream_ducking_state_changed_cb, nullptr, &__alarmStream);
353                 if (SOUND_MANAGER_ERROR_NONE != ret) {
354                         SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Fail to create stream ducking for alarm type, ret(%d/%s)", ret, get_error_message(ret));
355                         __alarmStream = nullptr;
356                         return TTSD_ERROR_OPERATION_FAILED;
357                 }
358         }
359
360         return TTSD_ERROR_NONE;
361 }
362
363 bool BackgroundVolume::isDuckingHandleValid()
364 {
365         if (__mediaStream == nullptr || __notificationStream == nullptr || __alarmStream == nullptr) {
366                 return false;
367         }
368
369         return true;
370 }
371
372 sound_stream_ducking_h BackgroundVolume::getStreamDuckingHandle(sound_stream_type_e type)
373 {
374         switch (type)
375         {
376         case SOUND_STREAM_TYPE_MEDIA:
377                 return __mediaStream;
378         case SOUND_STREAM_TYPE_NOTIFICATION:
379                 return __notificationStream;
380         case SOUND_STREAM_TYPE_ALARM:
381                 return __alarmStream;
382
383         default:
384                 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid stream type (%d)", type);
385                 break;
386         }
387
388         return nullptr;
389 }