[Release version 0.10.27] Remove unused code and dependency
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_sound.c
index c582349..7923f0b 100644 (file)
@@ -24,7 +24,6 @@
 =======================================================================================*/
 #include <mm_sound.h>
 #include <mm_sound_private.h>
-#include <audio-session-manager.h>
 #include "mm_camcorder_internal.h"
 #include "mm_camcorder_sound.h"
 
 /*---------------------------------------------------------------------------------------
 |    LOCAL VARIABLE DEFINITIONS for internal                                           |
 ---------------------------------------------------------------------------------------*/
-#define BLOCK_SIZE 2048
+#define SAMPLE_SOUND_RATE       44100
+#define DEFAULT_ACTIVE_DEVICE   0xffffffff
 
 /*---------------------------------------------------------------------------------------
 |    LOCAL FUNCTION PROTOTYPES:                                                                |
 ---------------------------------------------------------------------------------------*/
-static gboolean __prepare_buffer(SOUND_INFO *info, char *filename);
-static gboolean __cleanup_buffer(SOUND_INFO *info);
-static void *__sound_open_thread_func(void *data);
-static void *__sound_write_thread_func(void *data);
 static void __solo_sound_callback(void *data);
 
-static gboolean __prepare_buffer(SOUND_INFO *info, char *filename)
+static void __pulseaudio_play_sample_cb(pa_context *pulse_context, uint32_t stream_index, void *user_data)
 {
-       mmf_return_val_if_fail(info, FALSE);
-       mmf_return_val_if_fail(filename, FALSE);
+       SOUND_INFO *info = NULL;
 
-       info->infile = sf_open(filename, SFM_READ, &info->sfinfo);
-       if (!(info->infile)) {
-               _mmcam_dbg_err("failed to open file [%s]", filename);
-               return FALSE;
-       }
+       mmf_return_if_fail(user_data);
 
-       _mmcam_dbg_log("SOUND: frame       = %lld", info->sfinfo.frames);
-       _mmcam_dbg_log("SOUND: sameplerate = %d", info->sfinfo.samplerate);
-       _mmcam_dbg_log("SOUND: channel     = %d", info->sfinfo.channels);
-       _mmcam_dbg_log("SOUND: format      = 0x%x", info->sfinfo.format);
-
-       info->pcm_size = info->sfinfo.frames * info->sfinfo.channels * 2;
-       info->pcm_buf = (short *)malloc(info->pcm_size);
-       if (info->pcm_buf == NULL) {
-               _mmcam_dbg_err("pcm_buf malloc failed");
-               sf_close(info->infile);
-               info->infile = NULL;
-               return FALSE;
-       }
-       sf_read_short(info->infile, info->pcm_buf, info->pcm_size);
+       info = (SOUND_INFO *)user_data;
 
-       return TRUE;
-}
+       _mmcam_dbg_log("START - idx : %d", stream_index);
+
+       pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
+
+       _mmcam_dbg_log("DONE");
 
+       return;
+}
 
-static gboolean __cleanup_buffer(SOUND_INFO *info)
+static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
 {
-       mmf_return_val_if_fail(info, FALSE);
+       int state = 0;
+       SOUND_INFO *info = NULL;
 
-       if (info->infile) {
-               sf_close(info->infile);
-               info->infile = NULL;
-       }
+       mmf_return_if_fail(user_data);
 
-       if (info->pcm_buf) {
-               free(info->pcm_buf);
-               info->pcm_buf = NULL;
-       }
+       info = (SOUND_INFO *)user_data;
 
-       _mmcam_dbg_log("Done");
+       state = pa_context_get_state(pulse_context);
+       switch (state) {
+       case PA_CONTEXT_READY:
+               _mmcam_dbg_log("pulseaudio context READY");
+               if (info->pulse_context == pulse_context) {
+                       /* Signal */
+                       _mmcam_dbg_log("pulseaudio send signal");
+                       pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
+               }
+               break;
+       case PA_CONTEXT_TERMINATED:
+               if (info->pulse_context == pulse_context) {
+                       /* Signal */
+                       _mmcam_dbg_log("Context terminated : pulseaudio send signal");
+                       pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
+               }
+               break;
+       case PA_CONTEXT_UNCONNECTED:
+       case PA_CONTEXT_CONNECTING:
+       case PA_CONTEXT_AUTHORIZING:
+       case PA_CONTEXT_SETTING_NAME:
+       case PA_CONTEXT_FAILED:
+       default:
+               _mmcam_dbg_log("pulseaudio context %p, state %d",
+                              pulse_context, state);
+               break;
+       }
 
-       return TRUE;
+       return;
 }
 
