Remove unused header include code
[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         if (pulse_op) {
513                 pa_operation_unref(pulse_op);
514                 pulse_op = NULL;
515         }
516
517         pthread_mutex_unlock(&(info->open_mutex));
518
519         _mmcam_dbg_log("Done");
520
521         return TRUE;
522 }
523
524
525 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
526 {
527         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
528         SOUND_INFO *info = NULL;
529         mm_sound_device_in device_in;
530         mm_sound_device_out device_out;
531         int ret = 0;
532
533         mmf_return_val_if_fail(hcamcorder, FALSE);
534
535         info = &(hcamcorder->snd_info);
536
537         _mmcam_dbg_err("START");
538
539         pthread_mutex_lock(&(info->open_mutex));
540
541         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
542                 _mmcam_dbg_warn("not initialized");
543                 pthread_mutex_unlock(&(info->open_mutex));
544                 return TRUE;
545         }
546
547         /* Restore route */
548         _mmcam_dbg_log("restore route");
549         if (info->active_out_backup != DEFAULT_ACTIVE_DEVICE) {
550                 ret = mm_sound_get_active_device(&device_in, &device_out);
551                 if (ret != MM_ERROR_NONE) {
552                         _mmcam_dbg_err("mm_sound_get_active_device failed [%x]", ret);
553                 }
554
555                 _mmcam_dbg_log("current out [%x]", device_out);
556
557                 if (device_out != info->active_out_backup) {
558                         //ret = mm_sound_set_active_route_without_broadcast (info->active_out_backup);
559                         if (ret != MM_ERROR_NONE) {
560                                 _mmcam_dbg_err("mm_sound_set_active_route_without_broadcast [%x]", ret);
561                         }
562                 }
563         }
564
565         pa_threaded_mainloop_lock(info->pulse_mainloop);
566
567 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
568         /**
569          * Remove sample
570          */
571         _mmcam_dbg_log("remove sample");
572
573         /* Remove sample (ASYNC) */
574         pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
575
576         /* Wait for async operation */
577         pa_threaded_mainloop_wait(info->pulse_mainloop);
578 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
579         if (info->sample_stream) {
580                 pa_stream_disconnect(info->sample_stream);
581                 pa_stream_unref(info->sample_stream);
582                 info->sample_stream = NULL;
583         }
584 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
585
586         /**
587          * Release pulseaudio thread
588          */
589         _mmcam_dbg_log("release pulseaudio thread");
590
591         pa_context_disconnect(info->pulse_context);
592
593         /* Make sure we don't get any further callbacks */
594         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
595
596         pa_context_unref(info->pulse_context);
597         info->pulse_context = NULL;
598
599         pa_threaded_mainloop_unlock(info->pulse_mainloop);
600
601         pa_threaded_mainloop_stop(info->pulse_mainloop);
602         pa_threaded_mainloop_free(info->pulse_mainloop);
603         info->pulse_mainloop = NULL;
604
605 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
606         if (info->filename) {
607                 free(info->filename);
608                 info->filename = NULL;
609         }
610 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
611
612         info->state = _MMCAMCORDER_SOUND_STATE_NONE;
613         info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
614
615         /* release mutex and cond */
616         _mmcam_dbg_log("release play_mutex/cond");
617         pthread_mutex_destroy(&(info->play_mutex));
618         pthread_cond_destroy(&(info->play_cond));
619
620         pthread_mutex_unlock(&(info->open_mutex));
621
622         _mmcam_dbg_err("DONE");
623
624         return TRUE;
625 }
626
627
628 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
629 {
630         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
631
632         int sound_handle = 0;
633         int ret = MM_ERROR_NONE;
634         int sound_enable = TRUE;
635         int sound_played = FALSE;
636         int gain_type = VOLUME_GAIN_SHUTTER1;
637
638         mmf_return_if_fail(filepath && hcamcorder);
639
640         _mmcam_dbg_log("START : %s", filepath);
641
642         _mmcamcorder_sound_solo_play_wait(handle);
643
644         ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
645         if (ret != 0) {
646                 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
647                 return;
648         }
649
650         /* check filename to set gain_type */
651         if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND) ||
652             !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
653                 if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
654                         gain_type = VOLUME_GAIN_CAMCORDING;
655                 } else {
656                         gain_type = VOLUME_GAIN_SHUTTER1;
657                 }
658         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) {
659                 gain_type = VOLUME_GAIN_SHUTTER2;
660         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) {
661                 gain_type = VOLUME_GAIN_CAMCORDING;
662         }
663
664         _mmcam_dbg_log("gain type 0x%x", gain_type);
665
666         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
667                                           "capture-sound-enable", &sound_enable,
668                                           NULL);
669         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
670
671         if (!sound_enable) {
672                 /* send capture sound completed message */
673                 pthread_mutex_unlock(&(hcamcorder->sound_lock));
674                 return;
675         }
676
677
678         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON ||
679             hcamcorder->sub_context->info_image->sound_status) {
680                 ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED | gain_type,
681                                                     (mm_sound_stop_callback_func)__solo_sound_callback, (void*)hcamcorder, &sound_handle);
682                 sound_played = TRUE;
683         } else {
684                 _mmcam_dbg_warn("skip shutter sound");
685         }
686
687         _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
688
689         if (ret != MM_ERROR_NONE) {
690                 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
691         } else {
692                 if (sound_played) {
693                         /* increase capture sound count */
694                         hcamcorder->capture_sound_count++;
695                 }
696
697                 /* wait for sound completed signal */
698                 if (sync_play && sound_played) {
699                         struct timespec timeout;
700                         struct timeval tv;
701
702                         gettimeofday( &tv, NULL );
703                         timeout.tv_sec = tv.tv_sec + 2;
704                         timeout.tv_nsec = tv.tv_usec * 1000;
705
706                         _mmcam_dbg_log("Wait for signal");
707
708                         if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
709                                 _mmcam_dbg_log("signal received.");
710                         } else {
711                                 _mmcam_dbg_warn("capture sound play timeout.");
712                                 if (sound_handle > 0) {
713                                         mm_sound_stop_sound(sound_handle);
714                                 }
715                         }
716                 }
717         }
718
719         pthread_mutex_unlock(&(hcamcorder->sound_lock));
720
721         _mmcam_dbg_log("DONE");
722
723         return;
724 }
725
726 static void __solo_sound_callback(void *data)
727 {
728         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
729
730         mmf_return_if_fail(hcamcorder);
731
732         _mmcam_dbg_log("START");
733
734         /* decrease capture sound count */
735         pthread_mutex_lock(&(hcamcorder->sound_lock));
736         if (hcamcorder->capture_sound_count > 0) {
737                 hcamcorder->capture_sound_count--;
738         } else {
739                 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
740                 hcamcorder->capture_sound_count = 0;
741         }
742         pthread_mutex_unlock(&(hcamcorder->sound_lock));
743
744         _mmcam_dbg_log("Signal SEND");
745         pthread_cond_broadcast(&(hcamcorder->sound_cond));
746
747         _mmcam_dbg_log("DONE");
748
749         return;
750 }
751
752
753 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
754 {
755         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
756
757         mmf_return_if_fail(hcamcorder);
758
759         _mmcam_dbg_log("START");
760
761         /* check playing sound count */
762         pthread_mutex_lock(&(hcamcorder->sound_lock));
763         if (hcamcorder->capture_sound_count > 0) {
764                 struct timespec timeout;
765                 struct timeval tv;
766
767                 gettimeofday( &tv, NULL );
768                 timeout.tv_sec = tv.tv_sec + 2;
769                 timeout.tv_nsec = tv.tv_usec * 1000;
770
771                 _mmcam_dbg_log("Wait for signal");
772
773                 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
774                         _mmcam_dbg_log("signal received.");
775                 } else {
776                         _mmcam_dbg_warn("capture sound play timeout.");
777                 }
778         } else {
779                 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
780         }
781         pthread_mutex_unlock(&(hcamcorder->sound_lock));
782
783         _mmcam_dbg_log("DONE");
784
785         return;
786 }