Tizen 2.1 base
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_sound.c
1 /*
2  * libmm-camcorder
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jeongmo Yang <jm80.yang@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 /*=======================================================================================
23 |  INCLUDE FILES                                                                        |
24 =======================================================================================*/
25 #include <mm_sound.h>
26 #include <mm_sound_private.h>
27 #include <avsystem.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_NAME       "camera-shutter"
40 #define SAMPLE_SOUND_RATE       44100
41 #define DEFAULT_ACTIVE_DEVICE   -1
42
43 enum {
44         SOUND_DEVICE_TYPE_SPEAKER,              /* AVSYS_AUDIO_LVOL_DEV_TYPE_SPK */
45         SOUND_DEVICE_TYPE_HEADSET,              /* AVSYS_AUDIO_LVOL_DEV_TYPE_HEADSET */
46         SOUND_DEVICE_TYPE_BTHEADSET,    /* AVSYS_AUDIO_LVOL_DEV_TYPE_BTHEADSET */
47         SOUND_DEVICE_TYPE_NUM                   /* AVSYS_AUDIO_LVOL_DEV_TYPE_MAX */
48 };
49
50 /*---------------------------------------------------------------------------------------
51 |    LOCAL FUNCTION PROTOTYPES:                                                         |
52 ---------------------------------------------------------------------------------------*/
53 static void __solo_sound_callback(void *data);
54
55
56 static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
57 {
58         int state = 0;
59         SOUND_INFO *info = NULL;
60
61         mmf_return_if_fail(user_data);
62
63         info = (SOUND_INFO *)user_data;
64
65         state = pa_context_get_state(pulse_context);
66         switch (state) {
67         case PA_CONTEXT_READY:
68                 _mmcam_dbg_log("pulseaudio context READY");
69                 if (info->pulse_context == pulse_context) {
70                         /* Signal */
71                         _mmcam_dbg_log("pulseaudio send signal");
72                         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
73                 }
74                 break;
75         case PA_CONTEXT_TERMINATED:
76                 if (info->pulse_context == pulse_context) {
77                         /* Signal */
78                         _mmcam_dbg_log("Context terminated : pulseaudio send signal");
79                         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
80                 }
81                 break;
82         case PA_CONTEXT_UNCONNECTED:
83         case PA_CONTEXT_CONNECTING:
84         case PA_CONTEXT_AUTHORIZING:
85         case PA_CONTEXT_SETTING_NAME:
86         case PA_CONTEXT_FAILED:
87         default:
88                 _mmcam_dbg_log("pulseaudio context %p, state %d",
89                                pulse_context, state);
90                 break;
91         }
92
93         return;
94 }
95
96 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
97 static void __pulseaudio_stream_write_cb(pa_stream *stream, size_t length, void *user_data)
98 {
99         sf_count_t read_length;
100         short *data;
101         SOUND_INFO *info = NULL;
102
103         mmf_return_if_fail(user_data);
104
105         info = (SOUND_INFO *)user_data;
106
107         _mmcam_dbg_log("START");
108
109         data = pa_xmalloc(length);
110
111         read_length = (sf_count_t)(length/pa_frame_size(&(info->sample_spec)));
112
113         if ((sf_readf_short(info->infile, data, read_length)) != read_length) {
114                 pa_xfree(data);
115                 return;
116         }
117
118         pa_stream_write(stream, data, length, pa_xfree, 0, PA_SEEK_RELATIVE);
119
120         info->sample_length -= length;
121
122         if (info->sample_length <= 0) {
123                 pa_stream_set_write_callback(info->sample_stream, NULL, NULL);
124                 pa_stream_finish_upload(info->sample_stream);
125
126                 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
127                 _mmcam_dbg_log("send signal DONE");
128         }
129
130         _mmcam_dbg_log("DONE read_length %d", read_length);
131 }
132
133
134 static void __pulseaudio_remove_sample_finish_cb(pa_context *pulse_context, int success, void *user_data)
135 {
136         SOUND_INFO *info = NULL;
137
138         mmf_return_if_fail(user_data);
139
140         info = (SOUND_INFO *)user_data;
141
142         _mmcam_dbg_log("START");
143
144         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
145
146         _mmcam_dbg_log("DONE");
147 }
148 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
149
150 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
151 gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename)
152 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
153 gboolean _mmcamcorder_sound_init(MMHandleType handle)
154 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
155 {
156         int ret = 0;
157         int sound_enable = TRUE;
158         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
159         SOUND_INFO *info = NULL;
160         mm_sound_device_in device_in;
161         mm_sound_device_out device_out;
162         pa_mainloop_api *api = NULL;
163
164         mmf_return_val_if_fail(hcamcorder, FALSE);
165
166         /* check sound play enable */
167         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
168                                           "capture-sound-enable", &sound_enable,
169                                           NULL);
170         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
171         if (!sound_enable) {
172                 return TRUE;
173         }
174
175         info = &(hcamcorder->snd_info);
176
177         pthread_mutex_lock(&(info->open_mutex));
178
179         if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
180                 _mmcam_dbg_warn("already initialized [%d]", info->state);
181                 pthread_mutex_unlock(&(info->open_mutex));
182                 return TRUE;
183         }
184
185 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
186         if (info->filename) {
187                 free(info->filename);
188                 info->filename = NULL;
189         }
190
191         info->filename = strdup(filename);
192         if (info->filename == NULL) {
193                 _mmcam_dbg_err("strdup failed");
194                 return FALSE;
195         }
196 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
197
198         pthread_mutex_init(&(info->play_mutex), NULL);
199         pthread_cond_init(&(info->play_cond), NULL);
200
201 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
202         /* read sample */
203         memset (&(info->sfinfo), 0, sizeof(SF_INFO));
204         info->infile = sf_open(info->filename, SFM_READ, &(info->sfinfo));
205         if (!(info->infile)) {
206                 _mmcam_dbg_err("Failed to open sound file");
207                 goto SOUND_INIT_ERROR;
208         }
209 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
210
211         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) {
212                 int errorcode;
213                 ASM_resource_t mm_resource = mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER;
214
215                 /* set EXCLUSIVE session as PLAYING to pause other session */
216                 if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER,
217                                          ASM_STATE_PLAYING, mm_resource, &errorcode)) {
218                         _mmcam_dbg_err("Set state to playing failed 0x%x", errorcode);
219                         ret = MM_ERROR_POLICY_BLOCKED;
220                         goto SOUND_INIT_ERROR;
221                 }
222
223                 _mmcam_dbg_log("EXCLUSIVE session PLAYING done.");
224         } else {
225                 _mmcam_dbg_log("do not register session to pause another playing session");
226         }
227
228         /**
229          * Init Pulseaudio thread
230          */
231         /* create pulseaudio mainloop */
232         info->pulse_mainloop = pa_threaded_mainloop_new();
233         ret = pa_threaded_mainloop_start(info->pulse_mainloop);
234
235         /* lock pulseaudio thread */
236         pa_threaded_mainloop_lock(info->pulse_mainloop);
237         /* get pulseaudio api */
238         api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
239         /* create pulseaudio context */
240         info->pulse_context = pa_context_new(api, NULL);
241         /* set pulseaudio context callback */
242         pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
243
244         if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
245                 _mmcam_dbg_err("pa_context_connect error");
246         }
247
248         /* wait READY state of pulse context */
249         while (TRUE) {
250                 pa_context_state_t state = pa_context_get_state(info->pulse_context);
251
252                 _mmcam_dbg_log("pa context state is now %d", state);
253
254                 if (!PA_CONTEXT_IS_GOOD (state)) {
255                         _mmcam_dbg_log("connection failed");
256                         break;
257                 }
258
259                 if (state == PA_CONTEXT_READY) {
260                         _mmcam_dbg_log("pa context READY");
261                         break;
262                 }
263
264                 /* Wait until the context is ready */
265                 _mmcam_dbg_log("waiting..................");
266                 pa_threaded_mainloop_wait(info->pulse_mainloop);
267                 _mmcam_dbg_log("waiting DONE. check again...");
268         }
269
270         /* unlock pulseaudio thread */
271         pa_threaded_mainloop_unlock(info->pulse_mainloop);
272
273 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
274         /**
275          * Upload sample
276          */
277         if (pa_sndfile_read_sample_spec(info->infile, &(info->sample_spec)) < 0) {
278                 _mmcam_dbg_err("Failed to determine sample specification from file");
279                 goto SOUND_INIT_ERROR;
280         }
281
282         info->sample_spec.format = PA_SAMPLE_S16LE;
283
284         if (pa_sndfile_read_channel_map(info->infile, &(info->channel_map)) < 0) {
285                 pa_channel_map_init_extend(&(info->channel_map), info->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
286
287                 if (info->sample_spec.channels > 2) {
288                         _mmcam_dbg_warn("Failed to determine sample specification from file");
289                 }
290         }
291
292         info->sample_length = (size_t)info->sfinfo.frames * pa_frame_size(&(info->sample_spec));
293
294         pa_threaded_mainloop_lock(info->pulse_mainloop);
295
296         /* prepare uploading */
297         info->sample_stream = pa_stream_new(info->pulse_context, SAMPLE_SOUND_NAME, &(info->sample_spec), NULL);
298         /* set stream write callback */
299         pa_stream_set_write_callback(info->sample_stream, __pulseaudio_stream_write_cb, info);
300         /* upload sample (ASYNC) */
301         pa_stream_connect_upload(info->sample_stream, info->sample_length);
302         /* wait for upload completion */
303         pa_threaded_mainloop_wait(info->pulse_mainloop);
304
305         pa_threaded_mainloop_unlock (info->pulse_mainloop);
306
307         /* close sndfile */
308         sf_close(info->infile);
309         info->infile = NULL;
310 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
311
312         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) {
313                 /* backup current route */
314                 info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
315
316                 __ta__("        mm_sound_get_active_device",
317                 ret = mm_sound_get_active_device(&device_in, &device_out);
318                 );
319                 if (ret != MM_ERROR_NONE) {
320                         _mmcam_dbg_err("mm_sound_get_active_device failed [%x]. skip sound play.", ret);
321                         goto SOUND_INIT_ERROR;
322                 }
323
324                 _mmcam_dbg_log("current out [%x]", device_out);
325
326                 if (device_out != MM_SOUND_DEVICE_OUT_SPEAKER) {
327                         ret = mm_sound_set_active_route (MM_SOUND_ROUTE_OUT_SPEAKER);
328                         if (ret != MM_ERROR_NONE) {
329                                 _mmcam_dbg_err("mm_sound_set_active_route failed [%x]. skip sound play.", ret);
330                                 goto SOUND_INIT_ERROR;
331                         }
332                         info->active_out_backup = device_out;
333                 }
334         }
335
336         info->state = _MMCAMCORDER_SOUND_STATE_INIT;
337
338         _mmcam_dbg_log("init DONE");
339
340         pthread_mutex_unlock(&(info->open_mutex));
341
342         return TRUE;
343
344 SOUND_INIT_ERROR:
345
346 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
347         /**
348          * Release allocated resources
349          */
350         if (info->filename) {
351                 free(info->filename);
352                 info->filename = NULL;
353         }
354 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
355
356         /* remove pulse mainloop */
357         if (info->pulse_mainloop) {
358                 /* remove pulse context */
359                 if (info->pulse_context) {
360 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
361                         /* remove uploaded sample */
362                         if (info->sample_stream) {
363                                 pa_threaded_mainloop_lock(info->pulse_mainloop);
364
365                                 /* Remove sample (ASYNC) */
366                                 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
367
368                                 /* Wait for async operation */
369                                 pa_threaded_mainloop_wait(info->pulse_mainloop);
370                         }
371 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
372
373                         /* Make sure we don't get any further callbacks */
374                         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
375
376                         pa_context_disconnect(info->pulse_context);
377                         pa_context_unref(info->pulse_context);
378                         info->pulse_context = NULL;
379                 }
380
381                 pa_threaded_mainloop_stop(info->pulse_mainloop);
382                 pa_threaded_mainloop_free(info->pulse_mainloop);
383                 info->pulse_mainloop = NULL;
384         }
385
386         /* remove mutex and cond */
387         pthread_mutex_destroy(&(info->play_mutex));
388         pthread_cond_destroy(&(info->play_cond));
389
390         pthread_mutex_unlock(&(info->open_mutex));
391
392         return FALSE;
393 }
394
395
396 gboolean _mmcamcorder_sound_play(MMHandleType handle)
397 {
398         int ret = 0;
399         int sound_enable = TRUE;
400         int volume_type = AVSYS_AUDIO_VOLUME_TYPE_FIXED;
401         int device_type = SOUND_DEVICE_TYPE_SPEAKER;
402         int left_volume = 0, right_volume = 0;
403         float left_gain = 1.0f, right_gain = 1.0f;
404         int set_volume = 0;
405         int max_level = 0;
406         unsigned int volume_level;
407
408         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
409         SOUND_INFO *info = NULL;
410         pa_operation *pulse_op = NULL;
411
412         mmf_return_val_if_fail(hcamcorder, FALSE);
413
414         /* check sound play enable */
415         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
416                                           "capture-sound-enable", &sound_enable,
417                                           NULL);
418         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
419         if (!sound_enable) {
420                 return TRUE;
421         }
422
423         info = &(hcamcorder->snd_info);
424
425         pthread_mutex_lock(&(info->open_mutex));
426
427         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
428                 _mmcam_dbg_log("not initialized state:[%d]", info->state);
429                 pthread_mutex_unlock(&(info->open_mutex));
430                 return FALSE;
431         }
432
433         /* get volume level and set volume */
434         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_OFF) {
435                 gboolean sound_status = hcamcorder->sub_context->info_image->sound_status;
436                 mm_sound_device_in device_in = MM_SOUND_DEVICE_IN_NONE;
437                 mm_sound_device_out device_out = MM_SOUND_DEVICE_OUT_NONE;
438
439                 volume_type = AVSYS_AUDIO_VOLUME_TYPE_MEDIA;
440                 avsys_audio_get_volume_max_ex(volume_type, &max_level);
441
442                 /* get sound path */
443                 __ta__("                    mm_sound_get_active_device",
444                 mm_sound_get_active_device(&device_in, &device_out);
445                 );
446
447                 _mmcam_dbg_log("sound status %d, device out %x", sound_status, device_out);
448
449                 if (device_out == MM_SOUND_DEVICE_OUT_WIRED_ACCESSORY) {
450                         device_type = SOUND_DEVICE_TYPE_HEADSET;
451                 } else if (device_out == MM_SOUND_DEVICE_OUT_BT_A2DP) {
452                         device_type = SOUND_DEVICE_TYPE_BTHEADSET;
453                 }
454
455                 if (sound_status || device_out != MM_SOUND_DEVICE_OUT_SPEAKER) {
456                         volume_level = hcamcorder->sub_context->info_image->volume_level;
457                         _mmcam_dbg_log("current volume level %d", volume_level);
458                 } else {
459                         volume_level = 0;
460                         _mmcam_dbg_log("current state is SILENT mode and SPEAKER output");
461                 }
462
463                 if (volume_level > (unsigned int)max_level) {
464                         _mmcam_dbg_warn("invalid volume level. set max");
465                         volume_level = (unsigned int)max_level;
466                 }
467         } else {
468                 avsys_audio_get_volume_max_ex(volume_type, &max_level);
469                 volume_level = (unsigned int)max_level;
470         }
471
472         avsys_audio_get_volume_table(volume_type, device_type, (int)volume_level, &left_volume, &right_volume);
473         avsys_audio_get_volume_gain_table(
474                 AVSYS_AUDIO_VOLUME_GAIN_IDX(AVSYS_AUDIO_VOLUME_GAIN_SHUTTER2),
475                 device_type, &left_gain, &right_gain);
476         set_volume = left_volume * left_gain;
477         _mmcam_dbg_log("volume type %d, device type %d, volume level %d, left volume %d left gain %.2f set_volume %d",
478                                         volume_type, device_type, volume_level, left_volume, left_gain, set_volume);
479
480         _mmcam_dbg_log("shutter sound policy %d, volume %d",
481                        hcamcorder->shutter_sound_policy, set_volume);
482
483         _mmcam_dbg_log("Play start");
484
485         __ta__("                    pa_context_play_sample",
486         pulse_op = pa_context_play_sample(info->pulse_context,
487                                           SAMPLE_SOUND_NAME,
488                                           NULL,
489                                           set_volume,
490                                           NULL,
491                                           NULL);
492         );
493         if (pulse_op) {
494                 pa_operation_unref(pulse_op);
495                 pulse_op = NULL;
496         }
497
498         pthread_mutex_unlock(&(info->open_mutex));
499
500         _mmcam_dbg_log("Done");
501
502         return TRUE;
503 }
504
505
506 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
507 {
508         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
509         SOUND_INFO *info = NULL;
510         mm_sound_device_in device_in;
511         mm_sound_device_out device_out;
512         int ret = 0;
513
514         mmf_return_val_if_fail(hcamcorder, FALSE);
515
516         info = &(hcamcorder->snd_info);
517
518         _mmcam_dbg_err("START");
519
520         pthread_mutex_lock(&(info->open_mutex));
521
522         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
523                 _mmcam_dbg_warn("not initialized");
524                 pthread_mutex_unlock(&(info->open_mutex));
525                 return TRUE;
526         }
527
528         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) {
529                 /**
530                  * Restore route
531                  */
532                 _mmcam_dbg_log("restore route");
533                 if (info->active_out_backup != DEFAULT_ACTIVE_DEVICE) {
534                         ret = mm_sound_get_active_device(&device_in, &device_out);
535                         if (ret != MM_ERROR_NONE) {
536                                 _mmcam_dbg_err("mm_sound_get_active_device failed [%x]. skip sound play.", ret);
537                         }
538
539                         _mmcam_dbg_log("current out [%x]", device_out);
540
541                         if (device_out != info->active_out_backup) {
542                                 ret = mm_sound_set_active_route (info->active_out_backup);
543                                 if (ret != MM_ERROR_NONE) {
544                                         _mmcam_dbg_err("mm_sound_set_active_route failed [%x]. skip sound play.", ret);
545                                 }
546                         }
547                 }
548         }
549
550 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
551         /**
552          * Remove sample
553          */
554         _mmcam_dbg_log("remove sample");
555
556         pa_threaded_mainloop_lock(info->pulse_mainloop);
557
558         /* Remove sample (ASYNC) */
559         pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
560
561         /* Wait for async operation */
562         pa_threaded_mainloop_wait(info->pulse_mainloop);
563
564         pa_threaded_mainloop_unlock(info->pulse_mainloop);
565 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
566
567         /**
568          * Release pulseaudio thread
569          */
570         _mmcam_dbg_log("release pulseaudio thread");
571
572         pa_threaded_mainloop_lock(info->pulse_mainloop);
573
574         pa_context_disconnect(info->pulse_context);
575
576         /* Make sure we don't get any further callbacks */
577         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
578
579         pa_context_unref(info->pulse_context);
580         info->pulse_context = NULL;
581
582         pa_threaded_mainloop_unlock(info->pulse_mainloop);
583
584         pa_threaded_mainloop_stop(info->pulse_mainloop);
585         pa_threaded_mainloop_free(info->pulse_mainloop);
586         info->pulse_mainloop = NULL;
587
588 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
589         if (info->filename) {
590                 free(info->filename);
591                 info->filename = NULL;
592         }
593 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
594
595         info->state = _MMCAMCORDER_SOUND_STATE_NONE;
596         info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
597
598         /* release mutex and cond */
599         _mmcam_dbg_log("release play_mutex/cond");
600         pthread_mutex_destroy(&(info->play_mutex));
601         pthread_cond_destroy(&(info->play_cond));
602
603         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) {
604                 int errorcode = 0;
605                 ASM_resource_t mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER;
606
607                 /* stop EXCLUSIVE session */
608                 if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER,
609                                          ASM_STATE_STOP, mm_resource, &errorcode)) {
610                         _mmcam_dbg_err("EXCLUSIVE Set state to STOP failed 0x%x", errorcode);
611                 } else {
612                         _mmcam_dbg_log("EXCLUSIVE session STOP done.");
613                 }
614         }
615
616         pthread_mutex_unlock(&(info->open_mutex));
617
618         _mmcam_dbg_err("DONE");
619
620         return TRUE;
621 }
622
623
624 gboolean _mmcamcorder_sound_capture_play_cb(gpointer data)
625 {
626         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
627
628         mmf_return_val_if_fail(hcamcorder, FALSE);
629
630         _mmcam_dbg_log("Capture sound PLAY in idle callback");
631
632         _mmcamcorder_sound_solo_play((MMHandleType)hcamcorder, _MMCAMCORDER_FILEPATH_CAPTURE_SND, FALSE);
633
634         return FALSE;
635 }
636
637
638 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync)
639 {
640         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
641
642         int sound_handle = 0;
643         int ret = MM_ERROR_NONE;
644         int sound_enable = TRUE;
645         int gain_type = VOLUME_GAIN_SHUTTER1;
646
647         mmf_return_if_fail(filepath && hcamcorder);
648
649         _mmcam_dbg_log("START : %s", filepath);
650
651         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
652                                           "capture-sound-enable", &sound_enable,
653                                           NULL);
654         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
655         if (!sound_enable) {
656                 return;
657         }
658
659         ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
660         if (ret != 0) {
661                 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
662                 return;
663         }
664
665         /* check filename to set gain_type */
666         if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND)) {
667                 gain_type = VOLUME_GAIN_SHUTTER1;
668         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) {
669                 gain_type = VOLUME_GAIN_SHUTTER2;
670         } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND) ||
671                    !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) {
672                 gain_type = VOLUME_GAIN_CAMCORDING;
673         }
674
675         _mmcam_dbg_log("gain type 0x%x", gain_type);
676
677         if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) {
678                 __ta__("CAPTURE SOUND:mm_sound_play_loud_solo_sound",
679                 ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED | gain_type,
680                                                     __solo_sound_callback, (void*)hcamcorder, &sound_handle);
681                 );
682         } else {
683                 gboolean sound_status = hcamcorder->sub_context->info_image->sound_status;
684                 mm_sound_device_in device_in;
685                 mm_sound_device_out device_out;
686
687                 /* get sound path */
688                 mm_sound_get_active_device(&device_in, &device_out);
689
690                 _mmcam_dbg_log("sound status %d, device out %x", sound_status, device_out);
691
692                 if (sound_status || device_out != MM_SOUND_DEVICE_OUT_SPEAKER) {
693                         __ta__("CAPTURE SOUND:mm_sound_play_sound",
694                         ret = mm_sound_play_sound(filepath, VOLUME_TYPE_MEDIA | gain_type,
695                                                   __solo_sound_callback, (void*)hcamcorder, &sound_handle);
696                         );
697                 }
698         }
699         if (ret != MM_ERROR_NONE) {
700                 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
701         } else {
702                 if (sync) {
703                         struct timespec timeout;
704                         struct timeval tv;
705
706                         gettimeofday( &tv, NULL );
707                         timeout.tv_sec = tv.tv_sec + 2;
708                         timeout.tv_nsec = tv.tv_usec * 1000;
709
710                         _mmcam_dbg_log("Wait for signal");
711
712                         MMTA_ACUM_ITEM_BEGIN("CAPTURE SOUND:wait sound play finish", FALSE);
713
714                         if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
715                                 _mmcam_dbg_log("signal received.");
716                         } else {
717                                 _mmcam_dbg_warn("capture sound play timeout.");
718                                 if (sound_handle > 0) {
719                                         mm_sound_stop_sound(sound_handle);
720                                 }
721                         }
722
723                         MMTA_ACUM_ITEM_END("CAPTURE SOUND:wait sound play finish", FALSE);
724                 }
725         }
726
727         pthread_mutex_unlock(&(hcamcorder->sound_lock));
728
729         _mmcam_dbg_log("DONE");
730
731         return;
732 }
733
734 static void __solo_sound_callback(void *data)
735 {
736         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
737
738         mmf_return_if_fail(hcamcorder);
739
740         _mmcam_dbg_log("START");
741
742         _mmcam_dbg_log("Signal SEND");
743         pthread_cond_broadcast(&(hcamcorder->sound_cond));
744
745         _mmcam_dbg_log("DONE");
746
747         return;
748 }
749