-
-static void *__sound_open_thread_func(void *data)
+gboolean _mmcamcorder_sound_init(MMHandleType handle)
 {
        int ret = 0;
-       system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY;
+       int sound_enable = TRUE;
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        SOUND_INFO *info = NULL;
-       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
+       pa_mainloop_api *api = NULL;
+       int error = PA_ERR_INTERNAL;
 
-       mmf_return_val_if_fail(hcamcorder, NULL);
+       mmf_return_val_if_fail(hcamcorder, FALSE);
 
-       MMTA_ACUM_ITEM_BEGIN("    __sound_open_thread_func", FALSE);
+       /* check sound play enable */
+       ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
+                                         "capture-sound-enable", &sound_enable,
+                                         NULL);
+       _mmcam_dbg_log("Capture sound enable %d", sound_enable);
+       if (!sound_enable) {
+               _mmcam_dbg_warn("capture sound disabled");
+               return FALSE;
+       }
 
        info = &(hcamcorder->snd_info);
 
-       __ta__("        __prepare_buffer",
-       ret = __prepare_buffer(info, info->filename);
-       );
-       if (ret == FALSE) {
-               goto EXIT_FUNC;
-       }
+       pthread_mutex_lock(&(info->open_mutex));
 
-       __ta__("        mm_sound_pcm_play_open",
-       ret = mm_sound_pcm_play_open_ex(&(info->handle), info->sfinfo.samplerate,
-                                       (info->sfinfo.channels == 1) ? MMSOUND_PCM_MONO : MMSOUND_PCM_STEREO,
-                                       MMSOUND_PCM_S16_LE, VOLUME_TYPE_FIXED, ASM_EVENT_EXCLUSIVE_MMSOUND);
-       );
-       if (ret < 0) {
-               /* error */
-               _mmcam_dbg_err("mm_sound_pcm_play_open failed [%x]", ret);
-               __cleanup_buffer(info);
-               goto EXIT_FUNC;
-       } else {
-               /* success */
-               info->state = _MMCAMCORDER_SOUND_STATE_PREPARE;
-               _mmcam_dbg_log("mm_sound_pcm_play_open succeeded. state [%d]", info->state);
+       if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
+               _mmcam_dbg_warn("already initialized [%d]", info->state);
+               pthread_mutex_unlock(&(info->open_mutex));
+               return TRUE;
        }
 
