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.
14 #include "ttsd_main.h"
16 #include "BackgroundVolume.h"
21 static const char* __get_ducking_stream(sound_stream_type_e stream_type)
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";
33 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] Type is not handled. type(%d)", stream_type);
37 return "Non matched stream";
40 static void __sound_stream_ducking_state_changed_cb(sound_stream_ducking_h stream_ducking, bool is_ducked, void *user_data)
42 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] is ducked : %d", is_ducked);
46 BackgroundVolume::BackgroundVolume(long long int duckingDuration):
47 __duckingDuration(duckingDuration), __mediaStream(nullptr), __notificationStream(nullptr), __alarmStream(nullptr),
48 __postponedRecoverTimer(nullptr), __postponedModifyTimer(nullptr)
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);
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);
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);
62 __isVolumeDucked = false;
66 BackgroundVolume::~BackgroundVolume()
68 long long int diff = getDurationAfterDucking();
69 if (diff < __duckingDuration) {
70 usleep(__duckingDuration * 1000);
73 deactivateDuckingAll();
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);
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);
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;
93 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for media stream is already destroyed");
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;
102 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for notification stream is already destroyed");
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;
111 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Ducking handle for alarm stream is already destroyed");
115 void BackgroundVolume::setVolumeRatio(double ratio)
117 if (__volumeRatio.load() == ratio) {
118 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume is not changed (%lf).", ratio);
122 __volumeRatio = ratio;
123 ecore_main_loop_thread_safe_call_async(modifyVolumeOnMainThread, static_cast<void*>(this));
126 void BackgroundVolume::modifyVolumeOnMainThread(void* data)
128 if (nullptr == data) {
129 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
133 BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
134 if (!backgroundVolume->__isVolumeDucked.load()) {
135 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Volume is not changed yet.");
139 if (backgroundVolume->__postponedModifyTimer != nullptr) {
140 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Reserved volume modification exist. (%p)", backgroundVolume->__postponedModifyTimer);
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);
149 backgroundVolume->deactivateDuckingAll();
150 backgroundVolume->activateDuckingAll(0, ratio);
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);
158 Eina_Bool BackgroundVolume::postponedModifyTimerCb(void* data)
160 if (nullptr == data) {
161 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
165 BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
166 double ratio = backgroundVolume->__volumeRatio.load();
167 backgroundVolume->deactivateDuckingAll();
168 backgroundVolume->activateDuckingAll(0, ratio);
170 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delayed volume modification success. ratio(%lf)", ratio);
171 backgroundVolume->__postponedModifyTimer = nullptr;
175 double BackgroundVolume::getVolumeRatio()
177 return __volumeRatio.load();
180 void BackgroundVolume::applyVolumeRatio()
182 __isVolumeDucked = true;
183 ecore_main_loop_thread_safe_call_async(changeVolumeOnMainThread, static_cast<void*>(this));
186 void BackgroundVolume::changeVolumeOnMainThread(void* data)
188 if (nullptr == data) {
189 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
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);
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);
207 backgroundVolume->activateDuckingAll(backgroundVolume->__duckingDuration, ratio);
210 void BackgroundVolume::activateDuckingAll(unsigned int duration, double ratio)
212 activateDucking(SOUND_STREAM_TYPE_MEDIA, duration, ratio);
213 activateDucking(SOUND_STREAM_TYPE_NOTIFICATION, duration, ratio);
214 activateDucking(SOUND_STREAM_TYPE_ALARM, duration, ratio);
216 __changeVolumeTime = chrono::steady_clock::now();
219 bool BackgroundVolume::activateDucking(sound_stream_type_e type, unsigned int duration, double ratio)
221 bool isDucked = false;
222 sound_stream_ducking_h handle = getStreamDuckingHandle(type);
223 sound_manager_is_ducked(handle, &isDucked);
225 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] The %s is already ducked", __get_ducking_stream(type));
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));
234 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Activate ducking for %s", __get_ducking_stream(type));
238 void BackgroundVolume::recoverVolumeRatio()
240 __isVolumeDucked = false;
241 ecore_main_loop_thread_safe_call_async(recoverVolumeOnMainThread, static_cast<void*>(this));
244 void BackgroundVolume::recoverVolumeOnMainThread(void* data)
246 if (nullptr == data) {
247 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
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);
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);
263 long long int diff = backgroundVolume->getDurationAfterDucking();
264 if (diff >= backgroundVolume->__duckingDuration) {
265 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Direct deactivate ducking");
267 backgroundVolume->deactivateDuckingAll();
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);
275 long long int BackgroundVolume::getDurationAfterDucking()
277 auto currentTime = chrono::steady_clock::now();
278 chrono::milliseconds diff = chrono::duration_cast<chrono::milliseconds>(currentTime - __changeVolumeTime);
283 void BackgroundVolume::deactivateDuckingAll()
285 deactivateDucking(SOUND_STREAM_TYPE_MEDIA);
286 deactivateDucking(SOUND_STREAM_TYPE_NOTIFICATION);
287 deactivateDucking(SOUND_STREAM_TYPE_ALARM);
290 Eina_Bool BackgroundVolume::postponedRecoverTimerCb(void* data)
292 if (nullptr == data) {
293 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid data is passed");
297 BackgroundVolume* backgroundVolume = static_cast<BackgroundVolume*>(data);
298 backgroundVolume->deactivateDuckingAll();
299 backgroundVolume->__postponedRecoverTimer = nullptr;
301 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Delayed unset policy success");
305 void BackgroundVolume::deactivateDucking(sound_stream_type_e type)
307 bool isDucked = false;
308 sound_stream_ducking_h handle = getStreamDuckingHandle(type);
309 sound_manager_is_ducked(handle, &isDucked);
311 SLOG(LOG_DEBUG, tts_tag(), "[BackgroundVolume] The %s is already recovered from ducking", __get_ducking_stream(type));
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));
318 SLOG(LOG_INFO, tts_tag(), "[BackgroundVolume] Deactivate ducking for %s", __get_ducking_stream(type));
322 sound_stream_ducking_h BackgroundVolume::getStreamDuckingHandle(sound_stream_type_e type)
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;
334 SLOG(LOG_ERROR, tts_tag(), "[BackgroundVolume] Invalid stream type (%d)", type);