tizen beta release
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_audiorec.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_camcorder_internal.h"
26 #include "mm_camcorder_audiorec.h"
27 #include <math.h>
28
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);
51
52 /*=======================================================================================
53 |  FUNCTION DEFINITIONS                                                                 |
54 =======================================================================================*/
55
56 /*---------------------------------------------------------------------------------------
57 |    GLOBAL FUNCTION DEFINITIONS:                                                       |
58 ---------------------------------------------------------------------------------------*/
59
60
61 static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle)
62 {
63         int err = MM_ERROR_NONE;
64         char *aenc_name = NULL;
65         char *mux_name = NULL;
66
67         GstBus *bus = NULL;
68         GstPad *srcpad = NULL;
69         GstPad *sinkpad = NULL;
70         GList *element_list = NULL;
71
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;
77
78         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
79         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
80
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);
84
85         info = (_MMCamcorderAudioInfo *)sc->info;
86         
87         _mmcam_dbg_log("");
88
89         mux_elem = _mmcamcorder_get_type_element(handle, MM_CAM_FILE_FORMAT);
90         err = _mmcamcorder_conf_get_value_element_name( mux_elem, &mux_name );
91
92         if (!mux_name || !strcmp( mux_name, "wavenc" ) ) /* IF MUX in not chosen then record in raw amr file */
93         {
94                 //But shoud we support non-mux recording??
95                 _mmcam_dbg_log("Record without muxing.");
96                 info->bMuxing = FALSE;
97         }
98         else
99         {
100                 _mmcam_dbg_log("Record with mux.");
101                 info->bMuxing = TRUE;
102         }
103
104         //Create gstreamer element
105         //Main pipeline
106         __ta__("            camcorder_pipeline",  
107         _MMCAMCORDER_PIPELINE_MAKE(sc, _MMCAMCORDER_MAIN_PIPE, "camcorder_pipeline", err);
108         );
109
110         __ta__("        __mmcamcorder_create_audiosrc_bin",
111         err = _mmcamcorder_create_audiosrc_bin(handle);
112         );
113         if (err != MM_ERROR_NONE) {
114                 return err;
115         }
116
117         if (info->bMuxing) {
118                 /* Muxing. can use encodebin. */
119                 __ta__("        _mmcamcorder_create_encodesink_bin",
120                 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder);
121                 );
122                 if (err != MM_ERROR_NONE ) {
123                         return err;
124                 }
125         } else {
126                 /* without muxing. can't use encodebin. */
127                 aenc_elem = _mmcamcorder_get_type_element(handle, MM_CAM_AUDIO_ENCODER);
128                 if (!aenc_elem)
129                 {
130                         _mmcam_dbg_err("Fail to get type element");
131                         err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
132                         goto pipeline_creation_error;
133                 }
134
135                 err = _mmcamcorder_conf_get_value_element_name(aenc_elem, &aenc_name);
136
137                 if ((!err) || (!aenc_name))
138                 {
139                         _mmcam_dbg_err("Fail to get element name");
140                         err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
141                         goto pipeline_creation_error;
142                 }
143
144                 __ta__("        audiopipeline_audioqueue",  
145                 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_AQUE, "queue",  NULL, element_list, err);
146                 );
147
148                 if( strcmp( aenc_name, "wavenc" ) != 0 )
149                 {
150                         __ta__("        audiopipeline_audioconvertor",
151                         _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_CONV, "audioconvert",  NULL, element_list, err);
152                         );
153                 }
154
155                 __ta__("        audiopipeline_audioencoder",  
156                 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_AENC, aenc_name, NULL, element_list, err);
157                 );
158
159                 __ta__("        audiopipeline_filesink",  
160                 _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_SINK, "filesink", NULL, element_list, err);
161                 );
162
163                 /* audio encoder attribute setting */
164                 if(strcmp(aenc_name,"ari_amrnbenc") == 0) //ari_armnbenc supports attatching amr header
165                 {
166                         MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "write-header", TRUE);
167                 }
168                 
169         }
170
171         //Set basic infomation
172
173         if (info->bMuxing) /* IF MUX is indicated create MUX */
174         {
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,
178                                                                  NULL);
179
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);
183         }
184         else /* IF MUX in not chosen then record in raw amr file */
185         {
186                 if( !strcmp( aenc_name, "wavenc" ) )
187                 {
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,
193                                           NULL );
194
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,
199                                                         NULL ))
200                         {
201                                 err = MM_ERROR_CAMCORDER_GST_LINK;
202                                 goto pipeline_creation_error;
203                         }
204                 }
205                 else
206                 {
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,
213                                           NULL );
214
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,
220                                                         NULL ))
221                         {
222                                 err = MM_ERROR_CAMCORDER_GST_LINK;
223                                 goto pipeline_creation_error;
224                         }
225                 }
226         }       
227
228
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);
234         srcpad = NULL;
235
236         if(info->bMuxing)
237         {
238                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, 
239                                                                                 _MMCAMCORDER_HANDLER_AUDIOREC, 
240                                                                                 "pad-added", 
241                                                                                 __mmcamcorder_audiorec_pad_added_cb, 
242                                                                                 hcamcorder);            
243         }
244         else
245         {
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);
250                 srcpad = NULL;          
251         }
252
253         /*
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
257          */
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);
262
263         return MM_ERROR_NONE;
264
265 pipeline_creation_error:
266         return err;
267 }
268
269
270 int
271 _mmcamcorder_create_audio_pipeline(MMHandleType handle)
272 {
273         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
274         _MMCamcorderSubContext *sc = NULL;
275         
276         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
277         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
278
279         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
280
281         return __mmcamcorder_create_audiop_with_encodebin(handle);
282 }
283
284
285 /**
286  * This function destroy audio pipeline.
287  *
288  * @param[in]   handle          Handle of camcorder.
289  * @return      void
290  * @remarks
291  * @see         _mmcamcorder_destroy_pipeline()
292  *
293  */
294 void
295 _mmcamcorder_destroy_audio_pipeline(MMHandleType handle)
296 {
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);
302
303         mmf_return_if_fail(sc);
304         mmf_return_if_fail(sc->element);
305
306         info = sc->info;
307         
308         _mmcam_dbg_log("");
309
310         if(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)
311         {
312                 _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL);
313
314                 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL);
315                 
316                 if( info->bMuxing)
317                 {
318                         GstPad *reqpad = NULL;
319                         //release request pad
320                         /* FIXME */
321                         /*
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 
324                         */                              
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);       
328                         
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);
332                 }
333                 gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst);
334 //              sc->element[_MMCAMCORDER_MAIN_PIPE].gst = NULL;
335         }
336
337 }
338
339
340 /**
341  * This function operates each command on audio mode.
342  *
343  * @param       c               [in]    Handle of camcorder context.
344  * @param       command [in]    command type received from Multimedia Framework.
345  *
346  * @return      This function returns MM_ERROR_NONE on success, or the other values
347  *                      on error.
348  * @remark
349  * @see         _mmcamcorder_set_functions()
350  *
351  */
352  /* ADDED BY SISO */
353
354
355 void* _MMCamcorderStartHelperFunc(void *handle)
356 {
357         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
358         _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state);
359
360         return NULL;
361 }
362
363 void* _MMCamcorderStopHelperFunc(void *handle)
364 {
365         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);     
366         _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state);
367
368         return NULL;
369 }
370
371
372 int
373 _mmcamcorder_audio_command(MMHandleType handle, int command)
374 {
375         int cmd = command;
376         GstElement *pipeline = NULL;
377         GstElement *audioSrc = NULL;
378         int ret = MM_ERROR_NONE;
379         int err = 0;
380         char *dir_name = NULL;  
381         int size=0;
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;
387         
388         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
389         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
390
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;
395         info = sc->info;
396         
397         _mmcam_dbg_log("");
398
399         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
400         audioSrc = sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst;
401         switch(cmd)
402         {
403                 case _MMCamcorder_CMD_RECORD:
404                         //check status for resume case
405                         if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) 
406                         {
407                                 guint imax_time = 0;
408                                 char *temp_filename = NULL;
409
410                                 if(sc->pipeline_time) {
411                                         gst_pipeline_set_new_stream_time(GST_PIPELINE(pipeline), sc->pipeline_time);
412                                 }
413                                 sc->pipeline_time = RESET_PAUSE_TIME;
414
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,
419                                                                   NULL);
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;
424                                 }
425
426                                 info->filename = strdup(temp_filename);
427                                 if (!info->filename)
428                                 {
429                                         _mmcam_dbg_err("STRDUP was failed");
430                                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
431                                 }
432                                 
433                                 _mmcam_dbg_log("Record start : set file name using attribute - %s\n ",info->filename);
434
435                                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
436
437                                 sc->ferror_send = FALSE;
438                                 sc->ferror_count = 0;
439                                 sc->bget_eos = FALSE;
440                                 info->filesize =0;
441
442                                 /* set max time */
443                                 if (imax_time <= 0) {
444                                         info->max_time = 0; /* do not check */
445                                 } else {
446                                         info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
447                                 }
448
449 /*
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),                                                        
453                                                                  hcamcorder);                                                            
454 */                                                               
455 /* TODO : check free space before recording start, need to more discussion */                   
456 #if 1 
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)))
460                                 {
461                                         _mmcam_dbg_err("No more space for recording - %s : [%" G_GUINT64_FORMAT "]\n ", dir_name, free_space);                  
462                                         if(dir_name)
463                                         {
464                                                 g_free(dir_name);
465                                                 dir_name = NULL;
466                                         }                               
467                                         return MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
468                                 }
469                                 if(dir_name)
470                                 {
471                                         g_free(dir_name);
472                                         dir_name = NULL;
473                                 }
474 #endif
475                         }               
476
477                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
478                         if(ret<0) {
479                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
480                         }
481                         break;
482
483                 case _MMCamcorder_CMD_PAUSE:
484                         {
485                                 GstClock *clock = NULL;
486                                 int count = 0;
487                                 
488                                 if (info->b_commiting)
489                                 {
490                                         _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
491                                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
492                                 }
493
494                                 for(count=0; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++)
495                                 {
496                                         if(info->filesize > 0)
497                                         {
498                                                 break;
499                                         }
500                                         else if(count == _MMCAMCORDER_RETRIAL_COUNT)
501                                         {
502                                                 _mmcam_dbg_err("Pause fail, we are waiting for 100 milisecond, but still file size is %" G_GUINT64_FORMAT "", 
503                                                                         info->filesize);
504                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
505                                         }
506                                         else
507                                         {
508                                                 _mmcam_dbg_warn("Pause is Waiting for enough audio frame, retrial count[%d], file size is %" G_GUINT64_FORMAT "", 
509                                                                         count, info->filesize);                                 
510                                         }
511                                         usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
512                                 }
513
514                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
515                                 if(ret<0) {
516                                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
517                                 }       
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));
521                         }
522                         break;
523
524                 case _MMCamcorder_CMD_CANCEL:
525                         if (info->b_commiting)
526                         {
527                                 _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
528                                 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
529                         }
530                         
531 //                      ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL);
532                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
533                         if(ret<0) {
534                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
535                         }
536
537                         if(info->bMuxing)
538                         {
539                                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
540                         }
541                         else
542                         {
543                                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
544                         }
545
546                         _mmcamcorder_gst_set_state(handle,  sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL);
547
548                         sc->pipeline_time = 0;
549                         sc->pause_time = 0;
550                         sc->isMaxsizePausing = FALSE;
551                         sc->isMaxtimePausing = FALSE;
552                         
553                         if(info->filename)
554                         {
555                                 _mmcam_dbg_log("file delete(%s)", info->filename);
556                                 unlink(info->filename);
557                                 g_free(info->filename);
558                                 info->filename = NULL;                                  
559                         }
560
561                         break;
562                 case _MMCamcorder_CMD_COMMIT:
563                 {
564                         int count = 0;
565                         g_print("\n\n _MMCamcorder_CMD_COMMIT\n\n");
566
567                         if (info->b_commiting)
568                         {
569                                 _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
570                                 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
571                         }
572                         else
573                         {
574                                 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
575                                 info->b_commiting = TRUE;
576                         }                       
577                         
578                         for(count=0; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++)
579                         {
580                                 if(info->filesize > 0)
581                                 {
582                                         break;
583                                 }
584                                 else if(count == _MMCAMCORDER_RETRIAL_COUNT)
585                                 {
586                                         _mmcam_dbg_err("Commit fail, we are waiting for 100 milisecond, but still file size is %" G_GUINT64_FORMAT "", 
587                                                                 info->filesize);
588                                         info->b_commiting = FALSE;
589                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;                                            
590                                 }
591                                 else
592                                 {
593                                         _mmcam_dbg_warn("Commit is Waiting for enough audio frame, retrial count[%d], file size is %" G_GUINT64_FORMAT "", 
594                                                                 count, info->filesize);                                 
595                                 }
596                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
597                         }
598                         
599                         if (audioSrc) {
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);
604                                 pad = NULL;                                     
605                                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) == MM_CAMCORDER_STATE_PAUSED) // for pause -> commit case
606                                 {                               
607                                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);  
608                                         if(ret<0) {
609                                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
610                                         }                               
611                                 }
612                                 
613                         }
614
615                         //wait until finishing EOS
616                         _mmcam_dbg_log("Start to wait EOS");
617                         if ((ret =_mmcamcorder_get_eos_message(handle)) != MM_ERROR_NONE)
618                         {
619                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
620                         }
621 /*
622                          while ((!sc->get_eos)&&((retry_cnt--) > 0)) {
623                                 if ((gMessage = gst_bus_timed_pop (bus, timeout)) != NULL)
624                                 {
625                                         if (GST_MESSAGE_TYPE(gMessage) ==GST_MESSAGE_EOS)
626                                         {
627                                                 _mmcam_dbg_log("Get a EOS message");
628                                                 gst_message_unref(gMessage);
629                                                 break;
630                                         }
631                                         else
632                                         {
633                                                 _mmcam_dbg_log("Get another message(%x). Post this message to bus again.", GST_MESSAGE_TYPE(gMessage));
634                                                 gst_bus_post(bus, gMessage);
635                                         }
636                                 }
637                                 else
638                                 {
639                                         _mmcam_dbg_log("timeout of gst_bus_timed_pop()");
640                                         break;
641                                 }                                       
642                                 
643                                 usleep(100);            //To Prevent busy waiting
644                         }
645
646                         _mmcamcorder_audio_handle_eos((MMHandleType)hcamcorder);
647 */
648
649
650                 }
651                         break;
652
653                 case _MMCamcorder_CMD_PREVIEW_START:
654                 //      MM_CAMCORDER_START_CHANGE_STATE; 
655                         break;
656                 case _MMCamcorder_CMD_PREVIEW_STOP:
657                 //      MM_CAMCORDER_STOP_CHANGE_STATE; 
658                         //void
659                         break;
660
661                 default:
662                         ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
663                         break;
664         }
665
666 _ERR_CAMCORDER_AUDIO_COMMAND:
667         return ret;
668
669 }
670
671 int
672 _mmcamcorder_audio_handle_eos(MMHandleType handle)
673 {
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;
680
681         int err = MM_ERROR_NONE;
682                 
683         mmf_return_val_if_fail(hcamcorder, FALSE);
684         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
685
686         mmf_return_val_if_fail(sc, FALSE);
687         mmf_return_val_if_fail(sc->info, FALSE);
688         
689         _mmcam_dbg_err("");
690
691         info    = sc->info;
692
693         //changing pipeline for display
694         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
695         
696
697         __ta__("        _MMCamcorder_CMD_COMMIT:GST_STATE_READY",  
698         err = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
699         );
700
701         if( err != MM_ERROR_NONE )
702         {
703                 _mmcam_dbg_warn( "Failed:_MMCamcorder_CMD_COMMIT:GST_STATE_READY. err[%x]", err );
704         }
705
706 //      __ta__("        _MMCamcorder_CMD_COMMIT:GST_STATE_NULL",  
707 //      _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL);
708 //      )       
709
710         //Send message  
711         //Send recording report to application                          
712         msg.id = MM_MESSAGE_CAMCORDER_CAPTURED;
713
714         report = (MMCamRecordingReport*) malloc(sizeof(MMCamRecordingReport));  //who free this?
715         if (!report)
716         {
717                 //think more.
718                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
719                 return FALSE;
720         }
721
722         report->recording_filename = strdup(info->filename);
723         msg.param.data= report;
724
725         _mmcamcroder_send_message(handle, &msg);
726
727         
728         if(info->bMuxing)
729         {
730                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
731         }
732         else
733         {
734                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
735         }       
736         _mmcamcorder_gst_set_state(handle,  sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL);
737
738         sc->pipeline_time = 0;
739         sc->pause_time = 0;
740         sc->isMaxsizePausing = FALSE;
741         sc->isMaxtimePausing = FALSE;
742
743         g_free(info->filename);
744         info->filename = NULL;
745
746         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
747
748         info->b_commiting = FALSE;
749
750         return TRUE;
751 }
752
753
754 static float
755 __mmcamcorder_get_decibel(unsigned char* raw, int size, MMCamcorderAudioFormat format)
756 {
757         #define MAX_AMPLITUDE_MEAN_16BIT 23170.115738161934
758         #define MAX_AMPLITUDE_MEAN_08BIT    89.803909382810
759
760         int i = 0;
761         int depthByte = 0;
762         int count = 0;
763
764         short* pcm16 = 0;
765         char* pcm8 = 0;
766
767         float db = 0.0;
768         float rms = 0.0;
769         unsigned long long square_sum = 0;
770
771         if (format == MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE)
772                 depthByte = 2;
773         else            //MM_CAMCORDER_AUDIO_FORMAT_PCM_U8
774                 depthByte = 1;
775
776         for( ; i < size ; i += (depthByte<<1) )
777         {
778                 if (depthByte == 1)
779                 {
780                         pcm8 = (char *)(raw + i);
781                         square_sum += (*pcm8)*(*pcm8);
782                 }
783                 else            //2byte
784                 {
785                         pcm16 = (short*)(raw + i);
786                         square_sum += (*pcm16)*(*pcm16);
787                 }
788
789                 count++;
790         }
791
792         rms = sqrt( square_sum/count );
793
794         if (depthByte == 1)
795                 db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_08BIT );
796         else
797                 db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_16BIT );
798
799         /*
800         _mmcam_dbg_log("size[%d],depthByte[%d],count[%d],rms[%f],db[%f]",
801                        size, depthByte, count, rms, db);
802         */
803
804         return db;
805 }
806
807
808 static gboolean
809 __mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstBuffer *buffer, gpointer u_data)
810 {
811         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
812         double volume = 0.0;
813         int format = 0;
814         int channel = 0;
815         float curdcb = 0.0;
816         _MMCamcorderMsgItem msg;
817         int err = MM_ERROR_UNKNOWN;
818         char *err_name = NULL;
819
820         mmf_return_val_if_fail(hcamcorder, FALSE);
821
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,
827                                                                         NULL);
828         if (err < 0) 
829         {
830                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
831                 SAFE_FREE (err_name);
832                 return err;
833         }
834         
835         if(volume == 0) //mute
836                     memset (GST_BUFFER_DATA(buffer), 0,  GST_BUFFER_SIZE(buffer));
837
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);
842         );
843
844         msg.id = MM_MESSAGE_CAMCORDER_CURRENT_VOLUME;
845         msg.param.rec_volume_dB = curdcb;
846         _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
847
848         /* CALL audio stream callback */
849         if ((hcamcorder->astream_cb) && buffer && GST_BUFFER_DATA(buffer))
850         {
851                 MMCamcorderAudioStreamDataType stream;
852
853                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE)
854                 {
855                         _mmcam_dbg_warn("Not ready for stream callback");
856                         return TRUE;
857                 }
858
859                 /*
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);
862                 */
863
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;
870
871                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK( hcamcorder );
872
873                 if(hcamcorder->astream_cb)
874                 {
875                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
876                 }
877
878                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK( hcamcorder );
879         }
880
881         return TRUE;
882 }
883
884
885 static void
886 __mmcamcorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad,  MMHandleType handle)
887 {
888         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
889
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")))
893         {
894                 MMCAMCORDER_ADD_BUFFER_PROBE(pad, _MMCAMCORDER_HANDLER_AUDIOREC,
895                         __mmcamcorder_audio_dataprobe_record, hcamcorder);
896         }
897         else
898         {
899                 _mmcam_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));     
900         }
901
902         return;
903 }
904
905
906 static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data)
907 {
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;
914
915         _MMCamcorderSubContext *sc = NULL;
916         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
917         _MMCamcorderAudioInfo *info = NULL;
918         _MMCamcorderMsgItem msg;
919
920         mmf_return_val_if_fail(hcamcorder, FALSE);
921         mmf_return_val_if_fail(buffer, FALSE);
922
923         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
924         mmf_return_val_if_fail(sc && sc->info, FALSE);
925         info = sc->info;
926
927         if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
928                 _mmcam_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]",
929                                 sc->isMaxtimePausing, sc->isMaxsizePausing);
930                 return FALSE;
931         }
932
933         buffer_size = (guint64)GST_BUFFER_SIZE(buffer);
934
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 */
940                 }
941
942                 info->filesize += buffer_size;
943                 return TRUE;
944         }
945
946         if (sc->ferror_send) {
947                 _mmcam_dbg_warn("file write error, drop frames");
948                 return FALSE;
949         }
950
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);*/
955         } else {
956                 trailer_size = 0; /* no trailer */
957         }
958
959         filename = info->filename;
960
961         /* to minimizing free space check overhead */
962         count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL;
963         if (count++ == 0) {
964                 gint free_space_ret = _mmcamcorder_get_freespace(filename, &free_space);
965
966                 /*_mmcam_dbg_log("check free space for recording");*/
967
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;
977                                 } else {
978                                         msg.param.code = MM_ERROR_FILE_READ;
979                                 }
980                                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
981                         } else {
982                                 sc->ferror_count++;
983                         }
984
985                         return FALSE; /* skip this buffer */
986
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);
993
994                                 if (info->bMuxing) {
995                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
996                                 } else {
997                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
998                                 }
999
1000                                 sc->isMaxsizePausing = TRUE;
1001                                 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1002                                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1003
1004                                 return FALSE; /* skip this buffer */
1005                         }
1006                         break;
1007                 }
1008         }
1009
1010         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) {
1011                 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1012                 return FALSE;
1013         }
1014
1015         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1016
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);
1021
1022                 if (info->bMuxing) {
1023                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1024                 } else {
1025                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1026                 }
1027
1028                 sc->isMaxtimePausing = TRUE;
1029                 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1030                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1031
1032                 /* skip this buffer */
1033                 return FALSE;
1034         }
1035
1036         /* send message for recording time and recorded file size */
1037         if (info->b_commiting == FALSE) {
1038                 info->filesize += buffer_size;
1039
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);
1044
1045                 return TRUE;
1046         } else {
1047                 /* skip this buffer if commit process has been started */
1048                 return FALSE;
1049         }
1050 }