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