-       ret = mm_sound_route_get_system_policy(&route);
-       if (ret != MM_ERROR_NONE) {
-               _mmcam_dbg_err("mm_sound_route_get_system_policy failed [%x]", ret);
-               goto POLICY_ERROR;
+       pthread_mutex_init(&(info->play_mutex), NULL);
+       pthread_cond_init(&(info->play_cond), NULL);
+
+       /**
+        * Init Pulseaudio thread
+        */
+       /* create pulseaudio mainloop */
+       info->pulse_mainloop = pa_threaded_mainloop_new();
+       if (info->pulse_mainloop == NULL) {
+               _mmcam_dbg_err("pa_threaded_mainloop_new failed");
+               goto SOUND_INIT_ERROR;
        }
 
-       _mmcam_dbg_log("current policy [%d]", route);
-
-       if (route != SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY) {
-               ret = mm_sound_route_set_system_policy(SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY);
-               if (ret != MM_ERROR_NONE) {
-                       _mmcam_dbg_err("mm_sound_route_set_system_policy failed [%x]", ret);
-                       goto POLICY_ERROR;
-               }
-
-               info->route_policy_backup = route;
+       /* start PA mainloop */
+       ret = pa_threaded_mainloop_start(info->pulse_mainloop);
+       if (ret < 0) {
+               _mmcam_dbg_err("pa_threaded_mainloop_start failed");
+               goto SOUND_INIT_ERROR;
        }
 
-EXIT_FUNC:
-       pthread_cond_signal(&(info->open_cond));
-       pthread_mutex_unlock(&(info->open_mutex));
-
-       _mmcam_dbg_log("Done");
-
-       MMTA_ACUM_ITEM_END("    __sound_open_thread_func", FALSE);
-
-       return NULL;
+       /* lock pulseaudio thread */
+       pa_threaded_mainloop_lock(info->pulse_mainloop);
 
-POLICY_ERROR:
-       pthread_mutex_unlock(&(info->open_mutex));
-       _mmcamcorder_sound_finalize((MMHandleType)hcamcorder);
-
-       return NULL;
-}
-
-
-static void *__sound_write_thread_func(void *data)
-{
-       int ret = 0;
-       int bytes_to_write = 0;
-       int remain_bytes = 0;
-       system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY;
-       char *buffer_to_write = NULL;
-       SOUND_INFO *info = NULL;
-       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
-
-       mmf_return_val_if_fail(hcamcorder, NULL);
+       /* get pulseaudio api */
+       api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
+       if (api == NULL) {
+               _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
+               pa_threaded_mainloop_unlock(info->pulse_mainloop);
+               goto SOUND_INIT_ERROR;
+       }
 
-       info = &(hcamcorder->snd_info);
+       /* create pulseaudio context */
+       info->pulse_context = pa_context_new(api, NULL);
+       if (info->pulse_context == NULL) {
+               _mmcam_dbg_err("pa_context_new failed");
+               pa_threaded_mainloop_unlock(info->pulse_mainloop);
+               goto SOUND_INIT_ERROR;
+       }
 
-       _mmcam_dbg_log("RUN sound write thread");
+       /* set pulseaudio context callback */
+       pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
 
-       pthread_mutex_lock(&(info->play_mutex));
+       if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
+               _mmcam_dbg_err("pa_context_connect error");
+       }
 
-       do {
-               pthread_cond_wait(&(info->play_cond), &(info->play_mutex));
+       /* wait READY state of pulse context */
+       while (TRUE) {
+               pa_context_state_t state = pa_context_get_state(info->pulse_context);
 
-               _mmcam_dbg_log("Signal received. Play sound.");
+               _mmcam_dbg_log("pa context state is now %d", state);
 
-               if (info->thread_run == FALSE) {
-                       _mmcam_dbg_log("Exit thread command is detected");
+               if (!PA_CONTEXT_IS_GOOD (state)) {
+                       _mmcam_dbg_log("connection failed");
                        break;
                }
 
-               ret = mm_sound_route_get_system_policy(&route);
-               if (ret != MM_ERROR_NONE) {
-                       _mmcam_dbg_err("get_system_policy failed [%x]. skip sound play.", ret);
+               if (state == PA_CONTEXT_READY) {
+                       _mmcam_dbg_log("pa context READY");
                        break;
                }
 
-               _mmcam_dbg_log("current policy [%d]", route);
+               /* Wait until the context is ready */
+               _mmcam_dbg_log("waiting..................");
+               pa_threaded_mainloop_wait(info->pulse_mainloop);
+               _mmcam_dbg_log("waiting DONE. check again...");
+       }
 
-               if (route != SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY) {
-                       ret = mm_sound_route_set_system_policy(SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY);
-                       if (ret != MM_ERROR_NONE) {
-                               _mmcam_dbg_err("set_system_policy failed. skip sound play.");
-                               break;
-                       }
+       /* unlock pulseaudio thread */
+       pa_threaded_mainloop_unlock(info->pulse_mainloop);
 
-                       info->route_policy_backup = route;
-               }
+       if (info->sample_stream) {
+               pa_stream_connect_playback(info->sample_stream, NULL, NULL, 0, NULL, NULL);
 
-               buffer_to_write = (char *)info->pcm_buf;
-               remain_bytes = info->pcm_size;
-               bytes_to_write = 0;
+               for (;;) {
+                       pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
 
-               while (remain_bytes) {
-                       bytes_to_write = (remain_bytes >= BLOCK_SIZE) ? BLOCK_SIZE : remain_bytes;
-                       ret = mm_sound_pcm_play_write(info->handle, buffer_to_write, bytes_to_write);
-                       if (ret != bytes_to_write) {
-                               _mmcam_dbg_err("pcm write error [%x]", ret);
+                       if (state == PA_STREAM_READY) {
+                               _mmcam_dbg_warn("device READY done");
+                               break;
+                       }
+
+                       if (!PA_STREAM_IS_GOOD(state)) {
+                               error = pa_context_errno(info->pulse_context);
+                               _mmcam_dbg_err("pa context state is not good, %d", error);
+                               break;
                        }
-                       remain_bytes -= bytes_to_write;
-                       buffer_to_write += bytes_to_write;
+
+                       /* Wait until the stream is ready */
+                       pa_threaded_mainloop_wait(info->pulse_mainloop);
                }
-       } while (TRUE);
+       }
 
-       pthread_mutex_unlock(&(info->play_mutex));
+       //info->volume_type = PA_TIZEN_AUDIO_VOLUME_TYPE_FIXED;
+       info->volume_level = 0;
 
-       _mmcam_dbg_log("END sound write thread");
+       info->state = _MMCAMCORDER_SOUND_STATE_INIT;
 
-       return NULL;
-}
+       _mmcam_dbg_log("init DONE");
 
+       pthread_mutex_unlock(&(info->open_mutex));
 
-gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename)
-{
-       int ret = 0;
-       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
-       SOUND_INFO *info = NULL;
+       return TRUE;
 
-       mmf_return_val_if_fail(hcamcorder, FALSE);
+SOUND_INIT_ERROR:
+       /* remove pulse mainloop */
+       if (info->pulse_mainloop) {
+               pa_threaded_mainloop_lock(info->pulse_mainloop);
+
+               /* remove pulse context */
+               if (info->pulse_context) {
+                       /* release sample stream */
+                       if (info->sample_stream) {
+                               pa_stream_disconnect(info->sample_stream);
+                               pa_stream_unref(info->sample_stream);
+                               info->sample_stream = NULL;
+                       }
 
-       info = &(hcamcorder->snd_info);
+                       /* Make sure we don't get any further callbacks */
+                       pa_context_set_state_callback(info->pulse_context, NULL, NULL);
 
-       pthread_mutex_lock(&(info->open_mutex));
+                       pa_context_disconnect(info->pulse_context);
+                       pa_context_unref(info->pulse_context);
+                       info->pulse_context = NULL;
+               }
 
-       if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
-               _mmcam_dbg_warn("already initialized [%d]", info->state);
-               pthread_mutex_unlock(&(info->open_mutex));
-               return FALSE;
-       }
+               pa_threaded_mainloop_unlock(info->pulse_mainloop);
 
-       if (info->filename) {
-               free(info->filename);
-               info->filename = NULL;
+               pa_threaded_mainloop_stop(info->pulse_mainloop);
+               pa_threaded_mainloop_free(info->pulse_mainloop);
+               info->pulse_mainloop = NULL;
        }
 
-       info->filename = strdup(filename);
-       if (info->filename == NULL) {
-               _mmcam_dbg_err("strdup failed");
-               ret = FALSE;
-       } else {
-               pthread_mutex_init(&(info->play_mutex), NULL);
-               pthread_cond_init(&(info->play_cond), NULL);
-               if (pthread_create(&(info->thread), NULL, __sound_write_thread_func, (void *)handle) == 0) {
-                       info->thread_run = TRUE;
-                       info->state = _MMCAMCORDER_SOUND_STATE_INIT;
-                       info->route_policy_backup = -1;
-                       _mmcam_dbg_log("write thread created");
-                       ret = TRUE;
-               } else {
-                       _mmcam_dbg_err("failed to create write thread");
-                       free(info->filename);
-                       info->filename = NULL;
-                       ret = FALSE;
-               }
-       }
+       /* remove mutex and cond */
+       pthread_mutex_destroy(&(info->play_mutex));
+       pthread_cond_destroy(&(info->play_cond));
 
        pthread_mutex_unlock(&(info->open_mutex));
 
-       return ret;
+       return FALSE;
 }
 
 
-gboolean _mmcamcorder_sound_prepare(MMHandleType handle)
+gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
 {
-       int ret = FALSE;
-       pthread_t open_thread;
-       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
-       SOUND_INFO *info = NULL;
-
-       mmf_return_val_if_fail(hcamcorder, FALSE);
-
-       info = &(hcamcorder->snd_info);
-
-       pthread_mutex_lock(&(info->open_mutex));
-
-       if (info->state == _MMCAMCORDER_SOUND_STATE_INIT) {
-               if (pthread_create(&open_thread, NULL, __sound_open_thread_func, (void *)handle) == 0) {
-                       _mmcam_dbg_log("open thread created");
-                       ret = TRUE;
-               } else {
-                       _mmcam_dbg_err("failed to create open thread");
-                       ret = FALSE;
-                       pthread_mutex_unlock(&(info->open_mutex));
-               }
-       } else {
-               _mmcam_dbg_warn("Wrong state [%d]", info->state);
-               ret = FALSE;
-               pthread_mutex_unlock(&(info->open_mutex));
-       }
-
-       return ret;
-}
-
+       int sound_enable = TRUE;
+/*
+       int gain_type = VOLUME_GAIN_SHUTTER1;
+*/
 
-gboolean _mmcamcorder_sound_play(MMHandleType handle)
-{
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        SOUND_INFO *info = NULL;
-
-       mmf_return_val_if_fail(hcamcorder, FALSE);
+/*
+       pa_operation *pulse_op = NULL;
+*/
+
+       mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
+
+       /* check sound play enable */
+       mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
+                                   "capture-sound-enable", &sound_enable,
+                                   NULL);
+       _mmcam_dbg_log("Capture sound enable %d", sound_enable);
+       if (!sound_enable) {
+               _mmcam_dbg_warn("capture sound disabled");
+               return FALSE;
+       }
 
        info = &(hcamcorder->snd_info);
 
        pthread_mutex_lock(&(info->open_mutex));
 
-       if (info->state < _MMCAMCORDER_SOUND_STATE_PREPARE) {
+       if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
                _mmcam_dbg_log("not initialized state:[%d]", info->state);
                pthread_mutex_unlock(&(info->open_mutex));
                return FALSE;
        }
 
-       _mmcam_dbg_log("Play start");
+/*
+       if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_CAPTURE)) {
+               gain_type = VOLUME_GAIN_SHUTTER2;
+       } else if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP)) {
+               gain_type = VOLUME_GAIN_CAMCORDING;
+       }
+*/
+
+       _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
+
+       if (sync_play) {
+               pa_threaded_mainloop_lock(info->pulse_mainloop);
+/*
+               pulse_op = pa_ext_policy_play_sample(info->pulse_context,
+                                                 sample_name,
+                                                 info->volume_type,
+                                                 gain_type,
+                                                 info->volume_level,
+                                                 __pulseaudio_play_sample_cb,
+                                                 info);
+*/
+               _mmcam_dbg_log("wait for signal");
+               pa_threaded_mainloop_wait(info->pulse_mainloop);
+               _mmcam_dbg_log("received signal");
+
+               pa_threaded_mainloop_unlock(info->pulse_mainloop);
+       } else {
+/*
+               pulse_op = pa_ext_policy_play_sample(info->pulse_context,
+                                                 sample_name,
+                                                 info->volume_type,
+                                                 gain_type,
+                                                 info->volume_level,
+                                                 NULL,
+                                                 NULL);
+*/
+       }
 
-       pthread_mutex_lock(&(info->play_mutex));
-       pthread_cond_signal(&(info->play_cond));
-       pthread_mutex_unlock(&(info->play_mutex));
+/*
+       if (pulse_op) {
+               pa_operation_unref(pulse_op);
+               pulse_op = NULL;
+       }
+*/
 
        pthread_mutex_unlock(&(info->open_mutex));
 
@@ -359,76 +370,73 @@ gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
 
        info = &(hcamcorder->snd_info);
 
+       _mmcam_dbg_err("START");
+
        pthread_mutex_lock(&(info->open_mutex));
 
        if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
                _mmcam_dbg_warn("not initialized");
                pthread_mutex_unlock(&(info->open_mutex));
-               return FALSE;
+               return TRUE;
        }
 
-       info->thread_run = 0;
-       pthread_cond_signal(&(info->play_cond));
+       pa_threaded_mainloop_lock(info->pulse_mainloop);
 
-       if (info->thread) {
-               _mmcam_dbg_log("wait for sound write thread join");
-               pthread_join(info->thread, NULL);
-               _mmcam_dbg_log("join done");
+       if (info->sample_stream) {
+               pa_stream_disconnect(info->sample_stream);
+               pa_stream_unref(info->sample_stream);
+               info->sample_stream = NULL;
        }
 
-       if (info->state == _MMCAMCORDER_SOUND_STATE_PREPARE) {
-               _mmcam_dbg_log("restore route policy [%d]", info->route_policy_backup);
+       /**
+        * Release pulseaudio thread
+        */
+       _mmcam_dbg_log("release pulseaudio thread");
 
-               if (info->route_policy_backup != -1) {
-                       mm_sound_route_set_system_policy(info->route_policy_backup);
-               }
+       pa_context_disconnect(info->pulse_context);
 
-               mm_sound_pcm_play_close(info->handle);
-               __cleanup_buffer(info);
-       }
+       /* Make sure we don't get any further callbacks */
+       pa_context_set_state_callback(info->pulse_context, NULL, NULL);
 
-       if (info->filename) {
-               free(info->filename);
-               info->filename = NULL;
-       }
+       pa_context_unref(info->pulse_context);
+       info->pulse_context = NULL;
+
+       pa_threaded_mainloop_unlock(info->pulse_mainloop);
+
+       pa_threaded_mainloop_stop(info->pulse_mainloop);
+       pa_threaded_mainloop_free(info->pulse_mainloop);
+       info->pulse_mainloop = NULL;
 
        info->state = _MMCAMCORDER_SOUND_STATE_NONE;
-       info->route_policy_backup = -1;
 
+       /* release mutex and cond */
+       _mmcam_dbg_log("release play_mutex/cond");
        pthread_mutex_destroy(&(info->play_mutex));
        pthread_cond_destroy(&(info->play_cond));
 
        pthread_mutex_unlock(&(info->open_mutex));
 
-       _mmcam_dbg_log("Done");
+       _mmcam_dbg_err("DONE");
 
        return TRUE;
 }
 
 
-void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync)
+void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
 
        int sound_handle = 0;
-       int ret = 0;
+       int ret = MM_ERROR_NONE;
        int sound_enable = TRUE;
+       int sound_played = FALSE;
+       int gain_type = VOLUME_GAIN_SHUTTER1;
 
-       mmf_return_if_fail( filepath );
+       mmf_return_if_fail(filepath && hcamcorder);
 
-       _mmcam_dbg_log( "START" );
+       _mmcam_dbg_log("START : %s", filepath);
 
-       ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
-                                         "capture-sound-enable", &sound_enable,
-                                         NULL);
-       if (ret == MM_ERROR_NONE) {
-               if (sound_enable == FALSE) {
-                       _mmcam_dbg_log("Capture sound DISABLED.");
-                       return;
-               }
-       } else {
-               _mmcam_dbg_warn("capture-sound-enable get FAILED.[%x]", ret);
-       }
+       _mmcamcorder_sound_solo_play_wait(handle);
 
        ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
        if (ret != 0) {
@@ -436,14 +444,55 @@ void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gbo
                return;
        }
 
