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