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 =======================================================================================*/
26 #include <mm_sound_private.h>
27 #include <audio-session-manager.h>
28 #include "mm_camcorder_internal.h"
29 #include "mm_camcorder_sound.h"
31 /*---------------------------------------------------------------------------------------
32 | GLOBAL VARIABLE DEFINITIONS for internal |
33 ---------------------------------------------------------------------------------------*/
35 /*---------------------------------------------------------------------------------------
36 | LOCAL VARIABLE DEFINITIONS for internal |
37 ---------------------------------------------------------------------------------------*/
38 #define SAMPLE_SOUND_RATE 44100
39 #define DEFAULT_ACTIVE_DEVICE 0xffffffff
41 /*---------------------------------------------------------------------------------------
42 | LOCAL FUNCTION PROTOTYPES: |
43 ---------------------------------------------------------------------------------------*/
44 static void __solo_sound_callback(void *data);
46 static void __pulseaudio_play_sample_cb(pa_context *pulse_context, uint32_t stream_index, void *user_data)
48 SOUND_INFO *info = NULL;
50 mmf_return_if_fail(user_data);
52 info = (SOUND_INFO *)user_data;
54 _mmcam_dbg_log("START - idx : %d", stream_index);
56 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
58 _mmcam_dbg_log("DONE");
63 static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
66 SOUND_INFO *info = NULL;
68 mmf_return_if_fail(user_data);
70 info = (SOUND_INFO *)user_data;
72 state = pa_context_get_state(pulse_context);
74 case PA_CONTEXT_READY:
75 _mmcam_dbg_log("pulseaudio context READY");
76 if (info->pulse_context == pulse_context) {
78 _mmcam_dbg_log("pulseaudio send signal");
79 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
82 case PA_CONTEXT_TERMINATED:
83 if (info->pulse_context == pulse_context) {
85 _mmcam_dbg_log("Context terminated : pulseaudio send signal");
86 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
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:
95 _mmcam_dbg_log("pulseaudio context %p, state %d",
96 pulse_context, state);
104 #ifdef _MMCAMCORDER_FAST_AUDIO_OPEN
105 static void __pulseaudio_stream_state_cb(pa_stream *s, void *user_data)
107 pa_stream_state_t state = 0;
108 SOUND_INFO *info = NULL;
110 mmf_return_if_fail(user_data);
112 info = (SOUND_INFO *)user_data;
114 state = pa_stream_get_state(s);
116 case PA_STREAM_READY:
117 case PA_STREAM_FAILED:
118 case PA_STREAM_TERMINATED:
120 _mmcam_dbg_warn("pulseaudio stream %p, state %d, send signal", s, state);
121 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
124 case PA_STREAM_UNCONNECTED:
125 case PA_STREAM_CREATING:
126 _mmcam_dbg_log("pulseaudio stream %p, state %d", s, state);
132 #endif /* _MMCAMCORDER_FAST_AUDIO_OPEN */
134 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
135 static void __pulseaudio_stream_write_cb(pa_stream *stream, size_t length, void *user_data)
137 sf_count_t read_length;
139 SOUND_INFO *info = NULL;
141 mmf_return_if_fail(user_data);
143 info = (SOUND_INFO *)user_data;
145 _mmcam_dbg_log("START");
147 data = pa_xmalloc(length);
149 read_length = (sf_count_t)(length/pa_frame_size(&(info->sample_spec)));
151 if ((sf_readf_short(info->infile, data, read_length)) != read_length) {
156 pa_stream_write(stream, data, length, pa_xfree, 0, PA_SEEK_RELATIVE);
158 info->sample_length -= length;
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);
164 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
165 _mmcam_dbg_log("send signal DONE");
168 _mmcam_dbg_log("DONE read_length %d", read_length);
174 static void __pulseaudio_remove_sample_finish_cb(pa_context *pulse_context, int success, void *user_data)
176 SOUND_INFO *info = NULL;
178 mmf_return_if_fail(user_data);
180 info = (SOUND_INFO *)user_data;
182 _mmcam_dbg_log("START");
184 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
186 _mmcam_dbg_log("DONE");
190 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
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 */
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;
207 mmf_return_val_if_fail(hcamcorder, FALSE);
209 /* check sound play enable */
210 ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
211 "capture-sound-enable", &sound_enable,
213 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
215 _mmcam_dbg_warn("capture sound disabled");
219 info = &(hcamcorder->snd_info);
221 pthread_mutex_lock(&(info->open_mutex));
223 if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
224 _mmcam_dbg_warn("already initialized [%d]", info->state);
225 pthread_mutex_unlock(&(info->open_mutex));
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));
238 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
239 if (info->filename) {
240 free(info->filename);
241 info->filename = NULL;
244 info->filename = strdup(filename);
245 if (info->filename == NULL) {
246 _mmcam_dbg_err("strdup failed");
249 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
251 pthread_mutex_init(&(info->play_mutex), NULL);
252 pthread_cond_init(&(info->play_cond), NULL);
254 #ifdef _MMCAMCORDER_UPLOAD_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;
262 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
264 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM &&
265 hcamcorder->asm_register) {
268 if (!ASM_set_subevent(hcamcorder->asm_handle, ASM_SUB_EVENT_EXCLUSIVE, &errorcode)) {
270 case ERR_ASM_POLICY_CANNOT_PLAY_BY_CALL:
271 ret = MM_ERROR_POLICY_BLOCKED_BY_CALL;
273 case ERR_ASM_POLICY_CANNOT_PLAY_BY_ALARM:
274 ret = MM_ERROR_POLICY_BLOCKED_BY_ALARM;
277 ret = MM_ERROR_POLICY_BLOCKED;
281 _mmcam_dbg_err("Set ASM_SUB_EVENT_EXCLUSIVE failed: 0x%x", errorcode);
283 goto SOUND_INIT_ERROR;
286 _mmcam_dbg_log("set ASM_SUB_EVENT_EXCLUSIVE done.");
288 _mmcam_dbg_warn("skip session : _MMCAMCORDER_STATE_CHANGE_BY_ASM");
292 * Init Pulseaudio thread
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;
301 /* start PA mainloop */
302 ret = pa_threaded_mainloop_start(info->pulse_mainloop);
304 _mmcam_dbg_err("pa_threaded_mainloop_start failed");
305 goto SOUND_INIT_ERROR;
308 /* lock pulseaudio thread */
309 pa_threaded_mainloop_lock(info->pulse_mainloop);
311 /* get pulseaudio api */
312 api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
314 _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
315 pa_threaded_mainloop_unlock(info->pulse_mainloop);
316 goto SOUND_INIT_ERROR;
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;
327 /* set pulseaudio context callback */
328 pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
330 if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
331 _mmcam_dbg_err("pa_context_connect error");
334 /* wait READY state of pulse context */
336 pa_context_state_t state = pa_context_get_state(info->pulse_context);
338 _mmcam_dbg_log("pa context state is now %d", state);
340 if (!PA_CONTEXT_IS_GOOD (state)) {
341 _mmcam_dbg_log("connection failed");
345 if (state == PA_CONTEXT_READY) {
346 _mmcam_dbg_log("pa context READY");
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...");
356 /* unlock pulseaudio thread */
357 pa_threaded_mainloop_unlock(info->pulse_mainloop);
359 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
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;
368 info->sample_spec.format = PA_SAMPLE_S16LE;
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);
373 if (info->sample_spec.channels > 2) {
374 _mmcam_dbg_warn("Failed to determine sample specification from file");
378 info->sample_length = (size_t)info->sfinfo.frames * pa_frame_size(&(info->sample_spec));
380 pa_threaded_mainloop_lock(info->pulse_mainloop);
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);
391 pa_threaded_mainloop_unlock(info->pulse_mainloop);
394 sf_close(info->infile);
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;
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;
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);
414 pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
416 if (state == PA_STREAM_READY) {
417 _mmcam_dbg_warn("device READY done");
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);
427 /* Wait until the stream is ready */
428 pa_threaded_mainloop_wait(info->pulse_mainloop);
431 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
433 /* backup current route */
434 info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
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;
442 _mmcam_dbg_log("current out [%x]", device_out);
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;
450 info->active_out_backup = device_out;
453 info->volume_type = PA_TIZEN_VOLUME_TYPE_FIXED;
454 info->volume_level = 0;
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");
461 _mmcam_dbg_warn("sound handle closed successfully");
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.");
470 goto SOUND_INIT_ERROR;
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");
477 _mmcam_dbg_warn("sound handle closed successfully");
480 goto SOUND_INIT_ERROR;
483 #endif /* _MMCAMCORDER_PREOPEN_PCM */
485 info->state = _MMCAMCORDER_SOUND_STATE_INIT;
487 _mmcam_dbg_log("init DONE");
489 pthread_mutex_unlock(&(info->open_mutex));
495 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
497 * Release allocated resources
499 if (info->filename) {
500 free(info->filename);
501 info->filename = NULL;
503 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
505 /* remove pulse mainloop */
506 if (info->pulse_mainloop) {
507 pa_threaded_mainloop_lock(info->pulse_mainloop);
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);
516 /* Remove sample (ASYNC) */
517 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
519 /* Wait for async operation */
520 pa_threaded_mainloop_wait(info->pulse_mainloop);
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;
529 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
531 /* Make sure we don't get any further callbacks */
532 pa_context_set_state_callback(info->pulse_context, NULL, NULL);
534 pa_context_disconnect(info->pulse_context);
535 pa_context_unref(info->pulse_context);
536 info->pulse_context = NULL;
539 pa_threaded_mainloop_unlock(info->pulse_mainloop);
541 pa_threaded_mainloop_stop(info->pulse_mainloop);
542 pa_threaded_mainloop_free(info->pulse_mainloop);
543 info->pulse_mainloop = NULL;
546 /* remove mutex and cond */
547 pthread_mutex_destroy(&(info->play_mutex));
548 pthread_cond_destroy(&(info->play_cond));
550 pthread_mutex_unlock(&(info->open_mutex));
556 gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
558 int sound_enable = TRUE;
559 int gain_type = VOLUME_GAIN_SHUTTER1;
561 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
562 SOUND_INFO *info = NULL;
563 pa_operation *pulse_op = NULL;
565 mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
567 /* check sound play enable */
568 mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
569 "capture-sound-enable", &sound_enable,
571 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
573 _mmcam_dbg_warn("capture sound disabled");
577 info = &(hcamcorder->snd_info);
579 pthread_mutex_lock(&(info->open_mutex));
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));
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;
593 _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
596 pa_threaded_mainloop_lock(info->pulse_mainloop);
598 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
603 __pulseaudio_play_sample_cb,
606 _mmcam_dbg_log("wait for signal");
607 pa_threaded_mainloop_wait(info->pulse_mainloop);
608 _mmcam_dbg_log("received signal");
610 pa_threaded_mainloop_unlock(info->pulse_mainloop);
612 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
621 pa_operation_unref(pulse_op);
625 pthread_mutex_unlock(&(info->open_mutex));
627 _mmcam_dbg_log("Done");
633 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
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;
641 mmf_return_val_if_fail(hcamcorder, FALSE);
643 info = &(hcamcorder->snd_info);
645 _mmcam_dbg_err("START");
646 /*Add the delay because we don't know when shutter sound was complete */
648 pthread_mutex_lock(&(info->open_mutex));
650 if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
651 _mmcam_dbg_warn("not initialized");
652 pthread_mutex_unlock(&(info->open_mutex));
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);
663 _mmcam_dbg_log("sound handle closed successfully");
667 _mmcam_dbg_warn("sound handle is NULL");
669 #endif /* _MMCAMCORDER_PREOPEN_PCM */
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);
679 _mmcam_dbg_log("current out [%x]", device_out);
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);
689 pa_threaded_mainloop_lock(info->pulse_mainloop);
691 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
695 _mmcam_dbg_log("remove sample");
697 /* Remove sample (ASYNC) */
698 pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info));
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;
708 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
711 * Release pulseaudio thread
713 _mmcam_dbg_log("release pulseaudio thread");
715 pa_context_disconnect(info->pulse_context);
717 /* Make sure we don't get any further callbacks */
718 pa_context_set_state_callback(info->pulse_context, NULL, NULL);
720 pa_context_unref(info->pulse_context);
721 info->pulse_context = NULL;
723 pa_threaded_mainloop_unlock(info->pulse_mainloop);
725 pa_threaded_mainloop_stop(info->pulse_mainloop);
726 pa_threaded_mainloop_free(info->pulse_mainloop);
727 info->pulse_mainloop = NULL;
729 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
730 if (info->filename) {
731 free(info->filename);
732 info->filename = NULL;
734 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
736 info->state = _MMCAMCORDER_SOUND_STATE_NONE;
737 info->active_out_backup = DEFAULT_ACTIVE_DEVICE;
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));
744 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM &&
745 hcamcorder->asm_register) {
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");
753 _mmcam_dbg_err("ASM_set_subevent ASM_SUB_EVENT_SHARE failed 0x%x", errorcode);
756 _mmcam_dbg_err("ASM_set_subevent ASM_SUB_EVENT_NONE failed 0x%x", errorcode);
759 _mmcam_dbg_warn("skip session : _MMCAMCORDER_STATE_CHANGE_BY_ASM");
762 pthread_mutex_unlock(&(info->open_mutex));
764 _mmcam_dbg_err("DONE");
770 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
772 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
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;
780 mmf_return_if_fail(filepath && hcamcorder);
782 _mmcam_dbg_log("START : %s", filepath);
784 _mmcamcorder_sound_solo_play_wait(handle);
786 ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
788 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
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;
798 gain_type = VOLUME_GAIN_SHUTTER1;
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;
806 _mmcam_dbg_log("gain type 0x%x", gain_type);
808 ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
809 "capture-sound-enable", &sound_enable,
811 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
814 /* send capture sound completed message */
815 pthread_mutex_unlock(&(hcamcorder->sound_lock));
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);
826 _mmcam_dbg_warn("skip shutter sound");
829 _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
831 if (ret != MM_ERROR_NONE) {
832 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
835 /* increase capture sound count */
836 hcamcorder->capture_sound_count++;
839 /* wait for sound completed signal */
840 if (sync_play && sound_played) {
841 struct timespec timeout;
844 gettimeofday( &tv, NULL );
845 timeout.tv_sec = tv.tv_sec + 2;
846 timeout.tv_nsec = tv.tv_usec * 1000;
848 _mmcam_dbg_log("Wait for signal");
850 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
851 _mmcam_dbg_log("signal received.");
853 _mmcam_dbg_warn("capture sound play timeout.");
854 if (sound_handle > 0) {
855 mm_sound_stop_sound(sound_handle);
861 pthread_mutex_unlock(&(hcamcorder->sound_lock));
863 _mmcam_dbg_log("DONE");
868 static void __solo_sound_callback(void *data)
870 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
872 mmf_return_if_fail(hcamcorder);
874 _mmcam_dbg_log("START");
876 /* decrease capture sound count */
877 pthread_mutex_lock(&(hcamcorder->sound_lock));
878 if (hcamcorder->capture_sound_count > 0) {
879 hcamcorder->capture_sound_count--;
881 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
882 hcamcorder->capture_sound_count = 0;
884 pthread_mutex_unlock(&(hcamcorder->sound_lock));
886 _mmcam_dbg_log("Signal SEND");
887 pthread_cond_broadcast(&(hcamcorder->sound_cond));
889 _mmcam_dbg_log("DONE");
895 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
897 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
899 mmf_return_if_fail(hcamcorder);
901 _mmcam_dbg_log("START");
903 /* check playing sound count */
904 pthread_mutex_lock(&(hcamcorder->sound_lock));
905 if (hcamcorder->capture_sound_count > 0) {
906 struct timespec timeout;
909 gettimeofday( &tv, NULL );
910 timeout.tv_sec = tv.tv_sec + 2;
911 timeout.tv_nsec = tv.tv_usec * 1000;
913 _mmcam_dbg_log("Wait for signal");
915 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
916 _mmcam_dbg_log("signal received.");
918 _mmcam_dbg_warn("capture sound play timeout.");
921 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
923 pthread_mutex_unlock(&(hcamcorder->sound_lock));
925 _mmcam_dbg_log("DONE");