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