d2fda120f22695e10b752a21fcaa02c72d5e4c7a
[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         pa_mainloop_api *api = NULL;
171         int error = PA_ERR_INTERNAL;
172
173         mmf_return_val_if_fail(hcamcorder, FALSE);
174
175         /* check sound play enable */
176         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
177                                           "capture-sound-enable", &sound_enable,
178                                           NULL);
179         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
180         if (!sound_enable) {
181                 _mmcam_dbg_warn("capture sound disabled");
182                 return FALSE;
183         }
184
185         info = &(hcamcorder->snd_info);
186
187         pthread_mutex_lock(&(info->open_mutex));
188
189         if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
190                 _mmcam_dbg_warn("already initialized [%d]", info->state);
191                 pthread_mutex_unlock(&(info->open_mutex));
192                 return TRUE;
193         }
194
195 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
196         if (info->filename) {
197                 free(info->filename);
198                 info->filename = NULL;
199         }
200
201         info->filename = strdup(filename);
202         if (info->filename == NULL) {
203                 _mmcam_dbg_err("strdup failed");
204                 return FALSE;
205         }
206 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
207
208         pthread_mutex_init(&(info->play_mutex), NULL);
209         pthread_cond_init(&(info->play_cond), NULL);
210
211 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
212         /* read sample */
213         memset (&(info->sfinfo), 0, sizeof(SF_INFO));
214         info->infile = sf_open(info->filename, SFM_READ, &(info->sfinfo));
215         if (!(info->infile)) {
216                 _mmcam_dbg_err("Failed to open sound file");
217                 goto SOUND_INIT_ERROR;
218         }
219 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
220
221         /**
222          * Init Pulseaudio thread
223          */
224         /* create pulseaudio mainloop */
225         info->pulse_mainloop = pa_threaded_mainloop_new();
226         if (info->pulse_mainloop == NULL) {
227                 _mmcam_dbg_err("pa_threaded_mainloop_new failed");
228                 goto SOUND_INIT_ERROR;
229         }
230
231         /* start PA mainloop */
232         ret = pa_threaded_mainloop_start(info->pulse_mainloop);
233         if (ret < 0) {
234                 _mmcam_dbg_err("pa_threaded_mainloop_start failed");
235                 goto SOUND_INIT_ERROR;
236         }
237
238         /* lock pulseaudio thread */
239         pa_threaded_mainloop_lock(info->pulse_mainloop);
240
241         /* get pulseaudio api */
242         api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
243         if (api == NULL) {
244                 _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
245                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
246                 goto SOUND_INIT_ERROR;
247         }
248
249         /* create pulseaudio context */
250         info->pulse_context = pa_context_new(api, NULL);
251         if (info->pulse_context == NULL) {
252                 _mmcam_dbg_err("pa_context_new failed");
253                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
254                 goto SOUND_INIT_ERROR;
255         }
256
257         /* set pulseaudio context callback */
258         pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
259
260         if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
261                 _mmcam_dbg_err("pa_context_connect error");
262         }
263
264         /* wait READY state of pulse context */
265         while (TRUE) {
266                 pa_context_state_t state = pa_context_get_state(info->pulse_context);
267
268                 _mmcam_dbg_log("pa context state is now %d", state);
269
270                 if (!PA_CONTEXT_IS_GOOD (state)) {
271                         _mmcam_dbg_log("connection failed");
272                         break;
273                 }
274
275                 if (state == PA_CONTEXT_READY) {
276                         _mmcam_dbg_log("pa context READY");
277                         break;
278                 }
279
280                 /* Wait until the context is ready */
281                 _mmcam_dbg_log("waiting..................");
282                 pa_threaded_mainloop_wait(info->pulse_mainloop);
283                 _mmcam_dbg_log("waiting DONE. check again...");
284         }
285
286         /* unlock pulseaudio thread */
287         pa_threaded_mainloop_unlock(info->pulse_mainloop);
288
289 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
290         /**
291          * Upload sample
292          */
293         if (pa_sndfile_read_sample_spec(info->infile, &(info->sample_spec)) < 0) {
294                 _mmcam_dbg_err("Failed to determine sample specification from file");
295                 goto SOUND_INIT_ERROR;
296         }
297
298         info->sample_spec.format = PA_SAMPLE_S16LE;
299
300         if (pa_sndfile_read_channel_map(info->infile, &(info->channel_map)) < 0) {
301                 pa_channel_map_init_extend(&(info->channel_map), info->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
302
303                 if (info->sample_spec.channels > 2) {
304                         _mmcam_dbg_warn("Failed to determine sample specification from file");
305                 }
306         }
307
308         info->sample_length = (size_t)info->sfinfo.frames * pa_frame_size(&(info->sample_spec));
309
310         pa_threaded_mainloop_lock(info->pulse_mainloop);
311
312         /* prepare uploading */
313         info->sample_stream = pa_stream_new(info->pulse_context, SAMPLE_SOUND_NAME, &(info->sample_spec), NULL);
314         /* set stream write callback */
315         pa_stream_set_write_callback(info->sample_stream, __pulseaudio_stream_write_cb, info);
316         /* upload sample (ASYNC) */
317         pa_stream_connect_upload(info->sample_stream, info->sample_length);
318         /* wait for upload completion */
319         pa_threaded_mainloop_wait(info->pulse_mainloop);
320
321         pa_threaded_mainloop_unlock(info->pulse_mainloop);
322
323         /* close sndfile */
324         sf_close(info->infile);
325         info->infile = NULL;
326 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
327         if (info->sample_stream) {
328                 pa_stream_connect_playback(info->sample_stream, NULL, NULL, 0, NULL, NULL);
329
330                 for (;;) {
331                         pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
332
333                         if (state == PA_STREAM_READY) {
334                                 _mmcam_dbg_warn("device READY done");
335                                 break;
336                         }
337
338                         if (!PA_STREAM_IS_GOOD(state)) {
339                                 error = pa_context_errno(info->pulse_context);
340                                 _mmcam_dbg_err("pa context state is not good, %d", error);
341                                 break;
342                         }
343
344                         /* Wait until the stream is ready */
345                         pa_threaded_mainloop_wait(info->pulse_mainloop);
346                 }
347         }
348 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
349
350         //info->volume_type = PA_TIZEN_AUDIO_VOLUME_TYPE_FIXED;
351         info->volume_level = 0;
352
353         info->state = _MMCAMCORDER_SOUND_STATE_INIT;
354
355         _mmcam_dbg_log("init DONE");
356
357         pthread_mutex_unlock(&(info->open_mutex));
358
359         return TRUE;
360
361 SOUND_INIT_ERROR:
362
363 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
364         /**
365          * Release allocated resources
366          */
367         if (info->filename) {
368                 free(info->filename);
369                 info->filename = NULL;
370         }
371 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
372
373         /* remove pulse mainloop */
374         if (info->pulse_mainloop) {
375                 pa_threaded_mainloop_lock(info->pulse_mainloop);
376
377                 /* remove pulse context */
378                 if (info->pulse_context) {
379 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
380                         /* remove uploaded sample */
381                         if (info->sample_stream) {
382                                 pa_threaded_mainloop_lock(info->pulse_mainloop);
383
384                                 /* Remove sample (ASYNC) */
385                                 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
386
387                                 /* Wait for async operation */
388                                 pa_threaded_mainloop_wait(info->pulse_mainloop);
389                         }
390 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
391                         /* release sample stream */
392                         if (info->sample_stream) {
393                                 pa_stream_disconnect(info->sample_stream);
394                                 pa_stream_unref(info->sample_stream);
395                                 info->sample_stream = NULL;
396                         }
397 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
398
399                         /* Make sure we don't get any further callbacks */
400                         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
401
402                         pa_context_disconnect(info->pulse_context);
403                         pa_context_unref(info->pulse_context);
404                         info->pulse_context = NULL;
405                 }
406
407                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
408
409                 pa_threaded_mainloop_stop(info->pulse_mainloop);
410                 pa_threaded_mainloop_free(info->pulse_mainloop);
411                 info->pulse_mainloop = NULL;
412         }
413
414         /* remove mutex and cond */
415         pthread_mutex_destroy(&(info->play_mutex));
416         pthread_cond_destroy(&(info->play_cond));
417
418         pthread_mutex_unlock(&(info->open_mutex));
419
420         return FALSE;
421 }
422
423
424 gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
425 {
426         int sound_enable = TRUE;
427         int gain_type = VOLUME_GAIN_SHUTTER1;
428
429         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
430         SOUND_INFO *info = NULL;
431         pa_operation *pulse_op = NULL;
432
433         mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
434
435         /* check sound play enable */
436         mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
437                                     "capture-sound-enable", &sound_enable,
438                                     NULL);
439         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
440         if (!sound_enable) {
441                 _mmcam_dbg_warn("capture sound disabled");
442                 return FALSE;
443         }
444
445         info = &(hcamcorder->snd_info);
446
447         pthread_mutex_lock(&(info->open_mutex));
448
449         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
450                 _mmcam_dbg_log("not initialized state:[%d]", info->state);
451                 pthread_mutex_unlock(&(info->open_mutex));
452                 return FALSE;
453         }
454
455         if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_CAPTURE)) {
456                 gain_type = VOLUME_GAIN_SHUTTER2;
457         } else if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP)) {
458                 gain_type = VOLUME_GAIN_CAMCORDING;
459         }
460
461         _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
462
463         if (sync_play) {
464                 pa_threaded_mainloop_lock(info->pulse_mainloop);
465 /*
466                 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
467                                                   sample_name,
468                                                   info->volume_type,
469                                                   gain_type,
470                                                   info->volume_level,
471                                                   __pulseaudio_play_sample_cb,
472                                                   info);
473 */
474                 _mmcam_dbg_log("wait for signal");
475                 pa_threaded_mainloop_wait(info->pulse_mainloop);
476                 _mmcam_dbg_log("received signal");
477
478                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
479         } else {
480 /*
481                 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
482                                                   sample_name,
483                                                   info->volume_type,
484                                                   gain_type,
485                                                   info->volume_level,
486                                                   NULL,
487                                                   NULL);
488 */
489         }
490
491 /*
492         if (pulse_op) {
493                 pa_operation_unref(pulse_op);
494                 pulse_op = NULL;
495         }
496 */
497
498         pthread_mutex_unlock(&(info->open_mutex));
499
500         _mmcam_dbg_log("Done");
501
502         return TRUE;
503 }
504
505
506 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
507 {
508         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
509         SOUND_INFO *info = NULL;
510         mm_sound_device_in device_in;
511         mm_sound_device_out device_out;
512         int ret = 0;
513
514         mmf_return_val_if_fail(hcamcorder, FALSE);
515
516         info = &(hcamcorder->snd_info);
517
518         _mmcam_dbg_err("START");
519
520         pthread_mutex_lock(&(info->open_mutex));
521
522         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
523                 _mmcam_dbg_warn("not initialized");
524                 pthread_mutex_unlock(&(info->open_mutex));
525                 return TRUE;
526         }
527
528         pa_threaded_mainloop_lock(info->pulse_mainloop);
529
530 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
531         /**
532          * Remove sample
533          */
534         _mmcam_dbg_log("remove sample");
535
536         /* Remove sample (ASYNC) */
537         pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
538
539         /* Wait for async operation */
540         pa_threaded_mainloop_wait(info->pulse_mainloop);
541 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
542         if (info->sample_stream) {
543                 pa_stream_disconnect(info->sample_stream);
544                 pa_stream_unref(info->sample_stream);
545                 info->sample_stream = NULL;
546         }
547 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
548
549         /**
550          * Release pulseaudio thread
551          */
552         _mmcam_dbg_log("release pulseaudio thread");
553
554         pa_context_disconnect(info->pulse_context);
555
556         /* Make sure we don't get any further callbacks */
557         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
558
559         pa_context_unref(info->pulse_context);
560         info->pulse_context = NULL;
561
562         pa_threaded_mainloop_unlock(info->pulse_mainloop);
563
564         pa_threaded_mainloop_stop(info->pulse_mainloop);
565         pa_threaded_mainloop_free(info->pulse_mainloop);
566         info->pulse_mainloop = NULL;
567
568 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
569         if (info->filename) {
570                 free(info->filename);
571                 info->filename = NULL;
572         }
573 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
574
575         info->state = _MMCAMCORDER_SOUND_STATE_NONE;
576
577         /* release mutex and cond */
578         _mmcam_dbg_log("release play_mutex/cond");
579         pthread_mutex_destroy(&(info->play_mutex));
580         pthread_cond_destroy(&(info->play_cond));
581
582         pthread_mutex_unlock(&(info->open_mutex));
583
584         _mmcam_dbg_err("DONE");
585
586         return TRUE;
587 }
588
589
590 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
591 {
592         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
593
594         int sound_handle = 0;
595         int ret = MM_ERROR_NONE;
596         int sound_enable = TRUE;
597         int sound_played = FALSE;
598         int gain_type = VOLUME_GAIN_SHUTTER1;
599
600         mmf_return_if_fail(filepath && hcamcorder);
601
602         _mmcam_dbg_log("START : %s", filepath);
603
604         _mmcamcorder_sound_solo_play_wait(handle);
605
606         ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
607         if (ret != 0) {
608                 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
609                 return;
610         }
611
612         /* check filename to set gain_type */
613         if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND) ||
614             !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
615                 if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
616                         gain_type = VOLUME_GAIN_CAMCORDING;
617                 } else {
618                         gain_type = VOLUME_GAIN_SHUTTER1;
619                 }
620         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) {
621                 gain_type = VOLUME_GAIN_SHUTTER2;
622         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) {
623                 gain_type = VOLUME_GAIN_CAMCORDING;
624         }
625
626         _mmcam_dbg_log("gain type 0x%x", gain_type);
627
628         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
629                                           "capture-sound-enable", &sound_enable,
630                                           NULL);
631         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
632
633         if (!sound_enable) {
634                 /* send capture sound completed message */
635                 pthread_mutex_unlock(&(hcamcorder->sound_lock));
636                 return;
637         }
638
639
640         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON ||
641             hcamcorder->sub_context->info_image->sound_status) {
642                 ret = mm_sound_play_sound(filepath, VOLUME_TYPE_FIXED | gain_type,
643                                           (mm_sound_stop_callback_func)__solo_sound_callback, (void*)hcamcorder, &sound_handle);
644                 sound_played = TRUE;
645         } else {
646                 _mmcam_dbg_warn("skip shutter sound");
647         }
648
649         _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
650
651         if (ret != MM_ERROR_NONE) {
652                 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
653         } else {
654                 if (sound_played) {
655                         /* increase capture sound count */
656                         hcamcorder->capture_sound_count++;
657                 }
658
659                 /* wait for sound completed signal */
660                 if (sync_play && sound_played) {
661                         struct timespec timeout;
662                         struct timeval tv;
663
664                         gettimeofday( &tv, NULL );
665                         timeout.tv_sec = tv.tv_sec + 2;
666                         timeout.tv_nsec = tv.tv_usec * 1000;
667
668                         _mmcam_dbg_log("Wait for signal");
669
670                         if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
671                                 _mmcam_dbg_log("signal received.");
672                         } else {
673                                 _mmcam_dbg_warn("capture sound play timeout.");
674                                 if (sound_handle > 0) {
675                                         mm_sound_stop_sound(sound_handle);
676                                 }
677                         }
678                 }
679         }
680
681         pthread_mutex_unlock(&(hcamcorder->sound_lock));
682
683         _mmcam_dbg_log("DONE");
684
685         return;
686 }
687
688 static void __solo_sound_callback(void *data)
689 {
690         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
691
692         mmf_return_if_fail(hcamcorder);
693
694         _mmcam_dbg_log("START");
695
696         /* decrease capture sound count */
697         pthread_mutex_lock(&(hcamcorder->sound_lock));
698         if (hcamcorder->capture_sound_count > 0) {
699                 hcamcorder->capture_sound_count--;
700         } else {
701                 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
702                 hcamcorder->capture_sound_count = 0;
703         }
704         pthread_mutex_unlock(&(hcamcorder->sound_lock));
705
706         _mmcam_dbg_log("Signal SEND");
707         pthread_cond_broadcast(&(hcamcorder->sound_cond));
708
709         _mmcam_dbg_log("DONE");
710
711         return;
712 }
713
714
715 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
716 {
717         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
718
719         mmf_return_if_fail(hcamcorder);
720
721         _mmcam_dbg_log("START");
722
723         /* check playing sound count */
724         pthread_mutex_lock(&(hcamcorder->sound_lock));
725         if (hcamcorder->capture_sound_count > 0) {
726                 struct timespec timeout;
727                 struct timeval tv;
728
729                 gettimeofday( &tv, NULL );
730                 timeout.tv_sec = tv.tv_sec + 2;
731                 timeout.tv_nsec = tv.tv_usec * 1000;
732
733                 _mmcam_dbg_log("Wait for signal");
734
735                 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
736                         _mmcam_dbg_log("signal received.");
737                 } else {
738                         _mmcam_dbg_warn("capture sound play timeout.");
739                 }
740         } else {
741                 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
742         }
743         pthread_mutex_unlock(&(hcamcorder->sound_lock));
744
745         _mmcam_dbg_log("DONE");
746
747         return;
748 }