Update version to 1.70.7
[platform/core/uifw/voice-control.git] / client / vc_mgr_player.c
1 /*
2 * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <audio_io.h>
18 #include <Ecore.h>
19 #include <dlog.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
24 #include "vc_main.h"
25 #include "vc_mgr_player.h"
26 #include "vc_mgr_data.h"
27
28 typedef enum {
29         AUDIO_STATE_NONE = 0,
30         AUDIO_STATE_READY,
31         AUDIO_STATE_PLAY
32 } audio_state_e;
33
34 typedef struct {
35         vc_feedback_state_e state;
36
37         vc_feedback_event_e event;
38         int idx;
39 } player_s;
40
41 #define SOUND_BUFFER_LENGTH 2048
42
43 static bool g_player_init = false;
44
45 static player_s* g_playing_info;
46
47 static audio_state_e g_audio_state;
48
49 static vc_audio_type_e g_audio_type;
50
51 static vc_audio_channel_e g_audio_channel;
52
53 static int g_sampling_rate;
54
55 static audio_out_h g_audio_h;
56
57
58 static int __create_audio_out(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type)
59 {
60         int ret = -1;
61         audio_channel_e sample_channel = 0;
62         audio_sample_type_e sample_type = 0;
63
64         if (VC_AUDIO_CHANNEL_MONO == channel) {
65                 sample_channel = AUDIO_CHANNEL_MONO;
66         } else if (VC_AUDIO_CHANNEL_STEREO == channel) {
67                 sample_channel = AUDIO_CHANNEL_STEREO;
68         }
69
70         if (VC_AUDIO_TYPE_PCM_S16_LE == audio_type) {
71                 sample_type = AUDIO_SAMPLE_TYPE_S16_LE;
72         } else {
73                 sample_type = AUDIO_SAMPLE_TYPE_U8;
74         }
75
76         /* create audio_out new */
77         ret = audio_out_create_new(rate, sample_channel, sample_type, &g_audio_h);
78         if (AUDIO_IO_ERROR_NONE != ret) {
79                 g_audio_state = AUDIO_STATE_NONE;
80                 g_audio_h = NULL;
81                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to create audio. ret(%d)", ret);
82                 return -1;
83         } else {
84                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Create audio");
85         }
86
87         g_audio_channel = channel;
88         g_audio_type = audio_type;
89         g_sampling_rate = rate;
90
91         g_audio_state = AUDIO_STATE_READY;
92
93         return 0;
94 }
95
96 static int __destroy_audio_out()
97 {
98         if (NULL == g_audio_h) {
99                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Current handle is not valid");
100                 return -1;
101         }
102
103         int ret = -1;
104         ret = audio_out_destroy(g_audio_h);
105         if (AUDIO_IO_ERROR_NONE != ret) {
106                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to destroy audio. ret(%d)", ret);
107                 return -1;
108         } else {
109                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Destroy audio");
110         }
111
112         g_audio_channel = 0;
113         g_audio_type = 0;
114         g_sampling_rate = 0;
115
116         g_audio_state = AUDIO_STATE_NONE;
117         g_audio_h = NULL;
118
119         return 0;
120 }
121
122 int vc_mgr_player_init(int rate, vc_audio_channel_e channel, vc_audio_type_e audio_type)
123 {
124         g_audio_state = AUDIO_STATE_NONE;
125         g_audio_h = NULL;
126
127         ecore_thread_max_set(1);
128
129         int ret = -1;
130
131
132         ret = __create_audio_out(rate, channel, audio_type);
133         if (0 != ret) {
134                 return VC_ERROR_OPERATION_FAILED;
135         }
136
137         g_player_init = true;
138
139         return VC_ERROR_NONE;
140 }
141
142 int vc_mgr_player_release()
143 {
144         if (false == g_player_init) {
145                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Not initialized");
146                 return VC_ERROR_OPERATION_FAILED;
147         }
148
149         int ret = -1;
150
151         int thread_count = ecore_thread_active_get();
152         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Active thread count : %d", thread_count);
153         int count = 0;
154         while (0 < thread_count) {
155                 usleep(10000);
156
157                 count++;
158                 if (20 == count) {
159                         SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Thread is blocked. Player release continue");
160                         break;
161                 }
162
163                 thread_count = ecore_thread_active_get();
164         }
165
166         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Thread is release");
167
168         ret = __destroy_audio_out();
169         if (0 != ret) {
170                 return VC_ERROR_OPERATION_FAILED;
171         }
172
173         g_player_init = false;
174
175         return VC_ERROR_NONE;
176 }
177
178 static void __play_feedback_thread(void* data, Ecore_Thread* thread)
179 {
180         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Start thread");
181
182         if (NULL == g_playing_info) {
183                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] No current player");
184                 return;
185         }
186
187         player_s* player = g_playing_info;
188         vc_feedback_data_s* feedback_data = NULL;
189
190         int ret = -1;
191         int len = SOUND_BUFFER_LENGTH;
192         int idx = 0;
193
194         while (1) {
195                 /* get feedback data */
196                 ret = vc_mgr_data_get_feedback_data(&feedback_data);
197                 if (0 != ret || NULL == feedback_data) {
198                         /* empty queue */
199                         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] No feedback data. Waiting mode");
200
201                         /* waiting */
202                         while (1) {
203                                 usleep(10000);
204                                 if (0 < vc_mgr_data_get_feedback_data_size()) {
205                                         SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Resume thread");
206                                         break;
207                                 }
208
209                                 if (AUDIO_STATE_PLAY == g_audio_state) {
210                                         /* release audio & recover session */
211                                         ret = audio_out_unprepare(g_audio_h);
212                                         if (AUDIO_IO_ERROR_NONE != ret) {
213                                                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio");
214                                         } else {
215                                                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Unprepare audio");
216                                         }
217                                         g_audio_state = AUDIO_STATE_READY;
218                                 }
219                         }
220
221                         SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Finish to wait for new feedback data come");
222
223                         /* resume play thread */
224                         player->state = VC_FEEDBACK_STATE_PLAYING;
225                         continue;
226                 }
227
228                 if (VC_FEEDBACK_EVENT_START == feedback_data->event ||
229                                 (VC_FEEDBACK_EVENT_FINISH == player->event && VC_FEEDBACK_EVENT_FINISH == feedback_data->event)) {
230                         int pid = vc_mgr_data_get_pid();
231                         SLOG(LOG_INFO, TAG_VCM, "[Player DEBUG] Start utterance (%d)", pid);
232                 }
233
234                 player->event = feedback_data->event;
235                 idx = 0;
236                 /* If no feedback data and EVENT_FINISH */
237                 if (NULL == feedback_data->data || 0 >= feedback_data->data_size) {
238                         if (VC_FEEDBACK_EVENT_FINISH == feedback_data->event) {
239                                 int pid = vc_mgr_data_get_pid();
240                                 if (pid <= 0) {
241                                         return;
242                                 }
243                                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] No sound data");
244                         }
245                         SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Finish utterance");
246                         vc_mgr_data_clear_feedback_data(&feedback_data);
247                         continue;
248                 }
249
250                 if (g_sampling_rate != feedback_data->rate || g_audio_type != feedback_data->audio_type || g_audio_channel != feedback_data->channel) {
251                         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] change audio handle");
252                         if (NULL != g_audio_h) {
253                                 __destroy_audio_out();
254                         }
255
256                         if (0 > __create_audio_out(feedback_data->rate, feedback_data->channel, feedback_data->audio_type)) {
257                                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to create audio out");
258                                 vc_mgr_data_clear_feedback_data(&feedback_data);
259
260                                 return;
261                         }
262                 }
263
264                 while (VC_FEEDBACK_STATE_PLAYING == player->state) {
265                         if ((unsigned int)idx >= feedback_data->data_size)
266                                 break;
267
268                         if ((unsigned int)idx + SOUND_BUFFER_LENGTH > feedback_data->data_size) {
269                                 len = feedback_data->data_size - idx;
270                         } else {
271                                 len = SOUND_BUFFER_LENGTH;
272                         }
273
274                         if (AUDIO_STATE_READY == g_audio_state) {
275                                 /* request prepare */
276                                 ret = audio_out_prepare(g_audio_h);
277                                 if (AUDIO_IO_ERROR_NONE != ret) {
278                                         SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to prepare audio");
279                                         vc_mgr_data_clear_feedback_data(&feedback_data);
280                                         return;
281                                 }
282                                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Prepare audio");
283                                 g_audio_state = AUDIO_STATE_PLAY;
284                         }
285
286                         char* temp_data = feedback_data->data;
287                         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] data(%p), idx(%d), len(%d)", temp_data, idx, len);
288
289                         ret = audio_out_write(g_audio_h, &temp_data[idx], len);
290                         if (0 > ret) {
291                                 SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Fail to audio write - %d", ret);
292                         } else {
293                                 idx += len;
294                         }
295
296                         if (NULL == g_playing_info) {
297                                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Current player is NULL");
298                                 g_audio_state = AUDIO_STATE_READY;
299                                 ret = audio_out_unprepare(g_audio_h);
300                                 if (AUDIO_IO_ERROR_NONE != ret) {
301                                         SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio");
302                                 }
303
304                                 vc_mgr_data_clear_feedback_data(&feedback_data);
305
306                                 return;
307                         }
308                 }
309
310                 if (NULL == g_playing_info && VC_FEEDBACK_STATE_READY == player->state) {
311                         /* player stop */
312                         g_audio_state = AUDIO_STATE_READY;
313                         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Stop play thread");
314
315                         /* request to unprepare audio */
316                         ret = audio_out_unprepare(g_audio_h);
317                         if (AUDIO_IO_ERROR_NONE != ret) {
318                                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio");
319                         } else {
320                                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Unprepare audio");
321                         }
322
323                         vc_mgr_data_clear_feedback_data(&feedback_data);
324                         return;
325                 }
326
327                 if ((VC_FEEDBACK_STATE_PLAYING == player->state) && (VC_FEEDBACK_EVENT_FINISH == feedback_data->event)) {
328                         int pid = vc_mgr_data_get_pid();
329                         if (pid <= 0) {
330                                 return;
331                         }
332                         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] Finish utterance");
333                 }
334
335                 vc_mgr_data_clear_feedback_data(&feedback_data);
336
337                 if (NULL == g_playing_info) {
338                         SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Current player is NULL");
339                         g_audio_state = AUDIO_STATE_READY;
340                         ret = audio_out_unprepare(g_audio_h);
341                         if (AUDIO_IO_ERROR_NONE != ret) {
342                                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Fail to unprepare audio");
343                         }
344
345                         return;
346                 }
347
348         }
349
350 }
351
352 static void __end_play_feedback_thread(void* data, Ecore_Thread* thread)
353 {
354         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] End thread");
355 }
356
357 int vc_mgr_player_play()
358 {
359         if (false == g_player_init) {
360                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Not initialized");
361                 return VC_ERROR_OPERATION_FAILED;
362         }
363
364         if (NULL != g_playing_info) {
365                 SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Stop old player");
366                 vc_mgr_player_stop();
367         }
368
369         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] start play");
370
371         /* check sound queue size */
372         int data_size = vc_mgr_data_get_feedback_data_size();
373         if (0 == data_size) {
374                 SLOG(LOG_WARN, TAG_VCM, "[Player WARN] A sound queue of current player is empty");
375         } else if (0 < data_size) {
376                 SLOG(LOG_INFO, TAG_VCM, "[Player INFO] Run thread");
377                 ecore_thread_run(__play_feedback_thread, __end_play_feedback_thread, NULL, NULL);
378         }
379
380         return VC_ERROR_NONE;
381 }
382
383 int vc_mgr_player_stop()
384 {
385         if (false == g_player_init) {
386                 SLOG(LOG_ERROR, TAG_VCM, "[Player ERROR] Not initialized");
387                 return VC_ERROR_OPERATION_FAILED;
388         }
389
390         if (NULL != g_playing_info) {
391                 g_playing_info = NULL;
392                 SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] No more current playing");
393         }
394
395         SLOG(LOG_DEBUG, TAG_VCM, "[Player DEBUG] stop play");
396
397         int thread_count = ecore_thread_active_get();
398         int count = 0;
399
400         while (0 < thread_count) {
401                 usleep(10000);
402
403                 count++;
404                 if (30 == count) {
405                         SLOG(LOG_WARN, TAG_VCM, "[Player WARN] Thread is blocked. Player release continue");
406                         break;
407                 }
408
409                 thread_count = ecore_thread_active_get();
410         }
411
412         return VC_ERROR_NONE;
413 }