2 * Copyright (c) 2011-2014 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.
16 #include <sound_manager.h>
18 #include "ttsd_main.h"
19 #include "ttsd_player.h"
20 #include "ttsd_data.h"
21 #include "ttsd_dbus.h"
24 * Internal data structure
34 int uid; /** client id */
35 app_state_e state; /** client state */
37 /* Current utterance information */
38 ttsp_result_event_e event; /** event of last utterance */
42 sound_data_s paused_data;
45 #define SOUND_BUFFER_LENGTH 2048
47 /** player init info */
48 static bool g_player_init = false;
51 static GList *g_player_list;
53 /** current player information */
54 static player_s* g_playing_info;
57 static audio_state_e g_audio_state;
59 static ttsp_audio_type_e g_audio_type;
61 static int g_sampling_rate;
63 static audio_out_h g_audio_h;
69 player_s* __player_get_item(int uid)
72 player_s *data = NULL;
74 if (0 < g_list_length(g_player_list)) {
75 /* Get a first item */
76 iter = g_list_first(g_player_list);
78 while (NULL != iter) {
79 /* Get handle data from list */
80 data = (player_s*)iter->data;
87 iter = g_list_next(iter);
94 void __player_audio_io_interrupted_cb(audio_io_interrupted_code_e code, void *user_data)
96 SLOG(LOG_DEBUG, get_tag(), "===== INTERRUPTED CALLBACK");
98 SLOG(LOG_WARN, get_tag(), "[Player] code : %d", (int)code);
100 g_audio_state = AUDIO_STATE_READY;
102 if (NULL == g_playing_info) {
103 SLOG(LOG_WARN, get_tag(), "[Player WARNING] No current player");
107 if (APP_STATE_PLAYING == g_playing_info->state) {
108 g_playing_info->state = APP_STATE_PAUSED;
110 ttsd_data_set_client_state(g_playing_info->uid, APP_STATE_PAUSED);
112 int pid = ttsd_data_get_pid(g_playing_info->uid);
114 /* send message to client about changing state */
115 ttsdc_send_set_state_message(pid, g_playing_info->uid, APP_STATE_PAUSED);
118 SLOG(LOG_DEBUG, get_tag(), "=====");
119 SLOG(LOG_DEBUG, get_tag(), " ");
124 static int __create_audio_out(ttsp_audio_type_e type, int rate)
127 audio_sample_type_e sample_type;
129 if (TTSP_AUDIO_TYPE_RAW_S16 == type) {
130 sample_type = AUDIO_SAMPLE_TYPE_S16_LE;
132 sample_type = AUDIO_SAMPLE_TYPE_U8;
135 ret = audio_out_create(rate, AUDIO_CHANNEL_MONO, sample_type, SOUND_TYPE_MEDIA, &g_audio_h);
136 if (AUDIO_IO_ERROR_NONE != ret) {
137 g_audio_state = AUDIO_STATE_NONE;
139 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to create audio");
142 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Create audio");
145 if (TTSD_MODE_DEFAULT != ttsd_get_mode()) {
146 ret = audio_out_ignore_session(g_audio_h);
147 if (AUDIO_IO_ERROR_NONE != ret) {
148 g_audio_state = AUDIO_STATE_NONE;
150 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to set ignore session");
155 ret = audio_out_set_interrupted_cb(g_audio_h, __player_audio_io_interrupted_cb, NULL);
156 if (AUDIO_IO_ERROR_NONE != ret) {
157 g_audio_state = AUDIO_STATE_NONE;
159 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to set callback function");
164 g_sampling_rate = rate;
166 g_audio_state = AUDIO_STATE_READY;
171 static int __destroy_audio_out()
173 if (NULL == g_audio_h) {
174 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Current handle is not valid");
179 ret = audio_out_destroy(g_audio_h);
180 if (AUDIO_IO_ERROR_NONE != ret) {
181 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to destroy audio");
184 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Destroy audio");
190 g_audio_state = AUDIO_STATE_NONE;
196 static void __end_play_thread(void *data, Ecore_Thread *thread)
198 SLOG(LOG_DEBUG, get_tag(), "===== End thread");
202 static void __play_thread(void *data, Ecore_Thread *thread)
204 SLOG(LOG_DEBUG, get_tag(), "===== Start thread");
206 if (NULL == g_playing_info) {
207 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] No current player");
211 player_s* player = g_playing_info;
215 int len = SOUND_BUFFER_LENGTH;
219 if (true == player->is_paused_data) {
221 wdata.data = player->paused_data.data;
222 wdata.data_size = player->paused_data.data_size;
223 wdata.utt_id = player->paused_data.utt_id;
224 wdata.audio_type = player->paused_data.audio_type;
225 wdata.rate = player->paused_data.rate;
226 wdata.channels = player->paused_data.channels;
227 wdata.event = player->paused_data.event;
231 player->is_paused_data = false;
234 if (0 != ttsd_data_get_sound_data(player->uid, &wdata)) {
235 g_playing_info = NULL;
236 SLOG(LOG_DEBUG, get_tag(), "[Player] No sound data. Finish thread");
238 /* Request unprepare */
239 ret = audio_out_unprepare(g_audio_h);
240 if (AUDIO_IO_ERROR_NONE != ret) {
241 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
243 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Unprepare audio");
246 g_audio_state = AUDIO_STATE_READY;
250 /* If wdata's event is 'start', current wdata is first data of engine for synthesis.
251 * If wdata's event is 'finish', player should check previous event to know whether this wdata is first or not.
252 * When previous wdata's event is 'finish' and current wdata's event is 'finish',
253 * the player should send utt started event.
255 if (TTSP_RESULT_EVENT_START == wdata.event ||
256 (TTSP_RESULT_EVENT_FINISH == player->event && TTSP_RESULT_EVENT_FINISH == wdata.event)) {
257 int pid = ttsd_data_get_pid(player->uid);
260 SLOG(LOG_WARN, get_tag(), "[Send WARNIING] Current player is not valid");
264 if (0 != ttsdc_send_utt_start_message(pid, player->uid, wdata.utt_id)) {
265 SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Start Signal : pid(%d), uid(%d), uttid(%d)",
266 pid, player->uid, wdata.utt_id);
268 SLOG(LOG_DEBUG, get_tag(), "[Player] Start utterance : uid(%d), uttid(%d)", player->uid, wdata.utt_id);
271 /* Save last event to check utterance start */
272 player->event = wdata.event;
275 if (NULL == wdata.data || 0 >= wdata.data_size) {
276 if (TTSP_RESULT_EVENT_FINISH == wdata.event) {
277 SLOG(LOG_DEBUG, get_tag(), "No sound data");
278 /* send utterence finish signal */
279 int pid = ttsd_data_get_pid(player->uid);
282 SLOG(LOG_WARN, get_tag(), "[Send WARNIING] Current player is not valid");
285 if (0 != ttsdc_send_utt_finish_message(pid, player->uid, wdata.utt_id)) {
286 SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%d), uttid(%d)", pid, player->uid, wdata.utt_id);
289 SLOG(LOG_DEBUG, get_tag(), "[Player] Finish utterance : uid(%d), uttid(%d)", player->uid, wdata.utt_id);
294 SLOG(LOG_DEBUG, get_tag(), "[Player] Sound info : id(%d) size(%d) audiotype(%d) rate(%d) event(%d)",
295 wdata.utt_id, wdata.data_size, wdata.audio_type, wdata.rate, wdata.event);
297 if (g_sampling_rate != wdata.rate || g_audio_type != wdata.audio_type) {
298 SLOG(LOG_DEBUG, get_tag(), "[Player] Change audio handle : org type(%d) org rate(%d)", g_audio_type, g_sampling_rate);
299 if (NULL != g_audio_h) {
300 __destroy_audio_out();
303 if (0 > __create_audio_out(wdata.audio_type, wdata.rate)) {
304 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to create audio out");
309 while (APP_STATE_PLAYING == player->state || APP_STATE_PAUSED == player->state) {
310 if ((unsigned int)idx >= wdata.data_size)
313 if ((unsigned int)idx + SOUND_BUFFER_LENGTH > wdata.data_size) {
314 len = wdata.data_size - idx;
316 len = SOUND_BUFFER_LENGTH;
319 if (AUDIO_STATE_READY == g_audio_state) {
320 /* Request prepare */
321 ret = audio_out_prepare(g_audio_h);
322 if (AUDIO_IO_ERROR_NONE != ret) {
323 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to prepare audio : %d", ret);
324 g_playing_info = NULL;
327 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Prepare audio");
328 g_audio_state = AUDIO_STATE_PLAY;
331 char* temp_data = wdata.data;
332 ret = audio_out_write(g_audio_h, &temp_data[idx], len);
334 SLOG(LOG_WARN, get_tag(), "[Player WARNING] Fail to audio write - %d", ret);
339 if (APP_STATE_PAUSED == player->state) {
341 player->paused_data.data = wdata.data;
342 player->paused_data.data_size = wdata.data_size;
343 player->paused_data.utt_id = wdata.utt_id;
344 player->paused_data.audio_type = wdata.audio_type;
345 player->paused_data.rate = wdata.rate;
346 player->paused_data.channels = wdata.channels;
347 player->paused_data.event = wdata.event;
349 player->is_paused_data = true;
352 g_audio_state = AUDIO_STATE_READY;
353 SLOG(LOG_DEBUG, get_tag(), "[Player] Stop player thread by pause");
355 /* Request prepare */
356 ret = audio_out_unprepare(g_audio_h);
357 if (AUDIO_IO_ERROR_NONE != ret) {
358 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
360 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Unprepare audio");
366 if (NULL != wdata.data) {
371 if (APP_STATE_READY == player->state) {
372 g_audio_state = AUDIO_STATE_READY;
373 SLOG(LOG_DEBUG, get_tag(), "[Player] Stop player thread");
375 /* Request prepare */
376 ret = audio_out_unprepare(g_audio_h);
377 if (AUDIO_IO_ERROR_NONE != ret) {
378 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to unprepare audio : %d", ret);
380 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Unprepare audio");
385 if (TTSP_RESULT_EVENT_FINISH == wdata.event) {
386 /* send utterence finish signal */
387 int pid = ttsd_data_get_pid(player->uid);
390 SLOG(LOG_WARN, get_tag(), "[Send WARNIING] Current player is not valid");
394 if (0 != ttsdc_send_utt_finish_message(pid, player->uid, wdata.utt_id)) {
395 SLOG(LOG_ERROR, get_tag(), "[Send ERROR] Fail to send Utterance Completed Signal : pid(%d), uid(%d), uttid(%d)",
396 pid, player->uid, wdata.utt_id);
400 SLOG(LOG_DEBUG, get_tag(), "[Player] Finish utterance : uid(%d), uttid(%d)", player->uid, wdata.utt_id);
408 int ttsd_player_init()
410 g_playing_info = NULL;
411 g_audio_state = AUDIO_STATE_NONE;
416 if (TTSD_MODE_DEFAULT == ttsd_get_mode()) {
417 ret = sound_manager_set_session_type(SOUND_SESSION_TYPE_MEDIA);
419 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail to set session type");
422 ret = sound_manager_set_media_session_option(SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START, SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY);
424 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Fail set media session option");
426 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] set media session option");
430 ecore_thread_max_set(1);
432 ret = __create_audio_out(TTSP_AUDIO_TYPE_RAW_S16, 16000);
436 g_player_init = true;
441 int ttsd_player_release(void)
443 if (false == g_player_init) {
444 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
445 return TTSD_ERROR_OPERATION_FAILED;
450 ret = __destroy_audio_out();
454 SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] ==========================");
455 SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] Active thread count : %d", ecore_thread_active_get());
456 SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] ==========================");
458 /* The thread should be released */
459 int thread_count = ecore_thread_active_get();
461 while (0 < thread_count) {
466 SLOG(LOG_WARN, get_tag(), "[Player WARNING!!] Thread is blocked. Player release continue.");
470 thread_count = ecore_thread_active_get();
473 SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] Thread is released");
475 /* clear g_player_list */
476 g_playing_info = NULL;
477 g_player_init = false;
482 int ttsd_player_create_instance(int uid)
484 if (false == g_player_init) {
485 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
489 /* Check uid is duplicated */
490 if (NULL != __player_get_item(uid)) {
491 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] uid(%d) is already registered", uid);
495 player_s* new_client = (player_s*)calloc(1, sizeof(player_s));
497 new_client->uid = uid;
498 new_client->event = TTSP_RESULT_EVENT_FINISH;
499 new_client->state = APP_STATE_READY;
500 new_client->is_paused_data = false;
502 new_client->paused_data.data = NULL;
504 SLOG(LOG_DEBUG, get_tag(), "[Player] Create player : uid(%d)", uid);
506 g_player_list = g_list_append(g_player_list, new_client);
511 int ttsd_player_destroy_instance(int uid)
513 if (false == g_player_init) {
514 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
519 current = __player_get_item(uid);
520 if (NULL == current) {
521 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] uid(%d) is not valid", uid);
525 if (NULL != g_playing_info) {
526 if (uid == g_playing_info->uid) {
527 g_playing_info = NULL;
532 player_s *data = NULL;
534 if (0 < g_list_length(g_player_list)) {
535 /* Get a first item */
536 iter = g_list_first(g_player_list);
538 while (NULL != iter) {
539 /* Get handle data from list */
540 data = (player_s*)iter->data;
544 if (uid == data->uid) {
545 g_player_list = g_list_remove_link(g_player_list, iter);
552 iter = g_list_next(iter);
556 SLOG(LOG_DEBUG, get_tag(), "[PLAYER Success] Destroy instance");
561 int ttsd_player_play(int uid)
563 if (false == g_player_init) {
564 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
568 if (NULL != g_playing_info) {
569 if (uid == g_playing_info->uid) {
570 SLOG(LOG_DEBUG, get_tag(), "[Player] uid(%d) has already played", g_playing_info->uid);
575 SLOG(LOG_DEBUG, get_tag(), "[Player] start play : uid(%d)", uid);
577 /* Check sound queue size */
578 if (0 == ttsd_data_get_sound_data_size(uid)) {
579 SLOG(LOG_WARN, get_tag(), "[Player WARNING] A sound queue of current player(%d) is empty", uid);
585 current = __player_get_item(uid);
586 if (NULL == current) {
587 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] uid(%d) is not valid", uid);
591 current->state = APP_STATE_PLAYING;
593 g_playing_info = current;
595 SLOG(LOG_DEBUG, get_tag(), "[Player DEBUG] Active thread count : %d", ecore_thread_active_get());
597 if (0 < ttsd_data_get_sound_data_size(current->uid)) {
598 SLOG(LOG_DEBUG, get_tag(), "[Player] Run thread");
599 ecore_thread_run(__play_thread, __end_play_thread, NULL, NULL);
605 int ttsd_player_stop(int uid)
607 if (false == g_player_init) {
608 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
614 current = __player_get_item(uid);
615 if (NULL == current) {
616 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] uid(%d) is not valid", uid);
620 /* check whether uid is current playing or not */
621 if (NULL != g_playing_info) {
622 if (uid == g_playing_info->uid) {
623 /* release current playing info */
624 g_playing_info = NULL;
627 SLOG(LOG_DEBUG, get_tag(), "[Player] No current playing");
630 if (true == current->is_paused_data) {
631 if (NULL != current->paused_data.data) {
632 free(current->paused_data.data);
633 current->paused_data.data = NULL;
637 current->event = TTSP_RESULT_EVENT_FINISH;
638 current->state = APP_STATE_READY;
639 current->is_paused_data = false;
642 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] Stop player : uid(%d)", uid);
647 int ttsd_player_pause(int uid)
649 SLOG(LOG_DEBUG, get_tag(), "[Player] pause player : uid(%d)", uid);
651 if (false == g_player_init) {
652 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
658 current = __player_get_item(uid);
659 if (NULL == current) {
660 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] ttsd_player_pause() : uid(%d) is not valid", uid);
664 /* check whether uid is current playing or not */
665 if (NULL != g_playing_info) {
666 if (uid == g_playing_info->uid) {
667 /* release current playing info */
668 g_playing_info = NULL;
674 current->state = APP_STATE_PAUSED;
679 int ttsd_player_resume(int uid)
681 SLOG(LOG_DEBUG, get_tag(), "[Player] Resume player : uid(%d)", uid);
683 if (false == g_player_init) {
684 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
690 current = __player_get_item(uid);
691 if (NULL == current) {
692 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] uid(%d) is not valid", uid);
696 /* check current player */
697 if (NULL != g_playing_info)
698 g_playing_info = NULL;
700 current->state = APP_STATE_PLAYING;
701 g_playing_info = current;
703 SLOG(LOG_DEBUG, get_tag(), "[Player] Run thread");
704 ecore_thread_run(__play_thread, __end_play_thread, NULL, NULL);
709 int ttsd_player_all_stop()
711 if (false == g_player_init) {
712 SLOG(LOG_ERROR, get_tag(), "[Player ERROR] Not Initialized");
716 g_playing_info = NULL;
719 player_s *data = NULL;
721 if (0 < g_list_length(g_player_list)) {
722 /* Get a first item */
723 iter = g_list_first(g_player_list);
725 while (NULL != iter) {
726 /* Get handle data from list */
727 data = (player_s*)iter->data;
730 if (0 > ttsd_data_get_client_state(data->uid, &state)) {
731 SLOG(LOG_ERROR, get_tag(), "[player ERROR] uid(%d) is not valid", data->uid);
732 ttsd_player_destroy_instance(data->uid);
733 iter = g_list_next(iter);
737 if (APP_STATE_PLAYING == state || APP_STATE_PAUSED == state) {
738 data->event = TTSP_RESULT_EVENT_FINISH;
739 data->state = APP_STATE_READY;
741 if (true == data->is_paused_data) {
742 if (NULL != data->paused_data.data) {
743 free(data->paused_data.data);
744 data->paused_data.data = NULL;
748 data->is_paused_data = false;
753 iter = g_list_next(iter);
757 SLOG(LOG_DEBUG, get_tag(), "[Player SUCCESS] player all stop!!");