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