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 =======================================================================================*/
25 #include "mm_camcorder_internal.h"
26 #include "mm_camcorder_audiorec.h"
29 /*---------------------------------------------------------------------------------------
30 | GLOBAL VARIABLE DEFINITIONS for internal |
31 ---------------------------------------------------------------------------------------*/
32 #define MM_CAMCORDER_START_CHANGE_STATE _MMCamcorderStartHelperFunc((void *)hcamcorder)
33 #define MM_CAMCORDER_STOP_CHANGE_STATE _MMCamcorderStopHelperFunc((void *)hcamcorder)
34 /*---------------------------------------------------------------------------------------
35 | LOCAL VARIABLE DEFINITIONS for internal |
36 ---------------------------------------------------------------------------------------*/
37 #define RESET_PAUSE_TIME 0
38 #define _MMCAMCORDER_AUDIO_MINIMUM_SPACE (100*1024)
39 #define _MMCAMCORDER_AUDIO_MARGIN_SPACE (1*1024)
40 #define _MMCAMCORDER_RETRIAL_COUNT 10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME 20000 /* micro second */
42 #define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL 10
43 /*---------------------------------------------------------------------------------------
44 | LOCAL FUNCTION PROTOTYPES: |
45 ---------------------------------------------------------------------------------------*/
46 /* STATIC INTERNAL FUNCTION */
47 static gboolean __mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstBuffer *buffer, gpointer u_data);
48 static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data);
49 static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle);
50 static void __mmcamcorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle);
52 /*=======================================================================================
53 | FUNCTION DEFINITIONS |
54 =======================================================================================*/
56 /*---------------------------------------------------------------------------------------
57 | GLOBAL FUNCTION DEFINITIONS: |
58 ---------------------------------------------------------------------------------------*/
61 static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle)
63 int err = MM_ERROR_NONE;
64 char *aenc_name = NULL;
65 char *mux_name = NULL;
68 GstPad *srcpad = NULL;
69 GstPad *sinkpad = NULL;
70 GList *element_list = NULL;
72 _MMCamcorderAudioInfo *info = NULL;
73 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
74 _MMCamcorderSubContext *sc = NULL;
75 type_element *aenc_elem = NULL;
76 type_element *mux_elem = NULL;
78 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
79 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
81 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
82 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
83 mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
85 info = (_MMCamcorderAudioInfo *)sc->info;
89 mux_elem = _mmcamcorder_get_type_element(handle, MM_CAM_FILE_FORMAT);
90 err = _mmcamcorder_conf_get_value_element_name( mux_elem, &mux_name );
92 if (!mux_name || !strcmp( mux_name, "wavenc" ) ) /* IF MUX in not chosen then record in raw amr file */
94 //But shoud we support non-mux recording??
95 _mmcam_dbg_log("Record without muxing.");
96 info->bMuxing = FALSE;
100 _mmcam_dbg_log("Record with mux.");
101 info->bMuxing = TRUE;
104 //Create gstreamer element
106 __ta__(" camcorder_pipeline",
107 _MMCAMCORDER_PIPELINE_MAKE(sc, _MMCAMCORDER_MAIN_PIPE, "camcorder_pipeline", err);
110 __ta__(" __mmcamcorder_create_audiosrc_bin",
111 err = _mmcamcorder_create_audiosrc_bin(handle);
113 if (err != MM_ERROR_NONE) {
118 /* Muxing. can use encodebin. */
119 __ta__(" _mmcamcorder_create_encodesink_bin",
120 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder);
122 if (err != MM_ERROR_NONE ) {
126 /* without muxing. can't use encodebin. */
127 aenc_elem = _mmcamcorder_get_type_element(handle, MM_CAM_AUDIO_ENCODER);
130 _mmcam_dbg_err("Fail to get type element");
131 err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
132 goto pipeline_creation_error;
135 err = _mmcamcorder_conf_get_value_element_name(aenc_elem, &aenc_name);
137 if ((!err) || (!aenc_name))
139 _mmcam_dbg_err("Fail to get element name");
140 err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
141 goto pipeline_creation_error;
144 __ta__(" audiopipeline_audioqueue",
145 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_AQUE, "queue", NULL, element_list, err);
148 if( strcmp( aenc_name, "wavenc" ) != 0 )
150 __ta__(" audiopipeline_audioconvertor",
151 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_CONV, "audioconvert", NULL, element_list, err);
155 __ta__(" audiopipeline_audioencoder",
156 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_AENC, aenc_name, NULL, element_list, err);
159 __ta__(" audiopipeline_filesink",
160 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_SINK, "filesink", NULL, element_list, err);
163 /* audio encoder attribute setting */
164 if(strcmp(aenc_name,"ari_amrnbenc") == 0) //ari_armnbenc supports attatching amr header
166 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "write-header", TRUE);
171 //Set basic infomation
173 if (info->bMuxing) /* IF MUX is indicated create MUX */
175 gst_bin_add_many(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
176 sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
177 sc->element[_MMCAMCORDER_ENCSINK_BIN].gst,
180 srcpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
181 sinkpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
182 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
184 else /* IF MUX in not chosen then record in raw amr file */
186 if( !strcmp( aenc_name, "wavenc" ) )
188 gst_bin_add_many( GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
189 sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
190 sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst,
191 sc->element[_MMCAMCORDER_ENCSINK_AENC].gst,
192 sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,
195 if (!_MM_GST_ELEMENT_LINK_MANY( sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
196 sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst,
197 sc->element[_MMCAMCORDER_ENCSINK_AENC].gst,
198 sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,
201 err = MM_ERROR_CAMCORDER_GST_LINK;
202 goto pipeline_creation_error;
207 gst_bin_add_many( GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
208 sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
209 sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst,
210 sc->element[_MMCAMCORDER_ENCSINK_CONV].gst,
211 sc->element[_MMCAMCORDER_ENCSINK_AENC].gst,
212 sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,
215 if (!_MM_GST_ELEMENT_LINK_MANY( sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
216 sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst,
217 sc->element[_MMCAMCORDER_ENCSINK_CONV].gst,
218 sc->element[_MMCAMCORDER_ENCSINK_AENC].gst,
219 sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,
222 err = MM_ERROR_CAMCORDER_GST_LINK;
223 goto pipeline_creation_error;
229 //set data probe function
230 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
231 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_AUDIOREC,
232 __mmcamcorder_audio_dataprobe_voicerecorder, hcamcorder);
233 gst_object_unref(srcpad);
238 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst,
239 _MMCAMCORDER_HANDLER_AUDIOREC,
241 __mmcamcorder_audiorec_pad_added_cb,
246 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
247 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_AUDIOREC,
248 __mmcamcorder_audio_dataprobe_record, hcamcorder);
249 gst_object_unref(srcpad);
254 * To get the message callback from the gstreamer.
255 * This can be used to make the API calls asynchronous
256 * as per LiMO compliancy
258 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst));
259 hcamcorder->pipeline_cb_event_id = gst_bus_add_watch( bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder );
260 gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, hcamcorder);
261 gst_object_unref(bus);
263 return MM_ERROR_NONE;
265 pipeline_creation_error:
271 _mmcamcorder_create_audio_pipeline(MMHandleType handle)
273 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
274 _MMCamcorderSubContext *sc = NULL;
276 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
277 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
279 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
281 return __mmcamcorder_create_audiop_with_encodebin(handle);
286 * This function destroy audio pipeline.
288 * @param[in] handle Handle of camcorder.
291 * @see _mmcamcorder_destroy_pipeline()
295 _mmcamcorder_destroy_audio_pipeline(MMHandleType handle)
297 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
298 _MMCamcorderSubContext *sc = NULL;
299 _MMCamcorderAudioInfo* info = NULL;
300 mmf_return_if_fail(hcamcorder);
301 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
303 mmf_return_if_fail(sc);
304 mmf_return_if_fail(sc->element);
310 if(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)
312 _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL);
314 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL);
318 GstPad *reqpad = NULL;
319 //release request pad
322 The ref_count of mux is always # of streams in here, i don't know why it happens.
323 So, i unref the mux manually
325 reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
326 gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
327 gst_object_unref(reqpad);
329 if(GST_IS_ELEMENT(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst) && \
330 GST_OBJECT_REFCOUNT_VALUE(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst) > 1)
331 gst_object_unref(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst);
333 gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst);
334 // sc->element[_MMCAMCORDER_MAIN_PIPE].gst = NULL;
341 * This function operates each command on audio mode.
343 * @param c [in] Handle of camcorder context.
344 * @param command [in] command type received from Multimedia Framework.
346 * @return This function returns MM_ERROR_NONE on success, or the other values
349 * @see _mmcamcorder_set_functions()
355 void* _MMCamcorderStartHelperFunc(void *handle)
357 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
358 _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state);
363 void* _MMCamcorderStopHelperFunc(void *handle)
365 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
366 _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state);
373 _mmcamcorder_audio_command(MMHandleType handle, int command)
376 GstElement *pipeline = NULL;
377 GstElement *audioSrc = NULL;
378 int ret = MM_ERROR_NONE;
380 char *dir_name = NULL;
382 guint64 free_space = 0;
383 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
384 _MMCamcorderSubContext *sc = NULL;
385 _MMCamcorderAudioInfo *info = NULL;
386 char *err_attr_name = NULL;
388 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
389 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
391 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
392 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
393 mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
394 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
399 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
400 audioSrc = sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst;
403 case _MMCamcorder_CMD_RECORD:
404 //check status for resume case
405 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED)
408 char *temp_filename = NULL;
410 if(sc->pipeline_time) {
411 gst_pipeline_set_new_stream_time(GST_PIPELINE(pipeline), sc->pipeline_time);
413 sc->pipeline_time = RESET_PAUSE_TIME;
415 ret = mm_camcorder_get_attributes(handle, &err_attr_name,
416 MMCAM_TARGET_TIME_LIMIT, &imax_time,
417 MMCAM_FILE_FORMAT, &(info->fileformat),
418 MMCAM_TARGET_FILENAME, &temp_filename, &size,
420 if (ret != MM_ERROR_NONE) {
421 _mmcam_dbg_warn("failed to get attribute. (%s:%x)", err_attr_name, ret);
422 SAFE_FREE (err_attr_name);
423 goto _ERR_CAMCORDER_AUDIO_COMMAND;
426 info->filename = strdup(temp_filename);
429 _mmcam_dbg_err("STRDUP was failed");
430 goto _ERR_CAMCORDER_AUDIO_COMMAND;
433 _mmcam_dbg_log("Record start : set file name using attribute - %s\n ",info->filename);
435 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
437 sc->ferror_send = FALSE;
438 sc->ferror_count = 0;
439 sc->bget_eos = FALSE;
443 if (imax_time <= 0) {
444 info->max_time = 0; /* do not check */
446 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
450 //set data probe function
451 gst_pad_add_buffer_probe(gst_element_get_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src"),
452 G_CALLBACK(__mmcamcorder_audio_dataprobe_voicerecorder),
455 /* TODO : check free space before recording start, need to more discussion */
457 dir_name = g_path_get_dirname(info->filename);
458 err = _mmcamcorder_get_freespace(dir_name, &free_space);
459 if((err == -1) || free_space <= (_MMCAMCORDER_AUDIO_MINIMUM_SPACE+(5*1024)))
461 _mmcam_dbg_err("No more space for recording - %s : [%" G_GUINT64_FORMAT "]\n ", dir_name, free_space);
467 return MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
477 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
479 goto _ERR_CAMCORDER_AUDIO_COMMAND;
483 case _MMCamcorder_CMD_PAUSE:
485 GstClock *clock = NULL;
488 if (info->b_commiting)
490 _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
491 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
494 for(count=0; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++)
496 if(info->filesize > 0)
500 else if(count == _MMCAMCORDER_RETRIAL_COUNT)
502 _mmcam_dbg_err("Pause fail, we are waiting for 100 milisecond, but still file size is %" G_GUINT64_FORMAT "",
504 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
508 _mmcam_dbg_warn("Pause is Waiting for enough audio frame, retrial count[%d], file size is %" G_GUINT64_FORMAT "",
509 count, info->filesize);
511 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
514 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
516 goto _ERR_CAMCORDER_AUDIO_COMMAND;
518 //fixed me. consider delay.
519 clock = gst_pipeline_get_clock(GST_PIPELINE(pipeline));
520 sc->pipeline_time = gst_clock_get_time(clock) - gst_element_get_base_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst));
524 case _MMCamcorder_CMD_CANCEL:
525 if (info->b_commiting)
527 _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
528 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
531 // ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL);
532 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
534 goto _ERR_CAMCORDER_AUDIO_COMMAND;
539 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
543 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
546 _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL);
548 sc->pipeline_time = 0;
550 sc->isMaxsizePausing = FALSE;
551 sc->isMaxtimePausing = FALSE;
555 _mmcam_dbg_log("file delete(%s)", info->filename);
556 unlink(info->filename);
557 g_free(info->filename);
558 info->filename = NULL;
562 case _MMCamcorder_CMD_COMMIT:
565 g_print("\n\n _MMCamcorder_CMD_COMMIT\n\n");
567 if (info->b_commiting)
569 _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
570 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
574 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
575 info->b_commiting = TRUE;
578 for(count=0; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++)
580 if(info->filesize > 0)
584 else if(count == _MMCAMCORDER_RETRIAL_COUNT)
586 _mmcam_dbg_err("Commit fail, we are waiting for 100 milisecond, but still file size is %" G_GUINT64_FORMAT "",
588 info->b_commiting = FALSE;
589 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
593 _mmcam_dbg_warn("Commit is Waiting for enough audio frame, retrial count[%d], file size is %" G_GUINT64_FORMAT "",
594 count, info->filesize);
596 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
600 GstPad *pad = gst_element_get_static_pad (audioSrc, "src");
601 // gst_pad_push_event (pad, gst_event_new_eos());
602 ret = gst_element_send_event(audioSrc, gst_event_new_eos());
603 gst_object_unref(pad);
605 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) == MM_CAMCORDER_STATE_PAUSED) // for pause -> commit case
607 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
609 goto _ERR_CAMCORDER_AUDIO_COMMAND;
615 //wait until finishing EOS
616 _mmcam_dbg_log("Start to wait EOS");
617 if ((ret =_mmcamcorder_get_eos_message(handle)) != MM_ERROR_NONE)
619 goto _ERR_CAMCORDER_AUDIO_COMMAND;
622 while ((!sc->get_eos)&&((retry_cnt--) > 0)) {
623 if ((gMessage = gst_bus_timed_pop (bus, timeout)) != NULL)
625 if (GST_MESSAGE_TYPE(gMessage) ==GST_MESSAGE_EOS)
627 _mmcam_dbg_log("Get a EOS message");
628 gst_message_unref(gMessage);
633 _mmcam_dbg_log("Get another message(%x). Post this message to bus again.", GST_MESSAGE_TYPE(gMessage));
634 gst_bus_post(bus, gMessage);
639 _mmcam_dbg_log("timeout of gst_bus_timed_pop()");
643 usleep(100); //To Prevent busy waiting
646 _mmcamcorder_audio_handle_eos((MMHandleType)hcamcorder);
653 case _MMCamcorder_CMD_PREVIEW_START:
654 // MM_CAMCORDER_START_CHANGE_STATE;
656 case _MMCamcorder_CMD_PREVIEW_STOP:
657 // MM_CAMCORDER_STOP_CHANGE_STATE;
662 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
666 _ERR_CAMCORDER_AUDIO_COMMAND:
672 _mmcamcorder_audio_handle_eos(MMHandleType handle)
674 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
675 _MMCamcorderSubContext *sc = NULL;
676 _MMCamcorderAudioInfo *info = NULL;
677 GstElement *pipeline = NULL;
678 _MMCamcorderMsgItem msg;
679 MMCamRecordingReport * report;
681 int err = MM_ERROR_NONE;
683 mmf_return_val_if_fail(hcamcorder, FALSE);
684 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
686 mmf_return_val_if_fail(sc, FALSE);
687 mmf_return_val_if_fail(sc->info, FALSE);
693 //changing pipeline for display
694 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
697 __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_READY",
698 err = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
701 if( err != MM_ERROR_NONE )
703 _mmcam_dbg_warn( "Failed:_MMCamcorder_CMD_COMMIT:GST_STATE_READY. err[%x]", err );
706 // __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_NULL",
707 // _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL);
711 //Send recording report to application
712 msg.id = MM_MESSAGE_CAMCORDER_CAPTURED;
714 report = (MMCamRecordingReport*) malloc(sizeof(MMCamRecordingReport)); //who free this?
718 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
722 report->recording_filename = strdup(info->filename);
723 msg.param.data= report;
725 _mmcamcroder_send_message(handle, &msg);
730 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
734 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
736 _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL);
738 sc->pipeline_time = 0;
740 sc->isMaxsizePausing = FALSE;
741 sc->isMaxtimePausing = FALSE;
743 g_free(info->filename);
744 info->filename = NULL;
746 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
748 info->b_commiting = FALSE;
755 __mmcamcorder_get_decibel(unsigned char* raw, int size, MMCamcorderAudioFormat format)
757 #define MAX_AMPLITUDE_MEAN_16BIT 23170.115738161934
758 #define MAX_AMPLITUDE_MEAN_08BIT 89.803909382810
769 unsigned long long square_sum = 0;
771 if (format == MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE)
773 else //MM_CAMCORDER_AUDIO_FORMAT_PCM_U8
776 for( ; i < size ; i += (depthByte<<1) )
780 pcm8 = (char *)(raw + i);
781 square_sum += (*pcm8)*(*pcm8);
785 pcm16 = (short*)(raw + i);
786 square_sum += (*pcm16)*(*pcm16);
792 rms = sqrt( square_sum/count );
795 db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_08BIT );
797 db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_16BIT );
800 _mmcam_dbg_log("size[%d],depthByte[%d],count[%d],rms[%f],db[%f]",
801 size, depthByte, count, rms, db);
809 __mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstBuffer *buffer, gpointer u_data)
811 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
816 _MMCamcorderMsgItem msg;
817 int err = MM_ERROR_UNKNOWN;
818 char *err_name = NULL;
820 mmf_return_val_if_fail(hcamcorder, FALSE);
822 /* Set volume to audio input */
823 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
824 MMCAM_AUDIO_VOLUME, &volume,
825 MMCAM_AUDIO_FORMAT, &format,
826 MMCAM_AUDIO_CHANNEL, &channel,
830 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
831 SAFE_FREE (err_name);
835 if(volume == 0) //mute
836 memset (GST_BUFFER_DATA(buffer), 0, GST_BUFFER_SIZE(buffer));
838 /* Get current volume level of real input stream */
839 // currms = __mmcamcorder_get_RMS(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer), depth);
840 __ta__( "__mmcamcorder_get_decibel",
841 curdcb = __mmcamcorder_get_decibel(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer), format);
844 msg.id = MM_MESSAGE_CAMCORDER_CURRENT_VOLUME;
845 msg.param.rec_volume_dB = curdcb;
846 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
848 /* CALL audio stream callback */
849 if ((hcamcorder->astream_cb) && buffer && GST_BUFFER_DATA(buffer))
851 MMCamcorderAudioStreamDataType stream;
853 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE)
855 _mmcam_dbg_warn("Not ready for stream callback");
860 _mmcam_dbg_log("Call audio steramCb, data[%p], format[%d], channel[%d], length[%d], volume_dB[%f]",
861 GST_BUFFER_DATA(buffer), format, channel, GST_BUFFER_SIZE(buffer), curdcb);
864 stream.data = (void *)GST_BUFFER_DATA(buffer);
865 stream.format = format;
866 stream.channel = channel;
867 stream.length = GST_BUFFER_SIZE(buffer);
868 stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); //nano -> msecond
869 stream.volume_dB = curdcb;
871 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK( hcamcorder );
873 if(hcamcorder->astream_cb)
875 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
878 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK( hcamcorder );
886 __mmcamcorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle)
888 mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
890 _mmcam_dbg_log("ENTER(%s)", GST_PAD_NAME(pad));
891 //FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name?
892 if((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink")))
894 MMCAMCORDER_ADD_BUFFER_PROBE(pad, _MMCAMCORDER_HANDLER_AUDIOREC,
895 __mmcamcorder_audio_dataprobe_record, hcamcorder);
899 _mmcam_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));
906 static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data)
908 static int count = 0;
909 guint64 rec_pipe_time = 0;
910 guint64 free_space = 0;
911 guint64 buffer_size = 0;
912 guint64 trailer_size = 0;
913 char *filename = NULL;
915 _MMCamcorderSubContext *sc = NULL;
916 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
917 _MMCamcorderAudioInfo *info = NULL;
918 _MMCamcorderMsgItem msg;
920 mmf_return_val_if_fail(hcamcorder, FALSE);
921 mmf_return_val_if_fail(buffer, FALSE);
923 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
924 mmf_return_val_if_fail(sc && sc->info, FALSE);
927 if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
928 _mmcam_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]",
929 sc->isMaxtimePausing, sc->isMaxsizePausing);
933 buffer_size = (guint64)GST_BUFFER_SIZE(buffer);
935 if (info->filesize == 0) {
936 if (info->fileformat == MM_FILE_FORMAT_WAV) {
937 info->filesize += 44; /* wave header size */
938 } else if (info->fileformat == MM_FILE_FORMAT_AMR) {
939 info->filesize += 6; /* amr header size */
942 info->filesize += buffer_size;
946 if (sc->ferror_send) {
947 _mmcam_dbg_warn("file write error, drop frames");
951 /* get trailer size */
952 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
953 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
954 /*_mmcam_dbg_log("trailer_size %d", trailer_size);*/
956 trailer_size = 0; /* no trailer */
959 filename = info->filename;
961 /* to minimizing free space check overhead */
962 count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL;
964 gint free_space_ret = _mmcamcorder_get_freespace(filename, &free_space);
966 /*_mmcam_dbg_log("check free space for recording");*/
968 switch (free_space_ret) {
969 case -2: /* file not exist */
970 case -1: /* failed to get free space */
971 _mmcam_dbg_err("Error occured. [%d]", free_space_ret);
972 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
973 sc->ferror_send = TRUE;
974 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
975 if (free_space_ret == -2) {
976 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
978 msg.param.code = MM_ERROR_FILE_READ;
980 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
985 return FALSE; /* skip this buffer */
987 default: /* succeeded to get free space */
988 /* check free space for recording */
989 if (free_space < (guint64)(_MMCAMCORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
990 _mmcam_dbg_warn("No more space for recording!!!");
991 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]",
992 free_space, info->filesize);
995 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
997 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1000 sc->isMaxsizePausing = TRUE;
1001 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1002 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1004 return FALSE; /* skip this buffer */
1010 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) {
1011 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1015 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1017 /* check recording time limit and send recording status message */
1018 if (info->max_time > 0 && rec_pipe_time > info->max_time) {
1019 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1020 rec_pipe_time, info->max_time);
1022 if (info->bMuxing) {
1023 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1025 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1028 sc->isMaxtimePausing = TRUE;
1029 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1030 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1032 /* skip this buffer */
1036 /* send message for recording time and recorded file size */
1037 if (info->b_commiting == FALSE) {
1038 info->filesize += buffer_size;
1040 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1041 msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time;
1042 msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1043 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1047 /* skip this buffer if commit process has been started */