Update version (1.90.14)
[platform/core/uifw/tts.git] / server / ttsd_player.cpp
1 /*
2 *  Copyright (c) 2011-2016 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 #include "ttsd_data.h"
16 #include "ttsd_ipc.h"
17 #include "ttsd_player.h"
18 #include "ttsd_state.h"
19
20 #include "BackgroundVolume.h"
21 #include "AudioStream.h"
22 #include "PlayerThread.h"
23
24
25 #define SOUND_BUFFER_LENGTH     2048
26
27 /* CAUTION!
28 If you change this constant value. Please check the function 'set_timer_for_delay_recover()'.
29 If you choose too big value, it may cause integer overflow issue.
30 */
31 static const int SND_MGR_DUCKING_DURATION = 500;
32 static const intptr_t CHECK_TIMER_DELETE = 1;
33 static const int EXTRA_INFO_LENGTH = 20;
34
35 /* Sound buf save for test */
36 #define TTS_BUF_SAVE_FILE       "/usr/share/tts_pcm_save"
37 static bool g_is_buf_save = false;
38 static char g_temp_file_name[128] = {'\0',};
39 static FILE* g_pFile;
40 static int g_count = 0;
41 static pthread_mutex_t g_buf_save_mutex = PTHREAD_MUTEX_INITIALIZER;
42
43 /** player init info */
44 static bool g_player_init = false;
45
46 static std::atomic<bool> g_is_set_policy(false);
47
48 static BackgroundVolume* g_background_volume = nullptr;
49 static AudioStream* g_audio_stream = nullptr;
50 static PlayerThread* g_player_thread = nullptr;
51
52 /*
53 * Internal Interfaces
54 */
55 static void set_playing_status(bool is_playing)
56 {
57         int ret = vconf_set_bool(TTS_PLAYING_STATUS_KEY, is_playing ? 1 : 0);
58         SLOG(LOG_INFO, tts_tag(), "[Player] Set playing status (%s). ret(%d)", is_playing ? "True" : "False", ret);
59
60         if (is_playing) {
61                 ttsd_state_set_state(TTSD_STATE_PLAYING);
62         } else {
63                 if (ttsd_data_get_synth_control() == TTSD_SYNTHESIS_CONTROL_DOING) {
64                         ttsd_state_set_state(TTSD_STATE_SYNTHESIZING);
65                 } else {
66                         ttsd_state_set_state(TTSD_STATE_READY);
67                 }
68         }
69 }
70
71 static void open_buffer_dump_file()
72 {
73         pthread_mutex_lock(&g_buf_save_mutex);
74         if (g_pFile) {
75                 SLOG(LOG_ERROR, tts_tag(), "[Buffer Dump] File is already opened(%s)", g_temp_file_name);
76                 pthread_mutex_unlock(&g_buf_save_mutex);
77                 return;
78         }
79
80         g_count++;
81         while (1) {
82                 snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/tts_temp_%d_%d", getpid(), g_count);
83                 int ret = access(g_temp_file_name, 0);
84
85                 if (0 == ret) {
86                         SLOG(LOG_ERROR, tts_tag(), "[Recorder ERROR] File is already exist");
87                         if (0 == remove(g_temp_file_name)) {
88                                 SLOG(LOG_DEBUG, tts_tag(), "[Recorder] Remove file");
89                                 break;
90                         } else {
91                                 g_count++;
92                         }
93                 } else {
94                         break;
95                 }
96         }
97
98         SECURE_SLOG(LOG_DEBUG, tts_tag(), "[Recorder] Temp file name=[%s]", g_temp_file_name);
99
100         /* open test file */
101         g_pFile = fopen(g_temp_file_name, "wb+x");
102         if (NULL == g_pFile) {
103                 SLOG(LOG_ERROR, tts_tag(), "[Recorder ERROR] File not found!");
104         }
105
106         pthread_mutex_unlock(&g_buf_save_mutex);
107 }
108
109 static void close_buffer_dump_file()
110 {
111         pthread_mutex_lock(&g_buf_save_mutex);
112
113         if (g_pFile) {
114                 fclose(g_pFile);
115                 g_pFile = NULL;
116         }
117
118         pthread_mutex_unlock(&g_buf_save_mutex);
119 }
120
121 static void write_buffer_dump_file(const void* buffer, size_t length)
122 {
123         pthread_mutex_lock(&g_buf_save_mutex);
124
125         if (g_pFile) {
126                 size_t ret = fwrite(buffer, 1, length, g_pFile);
127                 SLOG(LOG_DEBUG, tts_tag(), "[Buffer Dump] Stored size(%zu / %zu)", ret, length);
128         } else {
129                 SLOG(LOG_ERROR, tts_tag(), "[Buffer Dump] File is not opened. Please check the file open");
130         }
131
132         pthread_mutex_unlock(&g_buf_save_mutex);
133 }
134
135 static int check_and_create_audio_stream(void)
136 {
137         if (nullptr != g_audio_stream)
138                 return 0;
139
140         SLOG(LOG_ERROR, tts_tag(), "[BG] g_audio_stream is null. Create a new instance");
141         g_audio_stream = new AudioStream();
142         if (nullptr == g_audio_stream) {
143                 SLOG(LOG_ERROR, tts_tag(), "[BG] Fail to allocate memory.");
144                 return -1;
145         }
146
147         return 0;
148 }
149
150 static void set_policy_for_playing(unsigned int uid)
151 {
152         /* In case of DEFAULT and INTERRUPT mode, acquire sound focus */
153         ttsd_mode_e mode = ttsd_data_get_mode(uid);
154         SLOG(LOG_INFO, tts_tag(), "[Player INFO] Current uid(%d)'s mode(%d)", uid, (int)mode);
155
156         if (-1 == check_and_create_audio_stream())
157                 return;
158
159         if (TTSD_MODE_DEFAULT == mode || TTSD_MODE_INTERRUPT == mode)
160                 g_audio_stream->acquireSoundFocus();
161
162         g_audio_stream->setSoundStreamInfo();
163         g_background_volume->applyVolumeRatio();
164         g_is_set_policy = true;
165         SLOG(LOG_ERROR, tts_tag(), "[BG] g_is_set_policy(%d)", static_cast<int>(g_is_set_policy.load()));
166         SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] set policy for playing");
167 }
168
169 static void unset_policy_for_playing(unsigned int uid)
170 {
171 /* In case of DEFAULT and INTERRUPT mode, release sound focus */
172         ttsd_mode_e mode = ttsd_data_get_mode(uid);
173         SLOG(LOG_INFO, tts_tag(), "[Player INFO] Current uid(%d)'s mode(%d)", uid, (int)mode);
174
175         if ((TTSD_MODE_DEFAULT == mode || TTSD_MODE_INTERRUPT == mode) && nullptr != g_audio_stream)
176                 g_audio_stream->releaseSoundFocus();
177
178         g_background_volume->recoverVolumeRatio();
179         g_is_set_policy = false;
180         SLOG(LOG_ERROR, tts_tag(), "[BG] g_is_set_policy(%d)", static_cast<int>(g_is_set_policy.load()));
181         SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] unset policy for playing");
182 }
183
184 static int notify_utterance_started_event(unsigned int uid, int utt_id)
185 {
186         int pid = ttsd_data_get_pid(uid);
187         if (pid <= 0) {
188                 SLOG(LOG_ERROR, tts_tag(), "[Player] Current player is not valid. uid(%u)", uid);
189                 return TTSD_ERROR_INVALID_PARAMETER;
190         }
191
192         if (true == g_is_buf_save) {
193                 open_buffer_dump_file();
194         }
195         set_playing_status(true);
196
197         if (0 != ttsdc_ipc_send_utt_start_message(pid, uid, utt_id)) {
198                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to send Utterance Started Signal : pid(%d), uid(%u), utt_id(%d)",
199                         pid, uid, utt_id);
200                 return TTSD_ERROR_OPERATION_FAILED;
201         }
202
203         SLOG(LOG_INFO, tts_tag(), "[Player] Start utterance : uid(%u), utt_id(%d)", uid, utt_id);
204         return TTSD_ERROR_NONE;
205 }
206
207 static int notify_utterance_completed_event(unsigned int uid, int utt_id)
208 {
209         int pid = ttsd_data_get_pid(uid);
210         if (pid <= 0) {
211                 SLOG(LOG_ERROR, tts_tag(), "[Player] Current player is not valid. uid(%u)", uid);
212                 return TTSD_ERROR_INVALID_PARAMETER;
213         }
214
215         if (true == g_is_buf_save) {
216                 close_buffer_dump_file();
217         }
218         set_playing_status(false);
219
220         if (0 != ttsdc_ipc_send_utt_finish_message(pid, uid, utt_id)) {
221                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%u), utt_id(%d)",
222                         pid, uid, utt_id);
223                 return TTSD_ERROR_OPERATION_FAILED;
224         }
225
226         SLOG(LOG_INFO, tts_tag(), "[Player] Complete utterance : uid(%u), utt_id(%d)", uid, utt_id);
227         return TTSD_ERROR_NONE;
228 }
229
230 static int play_sound_data(PlayerThread* player, unsigned int uid, sound_data_s* sound_data)
231 {
232         if (-1 == check_and_create_audio_stream())
233                 return TTSD_ERROR_OUT_OF_MEMORY;
234
235         if (TTSD_ERROR_NONE != g_audio_stream->setAudioFormat(sound_data->audio_type, sound_data->rate)) {
236                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to create audio out");
237                 return TTSD_ERROR_OPERATION_FAILED;
238         }
239
240         // Check whether set_policy is done or not
241         if (false == g_is_set_policy.load()) {
242                 SLOG(LOG_INFO, tts_tag(), "[Player INFO] Set policy. uid(%d)", uid);
243                 set_policy_for_playing(uid);
244         }
245
246         if (TTSD_ERROR_NONE != g_audio_stream->prepareAudioOut()) {
247                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Fail to prepare audio");
248                 return TTSD_ERROR_OPERATION_FAILED;
249         }
250
251         unsigned int idx = sound_data->played_data_size;
252         while (idx < sound_data->data_size) {
253                 app_tts_state_e state = ttsd_data_get_client_state(uid);
254                 if (APP_STATE_PLAYING != state && APP_STATE_PAUSED != state) {
255                         break;
256                 }
257
258                 unsigned int len = 0;
259                 if (idx + SOUND_BUFFER_LENGTH > sound_data->data_size) {
260                         len = sound_data->data_size - idx;
261                 } else {
262                         len = SOUND_BUFFER_LENGTH;
263                 }
264
265                 char* temp_data = sound_data->data;
266                 SLOG(LOG_INFO, tts_tag(), "[Player INFO] Before audio_out_write. data(%p), data[%d](%p), uid(%u), utt_id(%d), len(%u)",
267                                 temp_data, idx, &temp_data[idx], uid, sound_data->utt_id, len);
268
269                 if (true == g_is_buf_save) {
270                         write_buffer_dump_file(&temp_data[idx], len);
271                 }
272
273                 if (TTSD_ERROR_NONE != g_audio_stream->playAudioData(&temp_data[idx], len)) {
274                         SLOG(LOG_WARN, tts_tag(), "[Player WARNING] Fail to write audio");
275                 } else {
276                         idx += len;
277                         sound_data->played_data_size = idx;
278                         SLOG(LOG_INFO, tts_tag(), "[Player INFO] After audio_out_write");
279                 }
280
281                 if (APP_STATE_PAUSED == state) {
282                         return TTSD_ERROR_INVALID_STATE;
283                 }
284
285                 if (false == player->isCurrentUid(uid)) {
286                         return TTSD_ERROR_OPERATION_FAILED;
287                 }
288         }
289
290         return TTSD_ERROR_NONE;
291 }
292
293 static void wait_sound_data(PlayerThread* player, unsigned int uid)
294 {
295         ttsd_synthesis_control_e prev_synth_control = TTSD_SYNTHESIS_CONTROL_EXPIRED;
296         while (0 >= ttsd_data_get_sound_data_size(uid)) {
297                 usleep(10000);
298                 if (false == player->isCurrentUid(uid)) {
299                         return;
300                 }
301
302                 /* If engine is not on processing */
303                 ttsd_synthesis_control_e synth_control = ttsd_data_get_synth_control();
304                 if (prev_synth_control != synth_control)
305                         SLOG(LOG_INFO, tts_tag(), "[Server INFO] prev_synth_control(%d), synth_control(%d)", prev_synth_control, synth_control);
306                 if (TTSD_SYNTHESIS_CONTROL_DOING != synth_control) {
307                         if (AudioStream::AUDIO_STATE_PLAY == g_audio_stream->getState()) {
308                                 g_audio_stream->unprepareAudioOut();
309                                 unset_policy_for_playing(uid);  // uid == current uid
310                         }
311                 }
312                 prev_synth_control = synth_control;
313         }
314 }
315
316 static void set_paused_data(unsigned int uid, sound_data_s* sound_data) {
317         int ret = ttsd_data_set_paused_data(uid, sound_data);
318         if (TTSD_ERROR_NONE != ret) {
319                 ttsd_data_destroy_sound_data(sound_data);
320         }
321 }
322
323 static void play_utterance_cb(PlayerThread* player, unsigned int uid)
324 {
325         SLOG(LOG_DEBUG, tts_tag(), "[PLAYER] Start play utterance. uid(%u)", uid);
326
327         while (player->isCurrentUid(uid)) {
328                 sound_data_s* sound_data = ttsd_data_get_first_sound_data(uid);
329                 if (ttsd_data_is_paused_data_existing(uid)) {
330                         ttsd_data_set_paused_data(uid, nullptr);
331
332                         if (nullptr == sound_data) {
333                                 break;
334                         }
335                         set_playing_status(true);
336
337                         SLOG(LOG_INFO, tts_tag(), "[Player] Sound info : id(%d) data(%p) size(%d) audiotype(%d) rate(%d) event(%d)",
338                                 sound_data->utt_id, sound_data->data, sound_data->data_size, sound_data->audio_type, sound_data->rate, sound_data->event);
339                 } else {
340                         if (nullptr == sound_data) {
341                                 SLOG(LOG_ERROR, tts_tag(), "[Player] No sound data. Waiting mode");
342
343                                 wait_sound_data(player, uid);
344                                 if (false == player->isCurrentUid(uid)) {
345                                         SLOG(LOG_INFO, tts_tag(), "[Player] Finish thread");
346                                         break;
347                                 }
348
349                                 SLOG(LOG_INFO, tts_tag(), "[Player] Finish to wait for new audio data come");
350                                 continue;
351                         }
352
353                         /* If wdata's event is 'start', current wdata is first data of engine for synthesis.
354                          * If wdata's event is 'finish', player should check previous event to know whether this wdata is first or not.
355                          * When previous wdata's event is 'finish' and current wdata's event is 'finish',
356                          * the player should send utt started event.
357                          */
358                         ttse_result_event_e last_event = ttsd_data_get_last_sound_result_event(uid);
359                         if (TTSE_RESULT_EVENT_START == sound_data->event || (TTSE_RESULT_EVENT_FINISH == last_event && TTSE_RESULT_EVENT_FINISH == sound_data->event)) {
360                                 int ret = notify_utterance_started_event(uid, sound_data->utt_id);
361                                 if (TTSD_ERROR_INVALID_PARAMETER == ret) {
362                                         break;
363                                 }
364                         }
365
366                         /* Save last event to check utterance start */
367                         ttsd_data_set_last_sound_result_event(uid, sound_data->event);
368
369                         if (nullptr == sound_data->data || 0 >= sound_data->data_size) {
370                                 ttse_result_event_e event = sound_data->event;
371                                 int utt_id = sound_data->utt_id;
372
373                                 ttsd_data_destroy_sound_data(sound_data);
374                                 sound_data = nullptr;
375
376                                 SLOG(LOG_INFO, tts_tag(), "[Player] No Sound data. Event(%d), uid(%u), uttid(%d)", event, uid, utt_id);
377                                 if (TTSE_RESULT_EVENT_FINISH == event) {
378                                         unset_policy_for_playing(uid);
379                                         if (TTSD_ERROR_INVALID_PARAMETER == notify_utterance_completed_event(uid, utt_id)) {
380                                                 break;
381                                         }
382                                 }
383
384                                 continue;
385                         }
386                 }
387
388                 int ret = play_sound_data(player, uid, sound_data);
389                 if (TTSD_ERROR_INVALID_STATE == ret) {
390                         SLOG(LOG_DEBUG, tts_tag(), "[Player] Uid(%u) is paused", uid);
391                         set_paused_data(uid, sound_data);
392                         break;
393                 } else if (TTSD_ERROR_NONE != ret) {
394                         SLOG(LOG_ERROR, tts_tag(), "[Player] Fail to play audio data. uid(%u)", uid);
395                         ttsd_data_destroy_sound_data(sound_data);
396                         sound_data = nullptr;
397                         break;
398                 }
399
400                 ttse_result_event_e event = sound_data->event;
401                 int utt_id = sound_data->utt_id;
402
403                 ttsd_data_destroy_sound_data(sound_data);
404                 sound_data = nullptr;
405
406                 if (TTSE_RESULT_EVENT_FINISH == event) {
407                         unset_policy_for_playing(uid);
408                         if (TTSD_ERROR_NONE != notify_utterance_completed_event(uid, utt_id)) {
409                                 break;
410                         }
411                 }
412
413                 app_tts_state_e state = ttsd_data_get_client_state(uid);
414                 if (APP_STATE_READY == state) {
415                         /* player_stop */
416                         SLOG(LOG_DEBUG, tts_tag(), "[Player] Stop player thread");
417                         break;
418                 }
419         }
420
421         g_audio_stream->unprepareAudioOut();
422         unset_policy_for_playing(uid);
423
424         if (true == g_is_buf_save) {
425                 close_buffer_dump_file();
426         }
427
428         SLOG(LOG_DEBUG, tts_tag(), "[PLAYER] Finish play utterance. uid(%u)", uid);
429 }
430
431 /*
432 * Player Interfaces
433 */
434 int ttsd_player_init()
435 {
436         g_background_volume = new BackgroundVolume(SND_MGR_DUCKING_DURATION);
437         g_player_thread = new PlayerThread(play_utterance_cb);
438
439         g_is_set_policy = false;
440         g_player_init = true;
441
442         return 0;
443 }
444
445 int ttsd_player_release(void)
446 {
447         if (true == g_is_buf_save) {
448                 close_buffer_dump_file();
449         }
450
451         set_playing_status(false);
452         if (false == g_player_init) {
453                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
454                 return TTSD_ERROR_OPERATION_FAILED;
455         }
456
457         g_player_init = false;
458         g_player_thread->requestStop();
459         SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] Thread is released");
460
461         delete g_player_thread;
462         g_player_thread = nullptr;
463
464         delete g_audio_stream;
465         g_audio_stream = nullptr;
466
467         delete g_background_volume;
468         g_background_volume = nullptr;
469
470         SLOG(LOG_INFO, tts_tag(), "[Player] ttsd_player_release succeed");
471         return 0;
472 }
473
474 int ttsd_player_play(unsigned int uid)
475 {
476         if (false == g_player_init) {
477                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
478                 return TTSD_ERROR_OPERATION_FAILED;
479         }
480
481         if (0 > ttsd_data_is_client(uid)) {
482                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
483                 return -1;
484         }
485
486         unsigned int currentUid = g_player_thread->getCurrentUid();
487         if (0 < ttsd_data_is_client(currentUid) && uid == currentUid) {
488                 SLOG(LOG_DEBUG, tts_tag(), "[Player] uid(%u) has already played", uid);
489                 return TTSD_ERROR_NONE;
490         }
491
492         /* check whether saving PCM buffer or not */
493         if (0 == access(TTS_BUF_SAVE_FILE, 0)) {
494                 SLOG(LOG_DEBUG, tts_tag(), "[Player] Save PCM buffers");
495                 g_is_buf_save = true;
496         } else {
497                 SLOG(LOG_DEBUG, tts_tag(), "[Player] Do not save PCM buffers");
498                 g_is_buf_save = false;
499         }
500
501         SLOG(LOG_INFO, tts_tag(), "[Player] start play : uid(%u)", uid);
502         g_player_thread->requestPlay(uid);
503
504         return 0;
505 }
506
507 int ttsd_player_stop(unsigned int uid)
508 {
509         if (false == g_player_init) {
510                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
511                 return TTSD_ERROR_OPERATION_FAILED;
512         }
513
514         if (uid == g_player_thread->getCurrentUid()) {
515                 g_player_thread->requestStop();
516         } else {
517                 SLOG(LOG_DEBUG, tts_tag(), "[Player] No current playing");
518         }
519
520         if (true == g_is_buf_save) {
521                 close_buffer_dump_file();
522         }
523
524         set_playing_status(false);
525         ttsd_data_set_last_sound_result_event(uid, TTSE_RESULT_EVENT_FINISH);
526         ttsd_data_set_paused_data(uid, nullptr);
527
528         SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Stop player : uid(%u)", uid);
529
530         return 0;
531 }
532
533 int ttsd_player_pause(unsigned int uid)
534 {
535         SLOG(LOG_DEBUG, tts_tag(), "[Player] pause player : uid(%u)", uid);
536
537         if (false == g_player_init) {
538                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
539                 return TTSD_ERROR_OPERATION_FAILED;
540         }
541
542         if (0 > ttsd_data_is_client(uid)) {
543                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] ttsd_player_pause() : uid(%u) is not valid", uid);
544                 return -1;
545         }
546
547         if (uid == g_player_thread->getCurrentUid()) {
548                 SLOG(LOG_DEBUG, tts_tag(), "[Player DEBUG] release current playing info (%u)", uid);
549                 g_player_thread->requestStop();
550         }
551
552         if (true == g_is_buf_save) {
553                 close_buffer_dump_file();
554         }
555
556         set_playing_status(false);
557         SLOG(LOG_INFO, tts_tag(), "[Player SUCCESS] Pause player : uid(%u)", uid);
558         return 0;
559 }
560
561 static bool stop_all_client_callback(int pid, unsigned int uid, app_tts_state_e state, void* user_data)
562 {
563         if (0 > ttsd_data_is_client(uid)) {
564                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] uid(%u) is not valid", uid);
565                 return true;
566         }
567
568         if (APP_STATE_PLAYING == state || APP_STATE_PAUSED == state) {
569                 ttsd_data_set_last_sound_result_event(uid, TTSE_RESULT_EVENT_FINISH);
570                 ttsd_data_set_paused_data(uid, nullptr);
571         }
572
573         return true;
574 }
575
576 int ttsd_player_all_stop()
577 {
578         if (false == g_player_init) {
579                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
580                 return TTSD_ERROR_OPERATION_FAILED;
581         }
582
583         g_player_thread->requestStop();
584         ttsd_data_foreach_clients(stop_all_client_callback, nullptr);
585
586         SLOG(LOG_DEBUG, tts_tag(), "[Player SUCCESS] player all stop!!");
587         return TTSD_ERROR_NONE;
588 }
589
590 int ttsd_player_get_background_volume_ratio(double* ratio)
591 {
592         if (false == g_player_init) {
593                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
594                 return TTSD_ERROR_OPERATION_FAILED;
595         }
596
597         if (nullptr == ratio) {
598                 return TTSD_ERROR_INVALID_PARAMETER;
599         }
600
601         *ratio = g_background_volume->getVolumeRatio();
602         return TTSD_ERROR_NONE;
603 }
604
605 int ttsd_player_set_background_volume_ratio(double ratio)
606 {
607         if (false == g_player_init) {
608                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
609                 return TTSD_ERROR_OPERATION_FAILED;
610         }
611
612         SLOG(LOG_INFO, tts_tag(), "[Player DEBUG] ttsd_player_set_background_volume_ratio : %lf", ratio);
613         g_background_volume->setVolumeRatio(ratio);
614
615         return TTSD_ERROR_NONE;
616 }
617
618 int ttsd_player_wait_to_play(unsigned int uid)
619 {
620         if (false == g_player_init) {
621                 SLOG(LOG_ERROR, tts_tag(), "[Player ERROR] Not Initialized");
622                 return TTSD_ERROR_OPERATION_FAILED;
623         }
624
625         if (-1 == check_and_create_audio_stream())
626                 return TTSD_ERROR_OUT_OF_MEMORY;
627
628         SLOG(LOG_INFO, tts_tag(), "[Player INFO] wait to play (%u)", uid);
629
630         g_audio_stream->waitForPlay();
631         return TTSD_ERROR_NONE;
632 }