Release version 0.10.19
[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 "mm_camcorder_internal.h"
28 #include "mm_camcorder_sound.h"
29
30 /*---------------------------------------------------------------------------------------
31 |    GLOBAL VARIABLE DEFINITIONS for internal                                           |
32 ---------------------------------------------------------------------------------------*/
33
34 /*---------------------------------------------------------------------------------------
35 |    LOCAL VARIABLE DEFINITIONS for internal                                            |
36 ---------------------------------------------------------------------------------------*/
37 #define SAMPLE_SOUND_RATE       44100
38 #define DEFAULT_ACTIVE_DEVICE   0xffffffff
39
40 /*---------------------------------------------------------------------------------------
41 |    LOCAL FUNCTION PROTOTYPES:                                                         |
42 ---------------------------------------------------------------------------------------*/
43 static void __solo_sound_callback(void *data);
44
45 static void __pulseaudio_play_sample_cb(pa_context *pulse_context, uint32_t stream_index, void *user_data)
46 {
47         SOUND_INFO *info = NULL;
48
49         mmf_return_if_fail(user_data);
50
51         info = (SOUND_INFO *)user_data;
52
53         _mmcam_dbg_log("START - idx : %d", stream_index);
54
55         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
56
57         _mmcam_dbg_log("DONE");
58
59         return;
60 }
61
62 static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
63 {
64         int state = 0;
65         SOUND_INFO *info = NULL;
66
67         mmf_return_if_fail(user_data);
68
69         info = (SOUND_INFO *)user_data;
70
71         state = pa_context_get_state(pulse_context);
72         switch (state) {
73         case PA_CONTEXT_READY:
74                 _mmcam_dbg_log("pulseaudio context READY");
75                 if (info->pulse_context == pulse_context) {
76                         /* Signal */
77                         _mmcam_dbg_log("pulseaudio send signal");
78                         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
79                 }
80                 break;
81         case PA_CONTEXT_TERMINATED:
82                 if (info->pulse_context == pulse_context) {
83                         /* Signal */
84                         _mmcam_dbg_log("Context terminated : pulseaudio send signal");
85                         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
86                 }
87                 break;
88         case PA_CONTEXT_UNCONNECTED:
89         case PA_CONTEXT_CONNECTING:
90         case PA_CONTEXT_AUTHORIZING:
91         case PA_CONTEXT_SETTING_NAME:
92         case PA_CONTEXT_FAILED:
93         default:
94                 _mmcam_dbg_log("pulseaudio context %p, state %d",
95                                pulse_context, state);
96                 break;
97         }
98
99         return;
100 }
101
102 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
103 static void __pulseaudio_stream_write_cb(pa_stream *stream, size_t length, void *user_data)
104 {
105         sf_count_t read_length;
106         short *data;
107         SOUND_INFO *info = NULL;
108
109         mmf_return_if_fail(user_data);
110
111         info = (SOUND_INFO *)user_data;
112
113         _mmcam_dbg_log("START");
114
115         data = pa_xmalloc(length);
116
117         read_length = (sf_count_t)(length/pa_frame_size(&(info->sample_spec)));
118
119         if ((sf_readf_short(info->infile, data, read_length)) != read_length) {
120                 pa_xfree(data);
121                 return;
122         }
123
124         pa_stream_write(stream, data, length, pa_xfree, 0, PA_SEEK_RELATIVE);
125
126         info->sample_length -= length;
127
128         if (info->sample_length <= 0) {
129                 pa_stream_set_write_callback(info->sample_stream, NULL, NULL);
130                 pa_stream_finish_upload(info->sample_stream);
131
132                 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
133                 _mmcam_dbg_log("send signal DONE");
134         }
135
136         _mmcam_dbg_log("DONE read_length %d", read_length);
137
138         return;
139 }
140
141
142 static void __pulseaudio_remove_sample_finish_cb(pa_context *pulse_context, int success, void *user_data)
143 {
144         SOUND_INFO *info = NULL;
145
146         mmf_return_if_fail(user_data);
147
148         info = (SOUND_INFO *)user_data;
149
150         _mmcam_dbg_log("START");
151
152         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
153
154         _mmcam_dbg_log("DONE");
155
156         return;
157 }
158 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
159
160 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
161 gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename)
162 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
163 gboolean _mmcamcorder_sound_init(MMHandleType handle)
164 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
165 {
166         int ret = 0;
167         int sound_enable = TRUE;
168         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
169         SOUND_INFO *info = NULL;
170         mm_sound_device_in device_in;
171         mm_sound_device_out device_out;
172         pa_mainloop_api *api = NULL;
173         int error = PA_ERR_INTERNAL;
174
175         mmf_return_val_if_fail(hcamcorder, FALSE);
176
177         /* check sound play enable */
178         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
179                                           "capture-sound-enable", &sound_enable,
180                                           NULL);
181         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
182         if (!sound_enable) {
183                 _mmcam_dbg_warn("capture sound disabled");
184                 return FALSE;
185         }
186
187         info = &(hcamcorder->snd_info);
188
189         pthread_mutex_lock(&(info->open_mutex));
190
191         if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
192                 _mmcam_dbg_warn("already initialized [%d]", info->state);
193                 pthread_mutex_unlock(&(info->open_mutex));
194                 return TRUE;
195         }
196
197 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
198         if (info->filename) {
199                 free(info->filename);
200                 info->filename = NULL;
201         }
202
203         info->filename = strdup(filename);
204         if (info->filename == NULL) {
205                 _mmcam_dbg_err("strdup failed");
206                 return FALSE;
207         }
208 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
209
210         pthread_mutex_init(&(info->play_mutex), NULL);
211         pthread_cond_init(&(info->play_cond), NULL);
212
213 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
214         /* read sample */
215         memset (&(info->sfinfo), 0, sizeof(SF_INFO));
216         info->infile = sf_open(info->filename, SFM_READ, &(info->sfinfo));
217         if (!(info->infile)) {
218                 _mmcam_dbg_err("Failed to open sound file");
219                 goto SOUND_INIT_ERROR;
220         }
221 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
222
223         /**
224          * Init Pulseaudio thread
225          */
226         /* create pulseaudio mainloop */
227         info->pulse_mainloop = pa_threaded_mainloop_new();
228         if (info->pulse_mainloop == NULL) {
229                 _mmcam_dbg_err("pa_threaded_mainloop_new failed");
230                 goto SOUND_INIT_ERROR;
231         }
232
233         /* start PA mainloop */
234         ret = pa_threaded_mainloop_start(info->pulse_mainloop);
235         if (ret < 0) {
236                 _mmcam_dbg_err("pa_threaded_mainloop_start failed");
237                 goto SOUND_INIT_ERROR;
238         }
239
240         /* lock pulseaudio thread */
241         pa_threaded_mainloop_lock(info->pulse_mainloop);
242
243         /* get pulseaudio api */
244         api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
245         if (api == NULL) {
246                 _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
247                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
248                 goto SOUND_INIT_ERROR;
249         }
250
251         /* create pulseaudio context */
252         info->pulse_context = pa_context_new(api, NULL);
253         if (info->pulse_context == NULL) {
254                 _mmcam_dbg_err("pa_context_new failed");
255                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
256                 goto SOUND_INIT_ERROR;
257         }
258
259         /* set pulseaudio context callback */
260         pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
261
262         if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
263                 _mmcam_dbg_err("pa_context_connect error");
264         }
265
266         /* wait READY state of pulse context */
267         while (TRUE) {
268                 pa_context_state_t state = pa_context_get_state(info->pulse_context);
269
270                 _mmcam_dbg_log("pa context state is now %d", state);
271
272                 if (!PA_CONTEXT_IS_GOOD (state)) {
273                         _mmcam_dbg_log("connection failed");
274                         break;
275                 }
276
277                 if (state == PA_CONTEXT_READY) {
278                         _mmcam_dbg_log("pa context READY");
279                         break;
280                 }
281
282                 /* Wait until the context is ready */
283                 _mmcam_dbg_log("waiting..................");
284                 pa_threaded_mainloop_wait(info->pulse_mainloop);
285                 _mmcam_dbg_log("waiting DONE. check again...");
286         }
287
288         /* unlock pulseaudio thread */
289         pa_threaded_mainloop_unlock(info->pulse_mainloop);
290
291 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
292         /**
293          * Upload sample
294          */
295         if (pa_sndfile_read_sample_spec(info->infile, &(info->sample_spec)) < 0) {
296                 _mmcam_dbg_err("Failed to determine sample specification from file");
297                 goto SOUND_INIT_ERROR;
298         }
299
300         info->sample_spec.format = PA_SAMPLE_S16LE;
301
302         if (pa_sndfile_read_channel_map(info->infile, &(info->channel_map)) < 0) {
303                 pa_channel_map_init_extend(&(info->channel_map), info->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
304
305                 if (info->sample_spec.channels > 2) {
306                         _mmcam_dbg_warn("Failed to determine sample specification from file");
307                 }
308         }
309
310         info->sample_length = (size_t)info->sfinfo.frames * pa_frame_size(&(info->sample_spec));
311
312         pa_threaded_mainloop_lock(info->pulse_mainloop);
313
314         /* prepare uploading */
315         info->sample_stream = pa_stream_new(info->pulse_context, SAMPLE_SOUND_NAME, &(info->sample_spec), NULL);
316         /* set stream write callback */
317         pa_stream_set_write_callback(info->sample_stream, __pulseaudio_stream_write_cb, info);
318         /* upload sample (ASYNC) */
319         pa_stream_connect_upload(info->sample_stream, info->sample_length);
320         /* wait for upload completion */
321         pa_threaded_mainloop_wait(info->pulse_mainloop);
322
323         pa_threaded_mainloop_unlock(info->pulse_mainloop);
324
325         /* close sndfile */
326         sf_close(info->infile);
327         info->infile = NULL;
328 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
329         if (info->sample_stream) {
330                 pa_stream_connect_playback(info->sample_stream, NULL, NULL, 0, NULL, NULL);
331
332                 for (;;) {
333                         pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
334
335                         if (state == PA_STREAM_READY) {
336                                 _mmcam_dbg_warn("device READY done");
337                                 break;
338                         }
339
340                         if (!PA_STREAM_IS_GOOD(state)) {
341                                 error = pa_context_errno(info->pulse_context);
342                                 _mmcam_dbg_err("pa context state is not good, %d", error);
343                                 break;
344                         }
345
346                         /* Wait until the stream is ready */
347                         pa_threaded_mainloop_wait(info->pulse_mainloop);
348                 }
349         }
350 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
351
352         /* backup current route */
353         info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
354
355         ret = mm_sound_get_active_device(&device_in, &device_out);
356         if (ret != MM_ERROR_NONE) {
357                 _mmcam_dbg_err("mm_sound_get_active_device failed [%x]. skip sound play.", ret);
358                 goto SOUND_INIT_ERROR;
359         }
360
361         _mmcam_dbg_log("current out [%x]", device_out);
362
363         if (device_out != MM_SOUND_DEVICE_OUT_SPEAKER) {
364                 //ret = mm_sound_set_active_route_without_broadcast (MM_SOUND_ROUTE_OUT_SPEAKER);
365                 if (ret != MM_ERROR_NONE) {
366                         _mmcam_dbg_err("mm_sound_set_active_route_without_broadcast failed [%x]. skip sound play.", ret);
367                         goto SOUND_INIT_ERROR;
368                 }
369                 info->active_out_backup = device_out;
370         }
371
372         //info->volume_type = PA_TIZEN_AUDIO_VOLUME_TYPE_FIXED;
373         info->volume_level = 0;
374
375         info->state = _MMCAMCORDER_SOUND_STATE_INIT;
376
377         _mmcam_dbg_log("init DONE");
378
379         pthread_mutex_unlock(&(info->open_mutex));
380
381         return TRUE;
382
383 SOUND_INIT_ERROR:
384
385 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
386         /**
387          * Release allocated resources
388          */
389         if (info->filename) {
390                 free(info->filename);
391                 info->filename = NULL;
392         }
393 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
394
395         /* remove pulse mainloop */
396         if (info->pulse_mainloop) {
397                 pa_threaded_mainloop_lock(info->pulse_mainloop);
398
399                 /* remove pulse context */
400                 if (info->pulse_context) {
401 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
402                         /* remove uploaded sample */
403                         if (info->sample_stream) {
404                                 pa_threaded_mainloop_lock(info->pulse_mainloop);
405
406                                 /* Remove sample (ASYNC) */
407                                 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
408
409                                 /* Wait for async operation */
410                                 pa_threaded_mainloop_wait(info->pulse_mainloop);
411                         }
412 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
413                         /* release sample stream */
414                         if (info->sample_stream) {
415                                 pa_stream_disconnect(info->sample_stream);
416                                 pa_stream_unref(info->sample_stream);
417                                 info->sample_stream = NULL;
418                         }
419 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
420
421                         /* Make sure we don't get any further callbacks */
422                         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
423
424                         pa_context_disconnect(info->pulse_context);
425                         pa_context_unref(info->pulse_context);
426                         info->pulse_context = NULL;
427                 }
428
429                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
430
431                 pa_threaded_mainloop_stop(info->pulse_mainloop);
432                 pa_threaded_mainloop_free(info->pulse_mainloop);
433                 info->pulse_mainloop = NULL;
434         }
435
436         /* remove mutex and cond */
437         pthread_mutex_destroy(&(info->play_mutex));
438         pthread_cond_destroy(&(info->play_cond));
439
440         pthread_mutex_unlock(&(info->open_mutex));
441
442         return FALSE;
443 }
444
445
446 gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
447 {
448         int sound_enable = TRUE;
449         int gain_type = VOLUME_GAIN_SHUTTER1;
450
451         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
452         SOUND_INFO *info = NULL;
453         pa_operation *pulse_op = NULL;
454
455         mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
456
457         /* check sound play enable */
458         mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
459                                     "capture-sound-enable", &sound_enable,
460                                     NULL);
461         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
462         if (!sound_enable) {
463                 _mmcam_dbg_warn("capture sound disabled");
464                 return FALSE;
465         }
466
467         info = &(hcamcorder->snd_info);
468
469         pthread_mutex_lock(&(info->open_mutex));
470
471         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
472                 _mmcam_dbg_log("not initialized state:[%d]", info->state);
473                 pthread_mutex_unlock(&(info->open_mutex));
474                 return FALSE;
475         }
476
477         if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_CAPTURE)) {
478                 gain_type = VOLUME_GAIN_SHUTTER2;
479         } else if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP)) {
480                 gain_type = VOLUME_GAIN_CAMCORDING;
481         }
482
483         _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
484
485         if (sync_play) {
486                 pa_threaded_mainloop_lock(info->pulse_mainloop);
487 /*
488                 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
489                                                   sample_name,
490                                                   info->volume_type,
491                                                   gain_type,
492                                                   info->volume_level,
493                                                   __pulseaudio_play_sample_cb,
494                                                   info);
495 */
496                 _mmcam_dbg_log("wait for signal");
497                 pa_threaded_mainloop_wait(info->pulse_mainloop);
498                 _mmcam_dbg_log("received signal");
499
500                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
501         } else {
502 /*
503                 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
504                                                   sample_name,
505                                                   info->volume_type,
506                                                   gain_type,
507                                                   info->volume_level,
508                                                   NULL,
509                                                   NULL);
510 */
511         }
512
513 /*
514         if (pulse_op) {
515                 pa_operation_unref(pulse_op);
516                 pulse_op = NULL;
517         }
518 */
519
520         pthread_mutex_unlock(&(info->open_mutex));
521
522         _mmcam_dbg_log("Done");
523
524         return TRUE;
525 }
526
527
528 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
529 {
530         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
531         SOUND_INFO *info = NULL;
532         mm_sound_device_in device_in;
533         mm_sound_device_out device_out;
534         int ret = 0;
535
536         mmf_return_val_if_fail(hcamcorder, FALSE);
537
538         info = &(hcamcorder->snd_info);
539
540         _mmcam_dbg_err("START");
541
542         pthread_mutex_lock(&(info->open_mutex));
543
544         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
545                 _mmcam_dbg_warn("not initialized");
546                 pthread_mutex_unlock(&(info->open_mutex));
547                 return TRUE;
548         }
549
550         /* Restore route */
551         _mmcam_dbg_log("restore route");
552         if (info->active_out_backup != DEFAULT_ACTIVE_DEVICE) {
553                 ret = mm_sound_get_active_device(&device_in, &device_out);
554                 if (ret != MM_ERROR_NONE) {
555                         _mmcam_dbg_err("mm_sound_get_active_device failed [%x]", ret);
556                 }
557
558                 _mmcam_dbg_log("current out [%x]", device_out);
559
560                 if (device_out != info->active_out_backup) {
561                         //ret = mm_sound_set_active_route_without_broadcast (info->active_out_backup);
562                         if (ret != MM_ERROR_NONE) {
563                                 _mmcam_dbg_err("mm_sound_set_active_route_without_broadcast [%x]", ret);
564                         }
565                 }
566         }
567
568         pa_threaded_mainloop_lock(info->pulse_mainloop);
569
570 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
571         /**
572          * Remove sample
573          */
574         _mmcam_dbg_log("remove sample");
575
576         /* Remove sample (ASYNC) */
577         pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
578
579         /* Wait for async operation */
580         pa_threaded_mainloop_wait(info->pulse_mainloop);
581 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
582         if (info->sample_stream) {
583                 pa_stream_disconnect(info->sample_stream);
584                 pa_stream_unref(info->sample_stream);
585                 info->sample_stream = NULL;
586         }
587 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
588
589         /**
590          * Release pulseaudio thread
591          */
592         _mmcam_dbg_log("release pulseaudio thread");
593
594         pa_context_disconnect(info->pulse_context);
595
596         /* Make sure we don't get any further callbacks */
597         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
598
599         pa_context_unref(info->pulse_context);
600         info->pulse_context = NULL;
601
602         pa_threaded_mainloop_unlock(info->pulse_mainloop);
603
604         pa_threaded_mainloop_stop(info->pulse_mainloop);
605         pa_threaded_mainloop_free(info->pulse_mainloop);
606         info->pulse_mainloop = NULL;
607
608 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
609         if (info->filename) {
610                 free(info->filename);
611                 info->filename = NULL;
612         }
613 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
614
615         info->state = _MMCAMCORDER_SOUND_STATE_NONE;
616         info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
617
618         /* release mutex and cond */
619         _mmcam_dbg_log("release play_mutex/cond");
620         pthread_mutex_destroy(&(info->play_mutex));
621         pthread_cond_destroy(&(info->play_cond));
622
623         pthread_mutex_unlock(&(info->open_mutex));
624
625         _mmcam_dbg_err("DONE");
626
627         return TRUE;
628 }
629
630
631 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
632 {
633         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
634
635         int sound_handle = 0;
636         int ret = MM_ERROR_NONE;
637         int sound_enable = TRUE;
638         int sound_played = FALSE;
639         int gain_type = VOLUME_GAIN_SHUTTER1;
640
641         mmf_return_if_fail(filepath && hcamcorder);
642
643         _mmcam_dbg_log("START : %s", filepath);
644
645         _mmcamcorder_sound_solo_play_wait(handle);
646
647         ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
648         if (ret != 0) {
649                 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
650                 return;
651         }
652
653         /* check filename to set gain_type */
654         if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND) ||
655             !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
656                 if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
657                         gain_type = VOLUME_GAIN_CAMCORDING;
658                 } else {
659                         gain_type = VOLUME_GAIN_SHUTTER1;
660                 }
661         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) {
662                 gain_type = VOLUME_GAIN_SHUTTER2;
663         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) {
664                 gain_type = VOLUME_GAIN_CAMCORDING;
665         }
666
667         _mmcam_dbg_log("gain type 0x%x", gain_type);
668
669         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
670                                           "capture-sound-enable", &sound_enable,
671                                           NULL);
672         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
673
674         if (!sound_enable) {
675                 /* send capture sound completed message */
676                 pthread_mutex_unlock(&(hcamcorder->sound_lock));
677                 return;
678         }
679
680
681         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON ||
682             hcamcorder->sub_context->info_image->sound_status) {
683                 ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED | gain_type,
684                                                     (mm_sound_stop_callback_func)__solo_sound_callback, (void*)hcamcorder, &sound_handle);
685                 sound_played = TRUE;
686         } else {
687                 _mmcam_dbg_warn("skip shutter sound");
688         }
689
690         _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
691
692         if (ret != MM_ERROR_NONE) {
693                 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
694         } else {
695                 if (sound_played) {
696                         /* increase capture sound count */
697                         hcamcorder->capture_sound_count++;
698                 }
699
700                 /* wait for sound completed signal */
701                 if (sync_play && sound_played) {
702                         struct timespec timeout;
703                         struct timeval tv;
704
705                         gettimeofday( &tv, NULL );
706                         timeout.tv_sec = tv.tv_sec + 2;
707                         timeout.tv_nsec = tv.tv_usec * 1000;
708
709                         _mmcam_dbg_log("Wait for signal");
710
711                         if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
712                                 _mmcam_dbg_log("signal received.");
713                         } else {
714                                 _mmcam_dbg_warn("capture sound play timeout.");
715                                 if (sound_handle > 0) {
716                                         mm_sound_stop_sound(sound_handle);
717                                 }
718                         }
719                 }
720         }
721
722         pthread_mutex_unlock(&(hcamcorder->sound_lock));
723
724         _mmcam_dbg_log("DONE");
725
726         return;
727 }
728
729 static void __solo_sound_callback(void *data)
730 {
731         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
732
733         mmf_return_if_fail(hcamcorder);
734
735         _mmcam_dbg_log("START");
736
737         /* decrease capture sound count */
738         pthread_mutex_lock(&(hcamcorder->sound_lock));
739         if (hcamcorder->capture_sound_count > 0) {
740                 hcamcorder->capture_sound_count--;
741         } else {
742                 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
743                 hcamcorder->capture_sound_count = 0;
744         }
745         pthread_mutex_unlock(&(hcamcorder->sound_lock));
746
747         _mmcam_dbg_log("Signal SEND");
748         pthread_cond_broadcast(&(hcamcorder->sound_cond));
749
750         _mmcam_dbg_log("DONE");
751
752         return;
753 }
754
755
756 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
757 {
758         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
759
760         mmf_return_if_fail(hcamcorder);
761
762         _mmcam_dbg_log("START");
763
764         /* check playing sound count */
765         pthread_mutex_lock(&(hcamcorder->sound_lock));
766         if (hcamcorder->capture_sound_count > 0) {
767                 struct timespec timeout;
768                 struct timeval tv;
769
770                 gettimeofday( &tv, NULL );
771                 timeout.tv_sec = tv.tv_sec + 2;
772                 timeout.tv_nsec = tv.tv_usec * 1000;
773
774                 _mmcam_dbg_log("Wait for signal");
775
776                 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
777                         _mmcam_dbg_log("signal received.");
778                 } else {
779                         _mmcam_dbg_warn("capture sound play timeout.");
780                 }
781         } else {
782                 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
783         }
784         pthread_mutex_unlock(&(hcamcorder->sound_lock));
785
786         _mmcam_dbg_log("DONE");
787
788         return;
789 }