-       MMTA_ACUM_ITEM_BEGIN("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE);
+       /* check filename to set gain_type */
+       if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND) ||
+           !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
+               if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
+                       gain_type = VOLUME_GAIN_CAMCORDING;
+               } else {
+                       gain_type = VOLUME_GAIN_SHUTTER1;
+               }
+       } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) {
+               gain_type = VOLUME_GAIN_SHUTTER2;
+       } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) {
+               gain_type = VOLUME_GAIN_CAMCORDING;
+       }
+
+       _mmcam_dbg_log("gain type 0x%x", gain_type);
+
+       ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
+                                         "capture-sound-enable", &sound_enable,
+                                         NULL);
+       _mmcam_dbg_log("Capture sound enable %d", sound_enable);
+
+       if (!sound_enable) {
+               /* send capture sound completed message */
+               pthread_mutex_unlock(&(hcamcorder->sound_lock));
+               return;
+       }
+
+
+       if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON ||
+           hcamcorder->sub_context->info_image->sound_status) {
+               ret = mm_sound_play_sound(filepath, VOLUME_TYPE_FIXED | gain_type,
+                                         (mm_sound_stop_callback_func)__solo_sound_callback, (void*)hcamcorder, &sound_handle);
+               sound_played = TRUE;
+       } else {
+               _mmcam_dbg_warn("skip shutter sound");
+       }
+
+       _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
 
