tizen beta release
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_sound.c
1 /*
2  * libmm-camcorder
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jeongmo Yang <jm80.yang@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 /*=======================================================================================
23 |  INCLUDE FILES                                                                        |
24 =======================================================================================*/
25 #include <mm_sound.h>
26 #include <mm_sound_private.h>
27 #include <audio-session-manager.h>
28 #include "mm_camcorder_internal.h"
29 #include "mm_camcorder_sound.h"
30
31 /*---------------------------------------------------------------------------------------
32 |    GLOBAL VARIABLE DEFINITIONS for internal                                           |
33 ---------------------------------------------------------------------------------------*/
34
35 /*---------------------------------------------------------------------------------------
36 |    LOCAL VARIABLE DEFINITIONS for internal                                            |
37 ---------------------------------------------------------------------------------------*/
38 #define BLOCK_SIZE 2048
39
40 /*---------------------------------------------------------------------------------------
41 |    LOCAL FUNCTION PROTOTYPES:                                                         |
42 ---------------------------------------------------------------------------------------*/
43 static gboolean __prepare_buffer(SOUND_INFO *info, char *filename);
44 static gboolean __cleanup_buffer(SOUND_INFO *info);
45 static void *__sound_open_thread_func(void *data);
46 static void *__sound_write_thread_func(void *data);
47 static void __solo_sound_callback(void *data);
48
49 static gboolean __prepare_buffer(SOUND_INFO *info, char *filename)
50 {
51         mmf_return_val_if_fail(info, FALSE);
52         mmf_return_val_if_fail(filename, FALSE);
53
54         info->infile = sf_open(filename, SFM_READ, &info->sfinfo);
55         if (!(info->infile)) {
56                 _mmcam_dbg_err("failed to open file [%s]", filename);
57                 return FALSE;
58         }
59
60         _mmcam_dbg_log("SOUND: frame       = %lld", info->sfinfo.frames);
61         _mmcam_dbg_log("SOUND: sameplerate = %d", info->sfinfo.samplerate);
62         _mmcam_dbg_log("SOUND: channel     = %d", info->sfinfo.channels);
63         _mmcam_dbg_log("SOUND: format      = 0x%x", info->sfinfo.format);
64
65         info->pcm_size = info->sfinfo.frames * info->sfinfo.channels * 2;
66         info->pcm_buf = (short *)malloc(info->pcm_size);
67         if (info->pcm_buf == NULL) {
68                 _mmcam_dbg_err("pcm_buf malloc failed");
69                 sf_close(info->infile);
70                 info->infile = NULL;
71                 return FALSE;
72         }
73         sf_read_short(info->infile, info->pcm_buf, info->pcm_size);
74
75         return TRUE;
76 }
77
78
79 static gboolean __cleanup_buffer(SOUND_INFO *info)
80 {
81         mmf_return_val_if_fail(info, FALSE);
82
83         if (info->infile) {
84                 sf_close(info->infile);
85                 info->infile = NULL;
86         }
87
88         if (info->pcm_buf) {
89                 free(info->pcm_buf);
90                 info->pcm_buf = NULL;
91         }
92
93         _mmcam_dbg_log("Done");
94
95         return TRUE;
96 }
97
98
99 static void *__sound_open_thread_func(void *data)
100 {
101         int ret = 0;
102         system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY;
103         SOUND_INFO *info = NULL;
104         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
105
106         mmf_return_val_if_fail(hcamcorder, NULL);
107
108         MMTA_ACUM_ITEM_BEGIN("    __sound_open_thread_func", FALSE);
109
110         info = &(hcamcorder->snd_info);
111
112         __ta__("        __prepare_buffer",
113         ret = __prepare_buffer(info, info->filename);
114         );
115         if (ret == FALSE) {
116                 goto EXIT_FUNC;
117         }
118
119         __ta__("        mm_sound_pcm_play_open",
120         ret = mm_sound_pcm_play_open_ex(&(info->handle), info->sfinfo.samplerate,
121                                         (info->sfinfo.channels == 1) ? MMSOUND_PCM_MONO : MMSOUND_PCM_STEREO,
122                                         MMSOUND_PCM_S16_LE, VOLUME_TYPE_FIXED, ASM_EVENT_EXCLUSIVE_MMSOUND);
123         );
124         if (ret < 0) {
125                 /* error */
126                 _mmcam_dbg_err("mm_sound_pcm_play_open failed [%x]", ret);
127                 __cleanup_buffer(info);
128                 goto EXIT_FUNC;
129         } else {
130                 /* success */
131                 info->state = _MMCAMCORDER_SOUND_STATE_PREPARE;
132                 _mmcam_dbg_log("mm_sound_pcm_play_open succeeded. state [%d]", info->state);
133         }
134
135         ret = mm_sound_route_get_system_policy(&route);
136         if (ret != MM_ERROR_NONE) {
137                 _mmcam_dbg_err("mm_sound_route_get_system_policy failed [%x]", ret);
138                 goto POLICY_ERROR;
139         }
140
141         _mmcam_dbg_log("current policy [%d]", route);
142
143         if (route != SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY) {
144                 ret = mm_sound_route_set_system_policy(SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY);
145                 if (ret != MM_ERROR_NONE) {
146                         _mmcam_dbg_err("mm_sound_route_set_system_policy failed [%x]", ret);
147                         goto POLICY_ERROR;
148                 }
149
150                 info->route_policy_backup = route;
151         }
152
153 EXIT_FUNC:
154         pthread_cond_signal(&(info->open_cond));
155         pthread_mutex_unlock(&(info->open_mutex));
156
157         _mmcam_dbg_log("Done");
158
159         MMTA_ACUM_ITEM_END("    __sound_open_thread_func", FALSE);
160
161         return NULL;
162
163 POLICY_ERROR:
164         pthread_mutex_unlock(&(info->open_mutex));
165         _mmcamcorder_sound_finalize((MMHandleType)hcamcorder);
166
167         return NULL;
168 }
169
170
171 static void *__sound_write_thread_func(void *data)
172 {
173         int ret = 0;
174         int bytes_to_write = 0;
175         int remain_bytes = 0;
176         system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY;
177         char *buffer_to_write = NULL;
178         SOUND_INFO *info = NULL;
179         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
180
181         mmf_return_val_if_fail(hcamcorder, NULL);
182
183         info = &(hcamcorder->snd_info);
184
185         _mmcam_dbg_log("RUN sound write thread");
186
187         pthread_mutex_lock(&(info->play_mutex));
188
189         do {
190                 pthread_cond_wait(&(info->play_cond), &(info->play_mutex));
191
192                 _mmcam_dbg_log("Signal received. Play sound.");
193
194                 if (info->thread_run == FALSE) {
195                         _mmcam_dbg_log("Exit thread command is detected");
196                         break;
197                 }
198
199                 ret = mm_sound_route_get_system_policy(&route);
200                 if (ret != MM_ERROR_NONE) {
201                         _mmcam_dbg_err("get_system_policy failed [%x]. skip sound play.", ret);
202                         break;
203                 }
204
205                 _mmcam_dbg_log("current policy [%d]", route);
206
207                 if (route != SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY) {
208                         ret = mm_sound_route_set_system_policy(SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY);
209                         if (ret != MM_ERROR_NONE) {
210                                 _mmcam_dbg_err("set_system_policy failed. skip sound play.");
211                                 break;
212                         }
213
214                         info->route_policy_backup = route;
215                 }
216
217                 buffer_to_write = (char *)info->pcm_buf;
218                 remain_bytes = info->pcm_size;
219                 bytes_to_write = 0;
220
221                 while (remain_bytes) {
222                         bytes_to_write = (remain_bytes >= BLOCK_SIZE) ? BLOCK_SIZE : remain_bytes;
223                         ret = mm_sound_pcm_play_write(info->handle, buffer_to_write, bytes_to_write);
224                         if (ret != bytes_to_write) {
225                                 _mmcam_dbg_err("pcm write error [%x]", ret);
226                         }
227                         remain_bytes -= bytes_to_write;
228                         buffer_to_write += bytes_to_write;
229                 }
230         } while (TRUE);
231
232         pthread_mutex_unlock(&(info->play_mutex));
233
234         _mmcam_dbg_log("END sound write thread");
235
236         return NULL;
237 }
238
239
240 gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename)
241 {
242         int ret = 0;
243         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
244         SOUND_INFO *info = NULL;
245
246         mmf_return_val_if_fail(hcamcorder, FALSE);
247
248         info = &(hcamcorder->snd_info);
249
250         pthread_mutex_lock(&(info->open_mutex));
251
252         if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
253                 _mmcam_dbg_warn("already initialized [%d]", info->state);
254                 pthread_mutex_unlock(&(info->open_mutex));
255                 return FALSE;
256         }
257
258         if (info->filename) {
259                 free(info->filename);
260                 info->filename = NULL;
261         }
262
263         info->filename = strdup(filename);
264         if (info->filename == NULL) {
265                 _mmcam_dbg_err("strdup failed");
266                 ret = FALSE;
267         } else {
268                 pthread_mutex_init(&(info->play_mutex), NULL);
269                 pthread_cond_init(&(info->play_cond), NULL);
270                 if (pthread_create(&(info->thread), NULL, __sound_write_thread_func, (void *)handle) == 0) {
271                         info->thread_run = TRUE;
272                         info->state = _MMCAMCORDER_SOUND_STATE_INIT;
273                         info->route_policy_backup = -1;
274                         _mmcam_dbg_log("write thread created");
275                         ret = TRUE;
276                 } else {
277                         _mmcam_dbg_err("failed to create write thread");
278                         free(info->filename);
279                         info->filename = NULL;
280                         ret = FALSE;
281                 }
282         }
283
284         pthread_mutex_unlock(&(info->open_mutex));
285
286         return ret;
287 }
288
289
290 gboolean _mmcamcorder_sound_prepare(MMHandleType handle)
291 {
292         int ret = FALSE;
293         pthread_t open_thread;
294         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
295         SOUND_INFO *info = NULL;
296
297         mmf_return_val_if_fail(hcamcorder, FALSE);
298
299         info = &(hcamcorder->snd_info);
300
301         pthread_mutex_lock(&(info->open_mutex));
302
303         if (info->state == _MMCAMCORDER_SOUND_STATE_INIT) {
304                 if (pthread_create(&open_thread, NULL, __sound_open_thread_func, (void *)handle) == 0) {
305                         _mmcam_dbg_log("open thread created");
306                         ret = TRUE;
307                 } else {
308                         _mmcam_dbg_err("failed to create open thread");
309                         ret = FALSE;
310                         pthread_mutex_unlock(&(info->open_mutex));
311                 }
312         } else {
313                 _mmcam_dbg_warn("Wrong state [%d]", info->state);
314                 ret = FALSE;
315                 pthread_mutex_unlock(&(info->open_mutex));
316         }
317
318         return ret;
319 }
320
321
322 gboolean _mmcamcorder_sound_play(MMHandleType handle)
323 {
324         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
325         SOUND_INFO *info = NULL;
326
327         mmf_return_val_if_fail(hcamcorder, FALSE);
328
329         info = &(hcamcorder->snd_info);
330
331         pthread_mutex_lock(&(info->open_mutex));
332
333         if (info->state < _MMCAMCORDER_SOUND_STATE_PREPARE) {
334                 _mmcam_dbg_log("not initialized state:[%d]", info->state);
335                 pthread_mutex_unlock(&(info->open_mutex));
336                 return FALSE;
337         }
338
339         _mmcam_dbg_log("Play start");
340
341         pthread_mutex_lock(&(info->play_mutex));
342         pthread_cond_signal(&(info->play_cond));
343         pthread_mutex_unlock(&(info->play_mutex));
344
345         pthread_mutex_unlock(&(info->open_mutex));
346
347         _mmcam_dbg_log("Done");
348
349         return TRUE;
350 }
351
352
353 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
354 {
355         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
356         SOUND_INFO *info = NULL;
357
358         mmf_return_val_if_fail(hcamcorder, FALSE);
359
360         info = &(hcamcorder->snd_info);
361
362         pthread_mutex_lock(&(info->open_mutex));
363
364         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
365                 _mmcam_dbg_warn("not initialized");
366                 pthread_mutex_unlock(&(info->open_mutex));
367                 return FALSE;
368         }
369
370         info->thread_run = 0;
371         pthread_cond_signal(&(info->play_cond));
372
373         if (info->thread) {
374                 _mmcam_dbg_log("wait for sound write thread join");
375                 pthread_join(info->thread, NULL);
376                 _mmcam_dbg_log("join done");
377         }
378
379         if (info->state == _MMCAMCORDER_SOUND_STATE_PREPARE) {
380                 _mmcam_dbg_log("restore route policy [%d]", info->route_policy_backup);
381
382                 if (info->route_policy_backup != -1) {
383                         mm_sound_route_set_system_policy(info->route_policy_backup);
384                 }
385
386                 mm_sound_pcm_play_close(info->handle);
387                 __cleanup_buffer(info);
388         }
389
390         if (info->filename) {
391                 free(info->filename);
392                 info->filename = NULL;
393         }
394
395         info->state = _MMCAMCORDER_SOUND_STATE_NONE;
396         info->route_policy_backup = -1;
397
398         pthread_mutex_destroy(&(info->play_mutex));
399         pthread_cond_destroy(&(info->play_cond));
400
401         pthread_mutex_unlock(&(info->open_mutex));
402
403         _mmcam_dbg_log("Done");
404
405         return TRUE;
406 }
407
408
409 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync)
410 {
411         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
412
413         int sound_handle = 0;
414         int ret = 0;
415         int sound_enable = TRUE;
416
417         mmf_return_if_fail( filepath );
418
419         _mmcam_dbg_log( "START" );
420
421         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
422                                           "capture-sound-enable", &sound_enable,
423                                           NULL);
424         if (ret == MM_ERROR_NONE) {
425                 if (sound_enable == FALSE) {
426                         _mmcam_dbg_log("Capture sound DISABLED.");
427                         return;
428                 }
429         } else {
430                 _mmcam_dbg_warn("capture-sound-enable get FAILED.[%x]", ret);
431         }
432
433         ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
434         if (ret != 0) {
435                 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
436                 return;
437         }
438
439         MMTA_ACUM_ITEM_BEGIN("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE);
440
441         ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED, __solo_sound_callback,
442                                             (void*)hcamcorder, &sound_handle);
443         if (ret != MM_ERROR_NONE) {
444                 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
445         } else {
446                 if (sync) {
447                         struct timespec timeout;
448                         struct timeval tv;
449
450                         gettimeofday( &tv, NULL );
451                         timeout.tv_sec = tv.tv_sec + 2;
452                         timeout.tv_nsec = tv.tv_usec * 1000;
453
454                         _mmcam_dbg_log("Wait for signal");
455
456                         if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
457                                 _mmcam_dbg_log("signal received.");
458                         } else {
459                                 _mmcam_dbg_warn("capture sound play timeout.");
460                                 if (sound_handle > 0) {
461                                         mm_sound_stop_sound(sound_handle);
462                                 }
463                         }
464                 }
465         }
466
467         MMTA_ACUM_ITEM_END("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE);
468
469         pthread_mutex_unlock(&(hcamcorder->sound_lock));
470
471         _mmcam_dbg_log("DONE");
472
473         return;
474 }
475
476 static void __solo_sound_callback(void *data)
477 {
478         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
479
480         mmf_return_if_fail(hcamcorder);
481
482         _mmcam_dbg_log("START");
483
484         _mmcam_dbg_log("Signal SEND");
485         pthread_cond_broadcast(&(hcamcorder->sound_cond));
486
487         _mmcam_dbg_log("DONE");
488
489         return;
490 }
491