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