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