Release version 0.10.14
[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 "mm_camcorder_util.h"
28 #include <math.h>
29
30 /*---------------------------------------------------------------------------------------
31 |    GLOBAL VARIABLE DEFINITIONS for internal                                           |
32 ---------------------------------------------------------------------------------------*/
33 #define MM_CAMCORDER_START_CHANGE_STATE _MMCamcorderStartHelperFunc((void *)hcamcorder)
34 #define MM_CAMCORDER_STOP_CHANGE_STATE _MMCamcorderStopHelperFunc((void *)hcamcorder)
35 /*---------------------------------------------------------------------------------------
36 |    LOCAL VARIABLE DEFINITIONS for internal                                            |
37 ---------------------------------------------------------------------------------------*/
38 #define RESET_PAUSE_TIME                        0
39 #define _MMCAMCORDER_AUDIO_MINIMUM_SPACE        (100*1024)
40 #define _MMCAMCORDER_AUDIO_MARGIN_SPACE         (1*1024)
41 #define _MMCAMCORDER_RETRIAL_COUNT              10
42 #define _MMCAMCORDER_FRAME_WAIT_TIME            200000 /* micro second */
43 #define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL  10
44
45 /*---------------------------------------------------------------------------------------
46 |    LOCAL FUNCTION PROTOTYPES:                                                         |
47 ---------------------------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle);
52 static gboolean __mmcamcorder_audio_add_metadata_info_m4a(MMHandleType handle);
53
54 /*=======================================================================================
55 |  FUNCTION DEFINITIONS                                                                 |
56 =======================================================================================*/
57
58 /*---------------------------------------------------------------------------------------
59 |    GLOBAL FUNCTION DEFINITIONS:                                                       |
60 ---------------------------------------------------------------------------------------*/
61
62 static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle)
63 {
64         int err = MM_ERROR_NONE;
65         const char *aenc_name = NULL;
66         const char *mux_name = NULL;
67
68         GstBus *bus = NULL;
69         GstPad *srcpad = NULL;
70         GstPad *sinkpad = NULL;
71         GList *element_list = NULL;
72
73         _MMCamcorderAudioInfo *info = NULL;
74         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
75         _MMCamcorderSubContext *sc = NULL;
76         type_element *aenc_elem = NULL;
77         type_element *mux_elem = NULL;
78
79         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
80         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
81
82         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
83         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
84         mmf_return_val_if_fail(sc->info_audio, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
85
86         info = (_MMCamcorderAudioInfo *)sc->info_audio;
87
88         _mmcam_dbg_log("");
89
90         mux_elem = _mmcamcorder_get_type_element(handle, MM_CAM_FILE_FORMAT);
91         err = _mmcamcorder_conf_get_value_element_name( mux_elem, &mux_name );
92
93         if (!mux_name || !strcmp(mux_name, "wavenc")) {
94                 /* IF MUX in not chosen then record in raw file */
95                 _mmcam_dbg_log("Record without muxing.");
96                 info->bMuxing = FALSE;
97         } else {
98                 _mmcam_dbg_log("Record with mux.");
99                 info->bMuxing = TRUE;
100         }
101
102         /* Create GStreamer pipeline */
103         _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "camcorder_pipeline", err);
104
105         err = _mmcamcorder_create_audiosrc_bin(handle);
106         if (err != MM_ERROR_NONE) {
107                 return err;
108         }
109
110         if (info->bMuxing) {
111                 /* Muxing. can use encodebin. */
112                 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_AUDIO);
113                 if (err != MM_ERROR_NONE) {
114                         return err;
115                 }
116         } else {
117                 /* without muxing. can't use encodebin. */
118                 aenc_elem = _mmcamcorder_get_type_element(handle, MM_CAM_AUDIO_ENCODER);
119                 if (!aenc_elem) {
120                         _mmcam_dbg_err("Fail to get type element");
121                         err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
122                         goto pipeline_creation_error;
123                 }
124
125                 err = _mmcamcorder_conf_get_value_element_name(aenc_elem, &aenc_name);
126                 if ((!err) || (!aenc_name)) {
127                         _mmcam_dbg_err("Fail to get element name");
128                         err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
129                         goto pipeline_creation_error;
130                 }
131
132                 _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_AQUE, "queue",  NULL, element_list, err);
133
134                 if (strcmp(aenc_name, "wavenc") != 0) {
135                         _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_CONV, "audioconvert",  NULL, element_list, err);
136                 }
137
138                 _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_AENC, aenc_name, NULL, element_list, err);
139
140                 _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_SINK, "filesink", NULL, element_list, err);
141         }
142
143         /* Add and link elements */
144         if (info->bMuxing) {
145                 /* IF MUX is indicated create MUX */
146                 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
147                                  sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
148                                  sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
149                                  NULL);
150
151                 srcpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
152                 sinkpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
153                 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
154         } else {
155                 /* IF MUX in not chosen then record in raw amr file */
156                 if (!strcmp(aenc_name, "wavenc")) {
157                         gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
158                                          sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
159                                          sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst,
160                                          sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst,
161                                          sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst,
162                                          NULL);
163
164                         if (!_MM_GST_ELEMENT_LINK_MANY(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
165                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst,
166                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst,
167                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst,
168                                                        NULL)) {
169                                 err = MM_ERROR_CAMCORDER_GST_LINK;
170                                 goto pipeline_creation_error;
171                         }
172                 } else {
173                         gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
174                                          sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
175                                          sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst,
176                                          sc->encode_element[_MMCAMCORDER_ENCSINK_CONV].gst,
177                                          sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst,
178                                          sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst,
179                                          NULL);
180
181                         if (!_MM_GST_ELEMENT_LINK_MANY(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst,
182                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst,
183                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_CONV].gst,
184                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst,
185                                                        sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst,
186                                                        NULL)) {
187                                 err = MM_ERROR_CAMCORDER_GST_LINK;
188                                 goto pipeline_creation_error;
189                         }
190                 }
191         }
192
193         /* set data probe function */
194         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
195         MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_AUDIOREC,
196                                      __mmcamcorder_audio_dataprobe_voicerecorder, hcamcorder);
197         gst_object_unref(srcpad);
198         srcpad = NULL;
199
200         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
201         MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_AUDIOREC,
202                                      __mmcamcorder_audio_dataprobe_record, hcamcorder);
203         gst_object_unref(srcpad);
204         srcpad = NULL;
205
206         bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
207
208         /* register message callback  */
209         hcamcorder->pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
210
211         /* set sync callback */
212         gst_bus_set_sync_handler(bus, _mmcamcorder_audio_pipeline_bus_sync_callback, hcamcorder, NULL);
213
214         gst_object_unref(bus);
215         bus = NULL;
216
217         if (element_list) {
218                 g_list_free(element_list);
219                 element_list = NULL;
220         }
221
222         return MM_ERROR_NONE;
223
224 pipeline_creation_error:
225         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
226         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN);
227         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_AQUE);
228         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_CONV);
229         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_AENC);
230         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_SINK);
231         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_BIN);
232
233         if (element_list) {
234                 g_list_free(element_list);
235                 element_list = NULL;
236         }
237
238         return err;
239 }
240
241
242 int
243 _mmcamcorder_create_audio_pipeline(MMHandleType handle)
244 {
245         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
246         _MMCamcorderSubContext *sc = NULL;
247
248         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
249         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
250
251         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
252
253         return __mmcamcorder_create_audiop_with_encodebin(handle);
254 }
255
256
257 /**
258  * This function destroy audio pipeline.
259  *
260  * @param[in]   handle          Handle of camcorder.
261  * @return      void
262  * @remarks
263  * @see         _mmcamcorder_destroy_pipeline()
264  *
265  */
266 void
267 _mmcamcorder_destroy_audio_pipeline(MMHandleType handle)
268 {
269         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
270         _MMCamcorderSubContext *sc = NULL;
271         _MMCamcorderAudioInfo *info = NULL;
272         mmf_return_if_fail(hcamcorder);
273         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
274
275         mmf_return_if_fail(sc && sc->info_audio);
276         mmf_return_if_fail(sc->element);
277
278         info = sc->info_audio;
279
280         _mmcam_dbg_log("start");
281
282         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
283                 _mmcam_dbg_warn("release audio pipeline");
284
285                 _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
286
287                 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL);
288
289                 if (info->bMuxing) {
290                         GstPad *reqpad = NULL;
291                         /* FIXME:
292                             Release request pad
293                             The ref_count of mux is always # of streams in here, i don't know why it happens.
294                             So, i unref the mux manually
295                         */
296                         reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
297                         gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
298                         gst_object_unref(reqpad);
299
300                         if(GST_IS_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst) &&
301                            GST_OBJECT_REFCOUNT(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst) > 1) {
302                                 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst);
303                         }
304                 }
305                 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
306         }
307
308         _mmcam_dbg_log("done");
309
310         return;
311 }
312
313
314 /**
315  * This function operates each command on audio mode.
316  *
317  * @param       c               [in]    Handle of camcorder context.
318  * @param       command [in]    command type received from Multimedia Framework.
319  *
320  * @return      This function returns MM_ERROR_NONE on success, or the other values
321  *                      on error.
322  * @remark
323  * @see         _mmcamcorder_set_functions()
324  *
325  */
326  /* ADDED BY SISO */
327
328
329 void* _MMCamcorderStartHelperFunc(void *handle)
330 {
331         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
332         _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state);
333
334         return NULL;
335 }
336
337 void* _MMCamcorderStopHelperFunc(void *handle)
338 {
339         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
340         _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state);
341
342         return NULL;
343 }
344
345
346 int
347 _mmcamcorder_audio_command(MMHandleType handle, int command)
348 {
349         int cmd = command;
350         int ret = MM_ERROR_NONE;
351         int err = 0;
352         guint64 free_space = 0;
353         char *err_attr_name = NULL;
354
355         GstElement *pipeline = NULL;
356         GstElement *audioSrc = NULL;
357
358         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
359         _MMCamcorderSubContext *sc = NULL;
360         _MMCamcorderAudioInfo *info = NULL;
361
362         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
363         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
364
365         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
366         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
367         mmf_return_val_if_fail(sc->info_audio, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
368         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
369         info = sc->info_audio;
370
371         _mmcam_dbg_log("");
372
373         pipeline = sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst;
374         audioSrc = sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst;
375         switch (cmd) {
376         case _MMCamcorder_CMD_RECORD:
377                 /* check status for resume case */
378                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
379                         guint imax_size = 0;
380                         guint imax_time = 0;
381                         char *temp_filename = NULL;
382                         char *dir_name = NULL;
383                         int file_system_type = 0;
384                         int filename_length = 0;
385                         int root_directory_length = 0;
386
387                         if(sc->pipeline_time) {
388                                 gst_element_set_start_time(pipeline, sc->pipeline_time);
389                         }
390                         sc->pipeline_time = RESET_PAUSE_TIME;
391
392                         ret = mm_camcorder_get_attributes(handle, &err_attr_name,
393                                                           MMCAM_TARGET_MAX_SIZE, &imax_size,
394                                                           MMCAM_TARGET_TIME_LIMIT, &imax_time,
395                                                           MMCAM_FILE_FORMAT, &(info->fileformat),
396                                                           MMCAM_TARGET_FILENAME, &temp_filename, &filename_length,
397                                                           MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
398                                                           NULL);
399                         if (ret != MM_ERROR_NONE) {
400                                 _mmcam_dbg_warn("failed to get attribute. (%s:%x)", err_attr_name, ret);
401                                 SAFE_FREE(err_attr_name);
402                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
403                         }
404
405                         if (temp_filename == NULL) {
406                                 _mmcam_dbg_err("filename is not set");
407                                 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
408                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
409                         }
410
411                         info->filename = strdup(temp_filename);
412                         if (!info->filename) {
413                                 _mmcam_dbg_err("STRDUP was failed");
414                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
415                         }
416
417                         _mmcam_dbg_log("Record start : set file name using attribute - %s\n ",info->filename);
418
419                         MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
420
421                         sc->ferror_send = FALSE;
422                         sc->ferror_count = 0;
423                         sc->bget_eos = FALSE;
424                         info->filesize =0;
425
426                         /* set max size */
427                         if (imax_size <= 0) {
428                                 info->max_size = 0; /* do not check */
429                         } else {
430                                 info->max_size = ((guint64)imax_size) << 10; /* to byte */
431                         }
432
433                         /* set max time */
434                         if (imax_time <= 0) {
435                                 info->max_time = 0; /* do not check */
436                         } else {
437                                 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
438                         }
439
440                         /* TODO : check free space before recording start */
441                         dir_name = g_path_get_dirname(info->filename);
442                         if (dir_name) {
443                                 err = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
444
445                                 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
446
447                                 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
448                                         /* MSDOS_SUPER_MAGIC : 0x4d44 */
449                                         if (file_system_type == MSDOS_SUPER_MAGIC &&
450                                             (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
451                                                 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
452                                                                 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
453                                                 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
454                                         } else {
455                                                 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
456                                                                 file_system_type, info->max_size);
457                                         }
458                                 } else {
459                                         _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
460                                 }
461
462                                 g_free(dir_name);
463                                 dir_name = NULL;
464                         } else {
465                                 _mmcam_dbg_err("failed to get directory name");
466                                 err = -1;
467                         }
468
469                         if ((err == -1) || free_space <= (_MMCAMCORDER_AUDIO_MINIMUM_SPACE+(5*1024))) {
470                                 _mmcam_dbg_err("OUT of STORAGE [err:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
471                                                err, free_space, (_MMCAMCORDER_AUDIO_MINIMUM_SPACE+(5*1024)));
472                                 return MM_ERROR_OUT_OF_STORAGE;
473                         }
474                 }
475
476                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
477                 if (ret != MM_ERROR_NONE) {
478                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
479                 }
480                 break;
481
482         case _MMCamcorder_CMD_PAUSE:
483         {
484                 GstClock *pipe_clock = NULL;
485                 int count = 0;
486
487                 if (info->b_commiting) {
488                         _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
489                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
490                 }
491
492                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
493                         if (info->filesize > 0) {
494                                 break;
495                         } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
496                                 _mmcam_dbg_err("Pause fail, wait 200 ms, but file size is %lld",
497                                                info->filesize);
498                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
499                         } else {
500                                 _mmcam_dbg_warn("Wait for enough audio frame, retry count[%d], file size is %lld",
501                                                 count, info->filesize);
502                         }
503                         usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
504                 }
505
506                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
507                 if (ret != MM_ERROR_NONE) {
508                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
509                 }
510
511                 /* FIXME: consider delay. */
512                 pipe_clock = gst_pipeline_get_clock(GST_PIPELINE(pipeline));
513                 sc->pipeline_time = gst_clock_get_time(pipe_clock) - gst_element_get_base_time(GST_ELEMENT(pipeline));
514                 break;
515         }
516
517         case _MMCamcorder_CMD_CANCEL:
518                 if (info->b_commiting) {
519                         _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
520                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
521                 }
522
523                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
524                 if (ret != MM_ERROR_NONE) {
525                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
526                 }
527
528                 if (info->bMuxing) {
529                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
530                 } else {
531                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
532                 }
533
534                 _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL);
535
536                 sc->pipeline_time = 0;
537                 sc->pause_time = 0;
538                 sc->isMaxsizePausing = FALSE;
539                 sc->isMaxtimePausing = FALSE;
540
541                 if (info->filename) {
542                         _mmcam_dbg_log("file delete(%s)", info->filename);
543                         unlink(info->filename);
544                         g_free(info->filename);
545                         info->filename = NULL;
546                 }
547                 break;
548
549         case _MMCamcorder_CMD_COMMIT:
550         {
551                 int count = 0;
552
553                 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT");
554
555                 if (info->b_commiting) {
556                         _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
557                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
558                 } else {
559                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
560                         info->b_commiting = TRUE;
561                 }
562
563                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
564                         if (info->filesize > 0) {
565                                 break;
566                         } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
567                                 _mmcam_dbg_err("Commit fail, waited 200 ms, but file size is %lld", info->filesize);
568                                         info->b_commiting = FALSE;
569                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
570                         } else {
571                                 _mmcam_dbg_warn("Waiting for enough audio frame, re-count[%d], file size is %lld",
572                                                  count, info->filesize);
573                         }
574                         usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
575                 }
576
577                 if (audioSrc) {
578                         if (gst_element_send_event(audioSrc, gst_event_new_eos()) == FALSE) {
579                                 _mmcam_dbg_err("send EOS failed");
580                                 info->b_commiting = FALSE;
581                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
582                                 goto _ERR_CAMCORDER_AUDIO_COMMAND;
583                         }
584
585                         _mmcam_dbg_log("send EOS done");
586
587                         /* for pause -> commit case */
588                         if (_mmcamcorder_get_state((MMHandleType)hcamcorder) == MM_CAMCORDER_STATE_PAUSED) {
589                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
590                                 if (ret != MM_ERROR_NONE) {
591                                         info->b_commiting = FALSE;
592                                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
593                                 }
594                         }
595                 } else {
596                         _mmcam_dbg_err("No audio stream source");
597                         info->b_commiting = FALSE;
598                         ret = MM_ERROR_CAMCORDER_INTERNAL;
599                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
600                 }
601
602                 /* wait until finishing EOS */
603                 _mmcam_dbg_log("Start to wait EOS");
604                 if ((ret =_mmcamcorder_get_eos_message(handle)) != MM_ERROR_NONE) {
605                         info->b_commiting = FALSE;
606                         goto _ERR_CAMCORDER_AUDIO_COMMAND;
607                 }
608                 break;
609         }
610
611         case _MMCamcorder_CMD_PREVIEW_START:
612                 //MM_CAMCORDER_START_CHANGE_STATE;
613                 break;
614
615         case _MMCamcorder_CMD_PREVIEW_STOP:
616                 //MM_CAMCORDER_STOP_CHANGE_STATE;
617                 //void
618                 break;
619
620         default:
621                 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
622                 break;
623         }
624
625 _ERR_CAMCORDER_AUDIO_COMMAND:
626         return ret;
627 }
628
629 int _mmcamcorder_audio_handle_eos(MMHandleType handle)
630 {
631         int err = MM_ERROR_NONE;
632         mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle);
633         _MMCamcorderSubContext *sc = NULL;
634         _MMCamcorderAudioInfo *info = NULL;
635         GstElement *pipeline = NULL;
636         _MMCamcorderMsgItem msg;
637         MMCamRecordingReport * report;
638
639         mmf_return_val_if_fail(hcamcorder, FALSE);
640         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
641
642         mmf_return_val_if_fail(sc, FALSE);
643         mmf_return_val_if_fail(sc->info_audio, FALSE);
644
645         _mmcam_dbg_err("");
646
647         info = sc->info_audio;
648
649         pipeline = sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst;
650
651         err = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
652         if (err != MM_ERROR_NONE) {
653                 _mmcam_dbg_warn("Failed:_MMCamcorder_CMD_COMMIT:GST_STATE_READY. err[%x]", err);
654         }
655
656         /* Send recording report message to application */
657         msg.id = MM_MESSAGE_CAMCORDER_AUDIO_CAPTURED;
658         report = (MMCamRecordingReport*) malloc(sizeof(MMCamRecordingReport));
659         if (!report) {
660                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
661                 return FALSE;
662         }
663
664 /* START TAG HERE */
665         // MM_AUDIO_CODEC_AAC + MM_FILE_FORMAT_MP4
666         if(info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4){
667                 __mmcamcorder_audio_add_metadata_info_m4a(handle);
668         }
669 /* END TAG HERE */
670
671         report->recording_filename = strdup(info->filename);
672         msg.param.data= report;
673
674         _mmcamcorder_send_message(handle, &msg);
675
676         if (info->bMuxing) {
677                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
678         } else {
679                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
680         }
681
682         _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL);
683
684         sc->pipeline_time = 0;
685         sc->pause_time = 0;
686         sc->isMaxsizePausing = FALSE;
687         sc->isMaxtimePausing = FALSE;
688
689         g_free(info->filename);
690         info->filename = NULL;
691
692         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
693
694         info->b_commiting = FALSE;
695
696         return TRUE;
697 }
698
699
700 static float
701 __mmcamcorder_get_decibel(unsigned char* raw, int size, MMCamcorderAudioFormat format)
702 {
703         #define MAX_AMPLITUDE_MEAN_16BIT (23170.115738161934)
704         #define MAX_AMPLITUDE_MEAN_08BIT (89.803909382810)
705         #define DEFAULT_DECIBEL          (-80.0)
706
707         int i = 0;
708         int depthByte = 0;
709         int count = 0;
710
711         short* pcm16 = 0;
712         char* pcm8 = 0;
713
714         float db = DEFAULT_DECIBEL;
715         float rms = 0.0;
716         unsigned long long square_sum = 0;
717
718         if (format == MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE)
719                 depthByte = 2;
720         else            //MM_CAMCORDER_AUDIO_FORMAT_PCM_U8
721                 depthByte = 1;
722
723         for( ; i < size ; i += (depthByte<<1) )
724         {
725                 if (depthByte == 1)
726                 {
727                         pcm8 = (char *)(raw + i);
728                         square_sum += (*pcm8)*(*pcm8);
729                 }
730                 else            //2byte
731                 {
732                         pcm16 = (short*)(raw + i);
733                         square_sum += (*pcm16)*(*pcm16);
734                 }
735
736                 count++;
737         }
738
739         if (count > 0) {
740                 rms = sqrt( square_sum/count );
741                 if (depthByte == 1) {
742                         db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_08BIT );
743                 } else {
744                         db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_16BIT );
745                 }
746         }
747
748         /*
749         _mmcam_dbg_log("size[%d],depthByte[%d],count[%d],rms[%f],db[%f]",
750                        size, depthByte, count, rms, db);
751         */
752
753         return db;
754 }
755
756
757 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
758 {
759         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
760         double volume = 0.0;
761         int format = 0;
762         int channel = 0;
763         float curdcb = 0.0;
764         _MMCamcorderMsgItem msg;
765         int err = MM_ERROR_UNKNOWN;
766         char *err_name = NULL;
767         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
768         GstMapInfo mapinfo;
769
770         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
771
772         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
773
774         /* Set volume to audio input */
775         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
776                                                                         MMCAM_AUDIO_VOLUME, &volume,
777                                                                         MMCAM_AUDIO_FORMAT, &format,
778                                                                         MMCAM_AUDIO_CHANNEL, &channel,
779                                                                         NULL);
780         if (err < 0) {
781                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
782                 SAFE_FREE(err_name);
783                 return err;
784         }
785
786         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
787
788         if(volume == 0){
789                 memset(mapinfo.data, 0, mapinfo.size);
790         }
791
792         /* Get current volume level of real input stream */
793         curdcb = __mmcamcorder_get_decibel(mapinfo.data, mapinfo.size, format);
794
795         msg.id = MM_MESSAGE_CAMCORDER_CURRENT_VOLUME;
796         msg.param.rec_volume_dB = curdcb;
797         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
798
799         /* CALL audio stream callback */
800         if ((hcamcorder->astream_cb) && buffer && mapinfo.data && mapinfo.size > 0)
801         {
802                 MMCamcorderAudioStreamDataType stream;
803
804                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE)
805                 {
806                         _mmcam_dbg_warn("Not ready for stream callback");
807                         gst_buffer_unmap(buffer, &mapinfo);
808                         return GST_PAD_PROBE_OK;
809                 }
810
811                 /*
812                 _mmcam_dbg_log("Call audio steramCb, data[%p], format[%d], channel[%d], length[%d], volume_dB[%f]",
813                                GST_BUFFER_DATA(buffer), format, channel, GST_BUFFER_SIZE(buffer), curdcb);
814                 */
815
816                 stream.data = (void *)mapinfo.data;
817                 stream.format = format;
818                 stream.channel = channel;
819                 stream.length = mapinfo.size;
820                 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000);      //nano -> msecond
821                 stream.volume_dB = curdcb;
822
823                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK( hcamcorder );
824
825                 if(hcamcorder->astream_cb)
826                 {
827                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
828                 }
829
830                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK( hcamcorder );
831         }
832
833         gst_buffer_unmap(buffer, &mapinfo);
834         return GST_PAD_PROBE_OK;
835 }
836
837
838 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
839 {
840         static int count = 0;
841         guint64 rec_pipe_time = 0;
842         guint64 free_space = 0;
843         guint64 buffer_size = 0;
844         guint64 trailer_size = 0;
845         char *filename = NULL;
846         unsigned long long remained_time = 0;
847
848         _MMCamcorderSubContext *sc = NULL;
849         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
850         _MMCamcorderAudioInfo *audioinfo = NULL;
851         _MMCamcorderMsgItem msg;
852         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
853
854         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
855         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
856
857         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
858         mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_DROP);
859         audioinfo = sc->info_audio;
860
861         if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
862                 _mmcam_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]",
863                                 sc->isMaxtimePausing, sc->isMaxsizePausing);
864                 return GST_PAD_PROBE_DROP;
865         }
866
867         buffer_size = gst_buffer_get_size(buffer);
868
869         if (audioinfo->filesize == 0) {
870                 if (audioinfo->fileformat == MM_FILE_FORMAT_WAV) {
871                         audioinfo->filesize += 44; /* wave header size */
872                 } else if (audioinfo->fileformat == MM_FILE_FORMAT_AMR) {
873                         audioinfo->filesize += 6; /* amr header size */
874                 }
875
876                 audioinfo->filesize += buffer_size;
877                 return GST_PAD_PROBE_OK;
878         }
879
880         if (sc->ferror_send) {
881                 _mmcam_dbg_warn("file write error, drop frames");
882                 return GST_PAD_PROBE_DROP;
883         }
884
885         /* get trailer size */
886         if (audioinfo->fileformat == MM_FILE_FORMAT_3GP ||
887                         audioinfo->fileformat == MM_FILE_FORMAT_MP4 ||
888                         audioinfo->fileformat == MM_FILE_FORMAT_AAC) {
889                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
890                 /*_mmcam_dbg_log("trailer_size %d", trailer_size);*/
891         } else {
892                 trailer_size = 0; /* no trailer */
893         }
894
895         filename = audioinfo->filename;
896
897         /* to minimizing free space check overhead */
898         count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL;
899         if (count++ == 0) {
900                 char *dir_name = g_path_get_dirname(filename);
901                 gint free_space_ret = 0;
902
903                 if (dir_name) {
904                         free_space_ret = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
905                         g_free(dir_name);
906                         dir_name = NULL;
907                 } else {
908                         _mmcam_dbg_err("failed to get dir name from [%s]", filename);
909                         free_space_ret = -1;
910                 }
911
912                 /*_mmcam_dbg_log("check free space for recording");*/
913
914                 switch (free_space_ret) {
915                 case -2: /* file not exist */
916                 case -1: /* failed to get free space */
917                         _mmcam_dbg_err("Error occured. [%d]", free_space_ret);
918                         if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
919                                 sc->ferror_send = TRUE;
920                                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
921                                 if (free_space_ret == -2) {
922                                         msg.param.code = MM_ERROR_FILE_NOT_FOUND;
923                                 } else {
924                                         msg.param.code = MM_ERROR_FILE_READ;
925                                 }
926                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
927                         } else {
928                                 sc->ferror_count++;
929                         }
930
931                         return GST_PAD_PROBE_DROP; /* skip this buffer */
932
933                 default: /* succeeded to get free space */
934                         /* check free space for recording */
935                         if (free_space < (guint64)(_MMCAMCORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
936                                 _mmcam_dbg_warn("No more space for recording!!!");
937                                 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]",
938                                                 free_space, audioinfo->filesize);
939
940                                 if (audioinfo->bMuxing) {
941                                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
942                                 } else {
943                                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
944                                 }
945
946                                 sc->isMaxsizePausing = TRUE;
947                                 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
948                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
949
950                                 return GST_PAD_PROBE_DROP; /* skip this buffer */
951                         }
952                         break;
953                 }
954         }
955
956         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
957                 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
958                 return GST_PAD_PROBE_DROP;
959         }
960
961         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
962
963         /* calculate remained time can be recorded */
964         if (audioinfo->max_time > 0 && audioinfo->max_time < (remained_time + rec_pipe_time)) {
965                 remained_time = audioinfo->max_time - rec_pipe_time;
966         } else if (audioinfo->max_size > 0) {
967                 long double max_size = (long double)audioinfo->max_size;
968                 long double current_size = (long double)(audioinfo->filesize + buffer_size + trailer_size);
969
970                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
971         }
972
973         /*_mmcam_dbg_log("remained time : %u", remained_time);*/
974
975         /* check max size of recorded file */
976         if (audioinfo->max_size > 0 &&
977                         audioinfo->max_size < audioinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
978                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
979                 _mmcam_dbg_warn("Max [%" G_GUINT64_FORMAT "], file [%" G_GUINT64_FORMAT "], trailer : [%" G_GUINT64_FORMAT "]", \
980                                 audioinfo->max_size, audioinfo->filesize, trailer_size);
981
982                 /* just same as pause status. After blocking two queue, this function will not call again. */
983                 if (audioinfo->bMuxing) {
984                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
985                 } else {
986                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
987                 }
988
989                 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
990                 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
991                 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
992                 msg.param.recording_status.remained_time = 0;
993                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
994
995                 _mmcam_dbg_warn("Last filesize sent by message : %d", audioinfo->filesize + trailer_size);
996
997                 sc->isMaxsizePausing = TRUE;
998                 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
999                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1000
1001                 /* skip this buffer */
1002                 return GST_PAD_PROBE_DROP;
1003         }
1004
1005         /* check recording time limit and send recording status message */
1006         if (audioinfo->max_time > 0 && rec_pipe_time > audioinfo->max_time) {
1007                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1008                                 rec_pipe_time, audioinfo->max_time);
1009
1010                 if (audioinfo->bMuxing) {
1011                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1012                 } else {
1013                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1014                 }
1015
1016                 sc->isMaxtimePausing = TRUE;
1017                 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1018                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1019
1020                 /* skip this buffer */
1021                 return GST_PAD_PROBE_DROP;
1022         }
1023
1024         /* send message for recording time and recorded file size */
1025         if (audioinfo->b_commiting == FALSE) {
1026                 audioinfo->filesize += buffer_size;
1027
1028                 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1029                 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1030                 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
1031                 msg.param.recording_status.remained_time = remained_time;
1032                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1033
1034                 return GST_PAD_PROBE_OK;
1035         } else {
1036                 /* skip this buffer if commit process has been started */
1037                 return GST_PAD_PROBE_DROP;
1038         }
1039 }
1040
1041 /* START TAG HERE */
1042 static gboolean __mmcamcorder_audio_add_metadata_info_m4a(MMHandleType handle)
1043 {
1044         FILE *f = NULL;
1045         guchar buf[4];
1046         guint64 udta_size = 0;
1047         gint64 current_pos = 0;
1048         gint64 moov_pos = 0;
1049         gint64 udta_pos = 0;
1050         // supporting audio geo tag for mobile
1051         int gps_enable = 0;
1052         char *err_name = NULL;
1053         gdouble longitude = 0;
1054         gdouble latitude = 0;
1055         gdouble altitude = 0;
1056         _MMCamcorderLocationInfo geo_info = {0,0,0};
1057         _MMCamcorderLocationInfo loc_info = {0,0,0};
1058
1059         char err_msg[128] = {'\0',};
1060
1061         _MMCamcorderAudioInfo *info = NULL;
1062         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1063         _MMCamcorderSubContext *sc = NULL;
1064
1065         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1066         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1067
1068         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1069         mmf_return_val_if_fail(sc->info_audio, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1070
1071         info = sc->info_audio;
1072         mm_camcorder_get_attributes(handle, &err_name,
1073                                     MMCAM_TAG_GPS_ENABLE, &gps_enable,
1074                                     NULL);
1075
1076         if (gps_enable) {
1077                 mm_camcorder_get_attributes(handle, &err_name,
1078                                             MMCAM_TAG_LATITUDE, &latitude,
1079                                             MMCAM_TAG_LONGITUDE, &longitude,
1080                                             MMCAM_TAG_ALTITUDE, &altitude,
1081                                             NULL);
1082                 loc_info.longitude = _mmcamcorder_double_to_fix(longitude);
1083                 loc_info.latitude = _mmcamcorder_double_to_fix(latitude);
1084                 loc_info.altitude = _mmcamcorder_double_to_fix(altitude);
1085                 geo_info.longitude = longitude *10000;
1086                 geo_info.latitude = latitude *10000;
1087                 geo_info.altitude = altitude *10000;
1088         }
1089
1090         f = fopen64(info->filename, "rb+");
1091         if (f == NULL) {
1092                 strerror_r(errno, err_msg, 128);
1093                 _mmcam_dbg_err("file open failed [%s]", err_msg);
1094                 if (err_name) {
1095                         free(err_name);
1096                         err_name = NULL;
1097                 }
1098                 return FALSE;
1099         }
1100
1101         /* find udta container.
1102            if, there are udta container, write loci box after that
1103            else, make udta container and write loci box. */
1104         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1105                 size_t nread = 0;
1106
1107                 _mmcam_dbg_log("find udta container");
1108
1109                 /* read size */
1110                 if (fseek(f, -8L, SEEK_CUR) != 0) {
1111                         goto fail;
1112                 }
1113
1114                 udta_pos = ftello(f);
1115                 if (udta_pos < 0) {
1116                         goto ftell_fail;
1117                 }
1118
1119                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1120
1121                 _mmcam_dbg_log("recorded file fread %d", nread);
1122
1123                 udta_size = _mmcamcorder_get_container_size(buf);
1124
1125                 /* goto end of udta and write 'smta' box */
1126                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1127                         goto fail;
1128                 }
1129
1130                 if (gps_enable) {
1131                         if (!_mmcamcorder_write_loci(f, loc_info)) {
1132                                 goto fail;
1133                         }
1134
1135                         if (!_mmcamcorder_write_geodata( f, geo_info )) {
1136                                 goto fail;
1137                         }
1138                 }
1139
1140                 current_pos = ftello(f);
1141                 if (current_pos < 0) {
1142                         goto ftell_fail;
1143                 }
1144
1145                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1146                         goto fail;
1147                 }
1148         } else {
1149                 _mmcam_dbg_log("No udta container");
1150                 if (fseek(f, 0, SEEK_END) != 0) {
1151                         goto fail;
1152                 }
1153
1154                 if (!_mmcamcorder_write_udta(f, gps_enable, loc_info, geo_info)) {
1155                         goto fail;
1156                 }
1157         }
1158
1159         /* find moov container.
1160            update moov container size. */
1161         if((current_pos = ftello(f))<0)
1162                 goto ftell_fail;
1163
1164         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1165
1166                 _mmcam_dbg_log("found moov container");
1167                 if (fseek(f, -8L, SEEK_CUR) !=0) {
1168                         goto fail;
1169                 }
1170
1171                 moov_pos = ftello(f);
1172                 if (moov_pos < 0) {
1173                         goto ftell_fail;
1174                 }
1175
1176                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1177                         goto fail;
1178                 }
1179
1180
1181         } else {
1182                 _mmcam_dbg_err("No 'moov' container");
1183                 goto fail;
1184         }
1185
1186         fclose(f);
1187         if (err_name) {
1188                 free(err_name);
1189                 err_name = NULL;
1190         }
1191         return TRUE;
1192
1193 fail:
1194         fclose(f);
1195         if (err_name) {
1196                 free(err_name);
1197                 err_name = NULL;
1198         }
1199         return FALSE;
1200
1201 ftell_fail:
1202         _mmcam_dbg_err("ftell() returns negative value.");
1203         fclose(f);
1204         if (err_name) {
1205                 free(err_name);
1206                 err_name = NULL;
1207         }
1208         return FALSE;
1209 }
1210
1211 /* END TAG HERE */
1212