-       ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED, __solo_sound_callback,
-                                           (void*)hcamcorder, &sound_handle);
        if (ret != MM_ERROR_NONE) {
                _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
        } else {
-               if (sync) {
+               if (sound_played) {
+                       /* increase capture sound count */
+                       hcamcorder->capture_sound_count++;
+               }
+
+               /* wait for sound completed signal */
+               if (sync_play && sound_played) {
                        struct timespec timeout;
                        struct timeval tv;
 
@@ -464,8 +513,6 @@ void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gbo
                }
        }
 
-       MMTA_ACUM_ITEM_END("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE);
-
        pthread_mutex_unlock(&(hcamcorder->sound_lock));
 
        _mmcam_dbg_log("DONE");
@@ -481,6 +528,16 @@ static void __solo_sound_callback(void *data)
 
        _mmcam_dbg_log("START");
 
+       /* decrease capture sound count */
+       pthread_mutex_lock(&(hcamcorder->sound_lock));
+       if (hcamcorder->capture_sound_count > 0) {
+               hcamcorder->capture_sound_count--;
+       } else {
+               _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
+               hcamcorder->capture_sound_count = 0;
+       }
+       pthread_mutex_unlock(&(hcamcorder->sound_lock));
+
        _mmcam_dbg_log("Signal SEND");
        pthread_cond_broadcast(&(hcamcorder->sound_cond));
 
@@ -489,3 +546,38 @@ static void __solo_sound_callback(void *data)
        return;
 }
 
+
+void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
+{
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+
+       mmf_return_if_fail(hcamcorder);
+
+       _mmcam_dbg_log("START");
+
+       /* check playing sound count */
+       pthread_mutex_lock(&(hcamcorder->sound_lock));
+       if (hcamcorder->capture_sound_count > 0) {
+               struct timespec timeout;
+               struct timeval tv;
+
+               gettimeofday( &tv, NULL );
+               timeout.tv_sec = tv.tv_sec + 2;
+               timeout.tv_nsec = tv.tv_usec * 1000;
+
+               _mmcam_dbg_log("Wait for signal");
+
+               if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
+                       _mmcam_dbg_log("signal received.");
+               } else {
+                       _mmcam_dbg_warn("capture sound play timeout.");
+               }
+       } else {
+               _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
+       }
+       pthread_mutex_unlock(&(hcamcorder->sound_lock));
+
+       _mmcam_dbg_log("DONE");
+
+       return;
+}