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