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