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 "mm_camcorder_internal.h"
28 #include "mm_camcorder_sound.h"
30 /*---------------------------------------------------------------------------------------
31 | GLOBAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
34 /*---------------------------------------------------------------------------------------
35 | LOCAL VARIABLE DEFINITIONS for internal |
36 ---------------------------------------------------------------------------------------*/
37 #define SAMPLE_SOUND_RATE 44100
38 #define DEFAULT_ACTIVE_DEVICE 0xffffffff
40 /*---------------------------------------------------------------------------------------
41 | LOCAL FUNCTION PROTOTYPES: |
42 ---------------------------------------------------------------------------------------*/
43 static void __solo_sound_callback(void *data);
45 static void __pulseaudio_play_sample_cb(pa_context *pulse_context, uint32_t stream_index, void *user_data)
47 SOUND_INFO *info = NULL;
49 mmf_return_if_fail(user_data);
51 info = (SOUND_INFO *)user_data;
53 _mmcam_dbg_log("START - idx : %d", stream_index);
55 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
57 _mmcam_dbg_log("DONE");
62 static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
65 SOUND_INFO *info = NULL;
67 mmf_return_if_fail(user_data);
69 info = (SOUND_INFO *)user_data;
71 state = pa_context_get_state(pulse_context);
73 case PA_CONTEXT_READY:
74 _mmcam_dbg_log("pulseaudio context READY");
75 if (info->pulse_context == pulse_context) {
77 _mmcam_dbg_log("pulseaudio send signal");
78 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
81 case PA_CONTEXT_TERMINATED:
82 if (info->pulse_context == pulse_context) {
84 _mmcam_dbg_log("Context terminated : pulseaudio send signal");
85 pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
88 case PA_CONTEXT_UNCONNECTED:
89 case PA_CONTEXT_CONNECTING:
90 case PA_CONTEXT_AUTHORIZING:
91 case PA_CONTEXT_SETTING_NAME:
92 case PA_CONTEXT_FAILED:
94 _mmcam_dbg_log("pulseaudio context %p, state %d",
95 pulse_context, state);
102 gboolean _mmcamcorder_sound_init(MMHandleType handle)
105 int sound_enable = TRUE;
106 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
107 SOUND_INFO *info = NULL;
108 pa_mainloop_api *api = NULL;
109 int error = PA_ERR_INTERNAL;
111 mmf_return_val_if_fail(hcamcorder, FALSE);
113 /* check sound play enable */
114 ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
115 "capture-sound-enable", &sound_enable,
117 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
119 _mmcam_dbg_warn("capture sound disabled");
123 info = &(hcamcorder->snd_info);
125 pthread_mutex_lock(&(info->open_mutex));
127 if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
128 _mmcam_dbg_warn("already initialized [%d]", info->state);
129 pthread_mutex_unlock(&(info->open_mutex));
133 pthread_mutex_init(&(info->play_mutex), NULL);
134 pthread_cond_init(&(info->play_cond), NULL);
137 * Init Pulseaudio thread
139 /* create pulseaudio mainloop */
140 info->pulse_mainloop = pa_threaded_mainloop_new();
141 if (info->pulse_mainloop == NULL) {
142 _mmcam_dbg_err("pa_threaded_mainloop_new failed");
143 goto SOUND_INIT_ERROR;
146 /* start PA mainloop */
147 ret = pa_threaded_mainloop_start(info->pulse_mainloop);
149 _mmcam_dbg_err("pa_threaded_mainloop_start failed");
150 goto SOUND_INIT_ERROR;
153 /* lock pulseaudio thread */
154 pa_threaded_mainloop_lock(info->pulse_mainloop);
156 /* get pulseaudio api */
157 api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
159 _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
160 pa_threaded_mainloop_unlock(info->pulse_mainloop);
161 goto SOUND_INIT_ERROR;
164 /* create pulseaudio context */
165 info->pulse_context = pa_context_new(api, NULL);
166 if (info->pulse_context == NULL) {
167 _mmcam_dbg_err("pa_context_new failed");
168 pa_threaded_mainloop_unlock(info->pulse_mainloop);
169 goto SOUND_INIT_ERROR;
172 /* set pulseaudio context callback */
173 pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
175 if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
176 _mmcam_dbg_err("pa_context_connect error");
179 /* wait READY state of pulse context */
181 pa_context_state_t state = pa_context_get_state(info->pulse_context);
183 _mmcam_dbg_log("pa context state is now %d", state);
185 if (!PA_CONTEXT_IS_GOOD (state)) {
186 _mmcam_dbg_log("connection failed");
190 if (state == PA_CONTEXT_READY) {
191 _mmcam_dbg_log("pa context READY");
195 /* Wait until the context is ready */
196 _mmcam_dbg_log("waiting..................");
197 pa_threaded_mainloop_wait(info->pulse_mainloop);
198 _mmcam_dbg_log("waiting DONE. check again...");
201 /* unlock pulseaudio thread */
202 pa_threaded_mainloop_unlock(info->pulse_mainloop);
204 if (info->sample_stream) {
205 pa_stream_connect_playback(info->sample_stream, NULL, NULL, 0, NULL, NULL);
208 pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
210 if (state == PA_STREAM_READY) {
211 _mmcam_dbg_warn("device READY done");
215 if (!PA_STREAM_IS_GOOD(state)) {
216 error = pa_context_errno(info->pulse_context);
217 _mmcam_dbg_err("pa context state is not good, %d", error);
221 /* Wait until the stream is ready */
222 pa_threaded_mainloop_wait(info->pulse_mainloop);
226 //info->volume_type = PA_TIZEN_AUDIO_VOLUME_TYPE_FIXED;
227 info->volume_level = 0;
229 info->state = _MMCAMCORDER_SOUND_STATE_INIT;
231 _mmcam_dbg_log("init DONE");
233 pthread_mutex_unlock(&(info->open_mutex));
238 /* remove pulse mainloop */
239 if (info->pulse_mainloop) {
240 pa_threaded_mainloop_lock(info->pulse_mainloop);
242 /* remove pulse context */
243 if (info->pulse_context) {
244 /* release sample stream */
245 if (info->sample_stream) {
246 pa_stream_disconnect(info->sample_stream);
247 pa_stream_unref(info->sample_stream);
248 info->sample_stream = NULL;
251 /* Make sure we don't get any further callbacks */
252 pa_context_set_state_callback(info->pulse_context, NULL, NULL);
254 pa_context_disconnect(info->pulse_context);
255 pa_context_unref(info->pulse_context);
256 info->pulse_context = NULL;
259 pa_threaded_mainloop_unlock(info->pulse_mainloop);
261 pa_threaded_mainloop_stop(info->pulse_mainloop);
262 pa_threaded_mainloop_free(info->pulse_mainloop);
263 info->pulse_mainloop = NULL;
266 /* remove mutex and cond */
267 pthread_mutex_destroy(&(info->play_mutex));
268 pthread_cond_destroy(&(info->play_cond));
270 pthread_mutex_unlock(&(info->open_mutex));
276 gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
278 int sound_enable = TRUE;
280 int gain_type = VOLUME_GAIN_SHUTTER1;
283 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
284 SOUND_INFO *info = NULL;
286 pa_operation *pulse_op = NULL;
289 mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
291 /* check sound play enable */
292 mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
293 "capture-sound-enable", &sound_enable,
295 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
297 _mmcam_dbg_warn("capture sound disabled");
301 info = &(hcamcorder->snd_info);
303 pthread_mutex_lock(&(info->open_mutex));
305 if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
306 _mmcam_dbg_log("not initialized state:[%d]", info->state);
307 pthread_mutex_unlock(&(info->open_mutex));
312 if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_CAPTURE)) {
313 gain_type = VOLUME_GAIN_SHUTTER2;
314 } else if (!strcmp(sample_name, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP)) {
315 gain_type = VOLUME_GAIN_CAMCORDING;
319 _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
322 pa_threaded_mainloop_lock(info->pulse_mainloop);
324 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
329 __pulseaudio_play_sample_cb,
332 _mmcam_dbg_log("wait for signal");
333 pa_threaded_mainloop_wait(info->pulse_mainloop);
334 _mmcam_dbg_log("received signal");
336 pa_threaded_mainloop_unlock(info->pulse_mainloop);
339 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
351 pa_operation_unref(pulse_op);
356 pthread_mutex_unlock(&(info->open_mutex));
358 _mmcam_dbg_log("Done");
364 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
366 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
367 SOUND_INFO *info = NULL;
369 mmf_return_val_if_fail(hcamcorder, FALSE);
371 info = &(hcamcorder->snd_info);
373 _mmcam_dbg_err("START");
375 pthread_mutex_lock(&(info->open_mutex));
377 if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
378 _mmcam_dbg_warn("not initialized");
379 pthread_mutex_unlock(&(info->open_mutex));
383 pa_threaded_mainloop_lock(info->pulse_mainloop);
385 if (info->sample_stream) {
386 pa_stream_disconnect(info->sample_stream);
387 pa_stream_unref(info->sample_stream);
388 info->sample_stream = NULL;
392 * Release pulseaudio thread
394 _mmcam_dbg_log("release pulseaudio thread");
396 pa_context_disconnect(info->pulse_context);
398 /* Make sure we don't get any further callbacks */
399 pa_context_set_state_callback(info->pulse_context, NULL, NULL);
401 pa_context_unref(info->pulse_context);
402 info->pulse_context = NULL;
404 pa_threaded_mainloop_unlock(info->pulse_mainloop);
406 pa_threaded_mainloop_stop(info->pulse_mainloop);
407 pa_threaded_mainloop_free(info->pulse_mainloop);
408 info->pulse_mainloop = NULL;
410 info->state = _MMCAMCORDER_SOUND_STATE_NONE;
412 /* release mutex and cond */
413 _mmcam_dbg_log("release play_mutex/cond");
414 pthread_mutex_destroy(&(info->play_mutex));
415 pthread_cond_destroy(&(info->play_cond));
417 pthread_mutex_unlock(&(info->open_mutex));
419 _mmcam_dbg_err("DONE");
425 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
427 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
429 int sound_handle = 0;
430 int ret = MM_ERROR_NONE;
431 int sound_enable = TRUE;
432 int sound_played = FALSE;
433 int gain_type = VOLUME_GAIN_SHUTTER1;
435 mmf_return_if_fail(filepath && hcamcorder);
437 _mmcam_dbg_log("START : %s", filepath);
439 _mmcamcorder_sound_solo_play_wait(handle);
441 ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
443 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
447 /* check filename to set gain_type */
448 if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND) ||
449 !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
450 if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND)) {
451 gain_type = VOLUME_GAIN_CAMCORDING;
453 gain_type = VOLUME_GAIN_SHUTTER1;
455 } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) {
456 gain_type = VOLUME_GAIN_SHUTTER2;
457 } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) {
458 gain_type = VOLUME_GAIN_CAMCORDING;
461 _mmcam_dbg_log("gain type 0x%x", gain_type);
463 ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
464 "capture-sound-enable", &sound_enable,
466 _mmcam_dbg_log("Capture sound enable %d", sound_enable);
469 /* send capture sound completed message */
470 pthread_mutex_unlock(&(hcamcorder->sound_lock));
475 if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON ||
476 hcamcorder->sub_context->info_image->sound_status) {
477 ret = mm_sound_play_sound(filepath, VOLUME_TYPE_FIXED | gain_type,
478 (mm_sound_stop_callback_func)__solo_sound_callback, (void*)hcamcorder, &sound_handle);
481 _mmcam_dbg_warn("skip shutter sound");
484 _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
486 if (ret != MM_ERROR_NONE) {
487 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
490 /* increase capture sound count */
491 hcamcorder->capture_sound_count++;
494 /* wait for sound completed signal */
495 if (sync_play && sound_played) {
496 struct timespec timeout;
499 gettimeofday( &tv, NULL );
500 timeout.tv_sec = tv.tv_sec + 2;
501 timeout.tv_nsec = tv.tv_usec * 1000;
503 _mmcam_dbg_log("Wait for signal");
505 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
506 _mmcam_dbg_log("signal received.");
508 _mmcam_dbg_warn("capture sound play timeout.");
509 if (sound_handle > 0) {
510 mm_sound_stop_sound(sound_handle);
516 pthread_mutex_unlock(&(hcamcorder->sound_lock));
518 _mmcam_dbg_log("DONE");
523 static void __solo_sound_callback(void *data)
525 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
527 mmf_return_if_fail(hcamcorder);
529 _mmcam_dbg_log("START");
531 /* decrease capture sound count */
532 pthread_mutex_lock(&(hcamcorder->sound_lock));
533 if (hcamcorder->capture_sound_count > 0) {
534 hcamcorder->capture_sound_count--;
536 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
537 hcamcorder->capture_sound_count = 0;
539 pthread_mutex_unlock(&(hcamcorder->sound_lock));
541 _mmcam_dbg_log("Signal SEND");
542 pthread_cond_broadcast(&(hcamcorder->sound_cond));
544 _mmcam_dbg_log("DONE");
550 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
552 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
554 mmf_return_if_fail(hcamcorder);
556 _mmcam_dbg_log("START");
558 /* check playing sound count */
559 pthread_mutex_lock(&(hcamcorder->sound_lock));
560 if (hcamcorder->capture_sound_count > 0) {
561 struct timespec timeout;
564 gettimeofday( &tv, NULL );
565 timeout.tv_sec = tv.tv_sec + 2;
566 timeout.tv_nsec = tv.tv_usec * 1000;
568 _mmcam_dbg_log("Wait for signal");
570 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
571 _mmcam_dbg_log("signal received.");
573 _mmcam_dbg_warn("capture sound play timeout.");
576 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
578 pthread_mutex_unlock(&(hcamcorder->sound_lock));
580 _mmcam_dbg_log("DONE");