[Release version 0.10.27] Remove unused code and dependency
[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 "mm_camcorder_internal.h"
28 #include "mm_camcorder_sound.h"
29
30 /*---------------------------------------------------------------------------------------
31 |    GLOBAL VARIABLE DEFINITIONS for internal                                           |
32 ---------------------------------------------------------------------------------------*/
33
34 /*---------------------------------------------------------------------------------------
35 |    LOCAL VARIABLE DEFINITIONS for internal                                            |
36 ---------------------------------------------------------------------------------------*/
37 #define SAMPLE_SOUND_RATE       44100
38 #define DEFAULT_ACTIVE_DEVICE   0xffffffff
39
40 /*---------------------------------------------------------------------------------------
41 |    LOCAL FUNCTION PROTOTYPES:                                                         |
42 ---------------------------------------------------------------------------------------*/
43 static void __solo_sound_callback(void *data);
44
45 static void __pulseaudio_play_sample_cb(pa_context *pulse_context, uint32_t stream_index, void *user_data)
46 {
47         SOUND_INFO *info = NULL;
48
49         mmf_return_if_fail(user_data);
50
51         info = (SOUND_INFO *)user_data;
52
53         _mmcam_dbg_log("START - idx : %d", stream_index);
54
55         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
56
57         _mmcam_dbg_log("DONE");
58
59         return;
60 }
61
62 static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data)
63 {
64         int state = 0;
65         SOUND_INFO *info = NULL;
66
67         mmf_return_if_fail(user_data);
68
69         info = (SOUND_INFO *)user_data;
70
71         state = pa_context_get_state(pulse_context);
72         switch (state) {
73         case PA_CONTEXT_READY:
74                 _mmcam_dbg_log("pulseaudio context READY");
75                 if (info->pulse_context == pulse_context) {
76                         /* Signal */
77                         _mmcam_dbg_log("pulseaudio send signal");
78                         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
79                 }
80                 break;
81         case PA_CONTEXT_TERMINATED:
82                 if (info->pulse_context == pulse_context) {
83                         /* Signal */
84                         _mmcam_dbg_log("Context terminated : pulseaudio send signal");
85                         pa_threaded_mainloop_signal(info->pulse_mainloop, 0);
86                 }
87                 break;
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:
93         default:
94                 _mmcam_dbg_log("pulseaudio context %p, state %d",
95                                pulse_context, state);
96                 break;
97         }
98
99         return;
100 }
101
102 gboolean _mmcamcorder_sound_init(MMHandleType handle)
103 {
104         int ret = 0;
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;
110
111         mmf_return_val_if_fail(hcamcorder, FALSE);
112
113         /* check sound play enable */
114         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
115                                           "capture-sound-enable", &sound_enable,
116                                           NULL);
117         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
118         if (!sound_enable) {
119                 _mmcam_dbg_warn("capture sound disabled");
120                 return FALSE;
121         }
122
123         info = &(hcamcorder->snd_info);
124
125         pthread_mutex_lock(&(info->open_mutex));
126
127         if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) {
128                 _mmcam_dbg_warn("already initialized [%d]", info->state);
129                 pthread_mutex_unlock(&(info->open_mutex));
130                 return TRUE;
131         }
132
133         pthread_mutex_init(&(info->play_mutex), NULL);
134         pthread_cond_init(&(info->play_cond), NULL);
135
136         /**
137          * Init Pulseaudio thread
138          */
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;
144         }
145
146         /* start PA mainloop */
147         ret = pa_threaded_mainloop_start(info->pulse_mainloop);
148         if (ret < 0) {
149                 _mmcam_dbg_err("pa_threaded_mainloop_start failed");
150                 goto SOUND_INIT_ERROR;
151         }
152
153         /* lock pulseaudio thread */
154         pa_threaded_mainloop_lock(info->pulse_mainloop);
155
156         /* get pulseaudio api */
157         api = pa_threaded_mainloop_get_api(info->pulse_mainloop);
158         if (api == NULL) {
159                 _mmcam_dbg_err("pa_threaded_mainloop_get_api failed");
160                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
161                 goto SOUND_INIT_ERROR;
162         }
163
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;
170         }
171
172         /* set pulseaudio context callback */
173         pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info);
174
175         if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
176                 _mmcam_dbg_err("pa_context_connect error");
177         }
178
179         /* wait READY state of pulse context */
180         while (TRUE) {
181                 pa_context_state_t state = pa_context_get_state(info->pulse_context);
182
183                 _mmcam_dbg_log("pa context state is now %d", state);
184
185                 if (!PA_CONTEXT_IS_GOOD (state)) {
186                         _mmcam_dbg_log("connection failed");
187                         break;
188                 }
189
190                 if (state == PA_CONTEXT_READY) {
191                         _mmcam_dbg_log("pa context READY");
192                         break;
193                 }
194
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...");
199         }
200
201         /* unlock pulseaudio thread */
202         pa_threaded_mainloop_unlock(info->pulse_mainloop);
203
204         if (info->sample_stream) {
205                 pa_stream_connect_playback(info->sample_stream, NULL, NULL, 0, NULL, NULL);
206
207                 for (;;) {
208                         pa_stream_state_t state = pa_stream_get_state(info->sample_stream);
209
210                         if (state == PA_STREAM_READY) {
211                                 _mmcam_dbg_warn("device READY done");
212                                 break;
213                         }
214
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);
218                                 break;
219                         }
220
221                         /* Wait until the stream is ready */
222                         pa_threaded_mainloop_wait(info->pulse_mainloop);
223                 }
224         }
225
226         //info->volume_type = PA_TIZEN_AUDIO_VOLUME_TYPE_FIXED;
227         info->volume_level = 0;
228
229         info->state = _MMCAMCORDER_SOUND_STATE_INIT;
230
231         _mmcam_dbg_log("init DONE");
232
233         pthread_mutex_unlock(&(info->open_mutex));
234
235         return TRUE;
236
237 SOUND_INIT_ERROR:
238         /* remove pulse mainloop */
239         if (info->pulse_mainloop) {
240                 pa_threaded_mainloop_lock(info->pulse_mainloop);
241
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;
249                         }
250
251                         /* Make sure we don't get any further callbacks */
252                         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
253
254                         pa_context_disconnect(info->pulse_context);
255                         pa_context_unref(info->pulse_context);
256                         info->pulse_context = NULL;
257                 }
258
259                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
260
261                 pa_threaded_mainloop_stop(info->pulse_mainloop);
262                 pa_threaded_mainloop_free(info->pulse_mainloop);
263                 info->pulse_mainloop = NULL;
264         }
265
266         /* remove mutex and cond */
267         pthread_mutex_destroy(&(info->play_mutex));
268         pthread_cond_destroy(&(info->play_cond));
269
270         pthread_mutex_unlock(&(info->open_mutex));
271
272         return FALSE;
273 }
274
275
276 gboolean _mmcamcorder_sound_play(MMHandleType handle, const char *sample_name, gboolean sync_play)
277 {
278         int sound_enable = TRUE;
279 /*
280         int gain_type = VOLUME_GAIN_SHUTTER1;
281 */
282
283         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
284         SOUND_INFO *info = NULL;
285 /*
286         pa_operation *pulse_op = NULL;
287 */
288
289         mmf_return_val_if_fail(hcamcorder && sample_name, FALSE);
290
291         /* check sound play enable */
292         mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
293                                     "capture-sound-enable", &sound_enable,
294                                     NULL);
295         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
296         if (!sound_enable) {
297                 _mmcam_dbg_warn("capture sound disabled");
298                 return FALSE;
299         }
300
301         info = &(hcamcorder->snd_info);
302
303         pthread_mutex_lock(&(info->open_mutex));
304
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));
308                 return FALSE;
309         }
310
311 /*
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;
316         }
317 */
318
319         _mmcam_dbg_log("Play start - sample name [%s]", sample_name);
320
321         if (sync_play) {
322                 pa_threaded_mainloop_lock(info->pulse_mainloop);
323 /*
324                 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
325                                                   sample_name,
326                                                   info->volume_type,
327                                                   gain_type,
328                                                   info->volume_level,
329                                                   __pulseaudio_play_sample_cb,
330                                                   info);
331 */
332                 _mmcam_dbg_log("wait for signal");
333                 pa_threaded_mainloop_wait(info->pulse_mainloop);
334                 _mmcam_dbg_log("received signal");
335
336                 pa_threaded_mainloop_unlock(info->pulse_mainloop);
337         } else {
338 /*
339                 pulse_op = pa_ext_policy_play_sample(info->pulse_context,
340                                                   sample_name,
341                                                   info->volume_type,
342                                                   gain_type,
343                                                   info->volume_level,
344                                                   NULL,
345                                                   NULL);
346 */
347         }
348
349 /*
350         if (pulse_op) {
351                 pa_operation_unref(pulse_op);
352                 pulse_op = NULL;
353         }
354 */
355
356         pthread_mutex_unlock(&(info->open_mutex));
357
358         _mmcam_dbg_log("Done");
359
360         return TRUE;
361 }
362
363
364 gboolean _mmcamcorder_sound_finalize(MMHandleType handle)
365 {
366         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
367         SOUND_INFO *info = NULL;
368
369         mmf_return_val_if_fail(hcamcorder, FALSE);
370
371         info = &(hcamcorder->snd_info);
372
373         _mmcam_dbg_err("START");
374
375         pthread_mutex_lock(&(info->open_mutex));
376
377         if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) {
378                 _mmcam_dbg_warn("not initialized");
379                 pthread_mutex_unlock(&(info->open_mutex));
380                 return TRUE;
381         }
382
383         pa_threaded_mainloop_lock(info->pulse_mainloop);
384
385         if (info->sample_stream) {
386                 pa_stream_disconnect(info->sample_stream);
387                 pa_stream_unref(info->sample_stream);
388                 info->sample_stream = NULL;
389         }
390
391         /**
392          * Release pulseaudio thread
393          */
394         _mmcam_dbg_log("release pulseaudio thread");
395
396         pa_context_disconnect(info->pulse_context);
397
398         /* Make sure we don't get any further callbacks */
399         pa_context_set_state_callback(info->pulse_context, NULL, NULL);
400
401         pa_context_unref(info->pulse_context);
402         info->pulse_context = NULL;
403
404         pa_threaded_mainloop_unlock(info->pulse_mainloop);
405
406         pa_threaded_mainloop_stop(info->pulse_mainloop);
407         pa_threaded_mainloop_free(info->pulse_mainloop);
408         info->pulse_mainloop = NULL;
409
410         info->state = _MMCAMCORDER_SOUND_STATE_NONE;
411
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));
416
417         pthread_mutex_unlock(&(info->open_mutex));
418
419         _mmcam_dbg_err("DONE");
420
421         return TRUE;
422 }
423
424
425 void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync_play)
426 {
427         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
428
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;
434
435         mmf_return_if_fail(filepath && hcamcorder);
436
437         _mmcam_dbg_log("START : %s", filepath);
438
439         _mmcamcorder_sound_solo_play_wait(handle);
440
441         ret = pthread_mutex_trylock(&(hcamcorder->sound_lock));
442         if (ret != 0) {
443                 _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret));
444                 return;
445         }
446
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;
452                 } else {
453                         gain_type = VOLUME_GAIN_SHUTTER1;
454                 }
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;
459         }
460
461         _mmcam_dbg_log("gain type 0x%x", gain_type);
462
463         ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
464                                           "capture-sound-enable", &sound_enable,
465                                           NULL);
466         _mmcam_dbg_log("Capture sound enable %d", sound_enable);
467
468         if (!sound_enable) {
469                 /* send capture sound completed message */
470                 pthread_mutex_unlock(&(hcamcorder->sound_lock));
471                 return;
472         }
473
474
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);
479                 sound_played = TRUE;
480         } else {
481                 _mmcam_dbg_warn("skip shutter sound");
482         }
483
484         _mmcam_dbg_log("sync_play %d, sound_played %d, ret 0x%x", sync_play, sound_played, ret);
485
486         if (ret != MM_ERROR_NONE) {
487                 _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret );
488         } else {
489                 if (sound_played) {
490                         /* increase capture sound count */
491                         hcamcorder->capture_sound_count++;
492                 }
493
494                 /* wait for sound completed signal */
495                 if (sync_play && sound_played) {
496                         struct timespec timeout;
497                         struct timeval tv;
498
499                         gettimeofday( &tv, NULL );
500                         timeout.tv_sec = tv.tv_sec + 2;
501                         timeout.tv_nsec = tv.tv_usec * 1000;
502
503                         _mmcam_dbg_log("Wait for signal");
504
505                         if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
506                                 _mmcam_dbg_log("signal received.");
507                         } else {
508                                 _mmcam_dbg_warn("capture sound play timeout.");
509                                 if (sound_handle > 0) {
510                                         mm_sound_stop_sound(sound_handle);
511                                 }
512                         }
513                 }
514         }
515
516         pthread_mutex_unlock(&(hcamcorder->sound_lock));
517
518         _mmcam_dbg_log("DONE");
519
520         return;
521 }
522
523 static void __solo_sound_callback(void *data)
524 {
525         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data);
526
527         mmf_return_if_fail(hcamcorder);
528
529         _mmcam_dbg_log("START");
530
531         /* decrease capture sound count */
532         pthread_mutex_lock(&(hcamcorder->sound_lock));
533         if (hcamcorder->capture_sound_count > 0) {
534                 hcamcorder->capture_sound_count--;
535         } else {
536                 _mmcam_dbg_warn("invalid capture_sound_count %d, reset count", hcamcorder->capture_sound_count);
537                 hcamcorder->capture_sound_count = 0;
538         }
539         pthread_mutex_unlock(&(hcamcorder->sound_lock));
540
541         _mmcam_dbg_log("Signal SEND");
542         pthread_cond_broadcast(&(hcamcorder->sound_cond));
543
544         _mmcam_dbg_log("DONE");
545
546         return;
547 }
548
549
550 void _mmcamcorder_sound_solo_play_wait(MMHandleType handle)
551 {
552         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
553
554         mmf_return_if_fail(hcamcorder);
555
556         _mmcam_dbg_log("START");
557
558         /* check playing sound count */
559         pthread_mutex_lock(&(hcamcorder->sound_lock));
560         if (hcamcorder->capture_sound_count > 0) {
561                 struct timespec timeout;
562                 struct timeval tv;
563
564                 gettimeofday( &tv, NULL );
565                 timeout.tv_sec = tv.tv_sec + 2;
566                 timeout.tv_nsec = tv.tv_usec * 1000;
567
568                 _mmcam_dbg_log("Wait for signal");
569
570                 if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) {
571                         _mmcam_dbg_log("signal received.");
572                 } else {
573                         _mmcam_dbg_warn("capture sound play timeout.");
574                 }
575         } else {
576                 _mmcam_dbg_warn("no playing sound - count %d", hcamcorder->capture_sound_count);
577         }
578         pthread_mutex_unlock(&(hcamcorder->sound_lock));
579
580         _mmcam_dbg_log("DONE");
581
582         return;
583 }