Add tool package to separate testsuite binary
[platform/core/multimedia/libmm-streamrecorder.git] / src / mm_streamrecorder_gstdispatch.c
1 /*
2  * libmm-streamrecorder
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hyuntae Kim <ht1211.kim@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 <stdio.h>
26 #include <stdarg.h>
27 #include <sys/vfs.h>                    /* struct statfs */
28
29 #include "mm_streamrecorder_internal.h"
30 #include "mm_streamrecorder_gstdispatch.h"
31 #include "mm_streamrecorder_gstcommon.h"
32 #include "mm_streamrecorder_util.h"
33 #include "mm_streamrecorder_recorder.h"
34
35 /*-----------------------------------------------------------------------
36 |    GLOBAL VARIABLE DEFINITIONS for internal                           |
37 -----------------------------------------------------------------------*/
38
39 #define _MMSTREAMRECORDER_MINIMUM_FRAME              5
40 #define _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL  5
41 #define _MMSTREAMRECORDER_MINIMUM_SPACE         (512*1024)      /* byte */
42 #define _MMSTREAMRECORDER_MMS_MARGIN_SPACE              (512)   /* byte */
43 #define _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL  10
44 #define _MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE        (100*1024)
45
46 /*-----------------------------------------------------------------------
47 |    LOCAL VARIABLE DEFINITIONS for internal                            |
48 -----------------------------------------------------------------------*/
49
50 /*---------------------------------------------------------------------------
51 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
52 ---------------------------------------------------------------------------*/
53 /* STATIC INTERNAL FUNCTION */
54
55 /*===========================================================================================
56 |                                                                                                                                                                                       |
57 |  FUNCTION DEFINITIONS                                                                                                                                         |
58 ========================================================================================== */
59 /*---------------------------------------------------------------------------
60 |    GLOBAL FUNCTION DEFINITIONS:                                                                                       |
61 ---------------------------------------------------------------------------*/
62 void _mmstreamrecorder_remove_buffer_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
63 {
64         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
65         GList *list = NULL;
66         MMStreamRecorderHandlerItem *item = NULL;
67
68         mmf_return_if_fail(hstreamrecorder);
69
70         if (!hstreamrecorder->buffer_probes) {
71                 _mmstreamrec_dbg_warn("list for buffer probe is NULL");
72                 return;
73         }
74
75         _mmstreamrec_dbg_log("start - category : 0x%x", category);
76
77         list = hstreamrecorder->buffer_probes;
78         while (list) {
79                 item = list->data;
80                 if (!item) {
81                         _mmstreamrec_dbg_err("Remove buffer probe faild, the item is NULL");
82                         list = g_list_next(list);
83                         continue;
84                 }
85
86                 if (item->category & category) {
87                         if (item->object && GST_IS_PAD(item->object)) {
88                                 _mmstreamrec_dbg_log("Remove buffer probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
89                                 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
90                         } else {
91                                 _mmstreamrec_dbg_warn("Remove buffer probe faild, the pad is null or not pad, just remove item from list and free it");
92                         }
93
94                         list = g_list_next(list);
95                         hstreamrecorder->buffer_probes = g_list_remove(hstreamrecorder->buffer_probes, item);
96                         SAFE_FREE(item);
97                 } else {
98                         _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
99                         list = g_list_next(list);
100                 }
101         }
102
103         if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
104                 g_list_free(hstreamrecorder->buffer_probes);
105                 hstreamrecorder->buffer_probes = NULL;
106         }
107
108         _mmstreamrec_dbg_log("done");
109
110         return;
111 }
112
113 void _mmstreamrecorder_remove_event_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
114 {
115         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
116         GList *list = NULL;
117         MMStreamRecorderHandlerItem *item = NULL;
118
119         mmf_return_if_fail(hstreamrecorder);
120
121         if (!hstreamrecorder->event_probes) {
122                 _mmstreamrec_dbg_warn("list for event probe is NULL");
123                 return;
124         }
125
126         _mmstreamrec_dbg_log("start - category : 0x%x", category);
127
128         list = hstreamrecorder->event_probes;
129         while (list) {
130                 item = list->data;
131                 if (!item) {
132                         _mmstreamrec_dbg_err("Remove event probe faild, the item is NULL");
133                         list = g_list_next(list);
134                         continue;
135                 }
136
137                 if (item->category & category) {
138                         if (item->object && GST_IS_PAD(item->object)) {
139                                 _mmstreamrec_dbg_log("Remove event probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
140                                 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
141                         } else {
142                                 _mmstreamrec_dbg_warn("Remove event probe faild, the pad is null or not pad, just remove item from list and free it");
143                         }
144
145                         list = g_list_next(list);
146                         hstreamrecorder->event_probes = g_list_remove(hstreamrecorder->event_probes, item);
147                         SAFE_FREE(item);
148                 } else {
149                         _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
150                         list = g_list_next(list);
151                 }
152         }
153
154         if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
155                 g_list_free(hstreamrecorder->event_probes);
156                 hstreamrecorder->event_probes = NULL;
157         }
158
159         _mmstreamrec_dbg_log("done");
160
161         return;
162 }
163
164 void _mmstreamrecorder_remove_data_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
165 {
166         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
167         GList *list = NULL;
168         MMStreamRecorderHandlerItem *item = NULL;
169
170         mmf_return_if_fail(hstreamrecorder);
171
172         if (!hstreamrecorder->data_probes) {
173                 _mmstreamrec_dbg_warn("list for data probe is NULL");
174                 return;
175         }
176
177         _mmstreamrec_dbg_log("start - category : 0x%x", category);
178
179         list = hstreamrecorder->data_probes;
180         while (list) {
181                 item = list->data;
182                 if (!item) {
183                         _mmstreamrec_dbg_err("Remove data probe faild, the item is NULL");
184                         list = g_list_next(list);
185                         continue;
186                 }
187
188                 if (item->category & category) {
189                         if (item->object && GST_IS_PAD(item->object)) {
190                                 _mmstreamrec_dbg_log("Remove data probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
191                                 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
192                         } else {
193                                 _mmstreamrec_dbg_warn("Remove data probe faild, the pad is null or not pad, just remove item from list and free it");
194                         }
195
196                         list = g_list_next(list);
197                         hstreamrecorder->data_probes = g_list_remove(hstreamrecorder->data_probes, item);
198                         SAFE_FREE(item);
199                 } else {
200                         _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
201                         list = g_list_next(list);
202                 }
203         }
204
205         if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
206                 g_list_free(hstreamrecorder->data_probes);
207                 hstreamrecorder->data_probes = NULL;
208         }
209
210         _mmstreamrec_dbg_log("done");
211
212         return;
213 }
214
215 void _mmstreamrecorder_disconnect_signal(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
216 {
217         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
218         GList *list = NULL;
219         MMStreamRecorderHandlerItem *item = NULL;
220
221         mmf_return_if_fail(hstreamrecorder);
222
223         if (!hstreamrecorder->signals) {
224                 _mmstreamrec_dbg_warn("list for signal is NULL");
225                 return;
226         }
227
228         _mmstreamrec_dbg_log("start - category : 0x%x", category);
229
230         list = hstreamrecorder->signals;
231         while (list) {
232                 item = list->data;
233                 if (!item) {
234                         _mmstreamrec_dbg_err("Fail to Disconnecting signal, the item is NULL");
235                         list = g_list_next(list);
236                         continue;
237                 }
238
239                 if (item->category & category) {
240                         if (item->object && GST_IS_ELEMENT(item->object)) {
241                                 if (g_signal_handler_is_connected(item->object, item->handler_id)) {
242                                         _mmstreamrec_dbg_log("Disconnect signal from [%s] : [ID : %lu], [Category : %x]", GST_OBJECT_NAME(item->object), item->handler_id, item->category);
243                                         g_signal_handler_disconnect(item->object, item->handler_id);
244                                 } else {
245                                         _mmstreamrec_dbg_warn("Signal was not connected, cannot disconnect it :  [%s]  [ID : %lu], [Category : %x]", GST_OBJECT_NAME(item->object), item->handler_id, item->category);
246                                 }
247                         } else {
248                                 _mmstreamrec_dbg_err("Fail to Disconnecting signal, the element is null or not element, just remove item from list and free it");
249                         }
250
251                         list = g_list_next(list);
252                         hstreamrecorder->signals = g_list_remove(hstreamrecorder->signals, item);
253                         SAFE_FREE(item);
254                 } else {
255                         _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
256                         list = g_list_next(list);
257                 }
258         }
259
260         if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
261                 g_list_free(hstreamrecorder->signals);
262                 hstreamrecorder->signals = NULL;
263         }
264
265         _mmstreamrec_dbg_log("done");
266
267         return;
268 }
269
270 void _mmstreamrecorder_element_release_noti(gpointer data, GObject *where_the_object_was)
271 {
272         int i = 0;
273         _MMStreamRecorderSubContext *sc = (_MMStreamRecorderSubContext *) data;
274
275         mmf_return_if_fail(sc);
276
277         mmf_return_if_fail(sc->encode_element);
278
279         for (i = 0; i < _MMSTREAMRECORDER_ENCODE_PIPELINE_ELEMENT_NUM; i++) {
280                 if (sc->encode_element[i].gst && (G_OBJECT(sc->encode_element[i].gst) == where_the_object_was)) {
281                         _mmstreamrec_dbg_warn("The encode element[%d][%p] is finalized", sc->encode_element[i].id, sc->encode_element[i].gst);
282                         sc->encode_element[i].gst = NULL;
283                         sc->encode_element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
284                         return;
285                 }
286         }
287
288         _mmstreamrec_dbg_warn("there is no matching element %p", where_the_object_was);
289
290         return;
291 }
292
293 gboolean _mmstreamrecorder_msg_callback(void *data)
294 {
295         _MMStreamRecorderMsgItem *item = (_MMStreamRecorderMsgItem *) data;
296         mmf_streamrecorder_t *hstreamrecorder = NULL;
297         mmf_return_val_if_fail(item, FALSE);
298
299         hstreamrecorder = MMF_STREAMRECORDER(item->handle);
300         if (hstreamrecorder == NULL) {
301                 _mmstreamrec_dbg_warn("msg id:0x%x, item:%p, handle is NULL", item->id, item);
302                 goto MSG_CALLBACK_DONE;
303         }
304
305         _MMSTREAMRECORDER_LOCK((MMHandleType) hstreamrecorder);
306         if (hstreamrecorder->msg_data)
307                 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
308
309         _MMSTREAMRECORDER_UNLOCK((MMHandleType) hstreamrecorder);
310
311         /* _mmstreamrec_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hstreamrecorder->msg_cb, hstreamrecorder->msg_data, item); */
312         _MMSTREAMRECORDER_LOCK_MESSAGE_CALLBACK(hstreamrecorder);
313
314         if ((hstreamrecorder) && (hstreamrecorder->msg_cb))
315                 hstreamrecorder->msg_cb(item->id, (MMMessageParamType *) (&(item->param)), hstreamrecorder->msg_cb_param);
316
317         _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(hstreamrecorder);
318
319 MSG_CALLBACK_DONE:
320         /* release allocated memory */
321         if (item->id == MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED ||
322                 item->id == MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED) {
323                 MMStreamRecordingReport *report = (MMStreamRecordingReport *)item->param.data;
324                 if (report) {
325                         SAFE_FREE(report->recording_filename);
326                         SAFE_FREE(report);
327                         item->param.data = NULL;
328                 }
329         }
330         SAFE_FREE(item);
331
332         /* For not being called again */
333         return FALSE;
334 }
335
336 void _mmstreamrecorder_remove_all_handlers(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
337 {
338         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
339
340         _mmstreamrec_dbg_log("ENTER");
341
342         if (hstreamrecorder->signals)
343                 _mmstreamrecorder_disconnect_signal((MMHandleType) hstreamrecorder, category);
344         if (hstreamrecorder->data_probes)
345                 _mmstreamrecorder_remove_data_probe((MMHandleType) hstreamrecorder, category);
346         if (hstreamrecorder->event_probes)
347                 _mmstreamrecorder_remove_event_probe((MMHandleType) hstreamrecorder, category);
348         if (hstreamrecorder->buffer_probes)
349                 _mmstreamrecorder_remove_buffer_probe((MMHandleType) hstreamrecorder, category);
350
351         _mmstreamrec_dbg_log("LEAVE");
352 }
353
354 gboolean _mmstreamrecorder_send_message(MMHandleType handle, _MMStreamRecorderMsgItem *data)
355 {
356         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
357         _MMStreamRecorderMsgItem *item = NULL;
358
359         mmf_return_val_if_fail(hstreamrecorder, FALSE);
360         mmf_return_val_if_fail(data, FALSE);
361
362         /* _mmstreamrec_dbg_err("ENTER"); */
363
364         /* _mmstreamrec_dbg_err("data->id =  %x",data->id); */
365
366         switch (data->id) {
367         case MM_MESSAGE_STREAMRECORDER_STATE_CHANGED:
368                 data->param.union_type = MM_MSG_UNION_STATE;
369                 break;
370         case MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS:
371                 data->param.union_type = MM_MSG_UNION_RECORDING_STATUS;
372                 break;
373         case MM_MESSAGE_STREAMRECORDER_CONSUME_COMPLETE:        /* 0x801 */
374                 data->param.union_type = MM_MSG_UNION_CONSUME_RECORDER_BUFFER;
375                 break;
376         case MM_MESSAGE_STREAMRECORDER_TIME_LIMIT:
377         case MM_MESSAGE_STREAMRECORDER_MAX_SIZE:
378         case MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE:
379         case MM_MESSAGE_STREAMRECORDER_ERROR:
380         case MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED:
381         case MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED:
382         case MM_MESSAGE_READY_TO_RESUME:
383         default:
384                 data->param.union_type = MM_MSG_UNION_CODE;
385                 break;
386         }
387
388         item = g_malloc(sizeof(_MMStreamRecorderMsgItem));
389         if (!item)
390                 return FALSE;
391         memcpy(item, data, sizeof(_MMStreamRecorderMsgItem));
392         item->handle = handle;
393
394         _MMSTREAMRECORDER_LOCK(handle);
395         hstreamrecorder->msg_data = g_list_append(hstreamrecorder->msg_data, item);
396         /* _mmstreamrec_dbg_log("item[%p]", item); */
397
398         /* Use DEFAULT priority */
399         g_idle_add_full(G_PRIORITY_DEFAULT, _mmstreamrecorder_msg_callback, item, NULL);
400
401         _MMSTREAMRECORDER_UNLOCK(handle);
402
403         return TRUE;
404 }
405
406 gboolean _mmstreamrecorder_remove_message_all(MMHandleType handle)
407 {
408         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
409         _MMStreamRecorderMsgItem *item = NULL;
410         gboolean ret = TRUE;
411         GList *list = NULL;
412
413         mmf_return_val_if_fail(hstreamrecorder, FALSE);
414
415         _MMSTREAMRECORDER_LOCK(handle);
416
417         if (hstreamrecorder->msg_data) {
418                 list = hstreamrecorder->msg_data;
419
420                 while (list) {
421                         item = list->data;
422                         list = g_list_next(list);
423
424                         if (item) {
425                                 ret = g_idle_remove_by_data(item);
426                                 _mmstreamrec_dbg_log("Remove item[%p]. ret[%d]", item, ret);
427
428                                 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
429
430                                 SAFE_FREE(item);
431                         }
432                 }
433
434                 g_list_free(hstreamrecorder->msg_data);
435                 hstreamrecorder->msg_data = NULL;
436         }
437
438
439         _MMSTREAMRECORDER_UNLOCK(handle);
440
441         return ret;
442 }
443
444 gboolean _mmstreamrecorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error)
445 {
446         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
447         /* _MMstreamrecorderMsgItem msg; */
448         gchar *msg_src_element;
449         _MMStreamRecorderSubContext *sc = NULL;
450
451         return_val_if_fail(hstreamrecorder, FALSE);
452         return_val_if_fail(error, FALSE);
453         sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
454         mmf_return_val_if_fail(sc, FALSE);
455
456         _mmstreamrec_dbg_log("");
457
458         /* filtering filesink related errors */
459         if ((error->code == GST_RESOURCE_ERROR_WRITE || error->code == GST_RESOURCE_ERROR_SEEK)) {
460                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
461                         sc->ferror_send = TRUE;
462                         /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
463                 } else {
464                         sc->ferror_count++;
465                         _mmstreamrec_dbg_warn("Skip error");
466                         return TRUE;
467                 }
468         }
469
470         if (error->domain == GST_CORE_ERROR) {
471                 /* msg.param.code = __mmstreamrecorder_gst_handle_core_error(handle, error->code, message); */
472         } else if (error->domain == GST_LIBRARY_ERROR) {
473                 /* msg.param.code = __mmstreamrecorder_gst_handle_library_error(handle, error->code, message); */
474         } else if (error->domain == GST_RESOURCE_ERROR) {
475                 /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
476         } else if (error->domain == GST_STREAM_ERROR) {
477                 /* msg.param.code = __mmstreamrecorder_gst_handle_stream_error(handle, error->code, message); */
478         } else {
479                 _mmstreamrec_dbg_warn("This error domain is not defined.");
480
481                 /* we treat system error as an internal error */
482                 /* msg.param.code = MM_ERROR_streamrecorder_INTERNAL; */
483         }
484
485         if (message->src) {
486                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
487 /*              _mmstreamrec_dbg_err("-Msg src : [%s] Domain : [%s]   Error : [%s]  Code : [%d] is tranlated to error code : [0x%x]",
488                                                                 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
489         } else {
490 /*              _mmstreamrec_dbg_err("Domain : [%s]   Error : [%s]  Code : [%d] is tranlated to error code : [0x%x]",
491                                                                 g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
492         }
493
494 #ifdef _MMSTREAMRECORDER_SKIP_GST_FLOW_ERROR
495         /* Check whether send this error to application */
496 /*      if (msg.param.code == MM_ERROR_streamrecorder_GST_FLOW_ERROR) {
497                 _mmstreamrec_dbg_log("We got the error. But skip it.");
498                 return TRUE;
499         } */
500 #endif                                                  /* _MMstreamrecorder_SKIP_GST_FLOW_ERROR */
501
502         /* post error to application */
503         sc->error_occurs = TRUE;
504 /*      msg.id = MM_MESSAGE_streamrecorder_ERROR;
505         _mmstreamrecorder_send_message(handle, &msg); */
506
507         return TRUE;
508 }
509
510 gint _mmstreamrecorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message)
511 {
512         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
513         _MMStreamRecorderSubContext *sc = NULL;
514         GstElement *element = NULL;
515
516         _mmstreamrec_dbg_log("");
517
518         mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
519
520         sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
521         mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
522
523         /* Specific plugin - video encoder plugin */
524         element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
525
526         if (GST_ELEMENT_CAST(message->src) == element) {
527                 if (code == GST_CORE_ERROR_NEGOTIATION)
528                         return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
529                 else
530                         return MM_ERROR_STREAMRECORDER_ENCODER;
531         }
532
533         /* General */
534         switch (code) {
535         case GST_CORE_ERROR_STATE_CHANGE:
536                 return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
537         case GST_CORE_ERROR_NEGOTIATION:
538                 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
539         case GST_CORE_ERROR_MISSING_PLUGIN:
540         case GST_CORE_ERROR_SEEK:
541         case GST_CORE_ERROR_NOT_IMPLEMENTED:
542         case GST_CORE_ERROR_FAILED:
543         case GST_CORE_ERROR_TOO_LAZY:
544         case GST_CORE_ERROR_PAD:
545         case GST_CORE_ERROR_THREAD:
546         case GST_CORE_ERROR_EVENT:
547         case GST_CORE_ERROR_CAPS:
548         case GST_CORE_ERROR_TAG:
549         case GST_CORE_ERROR_CLOCK:
550         case GST_CORE_ERROR_DISABLED:
551         default:
552                 return MM_ERROR_STREAMRECORDER_GST_CORE;
553                 break;
554         }
555 }
556
557 gint _mmstreamrecorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message)
558 {
559         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
560         return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
561
562         _mmstreamrec_dbg_log("");
563
564         /* Specific plugin - NONE */
565
566         /* General */
567         switch (code) {
568         case GST_LIBRARY_ERROR_FAILED:
569         case GST_LIBRARY_ERROR_TOO_LAZY:
570         case GST_LIBRARY_ERROR_INIT:
571         case GST_LIBRARY_ERROR_SHUTDOWN:
572         case GST_LIBRARY_ERROR_SETTINGS:
573         case GST_LIBRARY_ERROR_ENCODE:
574         default:
575                 _mmstreamrec_dbg_err("Library error(%d)", code);
576                 return MM_ERROR_STREAMRECORDER_GST_LIBRARY;
577         }
578 }
579
580 gint _mmstreamrecorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message)
581 {
582         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
583         _MMStreamRecorderSubContext *sc = NULL;
584         GstElement *element = NULL;
585
586         mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
587
588         sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
589         mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
590
591         _mmstreamrec_dbg_log("");
592
593         /* Specific plugin */
594
595         /* encodebin */
596         element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
597         if (GST_ELEMENT_CAST(message->src) == element) {
598                 if (code == GST_RESOURCE_ERROR_FAILED) {
599                         _mmstreamrec_dbg_err("Encoder [Resource error]");
600                         return MM_ERROR_STREAMRECORDER_ENCODER_BUFFER;
601                 } else {
602                         _mmstreamrec_dbg_err("Encoder [General(%d)]", code);
603                         return MM_ERROR_STREAMRECORDER_ENCODER;
604                 }
605         }
606
607         /* General */
608         switch (code) {
609         case GST_RESOURCE_ERROR_WRITE:
610                 _mmstreamrec_dbg_err("File write error");
611                 return MM_ERROR_FILE_WRITE;
612         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
613                 _mmstreamrec_dbg_err("No left space");
614                 return MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
615         case GST_RESOURCE_ERROR_OPEN_WRITE:
616                 _mmstreamrec_dbg_err("Out of storage");
617                 return MM_ERROR_OUT_OF_STORAGE;
618         case GST_RESOURCE_ERROR_SEEK:
619                 _mmstreamrec_dbg_err("File read(seek)");
620                 return MM_ERROR_FILE_READ;
621         case GST_RESOURCE_ERROR_NOT_FOUND:
622         case GST_RESOURCE_ERROR_FAILED:
623         case GST_RESOURCE_ERROR_TOO_LAZY:
624         case GST_RESOURCE_ERROR_BUSY:
625         case GST_RESOURCE_ERROR_OPEN_READ:
626         case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
627         case GST_RESOURCE_ERROR_CLOSE:
628         case GST_RESOURCE_ERROR_READ:
629         case GST_RESOURCE_ERROR_SYNC:
630         case GST_RESOURCE_ERROR_SETTINGS:
631         default:
632                 _mmstreamrec_dbg_err("Resource error(%d)", code);
633                 return MM_ERROR_STREAMRECORDER_GST_RESOURCE;
634         }
635 }
636
637 gint _mmstreamrecorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message)
638 {
639         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
640         _MMStreamRecorderSubContext *sc = NULL;
641         GstElement *element = NULL;
642
643         mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
644
645         sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
646         mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
647
648         _mmstreamrec_dbg_log("");
649
650         /* Specific plugin */
651         /* video encoder */
652         element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
653         if (GST_ELEMENT_CAST(message->src) == element) {
654                 switch (code) {
655                 case GST_STREAM_ERROR_WRONG_TYPE:
656                         _mmstreamrec_dbg_err("Video encoder [wrong stream type]");
657                         return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
658                 case GST_STREAM_ERROR_ENCODE:
659                         _mmstreamrec_dbg_err("Video encoder [encode error]");
660                         return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
661                 case GST_STREAM_ERROR_FAILED:
662                         _mmstreamrec_dbg_err("Video encoder [stream failed]");
663                         return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
664                 default:
665                         _mmstreamrec_dbg_err("Video encoder [General(%d)]", code);
666                         return MM_ERROR_STREAMRECORDER_ENCODER;
667                 }
668         }
669
670         /* General plugin */
671         switch (code) {
672         case GST_STREAM_ERROR_FORMAT:
673                 _mmstreamrec_dbg_err("General [negotiation error(%d)]", code);
674                 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
675         case GST_STREAM_ERROR_FAILED:
676                 _mmstreamrec_dbg_err("General [flow error(%d)]", code);
677                 return MM_ERROR_STREAMRECORDER_GST_FLOW_ERROR;
678         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
679         case GST_STREAM_ERROR_DECODE:
680         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
681         case GST_STREAM_ERROR_NOT_IMPLEMENTED:
682         case GST_STREAM_ERROR_TOO_LAZY:
683         case GST_STREAM_ERROR_ENCODE:
684         case GST_STREAM_ERROR_DEMUX:
685         case GST_STREAM_ERROR_MUX:
686         case GST_STREAM_ERROR_DECRYPT:
687         case GST_STREAM_ERROR_DECRYPT_NOKEY:
688         case GST_STREAM_ERROR_WRONG_TYPE:
689         default:
690                 _mmstreamrec_dbg_err("General [error(%d)]", code);
691                 return MM_ERROR_STREAMRECORDER_GST_STREAM;
692         }
693 }
694
695 gboolean _mmstreamrecorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error)
696 {
697         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
698         gchar *debug = NULL;
699         GError *err = NULL;
700
701         return_val_if_fail(hstreamrecorder, FALSE);
702         return_val_if_fail(error, FALSE);
703
704         _mmstreamrec_dbg_log("");
705
706         gst_message_parse_warning(message, &err, &debug);
707
708         if (error->domain == GST_CORE_ERROR) {
709                 _mmstreamrec_dbg_warn("GST warning: GST_CORE domain");
710         } else if (error->domain == GST_LIBRARY_ERROR) {
711                 _mmstreamrec_dbg_warn("GST warning: GST_LIBRARY domain");
712         } else if (error->domain == GST_RESOURCE_ERROR) {
713                 _mmstreamrec_dbg_warn("GST warning: GST_RESOURCE domain");
714                 /* _mmstreamrecorder_gst_handle_resource_warning(handle, message, error); */
715         } else if (error->domain == GST_STREAM_ERROR) {
716                 _mmstreamrec_dbg_warn("GST warning: GST_STREAM domain");
717         } else {
718                 _mmstreamrec_dbg_warn("This error domain(%d) is not defined.", error->domain);
719         }
720
721         if (err != NULL) {
722                 g_error_free(err);
723                 err = NULL;
724         }
725         if (debug != NULL) {
726                 _mmstreamrec_dbg_err("Debug: %s", debug);
727                 g_free(debug);
728                 debug = NULL;
729         }
730
731         return TRUE;
732 }
733
734 gboolean _mmstreamrecorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data)
735 {
736         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(data);
737         /* _MMstreamrecorderMsgItem msg; */
738         _MMStreamRecorderSubContext *sc = NULL;
739
740         mmf_return_val_if_fail(hstreamrecorder, FALSE);
741         mmf_return_val_if_fail(message, FALSE);
742         /* _mmstreamrec_dbg_log("message type=(%d)", GST_MESSAGE_TYPE(message)); */
743
744         switch (GST_MESSAGE_TYPE(message)) {
745         case GST_MESSAGE_UNKNOWN:
746                 _mmstreamrec_dbg_log("GST_MESSAGE_UNKNOWN");
747                 break;
748         case GST_MESSAGE_EOS:
749                 {
750                         _mmstreamrec_dbg_log("Got EOS from element \"%s\".", GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
751
752                         sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
753                         mmf_return_val_if_fail(sc, TRUE);
754
755                         mmf_return_val_if_fail(sc->info_video, TRUE);
756                         if (sc->info_video->b_commiting)
757                                 _mmstreamrecorder_video_handle_eos((MMHandleType) hstreamrecorder);
758
759                         sc->bget_eos = TRUE;
760
761                         break;
762                 }
763         case GST_MESSAGE_ERROR:
764                 {
765                         GError *err;
766                         gchar *debug;
767                         gst_message_parse_error(message, &err, &debug);
768
769                         _mmstreamrec_dbg_err("GSTERR: %s", err->message);
770                         _mmstreamrec_dbg_err("Error Debug: %s", debug);
771
772                         _mmstreamrecorder_handle_gst_error((MMHandleType) hstreamrecorder, message, err);
773
774                         g_error_free(err);
775                         g_free(debug);
776                         break;
777                 }
778         case GST_MESSAGE_WARNING:
779                 {
780                         GError *err;
781                         gchar *debug;
782                         gst_message_parse_warning(message, &err, &debug);
783
784                         _mmstreamrec_dbg_warn("GSTWARN: %s", err->message);
785
786                         _mmstreamrecorder_handle_gst_warning((MMHandleType) hstreamrecorder, message, err);
787
788                         g_error_free(err);
789                         g_free(debug);
790                         break;
791                 }
792         case GST_MESSAGE_INFO:
793                 _mmstreamrec_dbg_log("GST_MESSAGE_INFO");
794                 break;
795         case GST_MESSAGE_TAG:
796                 _mmstreamrec_dbg_log("GST_MESSAGE_TAG");
797                 break;
798         case GST_MESSAGE_BUFFERING:
799                 _mmstreamrec_dbg_log("GST_MESSAGE_BUFFERING");
800                 break;
801         case GST_MESSAGE_STATE_CHANGED:
802                 {
803                         const GValue *vnewstate;
804                         GstState newstate;
805                         GstElement *pipeline = NULL;
806
807                         sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
808                         if ((sc) && (sc->encode_element)) {
809                                 if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
810                                         pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
811                                         if (message->src == (GstObject *) pipeline) {
812                                                 vnewstate = (GValue *) gst_structure_get_value(gst_message_get_structure(message), "new-state");
813                                                 newstate = (GstState) vnewstate->data[0].v_int;
814                                                 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_CHANGED[%s]", gst_element_state_get_name(newstate));
815                                                 if (newstate == GST_STATE_PLAYING) {
816                                                         if (hstreamrecorder->ini.generate_dot) {
817                                                                 GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), GST_DEBUG_GRAPH_SHOW_ALL, "streamrecorder_pipeline");
818                                                         }
819                                                 }
820                                         }
821                                 }
822                         }
823                         break;
824                 }
825         case GST_MESSAGE_STATE_DIRTY:
826                 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_DIRTY");
827                 break;
828         case GST_MESSAGE_STEP_DONE:
829                 _mmstreamrec_dbg_log("GST_MESSAGE_STEP_DONE");
830                 break;
831         case GST_MESSAGE_CLOCK_PROVIDE:
832                 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_PROVIDE");
833                 break;
834         case GST_MESSAGE_CLOCK_LOST:
835                 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_LOST");
836                 break;
837         case GST_MESSAGE_NEW_CLOCK:
838                 {
839                         GstClock *l_clock;
840                         gst_message_parse_new_clock(message, &l_clock);
841                         _mmstreamrec_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (l_clock ? GST_OBJECT_NAME(l_clock) : "NULL"));
842                         break;
843                 }
844         case GST_MESSAGE_STRUCTURE_CHANGE:
845                 _mmstreamrec_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE");
846                 break;
847         case GST_MESSAGE_STREAM_STATUS:
848                 _mmstreamrec_dbg_log("GST_MESSAGE_STREAM_STATUS");
849                 break;
850         case GST_MESSAGE_APPLICATION:
851                 _mmstreamrec_dbg_log("GST_MESSAGE_APPLICATION");
852                 break;
853         case GST_MESSAGE_ELEMENT:
854                 _mmstreamrec_dbg_log("GST_MESSAGE_ELEMENT");
855                 break;
856         case GST_MESSAGE_SEGMENT_START:
857                 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_START");
858                 break;
859         case GST_MESSAGE_SEGMENT_DONE:
860                 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_DONE");
861                 break;
862         case GST_MESSAGE_DURATION:
863                 _mmstreamrec_dbg_log("GST_MESSAGE_DURATION");
864                 break;
865         case GST_MESSAGE_LATENCY:
866                 _mmstreamrec_dbg_log("GST_MESSAGE_LATENCY");
867                 break;
868         case GST_MESSAGE_ASYNC_START:
869                 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_START");
870                 break;
871         case GST_MESSAGE_ASYNC_DONE:
872                 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_DONE");
873                 break;
874         case GST_MESSAGE_ANY:
875                 _mmstreamrec_dbg_log("GST_MESSAGE_ANY");
876                 break;
877         default:
878                 _mmstreamrec_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message));
879                 break;
880         }
881
882         return TRUE;
883 }
884
885 /**
886  * This function is record video data probing function.
887  * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
888  * this function will be called when data stream pass through the pad.
889  *
890  * @param[in]   pad             probing pad which calls this function.
891  * @param[in]   buffer          buffer which contains stream data.
892  * @param[in]   u_data          user data.
893  * @return      This function returns true on success, or false value with error
894  * @remarks
895  * @see
896  */
897 GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
898 {
899         GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
900         switch (GST_EVENT_TYPE(event)) {
901         case GST_EVENT_UNKNOWN:
902                 /* upstream events */
903         case GST_EVENT_QOS:
904         case GST_EVENT_SEEK:
905         case GST_EVENT_NAVIGATION:
906         case GST_EVENT_LATENCY:
907                 /* downstream serialized events */
908         case GST_EVENT_SEGMENT:
909         case GST_EVENT_TAG:
910         case GST_EVENT_BUFFERSIZE:
911                 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
912                 break;
913         case GST_EVENT_EOS:
914                 _mmstreamrec_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
915                 break;
916                 /* bidirectional events */
917         case GST_EVENT_FLUSH_START:
918         case GST_EVENT_FLUSH_STOP:
919                 _mmstreamrec_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
920                 break;
921         default:
922                 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
923                 break;
924         }
925
926         return GST_PAD_PROBE_OK;
927 }
928
929 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
930 {
931         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
932         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
933         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
934         guint64 buffer_size = 0;
935
936         _MMStreamRecorderSubContext *sc = NULL;
937         _MMStreamRecorderAudioInfo *audioinfo = NULL;
938
939         mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
940         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
941         sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
942
943         mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_OK);
944         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
945
946         audioinfo = sc->info_audio;
947
948         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
949         buffer_size = mapinfo.size;
950         gst_buffer_unmap(buffer, &mapinfo);
951
952         /*_mmstreamrec_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
953
954         if (audioinfo->audio_frame_count == 0) {
955                 audioinfo->filesize += buffer_size;
956                 audioinfo->audio_frame_count++;
957                 return GST_PAD_PROBE_OK;
958         }
959
960         if (sc->ferror_send || sc->isMaxsizePausing) {
961                 _mmstreamrec_dbg_warn("Recording is paused, drop frames");
962                 return GST_PAD_PROBE_DROP;
963         }
964
965         audioinfo->filesize += buffer_size;
966         audioinfo->audio_frame_count++;
967
968         return GST_PAD_PROBE_OK;
969 }
970
971 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
972 {
973         static int count = 0;
974         gint ret = 0;
975         guint vq_size = 0;
976         guint aq_size = 0;
977         guint64 free_space = 0;
978         guint64 buffer_size = 0;
979         guint64 trailer_size = 0;
980         guint64 queued_buffer = 0;
981         char *filename = NULL;
982         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
983         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
984
985         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
986         _MMStreamRecorderMsgItem msg;
987         _MMStreamRecorderSubContext *sc = NULL;
988         _MMStreamRecorderVideoInfo *videoinfo = NULL;
989         _MMStreamRecorderFileInfo *finfo = NULL;
990
991         mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
992         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
993
994         sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
995         mmf_return_val_if_fail(sc && sc->info_video && sc->info_file, TRUE);
996         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
997
998         videoinfo = sc->info_video;
999         finfo = sc->info_file;
1000
1001         /*_mmstreamrec_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1002         if (sc->ferror_send) {
1003                 _mmstreamrec_dbg_warn("file write error, drop frames");
1004                 return GST_PAD_PROBE_DROP;
1005         }
1006         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1007         buffer_size = mapinfo.size;
1008         gst_buffer_unmap(buffer, &mapinfo);
1009
1010         videoinfo->video_frame_count++;
1011         if (videoinfo->video_frame_count <= (guint64) _MMSTREAMRECORDER_MINIMUM_FRAME) {
1012                 /* _mmstreamrec_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", info->video_frame_count); */
1013                 videoinfo->filesize += buffer_size;
1014                 return GST_PAD_PROBE_OK;
1015         }
1016
1017         /* get trailer size */
1018         if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1019                 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1020         else
1021                 trailer_size = 0;
1022
1023         /* to minimizing free space check overhead */
1024         count = count % _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL;
1025         if (count++ == 0) {
1026                 filename = finfo->filename;
1027                 ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1028
1029                 /*_mmstreamrec_dbg_log("check free space for recording");*/
1030
1031                 switch (ret) {
1032                 case -2:                                /* file not exist */
1033                 case -1:                                /* failed to get free space */
1034                         _mmstreamrec_dbg_err("Error occured. [%d]", ret);
1035                         if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1036                                 sc->ferror_send = TRUE;
1037                                 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1038                                 if (ret == -2)
1039                                         msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1040                                 else
1041                                         msg.param.code = MM_ERROR_FILE_READ;
1042
1043                                 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1044                         } else {
1045                                 sc->ferror_count++;
1046                         }
1047
1048                         return GST_PAD_PROBE_DROP;      /* skip this buffer */
1049                         break;
1050                 default:                                /* succeeded to get free space */
1051                         /* check free space for recording */
1052                         /* get queued buffer size */
1053                         if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst)
1054                                 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1055
1056                         if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst)
1057                                 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1058
1059                         queued_buffer = aq_size + vq_size;
1060
1061                         /* check free space */
1062                         if (free_space < (_MMSTREAMRECORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1063                                 _mmstreamrec_dbg_warn("No more space for recording!!! Recording is paused.");
1064                                 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", free_space, trailer_size, buffer_size, queued_buffer);
1065
1066                                 if (!sc->isMaxsizePausing) {
1067                                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1068                                         sc->isMaxsizePausing = TRUE;
1069
1070                                         msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1071                                         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1072                                 }
1073
1074                                 return GST_PAD_PROBE_DROP;
1075                         }
1076                         break;
1077                 }
1078         }
1079
1080         videoinfo->filesize += (guint64) buffer_size;
1081
1082         /*
1083            _mmstreamrec_dbg_log("filesize %lld Byte, ", info->filesize);
1084          */
1085
1086         return GST_PAD_PROBE_OK;
1087 }
1088
1089 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1090 {
1091         guint64 trailer_size = 0;
1092         guint64 rec_pipe_time = 0;
1093         unsigned int remained_time = 0;
1094
1095         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1096         GstClockTime b_time;
1097
1098         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1099         _MMStreamRecorderMsgItem msg;
1100         _MMStreamRecorderSubContext *sc = NULL;
1101         _MMStreamRecorderVideoInfo *videoinfo = NULL;
1102         _MMStreamRecorderFileInfo *finfo = NULL;
1103
1104         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1105         mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1106
1107         sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1108         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1109         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1110         mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1111
1112         videoinfo = sc->info_video;
1113         finfo = sc->info_file;
1114
1115         b_time = GST_BUFFER_TIMESTAMP(buffer);
1116
1117         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1118
1119         if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1120                 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1121         else
1122                 trailer_size = 0;
1123
1124         /* check max time */
1125         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1126                 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1127
1128                 if (!sc->isMaxtimePausing) {
1129                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1130
1131                         sc->isMaxtimePausing = TRUE;
1132
1133                         msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1134                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1135                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1136                         msg.param.recording_status.remained_time = 0;
1137                         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1138
1139                         msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1140                         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1141                 }
1142
1143                 return GST_PAD_PROBE_DROP;
1144         }
1145
1146         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1147                 remained_time = videoinfo->max_time - rec_pipe_time;
1148
1149         msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1150         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1151         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1152         msg.param.recording_status.remained_time = remained_time;
1153         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1154
1155         /*
1156            _mmstreamrec_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1157            GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1158          */
1159
1160         return GST_PAD_PROBE_OK;
1161 }
1162
1163 GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1164 {
1165         _MMStreamRecorderMsgItem msg;
1166         guint64 trailer_size = 0;
1167         guint64 rec_pipe_time = 0;
1168         _MMStreamRecorderSubContext *sc = NULL;
1169         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1170         _MMStreamRecorderVideoInfo *videoinfo = NULL;
1171         _MMStreamRecorderFileInfo *finfo = NULL;
1172         unsigned int remained_time = 0;
1173         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1174
1175         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1176         mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1177         sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1178
1179         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1180         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1181         mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1182
1183         videoinfo = sc->info_video;
1184         finfo = sc->info_file;
1185
1186         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1187                 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1188                 return GST_PAD_PROBE_OK;
1189         }
1190
1191         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1192
1193         if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1194                 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1195         else
1196                 trailer_size = 0;
1197
1198         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1199                 remained_time = videoinfo->max_time - rec_pipe_time;
1200
1201         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1202                 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1203
1204                 if (!sc->isMaxtimePausing) {
1205                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1206
1207                         sc->isMaxtimePausing = TRUE;
1208
1209                         msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1210                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1211                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1212                         msg.param.recording_status.remained_time = 0;
1213                         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1214
1215                         msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1216                         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1217                 }
1218
1219                 return GST_PAD_PROBE_DROP;
1220         }
1221
1222         msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1223         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1224         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1225         msg.param.recording_status.remained_time = remained_time;
1226         _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1227
1228         /*
1229            _mmstreamrec_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1230            GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1231          */
1232
1233         return GST_PAD_PROBE_OK;
1234 }
1235
1236 void __mmstreamrecorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle)
1237 {
1238         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
1239
1240         _mmstreamrec_dbg_log("ENTER(%s)", GST_PAD_NAME(pad));
1241         /* FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name? */
1242         if ((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink")))
1243                 MMSTREAMRECORDER_ADD_BUFFER_PROBE(pad, _MMSTREAMRECORDER_HANDLER_AUDIOREC, __mmstreamrecorder_audio_dataprobe_record, hstreamrecorder);
1244         else
1245                 _mmstreamrec_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));
1246
1247         return;
1248 }
1249
1250 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1251 {
1252         static int count = 0;
1253         guint64 rec_pipe_time = 0;
1254         guint64 free_space = 0;
1255         guint64 buffer_size = 0;
1256         guint64 trailer_size = 0;
1257         char *filename = NULL;
1258         unsigned long long remained_time = 0;
1259         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1260
1261         _MMStreamRecorderSubContext *sc = NULL;
1262         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1263         _MMStreamRecorderAudioInfo *audioinfo = NULL;
1264         _MMStreamRecorderFileInfo *finfo = NULL;
1265         _MMStreamRecorderMsgItem msg;
1266
1267         mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_DROP);
1268         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1269
1270         sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
1271         mmf_return_val_if_fail(sc && sc->info_audio && sc->info_file, FALSE);
1272         audioinfo = sc->info_audio;
1273         finfo = sc->info_file;
1274
1275         if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
1276                 _mmstreamrec_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", sc->isMaxtimePausing, sc->isMaxsizePausing);
1277                 return GST_PAD_PROBE_DROP;
1278         }
1279
1280         buffer_size = gst_buffer_get_size(buffer);
1281
1282         if (audioinfo->filesize == 0) {
1283                 if (finfo->fileformat == MM_FILE_FORMAT_WAV)
1284                         audioinfo->filesize += 44;      /* wave header size */
1285                 else if (finfo->fileformat == MM_FILE_FORMAT_AMR)
1286                         audioinfo->filesize += 6;       /* amr header size */
1287
1288                 audioinfo->filesize += buffer_size;
1289                 return GST_PAD_PROBE_OK;
1290         }
1291
1292         if (sc->ferror_send) {
1293                 _mmstreamrec_dbg_warn("file write error, drop frames");
1294                 return GST_PAD_PROBE_DROP;
1295         }
1296
1297         /* get trailer size */
1298         if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4 || finfo->fileformat == MM_FILE_FORMAT_AAC) {
1299                 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1300                 /*_mmstreamrec_dbg_log("trailer_size %d", trailer_size);*/
1301         } else {
1302                 trailer_size = 0;               /* no trailer */
1303         }
1304
1305         filename = finfo->filename;
1306
1307         /* to minimizing free space check overhead */
1308         count = count % _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL;
1309         if (count++ == 0) {
1310                 gint free_space_ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1311
1312                 /*_mmstreamrec_dbg_log("check free space for recording");*/
1313
1314                 switch (free_space_ret) {
1315                 case -2:                                /* file not exist */
1316                 case -1:                                /* failed to get free space */
1317                         _mmstreamrec_dbg_err("Error occured. [%d]", free_space_ret);
1318                         if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1319                                 sc->ferror_send = TRUE;
1320                                 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1321                                 if (free_space_ret == -2)
1322                                         msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1323                                 else
1324                                         msg.param.code = MM_ERROR_FILE_READ;
1325
1326                                 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1327                         } else {
1328                                 sc->ferror_count++;
1329                         }
1330
1331                         return GST_PAD_PROBE_DROP;      /* skip this buffer */
1332
1333                 default:                                /* succeeded to get free space */
1334                         /* check free space for recording */
1335                         if (free_space < (guint64) (_MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
1336                                 _mmstreamrec_dbg_warn("No more space for recording!!!");
1337                                 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", free_space, audioinfo->filesize);
1338
1339                                 if (audioinfo->bMuxing)
1340                                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1341                                 else
1342                                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1343
1344                                 sc->isMaxsizePausing = TRUE;
1345                                 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1346                                 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1347
1348                                 return FALSE;   /* skip this buffer */
1349                         }
1350                         break;
1351                 }
1352         }
1353
1354         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1355                 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1356                 return GST_PAD_PROBE_DROP;
1357         }
1358
1359         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1360
1361         if (audioinfo->max_time > 0 && audioinfo->max_time < (remained_time + rec_pipe_time))
1362                 remained_time = audioinfo->max_time - rec_pipe_time;
1363
1364         /*_mmstreamrec_dbg_log("remained time : %u", remained_time);*/
1365
1366         /* check recording time limit and send recording status message */
1367         if (audioinfo->max_time > 0 && rec_pipe_time > audioinfo->max_time) {
1368                 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, audioinfo->max_time);
1369
1370                 if (audioinfo->bMuxing)
1371                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1372                 else
1373                         MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1374
1375                 sc->isMaxtimePausing = TRUE;
1376                 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1377                 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1378
1379                 /* skip this buffer */
1380                 return GST_PAD_PROBE_DROP;
1381         }
1382
1383         /* send message for recording time and recorded file size */
1384         if (audioinfo->b_commiting == FALSE) {
1385                 audioinfo->filesize += buffer_size;
1386
1387                 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1388                 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1389                 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
1390                 msg.param.recording_status.remained_time = remained_time;
1391                 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1392
1393                 return GST_PAD_PROBE_OK;
1394         } else {
1395                 /* skip this buffer if commit process has been started */
1396                 return GST_PAD_PROBE_DROP;
1397         }
1398 }