4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 /*=======================================================================================
24 =======================================================================================*/
27 #include <mm_sound_private.h>
28 #include <audio-session-manager.h>
29 #include "mm_camcorder_internal.h"
30 #include "mm_camcorder_sound.h"
32 /*---------------------------------------------------------------------------------------
33 | GLOBAL VARIABLE DEFINITIONS for internal |
34 ---------------------------------------------------------------------------------------*/
36 /*---------------------------------------------------------------------------------------
37 | LOCAL VARIABLE DEFINITIONS for internal |
38 ---------------------------------------------------------------------------------------*/
39 #define SAMPLE_SOUND_RATE 44100
40 #define DEFAULT_ACTIVE_DEVICE 0xffffffff
42 /*---------------------------------------------------------------------------------------
43 | LOCAL FUNCTION PROTOTYPES: |
44 ---------------------------------------------------------------------------------------*/
45 static void __solo_sound_callback(void *data);
47 static void __pulseaudio_play_sample_cb(pa_context *pulse_context, uint32_t stream_index, void *user_data)
49 SOUND_INFO *info = NULL;
51 mmf_return_if_fail(user_data);
53 info = (SOUND_INFO *)user_data;
55 _mmcam_dbg_log("START - idx : %d", stream_index);
57 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
59 _mmcam_dbg_log("DONE");
64 static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
67 SOUND_INFO *info = NULL;
69 mmf_return_if_fail(user_data);
71 info = (SOUND_INFO *)user_data;
73 state = pa_context_get_state(pulse_context);
75 case PA_CONTEXT_READY:
76 _mmcam_dbg_log("pulseaudio context READY");
77 if (info->pulse_context == pulse_context) {
79 _mmcam_dbg_log("pulseaudio send signal");
80 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
83 case PA_CONTEXT_TERMINATED:
84 if (info->pulse_context == pulse_context) {
86 _mmcam_dbg_log("Context terminated : pulseaudio send signal");
87 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
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:
96 _mmcam_dbg_log("pulseaudio context %p, state %d",
97 pulse_context, state);
105 #ifdef _MMCAMCORDER_FAST_AUDIO_OPEN
106 static void __pulseaudio_stream_state_cb(pa_stream *s, void *user_data)
108 pa_stream_state_t state = 0;
109 SOUND_INFO *info = NULL;
111 mmf_return_if_fail(user_data);
113 info = (SOUND_INFO *)user_data;
115 state = pa_stream_get_state(s);
117 case PA_STREAM_READY:
118 case PA_STREAM_FAILED:
119 case PA_STREAM_TERMINATED:
121 _mmcam_dbg_warn("pulseaudio stream %p, state %d, send signal", s, state);
122 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
125 case PA_STREAM_UNCONNECTED:
126 case PA_STREAM_CREATING:
127 _mmcam_dbg_log("pulseaudio stream %p, state %d", s, state);
133 #endif /* _MMCAMCORDER_FAST_AUDIO_OPEN */
135 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
136 static void __pulseaudio_stream_write_cb(pa_stream *stream, size_t length, void *user_data)
138 sf_count_t read_length;
140 SOUND_INFO *info = NULL;
142 mmf_return_if_fail(user_data);
144 info = (SOUND_INFO *)user_data;
146 _mmcam_dbg_log("START");
148 data = pa_xmalloc(length);
150 read_length = (sf_count_t)(length/pa_frame_size(&(info->sample_spec)));
152 if ((sf_readf_short(info->infile, data, read_length)) != read_length) {
157 pa_stream_write(stream, data, length, pa_xfree, 0, PA_SEEK_RELATIVE);
159 info->sample_length -= length;
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);
165 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
166 _mmcam_dbg_log("send signal DONE");
169 _mmcam_dbg_log("DONE read_length %d", read_length);
175 static void __pulseaudio_remove_sample_finish_cb(pa_context *pulse_context, int success, void *user_data)
177 SOUND_INFO *info = NULL;
179 mmf_return_if_fail(user_data);
181 info = (SOUND_INFO *)user_data;
183 _mmcam_dbg_log("START");
185 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
187 _mmcam_dbg_log("DONE");
191 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
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 */
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;
208 mmf_return_val_if_fail(hcamcorder, FALSE);
210 /* check sound play enable */
211 ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
212 "capture-sound-enable", &sound_enable,
214 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
216 _mmcam_dbg_warn("capture sound disabled");
220 info = &(hcamcorder->snd_info);
222 pthread_mutex_lock(&(info->open_mutex));
224 if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
225 _mmcam_dbg_warn("already initialized [%d]", info->state);
226 pthread_mutex_unlock(&(info->open_mutex));
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));
239 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
240 if (info->filename) {
241 free(info->filename);
242 info->filename = NULL;
245 info->filename = strdup(filename);
246 if (info->filename == NULL) {
247 _mmcam_dbg_err("strdup failed");
250 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
252 pthread_mutex_init(&(info->play_mutex), NULL);
253 pthread_cond_init(&(info->play_cond), NULL);
255 #ifdef _MMCAMCORDER_UPLOAD_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;
263 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
265 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM &&
266 hcamcorder->asm_register) {
269 if (!ASM_set_subevent(hcamcorder->asm_handle, ASM_SUB_EVENT_EXCLUSIVE, &errorcode)) {
271 case ERR_ASM_POLICY_CANNOT_PLAY_BY_CALL:
272 ret = MM_ERROR_POLICY_BLOCKED_BY_CALL;
274 case ERR_ASM_POLICY_CANNOT_PLAY_BY_ALARM:
275 ret = MM_ERROR_POLICY_BLOCKED_BY_ALARM;
278 ret = MM_ERROR_POLICY_BLOCKED;
282 _mmcam_dbg_err("Set ASM_SUB_EVENT_EXCLUSIVE failed: 0x%x", errorcode);
284 goto SOUND_INIT_ERROR;
287 _mmcam_dbg_log("set ASM_SUB_EVENT_EXCLUSIVE done.");
289 _mmcam_dbg_warn("skip session : _MMCAMCORDER_STATE_CHANGE_BY_ASM");
293 * Init Pulseaudio thread
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;
302 /* start PA mainloop */
303 ret = pa_threaded_mainloop_start(info->pulse_mainloop);
305 _mmcam_dbg_err("pa_threaded_mainloop_start failed");
306 goto SOUND_INIT_ERROR;
309 /* lock pulseaudio thread */
310 pa_threaded_mainloop_lock(info->pulse_mainloop);
312 /* get pulseaudio api */
313 api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
315 _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
316 pa_threaded_mainloop_unlock(info->pulse_mainloop);
317 goto SOUND_INIT_ERROR;
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;
328 /* set pulseaudio context callback */
329 pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
331 if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
332 _mmcam_dbg_err("pa_context_connect error");
335 /* wait READY state of pulse context */
337 pa_context_state_t state = pa_context_get_state(info->pulse_context);
339 _mmcam_dbg_log("pa context state is now %d", state);
341 if (!PA_CONTEXT_IS_GOOD (state)) {
342 _mmcam_dbg_log("connection failed");
346 if (state == PA_CONTEXT_READY) {
347 _mmcam_dbg_log("pa context READY");
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...");
357 /* unlock pulseaudio thread */
358 pa_threaded_mainloop_unlock(info->pulse_mainloop);
360 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
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;
369 info->sample_spec.format = PA_SAMPLE_S16LE;
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);
374 if (info->sample_spec.channels > 2) {
375 _mmcam_dbg_warn("Failed to determine sample specification from file");
379 info->sample_length = (size_t)info->sfinfo.frames * pa_frame_size(&(info->sample_spec));
381 pa_threaded_mainloop_lock(info->pulse_mainloop);
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);
392 pa_threaded_mainloop_unlock(info->pulse_mainloop);
395 sf_close(info->infile);
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;
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;
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);
415 pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
417 if (state == PA_STREAM_READY) {
418 _mmcam_dbg_warn("device READY done");
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);
428 /* Wait until the stream is ready */
429 pa_threaded_mainloop_wait(info->pulse_mainloop);
432 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
434 /* backup current route */
435 info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
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;
443 _mmcam_dbg_log("current out [%x]", device_out);
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;
451 info->active_out_backup = device_out;
454 info->volume_type = PA_TIZEN_VOLUME_TYPE_FIXED;
455 info->volume_level = 0;
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");
462 _mmcam_dbg_warn("sound handle closed successfully");
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.");
471 goto SOUND_INIT_ERROR;
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");
478 _mmcam_dbg_warn("sound handle closed successfully");
481 goto SOUND_INIT_ERROR;
484 #endif /* _MMCAMCORDER_PREOPEN_PCM */
486 info->state = _MMCAMCORDER_SOUND_STATE_INIT;
488 _mmcam_dbg_log("init DONE");
490 pthread_mutex_unlock(&(info->open_mutex));
496 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
498 * Release allocated resources
500 if (info->filename) {
501 free(info->filename);
502 info->filename = NULL;
504 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
506 /* remove pulse mainloop */
507 if (info->pulse_mainloop) {
508 pa_threaded_mainloop_lock(info->pulse_mainloop);
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);
517 /* Remove sample (ASYNC) */
518 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
520 /* Wait for async operation */
521 pa_threaded_mainloop_wait(info->pulse_mainloop);
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;
530 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
532 /* Make sure we don't get any further callbacks */
533 pa_context_set_state_callback(info->pulse_context, NULL, NULL);
535 pa_context_disconnect(info->pulse_context);
536 pa_context_unref(info->pulse_context);
537 info->pulse_context = NULL;
540 pa_threaded_mainloop_unlock(info->pulse_mainloop);
542 pa_threaded_mainloop_stop(info->pulse_mainloop);
543 pa_threaded_mainloop_free(info->pulse_mainloop);
544 info->pulse_mainloop = NULL;
547 /* remove mutex and cond */
548 pthread_mutex_destroy(&(info->play_mutex));
549 pthread_cond_destroy(&(info->play_cond));
551 pthread_mutex_unlock(&(info->open_mutex));
557 gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
559 int sound_enable = TRUE;
560 int gain_type = VOLUME_GAIN_SHUTTER1;
562 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
563 SOUND_INFO *info = NULL;
564 pa_operation *pulse_op = NULL;
566 mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
568 /* check sound play enable */
569 mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
570 "capture-sound-enable", &sound_enable,
572 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
574 _mmcam_dbg_warn("capture sound disabled");
578 info = &(hcamcorder->snd_info);
580 pthread_mutex_lock(&(info->open_mutex));
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));
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;
594 _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
597 pa_threaded_mainloop_lock(info->pulse_mainloop);
599 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
604 __pulseaudio_play_sample_cb,
607 _mmcam_dbg_log("wait for signal");
608 pa_threaded_mainloop_wait(info->pulse_mainloop);
609 _mmcam_dbg_log("received signal");
611 pa_threaded_mainloop_unlock(info->pulse_mainloop);
613 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
622 pa_operation_unref(pulse_op);
626 pthread_mutex_unlock(&(info->open_mutex));
628 _mmcam_dbg_log("Done");
634 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
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;
642 mmf_return_val_if_fail(hcamcorder, FALSE);
644 info = &(hcamcorder->snd_info);
646 _mmcam_dbg_err("START");
648 /*Add the delay because we don't know when shutter sound was complete */
650 pthread_mutex_lock(&(info->open_mutex));
652 if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
653 _mmcam_dbg_warn("not initialized");
654 pthread_mutex_unlock(&(info->open_mutex));
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);
665 _mmcam_dbg_log("sound handle closed successfully");
669 _mmcam_dbg_warn("sound handle is NULL");
671 #endif /* _MMCAMCORDER_PREOPEN_PCM */
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);
681 _mmcam_dbg_log("current out [%x]", device_out);
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);
691 pa_threaded_mainloop_lock(info->pulse_mainloop);
693 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
697 _mmcam_dbg_log("remove sample");
699 /* Remove sample (ASYNC) */
700 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
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;
710 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
713 * Release pulseaudio thread
715 _mmcam_dbg_log("release pulseaudio thread");
717 pa_context_disconnect(info->pulse_context);
719 /* Make sure we don't get any further callbacks */
720 pa_context_set_state_callback(info->pulse_context, NULL, NULL);
722 pa_context_unref(info->pulse_context);
723 info->pulse_context = NULL;
725 pa_threaded_mainloop_unlock(info->pulse_mainloop);
727 pa_threaded_mainloop_stop(info->pulse_mainloop);
728 pa_threaded_mainloop_free(info->pulse_mainloop);
729 info->pulse_mainloop = NULL;
731 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
732 if (info->filename) {
733 free(info->filename);
734 info->filename = NULL;
736 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
738 info->state = _MMCAMCORDER_SOUND_STATE_NONE;
739 info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
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));
746 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM &&
747 hcamcorder->asm_register) {
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");
755 _mmcam_dbg_err("ASM_set_subevent ASM_SUB_EVENT_SHARE failed 0x%x", errorcode);
758 _mmcam_dbg_err("ASM_set_subevent ASM_SUB_EVENT_NONE failed 0x%x", errorcode);
761 _mmcam_dbg_warn("skip session : _MMCAMCORDER_STATE_CHANGE_BY_ASM");
764 pthread_mutex_unlock(&(info->open_mutex));
766 _mmcam_dbg_err("DONE");
772 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
774 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
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',};
783 mmf_return_if_fail(filepath && hcamcorder);
785 _mmcam_dbg_log("START : %s", filepath);
787 _mmcamcorder_sound_solo_play_wait(handle);
789 ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
791 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
792 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", err_msg);
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;
802 gain_type = VOLUME_GAIN_SHUTTER1;
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;
810 _mmcam_dbg_log("gain type 0x%x", gain_type);
812 ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
813 "capture-sound-enable", &sound_enable,
815 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
818 /* send capture sound completed message */
819 pthread_mutex_unlock(&(hcamcorder->sound_lock));
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);
830 _mmcam_dbg_warn("skip shutter sound");
833 _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
835 if (ret != MM_ERROR_NONE) {
836 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
839 /* increase capture sound count */
840 hcamcorder->capture_sound_count++;
843 /* wait for sound completed signal */
844 if (sync_play && sound_played) {
845 struct timespec timeout;
848 gettimeofday( &tv, NULL );
849 timeout.tv_sec = tv.tv_sec + 2;
850 timeout.tv_nsec = tv.tv_usec * 1000;
852 _mmcam_dbg_log("Wait for signal");
854 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
855 _mmcam_dbg_log("signal received.");
857 _mmcam_dbg_warn("capture sound play timeout.");
858 if (sound_handle > 0) {
859 mm_sound_stop_sound(sound_handle);
865 pthread_mutex_unlock(&(hcamcorder->sound_lock));
867 _mmcam_dbg_log("DONE");
872 static void __solo_sound_callback(void *data)
874 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
876 mmf_return_if_fail(hcamcorder);
878 _mmcam_dbg_log("START");
880 /* decrease capture sound count */
881 pthread_mutex_lock(&(hcamcorder->sound_lock));
882 if (hcamcorder->capture_sound_count > 0) {
883 hcamcorder->capture_sound_count--;
885 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
886 hcamcorder->capture_sound_count = 0;
888 pthread_mutex_unlock(&(hcamcorder->sound_lock));
890 _mmcam_dbg_log("Signal SEND");
891 pthread_cond_broadcast(&(hcamcorder->sound_cond));
893 _mmcam_dbg_log("DONE");
899 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
901 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
903 mmf_return_if_fail(hcamcorder);
905 _mmcam_dbg_log("START");
907 /* check playing sound count */
908 pthread_mutex_lock(&(hcamcorder->sound_lock));
909 if (hcamcorder->capture_sound_count > 0) {
910 struct timespec timeout;
913 gettimeofday( &tv, NULL );
914 timeout.tv_sec = tv.tv_sec + 2;
915 timeout.tv_nsec = tv.tv_usec * 1000;
917 _mmcam_dbg_log("Wait for signal");
919 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
920 _mmcam_dbg_log("signal received.");
922 _mmcam_dbg_warn("capture sound play timeout.");
925 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
927 pthread_mutex_unlock(&(hcamcorder->sound_lock));
929 _mmcam_dbg_log("DONE");