[0.6.125] improve the complexity issue of gst_callback
[platform/core/multimedia/libmm-player.git] / src / mm_player_gst.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <dlog.h>
29 #include <mm_error.h>
30 #include <mm_attrs_private.h>
31
32 #include "mm_player_gst.h"
33 #include "mm_player_priv.h"
34 #include "mm_player_attrs.h"
35 #include "mm_player_utils.h"
36
37 /*===========================================================================================
38 |                                                                                                                                                                                       |
39 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
40 |                                                                                                                                                                                       |
41 ========================================================================================== */
42
43 /*---------------------------------------------------------------------------
44 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
45 ---------------------------------------------------------------------------*/
46
47 /*---------------------------------------------------------------------------
48 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
49 ---------------------------------------------------------------------------*/
50
51 /*---------------------------------------------------------------------------
52 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
53 ---------------------------------------------------------------------------*/
54
55 /*---------------------------------------------------------------------------
56 |    LOCAL #defines:                                                                                                            |
57 ---------------------------------------------------------------------------*/
58
59 /*---------------------------------------------------------------------------
60 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
61 ---------------------------------------------------------------------------*/
62
63 /*---------------------------------------------------------------------------
64 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
65 ---------------------------------------------------------------------------*/
66
67 /*---------------------------------------------------------------------------
68 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
69 ---------------------------------------------------------------------------*/
70
71 /*---------------------------------------------------------------------------
72 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
73 ---------------------------------------------------------------------------*/
74
75 /*---------------------------------------------------------------------------
76 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
77 ---------------------------------------------------------------------------*/
78
79 /*===========================================================================================
80 |                                                                                                                                                                                       |
81 |  FUNCTION DEFINITIONS                                                                                                                                         |
82 |                                                                                                                                                                                       |
83 ========================================================================================== */
84
85 /* NOTE : decide gstreamer state whether there is some playable track or not. */
86 static gint
87 __mmplayer_gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
88 {
89         gchar *src_element_name = NULL;
90         GstElement *src_element = NULL;
91         GstElementFactory *factory = NULL;
92         const gchar* klass = NULL;
93
94         MMPLAYER_FENTER();
95
96         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
97         MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
98         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
99         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
100                                                                 player->pipeline &&
101                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
102
103         src_element = GST_ELEMENT_CAST(message->src);
104         if (!src_element)
105                 goto INTERNAL_ERROR;
106
107         src_element_name = GST_ELEMENT_NAME(src_element);
108         if (!src_element_name)
109                 goto INTERNAL_ERROR;
110
111         factory = gst_element_get_factory(src_element);
112         if (!factory)
113                 goto INTERNAL_ERROR;
114
115         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
116         if (!klass)
117                 goto INTERNAL_ERROR;
118
119         LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
120                         error->code, error->message, src_element_name, klass);
121
122         /* check whether the error is posted from not-activated track or not */
123         if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
124                 int msg_src_pos = 0;
125                 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
126                 LOGD("current  active pad index  -%d", active_pad_index);
127
128                 if  (src_element_name) {
129                         int idx = 0;
130
131                         if (player->audio_decoders) {
132                                 GList *adec = player->audio_decoders;
133                                 for (; adec ; adec = g_list_next(adec)) {
134                                         gchar *name = adec->data;
135
136                                         LOGD("found audio decoder name  = %s", name);
137                                         if (g_strrstr(name, src_element_name)) {
138                                                 msg_src_pos = idx;
139                                                 break;
140                                         }
141                                         idx++;
142                                 }
143                         }
144                         LOGD("active pad = %d, error src index = %d", active_pad_index,  msg_src_pos);
145                 }
146
147                 if (active_pad_index != msg_src_pos) {
148                         LOGD("skip error because error is posted from no activated track");
149                         return MM_ERROR_NONE;
150                 }
151         }
152
153         switch (error->code) {
154         case GST_STREAM_ERROR_DECODE:
155         {
156                 /* Demuxer can't parse one track because it's corrupted.
157                  * So, the decoder for it is not linked.
158                  * But, it has one playable track.
159                  */
160                 if (g_strrstr(klass, "Demux")) {
161                         if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
162                                 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
163                         } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
164                                 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
165                         } else {
166                                 if (player->pipeline->audiobin) // PCM
167                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
168                                 else
169                                         goto CODEC_NOT_FOUND;
170                         }
171                 }
172                 return MM_ERROR_PLAYER_INVALID_STREAM;
173         }
174                 break;
175
176         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
177         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
178         case GST_STREAM_ERROR_WRONG_TYPE:
179         {
180                 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
181                         LOGE("Not supported subtitle.");
182                         return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
183                 }
184                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
185         }
186
187         case GST_STREAM_ERROR_FAILED:
188         {
189                 /* Decoder Custom Message */
190                 if (strstr(error->message, "ongoing")) {
191                         if (strncasecmp(klass, "audio", 5)) {
192                                 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
193                                         LOGD("Video can keep playing.\n");
194                                         return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
195                                 } else
196                                         goto CODEC_NOT_FOUND;
197
198                         } else if (strncasecmp(klass, "video", 5)) {
199                                 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
200                                         LOGD("Audio can keep playing.\n");
201                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
202                                 } else
203                                         goto CODEC_NOT_FOUND;
204                         }
205                 }
206                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
207         }
208                 break;
209
210         case GST_STREAM_ERROR_DECRYPT:
211         case GST_STREAM_ERROR_DECRYPT_NOKEY:
212         {
213                 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
214
215                 if (strstr(error->message, "rights expired"))
216                         return MM_ERROR_PLAYER_DRM_EXPIRED;
217                 else if (strstr(error->message, "no rights"))
218                         return MM_ERROR_PLAYER_DRM_NO_LICENSE;
219                 else if (strstr(error->message, "has future rights"))
220                         return MM_ERROR_PLAYER_DRM_FUTURE_USE;
221                 else if (strstr(error->message, "opl violation"))
222                         return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
223                 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
224         }
225                 break;
226
227         default:
228                 break;
229         }
230
231         MMPLAYER_FLEAVE();
232
233         return MM_ERROR_PLAYER_INVALID_STREAM;
234
235 INTERNAL_ERROR:
236         return MM_ERROR_PLAYER_INTERNAL;
237
238 CODEC_NOT_FOUND:
239         LOGD("not found any available codec. Player should be destroyed.\n");
240         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
241 }
242
243 gint
244 __mmplayer_gst_handle_core_error(mm_player_t* player, int code)
245 {
246         gint trans_err = MM_ERROR_NONE;
247
248         MMPLAYER_FENTER();
249
250         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
251
252         switch (code) {
253         case GST_CORE_ERROR_MISSING_PLUGIN:
254                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
255         case GST_CORE_ERROR_STATE_CHANGE:
256         case GST_CORE_ERROR_SEEK:
257         case GST_CORE_ERROR_NOT_IMPLEMENTED:
258         case GST_CORE_ERROR_FAILED:
259         case GST_CORE_ERROR_TOO_LAZY:
260         case GST_CORE_ERROR_PAD:
261         case GST_CORE_ERROR_THREAD:
262         case GST_CORE_ERROR_NEGOTIATION:
263         case GST_CORE_ERROR_EVENT:
264         case GST_CORE_ERROR_CAPS:
265         case GST_CORE_ERROR_TAG:
266         case GST_CORE_ERROR_CLOCK:
267         case GST_CORE_ERROR_DISABLED:
268         default:
269                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
270                 break;
271         }
272
273         MMPLAYER_FLEAVE();
274
275         return trans_err;
276 }
277
278 gint
279 __mmplayer_gst_handle_library_error(mm_player_t* player, int code)
280 {
281         gint trans_err = MM_ERROR_NONE;
282
283         MMPLAYER_FENTER();
284
285         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
286
287         switch (code) {
288         case GST_LIBRARY_ERROR_FAILED:
289         case GST_LIBRARY_ERROR_TOO_LAZY:
290         case GST_LIBRARY_ERROR_INIT:
291         case GST_LIBRARY_ERROR_SHUTDOWN:
292         case GST_LIBRARY_ERROR_SETTINGS:
293         case GST_LIBRARY_ERROR_ENCODE:
294         default:
295                 trans_err =  MM_ERROR_PLAYER_INVALID_STREAM;
296                 break;
297         }
298
299         MMPLAYER_FLEAVE();
300
301         return trans_err;
302 }
303
304 gint
305 __mmplayer_gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
306 {
307         gint trans_err = MM_ERROR_NONE;
308
309         MMPLAYER_FENTER();
310
311         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
312
313         switch (code) {
314         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
315                 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
316                 break;
317         case GST_RESOURCE_ERROR_NOT_FOUND:
318         case GST_RESOURCE_ERROR_OPEN_READ:
319                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
320                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
321                         trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
322                         break;
323                 }
324         case GST_RESOURCE_ERROR_READ:
325                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
326                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
327                         trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
328                         break;
329                 } else if (message != NULL && message->src != NULL) {
330                         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
331                         MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
332
333                         if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
334                                 path_type = MMPLAYER_PATH_VOD;
335                         else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
336                                 path_type = MMPLAYER_PATH_TEXT;
337
338                         if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
339                                 /* check storage state */
340                                 storage_get_state(player->storage_info[path_type].id, &storage_state);
341                                 player->storage_info[path_type].state = storage_state;
342                                 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
343                         }
344                 } /* fall through */
345         case GST_RESOURCE_ERROR_WRITE:
346         case GST_RESOURCE_ERROR_FAILED:
347         case GST_RESOURCE_ERROR_SEEK:
348         case GST_RESOURCE_ERROR_TOO_LAZY:
349         case GST_RESOURCE_ERROR_BUSY:
350         case GST_RESOURCE_ERROR_OPEN_WRITE:
351         case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
352         case GST_RESOURCE_ERROR_CLOSE:
353         case GST_RESOURCE_ERROR_SYNC:
354         case GST_RESOURCE_ERROR_SETTINGS:
355         default:
356                 trans_err = MM_ERROR_PLAYER_INTERNAL;
357         break;
358         }
359
360         MMPLAYER_FLEAVE();
361
362         return trans_err;
363 }
364
365 gint
366 __mmplayer_gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
367 {
368         gint trans_err = MM_ERROR_NONE;
369
370         MMPLAYER_FENTER();
371
372         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
373         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
374         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
375
376         switch (error->code) {
377         case GST_STREAM_ERROR_FAILED:
378         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
379         case GST_STREAM_ERROR_DECODE:
380         case GST_STREAM_ERROR_WRONG_TYPE:
381         case GST_STREAM_ERROR_DECRYPT:
382         case GST_STREAM_ERROR_DECRYPT_NOKEY:
383         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
384                 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
385                 break;
386
387         case GST_STREAM_ERROR_NOT_IMPLEMENTED:
388         case GST_STREAM_ERROR_TOO_LAZY:
389         case GST_STREAM_ERROR_ENCODE:
390         case GST_STREAM_ERROR_DEMUX:
391         case GST_STREAM_ERROR_MUX:
392         case GST_STREAM_ERROR_FORMAT:
393         default:
394                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
395                 break;
396         }
397
398         MMPLAYER_FLEAVE();
399
400         return trans_err;
401 }
402
403 gboolean
404 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
405 {
406         MMMessageParamType msg_param;
407         gchar *msg_src_element;
408
409         MMPLAYER_FENTER();
410
411         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
412         MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
413
414         /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
415
416         memset(&msg_param, 0, sizeof(MMMessageParamType));
417
418         if (error->domain == GST_CORE_ERROR) {
419                 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
420         } else if (error->domain == GST_LIBRARY_ERROR) {
421                 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
422         } else if (error->domain == GST_RESOURCE_ERROR) {
423                 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
424         } else if (error->domain == GST_STREAM_ERROR) {
425                 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
426         } else {
427                 LOGW("This error domain is not defined.\n");
428
429                 /* we treat system error as an internal error */
430                 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
431         }
432
433         if (message->src) {
434                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
435
436                 msg_param.data = (void *) error->message;
437
438                 LOGE("-Msg src : [%s]   Domain : [%s]   Error : [%s]  Code : [%d] is tranlated to error code : [0x%x]\n",
439                         msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
440         }
441
442         /* no error */
443         if (msg_param.code == MM_ERROR_NONE)
444                 return TRUE;
445
446         /* skip error to avoid duplicated posting */
447         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
448                  (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
449                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
450                  (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
451
452                 /* The error will be handled by mused.
453                  * @ref _mmplayer_manage_external_storage_state() */
454
455                 LOGW("storage is removed, skip error post");
456                 return TRUE;
457         }
458
459         /* post error to application */
460         if (!player->msg_posted) {
461                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
462                 /* don't post more if one was sent already */
463                 player->msg_posted = TRUE;
464         } else
465                 LOGD("skip error post because it's sent already.\n");
466
467         MMPLAYER_FLEAVE();
468
469         return TRUE;
470 }
471
472 static gboolean
473 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
474 {
475         LOGD("\n");
476         MMMessageParamType msg_param;
477         gchar *msg_src_element = NULL;
478         GstStructure *s = NULL;
479         guint error_id = 0;
480         gchar *error_string = NULL;
481
482         MMPLAYER_FENTER();
483
484         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
485         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
486
487         s = gst_structure_copy(gst_message_get_structure(message));
488
489
490         if (!gst_structure_get_uint(s, "error_id", &error_id))
491                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
492
493         switch (error_id) {
494         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
495                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
496                 break;
497         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
498                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
499                 break;
500         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
501                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
502                 break;
503         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
504                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
505                 break;
506         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
507                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
508                 break;
509         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
510                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
511                 break;
512         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
513                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
514                 break;
515         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
516                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
517                 break;
518         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
519                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
520                 break;
521         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
522                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
523                 break;
524         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
525                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
526                 break;
527         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
528                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
529                 break;
530         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
531                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
532                 break;
533         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
534                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
535                 break;
536         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
537                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
538                 break;
539         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
540                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
541                 break;
542         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
543                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
544                 break;
545         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
546                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
547                 break;
548         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
549                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
550                 break;
551         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
552                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
553                 break;
554         case MMPLAYER_STREAMING_ERROR_GONE:
555                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
556                 break;
557         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
558                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
559                 break;
560         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
561                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
562                 break;
563         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
564                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
565                 break;
566         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
567                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
568                 break;
569         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
570                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
571                 break;
572         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
573                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
574                 break;
575         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
576                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
577                 break;
578         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
579                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
580                 break;
581         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
582                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
583                 break;
584         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
585                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
586                 break;
587         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
588                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
589                 break;
590         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
591                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
592                 break;
593         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
594                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
595                 break;
596         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
597                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
598                 break;
599         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
600                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
601                 break;
602         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
603                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
604                 break;
605         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
606                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
607                 break;
608         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
609                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
610                 break;
611         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
612                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
613                 break;
614         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
615                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
616                 break;
617         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
618                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
619                 break;
620         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
621                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
622                 break;
623         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
624                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
625                 break;
626         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
627                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
628                 break;
629         default:
630                 {
631                         gst_structure_free(s);
632                         return MM_ERROR_PLAYER_STREAMING_FAIL;
633                 }
634         }
635
636         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
637         if (error_string)
638                 msg_param.data = (void *) error_string;
639
640         if (message->src) {
641                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
642
643                 LOGE("-Msg src : [%s] Code : [%x] Error : [%s]  \n",
644                         msg_src_element, msg_param.code, (char*)msg_param.data);
645         }
646
647         /* post error to application */
648         if (!player->msg_posted) {
649                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
650
651                 /* don't post more if one was sent already */
652                 player->msg_posted = TRUE;
653         } else
654                 LOGD("skip error post because it's sent already.\n");
655
656         gst_structure_free(s);
657         g_free(error_string);
658
659         MMPLAYER_FLEAVE();
660         return TRUE;
661
662 }
663
664 static void
665 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata)
666 {
667         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
668         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
669         gst_tag_list_get_string(tags, "stitching_software",
670                         &metadata->stitching_software);
671         gst_tag_list_get_string(tags, "projection_type",
672                         &metadata->projection_type_string);
673         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
674         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
675         gst_tag_list_get_int(tags, "init_view_heading",
676                         &metadata->init_view_heading);
677         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
678         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
679         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
680         gst_tag_list_get_int(tags, "full_pano_width_pixels",
681                         &metadata->full_pano_width_pixels);
682         gst_tag_list_get_int(tags, "full_pano_height_pixels",
683                         &metadata->full_pano_height_pixels);
684         gst_tag_list_get_int(tags, "cropped_area_image_width",
685                         &metadata->cropped_area_image_width);
686         gst_tag_list_get_int(tags, "cropped_area_image_height",
687                         &metadata->cropped_area_image_height);
688         gst_tag_list_get_int(tags, "cropped_area_left",
689                         &metadata->cropped_area_left);
690         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
691         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
692         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
693         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
694 }
695
696 static gboolean
697 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
698 {
699
700 /* macro for better code readability */
701 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
702 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
703         if (string != NULL) { \
704                 SECURE_LOGD("update tag string : %s\n", string); \
705                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
706                         char *new_string = malloc(MM_MAX_STRING_LENGTH); \
707                         strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
708                         new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
709                         mm_attrs_set_string_by_name(attribute, playertag, new_string); \
710                         g_free(new_string); \
711                         new_string = NULL; \
712                 } else { \
713                         mm_attrs_set_string_by_name(attribute, playertag, string); \
714                 } \
715                 g_free(string); \
716                 string = NULL; \
717         } \
718 }
719
720 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
721 do {    \
722         GstSample *sample = NULL;\
723         if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
724                 GstMapInfo info = GST_MAP_INFO_INIT;\
725                 buffer = gst_sample_get_buffer(sample);\
726                 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
727                         LOGD("failed to get image data from tag");\
728                         gst_sample_unref(sample);\
729                         return FALSE;\
730                 } \
731                 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
732                 MMPLAYER_FREEIF(player->album_art);\
733                 player->album_art = (gchar *)g_malloc(info.size);\
734                 if (player->album_art) {\
735                         memcpy(player->album_art, info.data, info.size);\
736                         mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
737                         if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
738                                 msg_param.data = (void *)player->album_art;\
739                                 msg_param.size = info.size;\
740                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
741                                 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
742                         } \
743                 } \
744                 gst_buffer_unmap(buffer, &info);\
745                 gst_sample_unref(sample);\
746         }       \
747 } while (0)
748
749 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
750 do {    \
751         if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
752                 if (v_uint) { \
753                         int i = 0; \
754                         gchar *tag_list_str = NULL; \
755                         MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
756                         if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
757                                 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
758                         else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
759                                 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
760                         else \
761                                 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
762                         if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
763                                 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
764                                         mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
765                                 player->bitrate[track_type] = v_uint; \
766                                 player->total_bitrate = 0; \
767                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
768                                         player->total_bitrate += player->bitrate[i]; \
769                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
770                                 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
771                         } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
772                                 player->maximum_bitrate[track_type] = v_uint; \
773                                 player->total_maximum_bitrate = 0; \
774                                 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
775                                         player->total_maximum_bitrate += player->maximum_bitrate[i]; \
776                                 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
777                                 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
778                         } else { \
779                                 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
780                         } \
781                         v_uint = 0;\
782                         g_free(tag_list_str); \
783                 } \
784         } \
785 } while (0)
786
787 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
788 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
789         if (date != NULL) {\
790                 string = g_strdup_printf("%d", g_date_get_year(date));\
791                 mm_attrs_set_string_by_name(attribute, playertag, string);\
792                 SECURE_LOGD("metainfo year : %s\n", string);\
793                 MMPLAYER_FREEIF(string);\
794                 g_date_free(date);\
795         } \
796 }
797
798 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
799 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
800         if (datetime != NULL) {\
801                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
802                 mm_attrs_set_string_by_name(attribute, playertag, string);\
803                 SECURE_LOGD("metainfo year : %s\n", string);\
804                 MMPLAYER_FREEIF(string);\
805                 gst_date_time_unref(datetime);\
806         } \
807 }
808
809 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
810 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
811         if (v_uint64) {\
812                 /* FIXIT : don't know how to store date */\
813                 g_assert(1);\
814                 v_uint64 = 0;\
815         } \
816 }
817
818 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
819 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
820         if (v_double) {\
821                 /* FIXIT : don't know how to store date */\
822                 g_assert(1);\
823                 v_double = 0;\
824         } \
825 }
826
827         /* function start */
828         GstTagList* tag_list = NULL;
829
830         MMHandleType attrs = 0;
831
832         char *string = NULL;
833         guint v_uint = 0;
834         GDate *date = NULL;
835         GstDateTime *datetime = NULL;
836         /* album cover */
837         GstBuffer *buffer = NULL;
838         gint index = 0;
839         MMMessageParamType msg_param = {0, };
840
841         /* currently not used. but those are needed for above macro */
842         //guint64 v_uint64 = 0;
843         //gdouble v_double = 0;
844
845         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
846
847         attrs = MMPLAYER_GET_ATTRS(player);
848
849         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
850
851         /* get tag list from gst message */
852         gst_message_parse_tag(msg, &tag_list);
853
854         /* store tags to player attributes */
855         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
856         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
857         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
858         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
859         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
860         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
861         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
862         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
863         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
864         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
865         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
866         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
867         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
868         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
869         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
870         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
871         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
872         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
873         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
874         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
875         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
876         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
877         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
878         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
879         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
880         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
881         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
882         /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
883         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
884         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
885         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
886         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
887         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
888         MMPLAYER_UPDATE_TAG_LOCK(player);
889         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
890         MMPLAYER_UPDATE_TAG_UNLOCK(player);
891         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
892         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
893         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
894         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
895         /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
896         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
897         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
898         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
899         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
900         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
901         /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
902         /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
903         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
904
905         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
906                 if (player->video360_metadata.is_spherical == -1) {
907                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
908                         mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
909                                         player->video360_metadata.is_spherical);
910                         if (player->video360_metadata.is_spherical == 1) {
911                                 LOGD("This is spherical content for 360 playback.");
912                                 player->is_content_spherical = TRUE;
913                         } else {
914                                 LOGD("This is not spherical content");
915                                 player->is_content_spherical = FALSE;
916                         }
917
918                         if (player->video360_metadata.projection_type_string) {
919                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
920                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
921                                 } else {
922                                         LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
923                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
924                                 }
925                         }
926
927                         if (player->video360_metadata.stereo_mode_string) {
928                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
929                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
930                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
931                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
932                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
933                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
934                                 } else {
935                                         LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
936                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
937                                 }
938                         }
939                 }
940         }
941
942         if (mmf_attrs_commit(attrs))
943                 LOGE("failed to commit.\n");
944
945         gst_tag_list_free(tag_list);
946
947         return TRUE;
948 }
949
950 /* if retval is FALSE, it will be dropped for perfomance. */
951 static gboolean
952 __mmplayer_gst_check_useful_message(mm_player_t *player, GstMessage * message)
953 {
954         gboolean retval = FALSE;
955
956         if (!(player->pipeline && player->pipeline->mainbin)) {
957                 LOGE("player pipeline handle is null");
958                 return TRUE;
959         }
960
961         switch (GST_MESSAGE_TYPE(message)) {
962         case GST_MESSAGE_TAG:
963         case GST_MESSAGE_EOS:
964         case GST_MESSAGE_ERROR:
965         case GST_MESSAGE_WARNING:
966         case GST_MESSAGE_CLOCK_LOST:
967         case GST_MESSAGE_NEW_CLOCK:
968         case GST_MESSAGE_ELEMENT:
969         case GST_MESSAGE_DURATION_CHANGED:
970         case GST_MESSAGE_ASYNC_START:
971                 retval = TRUE;
972                 break;
973         case GST_MESSAGE_ASYNC_DONE:
974         case GST_MESSAGE_STATE_CHANGED:
975                 /* we only handle messages from pipeline */
976                 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
977                         retval = TRUE;
978                 else
979                         retval = FALSE;
980                 break;
981         case GST_MESSAGE_BUFFERING:
982         {
983                 gint buffer_percent = 0;
984
985                 retval = TRUE;
986                 gst_message_parse_buffering(message, &buffer_percent);
987                 if (buffer_percent != MAX_BUFFER_PERCENT) {
988                         LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
989                         break;
990                 }
991
992                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
993                         LOGW("can't get cmd lock, send msg to bus");
994                         break;
995                 }
996
997                 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
998                         LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
999                         player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1000                 }
1001
1002                 MMPLAYER_CMD_UNLOCK(player);
1003
1004                 break;
1005         }
1006         default:
1007                 retval = FALSE;
1008                 break;
1009         }
1010
1011         return retval;
1012 }
1013
1014 static void
1015 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
1016 {
1017         MMHandleType attrs = 0;
1018         guint64 data_size = 0;
1019         gchar* path = NULL;
1020         gint64 pos_nsec = 0;
1021         struct stat sb;
1022
1023         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1024
1025         __mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec);      /* to update player->last_position */
1026
1027         attrs = MMPLAYER_GET_ATTRS(player);
1028         if (!attrs) {
1029                 LOGE("fail to get attributes.\n");
1030                 return;
1031         }
1032
1033         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
1034                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
1035
1036                 if (stat(path, &sb) == 0)
1037                         data_size = (guint64)sb.st_size;
1038         } else if (MMPLAYER_IS_HTTP_STREAMING(player))
1039                 data_size = player->http_content_size;
1040
1041         __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1042         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1043
1044         return;
1045 }
1046
1047 static int
1048 __mmplayer_handle_buffering_playback(mm_player_t* player)
1049 {
1050         int ret = MM_ERROR_NONE;
1051         MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
1052         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1053         MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
1054         MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
1055
1056         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1057                 LOGW("do nothing for buffering msg\n");
1058                 ret = MM_ERROR_PLAYER_INVALID_STATE;
1059                 goto exit;
1060         }
1061
1062         prev_state = MMPLAYER_PREV_STATE(player);
1063         current_state = MMPLAYER_CURRENT_STATE(player);
1064         target_state = MMPLAYER_TARGET_STATE(player);
1065         pending_state = MMPLAYER_PENDING_STATE(player);
1066
1067         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1068                 MMPLAYER_STATE_GET_NAME(prev_state),
1069                 MMPLAYER_STATE_GET_NAME(current_state),
1070                 MMPLAYER_STATE_GET_NAME(pending_state),
1071                 MMPLAYER_STATE_GET_NAME(target_state),
1072                 player->streamer->buffering_state);
1073
1074         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1075                 /* NOTE : if buffering has done, player has to go to target state. */
1076                 switch (target_state) {
1077                 case MM_PLAYER_STATE_PAUSED:
1078                         {
1079                                 switch (pending_state) {
1080                                 case MM_PLAYER_STATE_PLAYING:
1081                                         __mmplayer_gst_pause(player, TRUE);
1082                                         break;
1083
1084                                 case MM_PLAYER_STATE_PAUSED:
1085                                         LOGD("player is already going to paused state, there is nothing to do.\n");
1086                                         break;
1087
1088                                 case MM_PLAYER_STATE_NONE:
1089                                 case MM_PLAYER_STATE_NULL:
1090                                 case MM_PLAYER_STATE_READY:
1091                                 default:
1092                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1093                                         break;
1094                                 }
1095                         }
1096                         break;
1097
1098                 case MM_PLAYER_STATE_PLAYING:
1099                         {
1100                                 switch (pending_state) {
1101                                 case MM_PLAYER_STATE_NONE:
1102                                         {
1103                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1104                                                         __mmplayer_gst_resume(player, TRUE);
1105                                         }
1106                                         break;
1107
1108                                 case MM_PLAYER_STATE_PAUSED:
1109                                         /* NOTE: It should be worked as asynchronously.
1110                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1111                                          */
1112                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
1113                                                 /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet.
1114                                                  * The current state should be changed to paused purposely to prevent state conflict.
1115                                                  */
1116                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1117                                         }
1118                                         __mmplayer_gst_resume(player, TRUE);
1119                                         break;
1120
1121                                 case MM_PLAYER_STATE_PLAYING:
1122                                         LOGD("player is already going to playing state, there is nothing to do.\n");
1123                                         break;
1124
1125                                 case MM_PLAYER_STATE_NULL:
1126                                 case MM_PLAYER_STATE_READY:
1127                                 default:
1128                                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1129                                         break;
1130                                 }
1131                         }
1132                         break;
1133
1134                 case MM_PLAYER_STATE_NULL:
1135                 case MM_PLAYER_STATE_READY:
1136                 case MM_PLAYER_STATE_NONE:
1137                 default:
1138                         LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
1139                         break;
1140                 }
1141         } else {
1142                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1143                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1144                  */
1145                 switch (pending_state) {
1146                 case MM_PLAYER_STATE_NONE:
1147                         {
1148                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1149                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1150                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1151                                                 LOGD("set pause state during buffering\n");
1152                                                 __mmplayer_gst_pause(player, TRUE);
1153                                         }
1154                                 }
1155                         }
1156                         break;
1157
1158                 case MM_PLAYER_STATE_PLAYING:
1159                         /* rtsp streaming pause makes rtsp server stop sending data. */
1160                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
1161                                 __mmplayer_gst_pause(player, TRUE);
1162                         break;
1163
1164                 case MM_PLAYER_STATE_PAUSED:
1165                         break;
1166
1167                 case MM_PLAYER_STATE_NULL:
1168                 case MM_PLAYER_STATE_READY:
1169                 default:
1170                         LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
1171                         break;
1172                 }
1173         }
1174
1175 exit:
1176         return ret;
1177 }
1178
1179 static VariantData *
1180 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
1181 {
1182         VariantData *var_info = NULL;
1183         g_return_val_if_fail(self != NULL, NULL);
1184
1185         var_info = g_new0(VariantData, 1);
1186         if (!var_info) return NULL;
1187         var_info->bandwidth = self->bandwidth;
1188         var_info->width = self->width;
1189         var_info->height = self->height;
1190         return var_info;
1191 }
1192
1193 static gboolean
1194 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1195 {
1196         gint64 bytes = 0;
1197
1198         MMPLAYER_FENTER();
1199
1200         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1201         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1202
1203         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1204                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1205                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1206
1207                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1208                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1209                         player->http_content_size = (bytes > 0) ? (bytes) : (0);
1210                 }
1211         } else {
1212                 /* handling audio clip which has vbr. means duration is keep changing */
1213                 __mmplayer_update_content_attrs(player, ATTR_DURATION);
1214         }
1215
1216         MMPLAYER_FLEAVE();
1217
1218         return TRUE;
1219 }
1220
1221 static gboolean
1222 __mmplayer_eos_timer_cb(gpointer u_data)
1223 {
1224         mm_player_t* player = NULL;
1225         MMHandleType attrs = 0;
1226         int count = 0;
1227
1228         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1229
1230         player = (mm_player_t*) u_data;
1231         attrs = MMPLAYER_GET_ATTRS(player);
1232
1233         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1234
1235         if (count == -1) {
1236                 gint ret_value = 0;
1237                 ret_value = __mmplayer_gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
1238                 if (ret_value != MM_ERROR_NONE)
1239                         LOGE("seeking to 0 failed in repeat play");
1240         } else {
1241                 /* posting eos */
1242                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1243         }
1244
1245         /* we are returning FALSE as we need only one posting */
1246         return FALSE;
1247 }
1248
1249 static void
1250 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
1251 {
1252         MMPLAYER_RETURN_IF_FAIL(player);
1253
1254         /* post now if delay is zero */
1255         if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
1256                 LOGD("eos delay is zero. posting EOS now\n");
1257                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1258
1259                 if (player->set_mode.pcm_extraction)
1260                         __mmplayer_cancel_eos_timer(player);
1261
1262                 return;
1263         }
1264
1265         /* cancel if existing */
1266         __mmplayer_cancel_eos_timer(player);
1267
1268         /* init new timeout */
1269         /* NOTE : consider give high priority to this timer */
1270         LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
1271
1272         player->eos_timer = g_timeout_add(delay_in_ms,
1273                 __mmplayer_eos_timer_cb, player);
1274
1275         player->context.global_default = g_main_context_default();
1276         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1277
1278         /* check timer is valid. if not, send EOS now */
1279         if (player->eos_timer == 0) {
1280                 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
1281                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1282         }
1283 }
1284
1285 static int __mmplayer_gst_pending_seek(mm_player_t* player)
1286 {
1287         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
1288         int ret = MM_ERROR_NONE;
1289
1290         MMPLAYER_FENTER();
1291
1292         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1293
1294         if (!player->pending_seek.is_pending) {
1295                 LOGD("pending seek is not reserved. nothing to do.\n");
1296                 return ret;
1297         }
1298
1299         /* check player state if player could pending seek or not. */
1300         current_state = MMPLAYER_CURRENT_STATE(player);
1301
1302         if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
1303                 LOGW("try to pending seek in %s state, try next time. \n",
1304                         MMPLAYER_STATE_GET_NAME(current_state));
1305                 return ret;
1306         }
1307
1308         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1309
1310         ret = __mmplayer_gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
1311
1312         if (MM_ERROR_NONE != ret)
1313                 LOGE("failed to seek pending postion. just keep staying current position.\n");
1314
1315         player->pending_seek.is_pending = FALSE;
1316
1317         MMPLAYER_FLEAVE();
1318
1319         return ret;
1320 }
1321
1322 static void
1323 __mmplayer_gst_handle_async(mm_player_t* player, gboolean async, enum MMPlayerSinkType type)
1324 {
1325         MMPlayerGstElement *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1326
1327         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1328
1329         audiobin = player->pipeline->audiobin; /* can be null */
1330         videobin = player->pipeline->videobin; /* can be null */
1331         textbin = player->pipeline->textbin;   /* can be null */
1332
1333         LOGD("Async will be set to %d about 0x%X type sink", async, type);
1334
1335         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1336                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1337
1338         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1339                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1340
1341         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1342                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1343
1344         return;
1345 }
1346
1347 static void
1348 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
1349 {
1350         MMPlayerGstElement *textbin;
1351         MMPLAYER_FENTER();
1352
1353         MMPLAYER_RETURN_IF_FAIL(player &&
1354                                         player->pipeline &&
1355                                         player->pipeline->textbin);
1356
1357         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1358
1359         textbin = player->pipeline->textbin;
1360
1361         if (is_drop) {
1362                 LOGD("Drop subtitle text after getting EOS\n");
1363
1364                 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_TEXT_SINK);
1365                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1366
1367                 player->is_subtitle_force_drop = TRUE;
1368         } else {
1369                 if (player->is_subtitle_force_drop == TRUE) {
1370                         LOGD("Enable subtitle data path without drop\n");
1371
1372                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1373                         __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_TEXT_SINK);
1374
1375                         LOGD("non-connected with external display");
1376
1377                         player->is_subtitle_force_drop = FALSE;
1378                 }
1379         }
1380 }
1381
1382 static void
1383 __mmplayer_gst_handle_eos_message(mm_player_t* player, GstMessage *msg)
1384 {
1385         MMHandleType attrs = 0;
1386         gint count = 0;
1387
1388         MMPLAYER_FENTER();
1389
1390         /* NOTE : EOS event is comming multiple time. watch out it */
1391         /* check state. we only process EOS when pipeline state goes to PLAYING */
1392         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1393                 LOGD("EOS received on non-playing state. ignoring it");
1394                 return;
1395         }
1396
1397         if (player->pipeline) {
1398                 if (player->pipeline->textbin)
1399                         __mmplayer_drop_subtitle(player, TRUE);
1400
1401                 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1402                         GstPad *pad = NULL;
1403
1404                         pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1405
1406                         LOGD("release audio callback");
1407
1408                         /* release audio callback */
1409                         gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1410                         player->audio_cb_probe_id = 0;
1411                         /* audio callback should be free because it can be called even though probe remove.*/
1412                         player->audio_stream_cb = NULL;
1413                         player->audio_stream_cb_user_param = NULL;
1414
1415                 }
1416         }
1417         if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1418                 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1419
1420         /* rewind if repeat count is greater then zero */
1421         /* get play count */
1422         attrs = MMPLAYER_GET_ATTRS(player);
1423
1424         if (attrs) {
1425                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1426
1427                 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1428
1429                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1430                         if (player->playback_rate < 0.0) {
1431                                 player->resumed_by_rewind = TRUE;
1432                                 _mmplayer_set_mute((MMHandleType)player, 0);
1433                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1434                         }
1435
1436                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1437
1438                         /* initialize */
1439                         player->sent_bos = FALSE;
1440
1441                         LOGD("do not post eos msg for repeating");
1442                         return;
1443                 }
1444         }
1445
1446         if (player->pipeline)
1447                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1448
1449         /* post eos message to application */
1450         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1451
1452         /* reset last position */
1453         player->last_position = 0;
1454
1455         MMPLAYER_FLEAVE();
1456         return;
1457 }
1458
1459 static void
1460 __mmplayer_gst_handle_error_message(mm_player_t* player, GstMessage *msg)
1461 {
1462         GError *error = NULL;
1463         gchar* debug = NULL;
1464
1465         MMPLAYER_FENTER();
1466
1467         /* generating debug info before returning error */
1468         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1469
1470         /* get error code */
1471         gst_message_parse_error(msg, &error, &debug);
1472
1473         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1474                 /* Note : the streaming error from the streaming source is handled
1475                  *       using __mmplayer_handle_streaming_error.
1476                  */
1477                 __mmplayer_handle_streaming_error(player, msg);
1478
1479                 /* dump state of all element */
1480                 __mmplayer_dump_pipeline_state(player);
1481         } else {
1482                 /* traslate gst error code to msl error code. then post it
1483                  * to application if needed
1484                  */
1485                 __mmplayer_handle_gst_error(player, msg, error);
1486
1487                 if (debug)
1488                         LOGE("error debug : %s", debug);
1489         }
1490
1491         if (MMPLAYER_IS_HTTP_PD(player))
1492                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1493
1494         MMPLAYER_FREEIF(debug);
1495         g_error_free(error);
1496
1497         MMPLAYER_FLEAVE();
1498         return;
1499 }
1500
1501 static void
1502 __mmplayer_gst_handle_buffering_message(mm_player_t* player, GstMessage *msg)
1503 {
1504         MMMessageParamType msg_param = {0, };
1505         int bRet = MM_ERROR_NONE;
1506
1507         MMPLAYER_FENTER();
1508         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1509
1510         if (!MMPLAYER_IS_STREAMING(player)) {
1511                 LOGW("this is not streaming playback.");
1512                 return;
1513         }
1514
1515         if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1516                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1517                         /* skip the playback control by buffering msg while user request is handled. */
1518                         gint per = 0;
1519
1520                         LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1521
1522                         gst_message_parse_buffering(msg, &per);
1523                         LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1524
1525                         msg_param.connection.buffering = per;
1526                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1527                         return;
1528                 }
1529         } else {
1530                 MMPLAYER_CMD_LOCK(player);
1531         }
1532
1533         if (!player->streamer) {
1534                 LOGW("Pipeline is shutting down");
1535                 MMPLAYER_CMD_UNLOCK(player);
1536                 return;
1537         }
1538
1539         /* ignore the remained buffering message till getting 100% msg */
1540         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1541                 gint buffer_percent = 0;
1542
1543                 gst_message_parse_buffering(msg, &buffer_percent);
1544
1545                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1546                         LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1547                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1548                 }
1549                 MMPLAYER_CMD_UNLOCK(player);
1550                 return;
1551         }
1552
1553         /* ignore the remained buffering message */
1554         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1555                 gint buffer_percent = 0;
1556
1557                 gst_message_parse_buffering(msg, &buffer_percent);
1558
1559                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1560                                         player->streamer->buffering_percent, buffer_percent);
1561
1562                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1563                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1564                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1565
1566                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1567                 } else {
1568                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1569                         MMPLAYER_CMD_UNLOCK(player);
1570                         return;
1571                 }
1572         }
1573
1574         __mmplayer_update_buffer_setting(player, msg);
1575
1576         bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1577
1578         if (bRet == MM_ERROR_NONE) {
1579                 msg_param.connection.buffering = player->streamer->buffering_percent;
1580                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1581
1582                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1583                         player->pending_resume &&
1584                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1585
1586                         player->is_external_subtitle_added_now = FALSE;
1587                         player->pending_resume = FALSE;
1588                         _mmplayer_resume((MMHandleType)player);
1589                 }
1590
1591                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1592                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1593
1594                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1595                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1596                                         player->seek_state = MMPLAYER_SEEK_NONE;
1597                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1598                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1599                                         /* Considering the async state trasition in case of RTSP.
1600                                            After getting state change gst msg, seek cmpleted msg will be posted. */
1601                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1602                                 }
1603                         }
1604                 }
1605         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1606                 if (!player->streamer) {
1607                         LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1608                         MMPLAYER_CMD_UNLOCK(player);
1609                         return;
1610                 }
1611
1612                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1613
1614                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1615                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1616
1617                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1618                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1619                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1620                         } else {
1621                                 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1622                         }
1623                 } else {
1624                         msg_param.connection.buffering = player->streamer->buffering_percent;
1625                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1626                 }
1627         }
1628         MMPLAYER_CMD_UNLOCK(player);
1629
1630         MMPLAYER_FLEAVE();
1631         return;
1632
1633 }
1634
1635 static void
1636 __mmplayer_gst_handle_state_message(mm_player_t* player, GstMessage *msg)
1637 {
1638         MMPlayerGstElement *mainbin;
1639         const GValue *voldstate, *vnewstate, *vpending;
1640         GstState oldstate = GST_STATE_NULL;
1641         GstState newstate = GST_STATE_NULL;
1642         GstState pending = GST_STATE_NULL;
1643
1644         MMPLAYER_FENTER();
1645         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1646
1647         mainbin = player->pipeline->mainbin;
1648
1649         /* we only handle messages from pipeline */
1650         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1651                 return;
1652
1653         /* get state info from msg */
1654         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1655         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1656         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1657
1658         if (!voldstate || !vnewstate) {
1659                 LOGE("received msg has wrong format.");
1660                 return;
1661         }
1662
1663         oldstate = (GstState)voldstate->data[0].v_int;
1664         newstate = (GstState)vnewstate->data[0].v_int;
1665         if (vpending)
1666                 pending = (GstState)vpending->data[0].v_int;
1667
1668         LOGD("state changed [%s] : %s ---> %s     final : %s",
1669                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1670                 gst_element_state_get_name((GstState)oldstate),
1671                 gst_element_state_get_name((GstState)newstate),
1672                 gst_element_state_get_name((GstState)pending));
1673
1674         if (newstate == GST_STATE_PLAYING) {
1675                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1676
1677                         int retVal = MM_ERROR_NONE;
1678                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1679
1680                         retVal = __mmplayer_gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1681
1682                         if (MM_ERROR_NONE != retVal)
1683                                 LOGE("failed to seek pending postion. just keep staying current position.");
1684
1685                         player->pending_seek.is_pending = FALSE;
1686                 }
1687         }
1688
1689         if (oldstate == newstate) {
1690                 LOGD("pipeline reports state transition to old state");
1691                 return;
1692         }
1693
1694         switch (newstate) {
1695         case GST_STATE_PAUSED:
1696                 {
1697                         gboolean prepare_async = FALSE;
1698
1699                         if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1700                                 __mmplayer_configure_audio_callback(player);
1701
1702                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1703                                 // managed prepare async case
1704                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1705                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1706                         }
1707
1708                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1709                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1710
1711                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1712                                         __mm_player_streaming_set_content_bitrate(player->streamer,
1713                                                 player->total_maximum_bitrate, player->total_bitrate);
1714
1715                                 if (player->pending_seek.is_pending) {
1716                                         LOGW("trying to do pending seek");
1717                                         MMPLAYER_CMD_LOCK(player);
1718                                         __mmplayer_gst_pending_seek(player);
1719                                         MMPLAYER_CMD_UNLOCK(player);
1720                                 }
1721                         }
1722                 }
1723                 break;
1724
1725         case GST_STATE_PLAYING:
1726                 {
1727                         if (MMPLAYER_IS_STREAMING(player)) {
1728                                 // managed prepare async case when buffering is completed
1729                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1730                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1731                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1732                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1733
1734                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1735
1736                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1737                                         if (player->streamer->buffering_percent < 100) {
1738
1739                                                 MMMessageParamType msg_param = {0, };
1740                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1741
1742                                                 msg_param.connection.buffering = 100;
1743                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1744                                         }
1745                                 }
1746                         }
1747
1748                         if (player->gapless.stream_changed) {
1749                                 __mmplayer_update_content_attrs(player, ATTR_ALL);
1750                                 player->gapless.stream_changed = FALSE;
1751                         }
1752
1753                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1754                                 player->seek_state = MMPLAYER_SEEK_NONE;
1755                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1756                         }
1757                 }
1758                 break;
1759         case GST_STATE_VOID_PENDING:
1760         case GST_STATE_NULL:
1761         case GST_STATE_READY:
1762         default:
1763                 break;
1764         }
1765
1766         MMPLAYER_FLEAVE();
1767         return;
1768 }
1769
1770 static void
1771 __mmplayer_gst_handle_element_message(mm_player_t* player, GstMessage *msg)
1772 {
1773         const gchar *structure_name;
1774         gint count = 0, idx = 0;
1775         MMHandleType attrs = 0;
1776
1777         MMPLAYER_FENTER();
1778         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1779
1780         attrs = MMPLAYER_GET_ATTRS(player);
1781         if (!attrs) {
1782                 LOGE("Failed to get content attribute");
1783                 return;
1784         }
1785
1786         if (gst_message_get_structure(msg) == NULL)
1787                 return;
1788
1789         structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1790         if (!structure_name)
1791                 return;
1792
1793         LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1794
1795         if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1796                 const GValue *var_info = NULL;
1797
1798                 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1799                 if (var_info != NULL) {
1800                         if (player->adaptive_info.var_list)
1801                                 g_list_free_full(player->adaptive_info.var_list, g_free);
1802
1803                         /* share addr or copy the list */
1804                         player->adaptive_info.var_list =
1805                                 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1806
1807                         count = g_list_length(player->adaptive_info.var_list);
1808                         if (count > 0) {
1809                                 VariantData *temp = NULL;
1810
1811                                 /* print out for debug */
1812                                 LOGD("num of variant_info %d", count);
1813                                 for (idx = 0; idx < count; idx++) {
1814                                         temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1815                                         if (temp)
1816                                                 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1817                                 }
1818                         }
1819                 }
1820         }
1821
1822         if (!strcmp(structure_name, "prepare-decode-buffers")) {
1823                 gint num_buffers = 0;
1824                 gint extra_num_buffers = 0;
1825
1826                 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1827                         player->video_num_buffers = num_buffers;
1828                         LOGD("video_num_buffers : %d", player->video_num_buffers);
1829                 }
1830
1831                 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1832                         player->video_extra_num_buffers = extra_num_buffers;
1833                         LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1834                 }
1835                 return;
1836         }
1837
1838         if (!strcmp(structure_name, "Language_list")) {
1839                 const GValue *lang_list = NULL;
1840                 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1841                 if (lang_list != NULL) {
1842                         count = g_list_length((GList *)g_value_get_pointer(lang_list));
1843                         if (count > 1)
1844                                 LOGD("Total audio tracks(from parser) = %d \n", count);
1845                 }
1846         }
1847
1848         if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1849                 const GValue *lang_list = NULL;
1850                 MMPlayerLangStruct *temp = NULL;
1851
1852                 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1853                 if (lang_list != NULL) {
1854                         count = g_list_length((GList *)g_value_get_pointer(lang_list));
1855                         if (count) {
1856                                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1857                                 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1858                                 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1859                                 if (mmf_attrs_commit(attrs))
1860                                         LOGE("failed to commit.\n");
1861                                 LOGD("Total subtitle tracks = %d \n", count);
1862
1863                                 while (count) {
1864                                         temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1865                                         if (temp)
1866                                                 LOGD("value of lang_key is %s and lang_code is %s",
1867                                                                         temp->language_key, temp->language_code);
1868                                         count--;
1869                                 }
1870                                 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1871                                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1872                         }
1873                 }
1874         }
1875
1876         /* custom message */
1877         if (!strcmp(structure_name, "audio_codec_not_supported")) {
1878                 MMMessageParamType msg_param = {0,};
1879                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1880                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1881         }
1882
1883         /* custom message for RTSP attribute :
1884                 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1885                 sdp which has contents info is received when rtsp connection is opened.
1886                 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1887         if (!strcmp(structure_name, "rtspsrc_properties")) {
1888
1889                 gchar *audio_codec = NULL;
1890                 gchar *video_codec = NULL;
1891                 gchar *video_frame_size = NULL;
1892
1893                 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1894                 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1895                 player->streaming_type = __mmplayer_get_stream_service_type(player);
1896
1897                 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1898                 LOGD("rtsp_audio_codec : %s", audio_codec);
1899                 if (audio_codec)
1900                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1901
1902                 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1903                 LOGD("rtsp_video_codec : %s", video_codec);
1904                 if (video_codec)
1905                         mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1906
1907                 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1908                 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1909                 if (video_frame_size) {
1910
1911                         char *seperator = strchr(video_frame_size, '-');
1912                         if (seperator) {
1913
1914                                 char video_width[10] = {0,};
1915                                 int frame_size_len = strlen(video_frame_size);
1916                                 int separtor_len = strlen(seperator);
1917
1918                                 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1919                                 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1920
1921                                 seperator++;
1922                                 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1923                         }
1924                 }
1925
1926                 if (mmf_attrs_commit(attrs))
1927                         LOGE("failed to commit.\n");
1928         }
1929
1930         MMPLAYER_FLEAVE();
1931         return;
1932 }
1933
1934 static void
1935 __mmplayer_gst_handle_async_done_message(mm_player_t* player, GstMessage *msg)
1936 {
1937         MMPlayerGstElement *mainbin;
1938
1939         MMPLAYER_FENTER();
1940         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1941
1942         mainbin = player->pipeline->mainbin;
1943
1944         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1945
1946         /* we only handle messages from pipeline */
1947         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1948                 return;
1949
1950         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1951                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1952                         player->seek_state = MMPLAYER_SEEK_NONE;
1953                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1954                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1955                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1956                                 LOGD("sync %s state(%s) with parent state(%s)",
1957                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1958                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1959                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1960
1961                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1962                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1963                                    Because the buffering state is controlled according to the state transition for force resume,
1964                                    the decodebin state should be paused as player state. */
1965                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1966                         }
1967
1968                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1969                                 (player->streamer) &&
1970                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1971                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1972                                 GstQuery *query = NULL;
1973                                 gboolean busy = FALSE;
1974                                 gint percent = 0;
1975
1976                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1977                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1978                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1979                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1980                                         gst_query_unref(query);
1981
1982                                         LOGD("buffered percent(%s): %d\n",
1983                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1984                                 }
1985
1986                                 if (percent >= 100)
1987                                         __mmplayer_handle_buffering_playback(player);
1988                         }
1989
1990                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1991                 }
1992         }
1993
1994         MMPLAYER_FLEAVE();
1995         return;
1996 }
1997
1998
1999 #if 0
2000 #endif
2001
2002 int
2003 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element,  GstState state, gboolean async, gint timeout)
2004 {
2005         GstState element_state = GST_STATE_VOID_PENDING;
2006         GstState element_pending_state = GST_STATE_VOID_PENDING;
2007         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2008
2009         MMPLAYER_FENTER();
2010
2011         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2012         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2013
2014         LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2015
2016         /* set state */
2017         ret = gst_element_set_state(element, state);
2018
2019         if (ret == GST_STATE_CHANGE_FAILURE) {
2020                 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
2021
2022                 /* dump state of all element */
2023                 __mmplayer_dump_pipeline_state(player);
2024
2025                 return MM_ERROR_PLAYER_INTERNAL;
2026         }
2027
2028         /* return here so state transition to be done in async mode */
2029         if (async) {
2030                 LOGD("async state transition. not waiting for state complete.\n");
2031                 return MM_ERROR_NONE;
2032         }
2033
2034         /* wait for state transition */
2035         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2036
2037         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2038                 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
2039                         GST_ELEMENT_NAME(element),
2040                         gst_element_state_get_name(state), timeout);
2041
2042                 LOGE(" [%s] state : %s   pending : %s \n",
2043                         GST_ELEMENT_NAME(element),
2044                         gst_element_state_get_name(element_state),
2045                         gst_element_state_get_name(element_pending_state));
2046
2047                 /* dump state of all element */
2048                 __mmplayer_dump_pipeline_state(player);
2049
2050                 return MM_ERROR_PLAYER_INTERNAL;
2051         }
2052
2053         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
2054
2055         MMPLAYER_FLEAVE();
2056
2057         return MM_ERROR_NONE;
2058 }
2059
2060 void
2061 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
2062 {
2063         mm_player_t* player = (mm_player_t*)(data);
2064
2065         MMPLAYER_RETURN_IF_FAIL(player);
2066         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
2067
2068         switch (GST_MESSAGE_TYPE(msg)) {
2069         case GST_MESSAGE_UNKNOWN:
2070                 LOGD("unknown message received\n");
2071                 break;
2072
2073         case GST_MESSAGE_EOS:
2074                 LOGD("GST_MESSAGE_EOS received");
2075                 __mmplayer_gst_handle_eos_message(player, msg);
2076                 break;
2077
2078         case GST_MESSAGE_ERROR:
2079                 __mmplayer_gst_handle_error_message(player, msg);
2080                 break;
2081
2082         case GST_MESSAGE_WARNING:
2083                 {
2084                         char* debug = NULL;
2085                         GError* error = NULL;
2086
2087                         gst_message_parse_warning(msg, &error, &debug);
2088
2089                         LOGD("warning : %s\n", error->message);
2090                         LOGD("debug : %s\n", debug);
2091
2092                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
2093
2094                         MMPLAYER_FREEIF(debug);
2095                         g_error_free(error);
2096                 }
2097                 break;
2098
2099         case GST_MESSAGE_TAG:
2100                 {
2101                         LOGD("GST_MESSAGE_TAG\n");
2102                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
2103                                 LOGW("failed to extract tags from gstmessage\n");
2104                 }
2105                 break;
2106
2107         case GST_MESSAGE_BUFFERING:
2108                 __mmplayer_gst_handle_buffering_message(player, msg);
2109                 break;
2110
2111         case GST_MESSAGE_STATE_CHANGED:
2112                 __mmplayer_gst_handle_state_message(player, msg);
2113                 break;
2114
2115         case GST_MESSAGE_CLOCK_LOST:
2116                         {
2117                                 GstClock *clock = NULL;
2118                                 gboolean need_new_clock = FALSE;
2119
2120                                 gst_message_parse_clock_lost(msg, &clock);
2121                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2122
2123                                 if (!player->videodec_linked)
2124                                         need_new_clock = TRUE;
2125                                 else if (!player->ini.use_system_clock)
2126                                         need_new_clock = TRUE;
2127
2128                                 if (need_new_clock) {
2129                                         LOGD("Provide clock is TRUE, do pause->resume\n");
2130                                         __mmplayer_gst_pause(player, FALSE);
2131                                         __mmplayer_gst_resume(player, FALSE);
2132                                 }
2133                         }
2134                         break;
2135
2136         case GST_MESSAGE_NEW_CLOCK:
2137                         {
2138                                 GstClock *clock = NULL;
2139                                 gst_message_parse_new_clock(msg, &clock);
2140                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
2141                         }
2142                         break;
2143
2144         case GST_MESSAGE_ELEMENT:
2145                 __mmplayer_gst_handle_element_message(player, msg);
2146                         break;
2147
2148         case GST_MESSAGE_DURATION_CHANGED:
2149                 {
2150                         LOGD("GST_MESSAGE_DURATION_CHANGED\n");
2151                         if (!__mmplayer_gst_handle_duration(player, msg))
2152                                 LOGW("failed to update duration");
2153                 }
2154                 break;
2155
2156         case GST_MESSAGE_ASYNC_START:
2157                         LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2158                 break;
2159
2160         case GST_MESSAGE_ASYNC_DONE:
2161                 __mmplayer_gst_handle_async_done_message(player, msg);
2162                 break;
2163
2164         #if 0 /* delete unnecessary logs */
2165         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
2166         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START\n"); break;
2167         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS\n"); break;
2168         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS\n"); break;
2169         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY\n"); break;
2170         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2171         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
2172         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE\n"); break;
2173         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
2174         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
2175         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
2176         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION\n"); break;
2177         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
2178         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
2179         case GST_MESSAGE_LATENCY:                               LOGD("GST_MESSAGE_LATENCY\n"); break;
2180         #endif
2181
2182         default:
2183                 break;
2184         }
2185
2186         /* should not call 'gst_message_unref(msg)' */
2187         return;
2188 }
2189
2190 GstBusSyncReply
2191 __mmplayer_gst_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
2192 {
2193         mm_player_t *player = (mm_player_t *)data;
2194         GstBusSyncReply reply = GST_BUS_DROP;
2195
2196         if (!(player->pipeline && player->pipeline->mainbin)) {
2197                 LOGE("player pipeline handle is null");
2198                 return GST_BUS_PASS;
2199         }
2200
2201         if (!__mmplayer_gst_check_useful_message(player, message)) {
2202                 gst_message_unref(message);
2203                 return GST_BUS_DROP;
2204         }
2205
2206         switch (GST_MESSAGE_TYPE(message)) {
2207         case GST_MESSAGE_STATE_CHANGED:
2208                 /* post directly for fast launch */
2209                 if (player->sync_handler) {
2210                         __mmplayer_gst_bus_msg_callback(message, player);
2211                         reply = GST_BUS_DROP;
2212                 } else
2213                         reply = GST_BUS_PASS;
2214                 break;
2215         case GST_MESSAGE_TAG:
2216                 __mmplayer_gst_extract_tag_from_msg(player, message);
2217
2218                 #if 0 // debug
2219                 {
2220                         GstTagList *tags = NULL;
2221
2222                         gst_message_parse_tag(message, &tags);
2223                         if (tags) {
2224                                 LOGE("TAGS received from element \"%s\".\n",
2225                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2226
2227                                 gst_tag_list_foreach(tags, print_tag, NULL);
2228                                 gst_tag_list_free(tags);
2229                                 tags = NULL;
2230                         }
2231                         break;
2232                 }
2233                 #endif
2234                 break;
2235
2236         case GST_MESSAGE_DURATION_CHANGED:
2237                 __mmplayer_gst_handle_duration(player, message);
2238                 break;
2239         case GST_MESSAGE_ASYNC_DONE:
2240                 /* NOTE:Don't call gst_callback directly
2241                  * because previous frame can be showed even though this message is received for seek.
2242                  */
2243         default:
2244                 reply = GST_BUS_PASS;
2245                 break;
2246         }
2247
2248         if (reply == GST_BUS_DROP)
2249                 gst_message_unref(message);
2250
2251         return reply;
2252 }
2253
2254 int __mmplayer_gst_start(mm_player_t* player)
2255 {
2256         int ret = MM_ERROR_NONE;
2257         gboolean async = FALSE;
2258
2259         MMPLAYER_FENTER();
2260
2261         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2262
2263         /* NOTE : if SetPosition was called before Start. do it now */
2264         /* streaming doesn't support it. so it should be always sync */
2265         /* !!create one more api to check if there is pending seek rather than checking variables */
2266         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2267                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2268                 ret = __mmplayer_gst_pause(player, FALSE);
2269                 if (ret != MM_ERROR_NONE) {
2270                         LOGE("failed to set state to PAUSED for pending seek");
2271                         return ret;
2272                 }
2273
2274                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
2275                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
2276                                 LOGW("failed to seek pending postion. starting from the begin of content");
2277         }
2278
2279         LOGD("current state before doing transition");
2280         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2281         MMPLAYER_PRINT_STATE(player);
2282
2283         /* set pipeline state to PLAYING  */
2284         ret = __mmplayer_gst_set_state(player,
2285                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2286
2287         if (ret == MM_ERROR_NONE) {
2288                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
2289         } else {
2290                 LOGE("failed to set state to PLAYING");
2291                 return ret;
2292         }
2293
2294         /* generating debug info before returning error */
2295         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
2296
2297         MMPLAYER_FLEAVE();
2298
2299         return ret;
2300 }
2301
2302 int __mmplayer_gst_stop(mm_player_t* player)
2303 {
2304         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
2305         MMHandleType attrs = 0;
2306         gboolean rewind = FALSE;
2307         gint timeout = 0;
2308         int ret = MM_ERROR_NONE;
2309
2310         MMPLAYER_FENTER();
2311
2312         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2313         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2314
2315         LOGD("current state before doing transition");
2316         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
2317         MMPLAYER_PRINT_STATE(player);
2318
2319         attrs = MMPLAYER_GET_ATTRS(player);
2320         if (!attrs) {
2321                 LOGE("cannot get content attribute\n");
2322                 return MM_ERROR_PLAYER_INTERNAL;
2323         }
2324
2325         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
2326         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
2327
2328         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
2329                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
2330                 rewind = TRUE;
2331
2332         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
2333                 /* disable the async state transition because there could be no data in the pipeline */
2334                 __mmplayer_gst_handle_async(player, FALSE, MMPLAYER_SINK_ALL);
2335         }
2336
2337         /* set gst state */
2338         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
2339
2340         if (player->es_player_push_mode || MMPLAYER_IS_HTTP_PD(player)) {
2341                 /* enable the async state transition as default operation */
2342                 __mmplayer_gst_handle_async(player, TRUE, MMPLAYER_SINK_ALL);
2343         }
2344
2345         /* return if set_state has failed */
2346         if (ret != MM_ERROR_NONE) {
2347                 LOGE("failed to set state.\n");
2348                 return ret;
2349         }
2350
2351         /* rewind */
2352         if (rewind) {
2353                 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2354                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
2355                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
2356                         LOGW("failed to rewind\n");
2357                         ret = MM_ERROR_PLAYER_SEEK;
2358                 }
2359         }
2360
2361         /* initialize */
2362         player->sent_bos = FALSE;
2363
2364         if (player->es_player_push_mode) //for cloudgame
2365                 timeout = 0;
2366
2367         /* wait for seek to complete */
2368         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
2369         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
2370                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
2371         } else {
2372                 LOGE("fail to stop player.\n");
2373                 ret = MM_ERROR_PLAYER_INTERNAL;
2374                 __mmplayer_dump_pipeline_state(player);
2375         }
2376
2377         /* generate dot file if enabled */
2378         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
2379
2380         MMPLAYER_FLEAVE();
2381
2382         return ret;
2383 }
2384
2385 int __mmplayer_gst_pause(mm_player_t* player, gboolean async)
2386 {
2387         int ret = MM_ERROR_NONE;
2388
2389         MMPLAYER_FENTER();
2390
2391         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2392         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2393
2394         LOGD("current state before doing transition");
2395         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
2396         MMPLAYER_PRINT_STATE(player);
2397
2398         /* set pipeline status to PAUSED */
2399         ret = __mmplayer_gst_set_state(player,
2400                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
2401
2402         if (FALSE == async) {
2403                 if (ret != MM_ERROR_NONE) {
2404                         GstMessage *msg = NULL;
2405                         GTimer *timer = NULL;
2406                         gdouble MAX_TIMEOUT_SEC = 3;
2407
2408                         LOGE("failed to set state to PAUSED");
2409
2410                         if (!player->bus_watcher) {
2411                                 LOGE("there is no bus msg thread. pipeline is shutting down.");
2412                                 return ret;
2413                         }
2414
2415                         if (player->msg_posted) {
2416                                 LOGE("error msg is already posted.");
2417                                 return ret;
2418                         }
2419
2420                         timer = g_timer_new();
2421                         g_timer_start(timer);
2422
2423                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2424
2425                         do {
2426                                 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
2427                                 if (msg) {
2428                                         if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
2429                                                 GError *error = NULL;
2430
2431                                                 /* parse error code */
2432                                                 gst_message_parse_error(msg, &error, NULL);
2433
2434                                                 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
2435                                                         /* Note : the streaming error from the streaming source is handled
2436                                                          *   using __mmplayer_handle_streaming_error.
2437                                                          */
2438                                                         __mmplayer_handle_streaming_error(player, msg);
2439
2440                                                 } else if (error) {
2441                                                         LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
2442
2443                                                         if (error->domain == GST_STREAM_ERROR)
2444                                                                 ret = __mmplayer_gst_handle_stream_error(player, error, msg);
2445                                                         else if (error->domain == GST_RESOURCE_ERROR)
2446                                                                 ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
2447                                                         else if (error->domain == GST_LIBRARY_ERROR)
2448                                                                 ret = __mmplayer_gst_handle_library_error(player, error->code);
2449                                                         else if (error->domain == GST_CORE_ERROR)
2450                                                                 ret = __mmplayer_gst_handle_core_error(player, error->code);
2451
2452                                                         g_error_free(error);
2453                                                 }
2454                                                 player->msg_posted = TRUE;
2455                                         }
2456                                         gst_message_unref(msg);
2457                                 }
2458                         } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
2459                         /* clean */
2460                         gst_object_unref(bus);
2461                         g_timer_stop(timer);
2462                         g_timer_destroy(timer);
2463
2464                         return ret;
2465
2466                 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
2467                                    (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
2468
2469                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
2470
2471                 } else {
2472                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
2473                 }
2474         }
2475
2476         /* generate dot file before returning error */
2477         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
2478
2479         MMPLAYER_FLEAVE();
2480
2481         return ret;
2482 }
2483
2484 int __mmplayer_gst_resume(mm_player_t* player, gboolean async)
2485 {
2486         int ret = MM_ERROR_NONE;
2487         gint timeout = 0;
2488
2489         MMPLAYER_FENTER();
2490
2491         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
2492                 MM_ERROR_PLAYER_NOT_INITIALIZED);
2493
2494         LOGD("current state before doing transition");
2495         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
2496         MMPLAYER_PRINT_STATE(player);
2497
2498         if (async)
2499                 LOGD("do async state transition to PLAYING");
2500
2501         /* set pipeline state to PLAYING */
2502         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
2503
2504         ret = __mmplayer_gst_set_state(player,
2505                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
2506         if (ret != MM_ERROR_NONE) {
2507                 LOGE("failed to set state to PLAYING");
2508                 goto EXIT;
2509         } else {
2510                 if (async == FALSE)
2511                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
2512         }
2513
2514 EXIT:
2515         /* generate dot file */
2516         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
2517
2518         MMPLAYER_FLEAVE();
2519
2520         return ret;
2521 }
2522
2523 /* sending event to one of sinkelements */
2524 gboolean
2525 __mmplayer_gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
2526 {
2527         GstEvent * event2 = NULL;
2528         GList *sinks = NULL;
2529         gboolean res = FALSE;
2530         MMPLAYER_FENTER();
2531
2532         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2533         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
2534
2535         /* While adding subtitles in live feeds seek is getting called.
2536            Adding defensive check in framework layer.*/
2537         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
2538                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
2539                         LOGE("Should not send seek event during live playback");
2540                         return TRUE;
2541                 }
2542         }
2543
2544         if (player->play_subtitle)
2545                 event2 = gst_event_copy((const GstEvent *)event);
2546
2547         sinks = player->sink_elements;
2548         while (sinks) {
2549                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
2550
2551                 if (GST_IS_ELEMENT(sink)) {
2552                         /* keep ref to the event */
2553                         gst_event_ref(event);
2554
2555                         if ((res = gst_element_send_event(sink, event))) {
2556                                 LOGD("sending event[%s] to sink element [%s] success!\n",
2557                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
2558
2559                                 /* rtsp case, asyn_done is not called after seek during pause state */
2560                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
2561                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
2562                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
2563                                                         LOGD("RTSP seek completed, after pause state..\n");
2564                                                         player->seek_state = MMPLAYER_SEEK_NONE;
2565                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2566                                                 }
2567
2568                                         }
2569                                 }
2570
2571                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2572                                         sinks = g_list_next(sinks);
2573                                         continue;
2574                                 } else {
2575                                         break;
2576                                 }
2577                         }
2578
2579                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
2580                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
2581                 }
2582
2583                 sinks = g_list_next(sinks);
2584         }
2585
2586         /* Note : Textbin is not linked to the video or audio bin.
2587          * It needs to send the event to the text sink seperatelly.
2588          */
2589          if (player->play_subtitle && player->pipeline) {
2590                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
2591
2592                 if (GST_IS_ELEMENT(text_sink)) {
2593                         /* keep ref to the event */
2594                         gst_event_ref(event2);
2595
2596                         if ((res = gst_element_send_event(text_sink, event2)))
2597                                 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
2598                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
2599                         else
2600                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
2601                                         GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
2602
2603                         gst_event_unref(event2);
2604                 }
2605          }
2606
2607         gst_event_unref(event);
2608
2609         MMPLAYER_FLEAVE();
2610
2611         return res;
2612 }
2613
2614 gboolean
2615 __mmplayer_gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
2616                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
2617                         gint64 cur, GstSeekType stop_type, gint64 stop)
2618 {
2619         GstEvent* event = NULL;
2620         gboolean result = FALSE;
2621
2622         MMPLAYER_FENTER();
2623
2624         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2625
2626         if (player->pipeline && player->pipeline->textbin)
2627                 __mmplayer_drop_subtitle(player, FALSE);
2628
2629         event = gst_event_new_seek(rate, format, flags, cur_type,
2630                 cur, stop_type, stop);
2631
2632         result = __mmplayer_gst_send_event_to_sink(player, event);
2633
2634         MMPLAYER_FLEAVE();
2635
2636         return result;
2637 }
2638
2639 int
2640 __mmplayer_gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
2641 {
2642         gint64 dur_nsec = 0;
2643         gint64 pos_nsec = 0;
2644         gboolean ret = TRUE;
2645         gboolean accurated = FALSE;
2646         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
2647
2648         MMPLAYER_FENTER();
2649         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2650         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
2651
2652         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
2653                 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
2654                 goto PENDING;
2655
2656         if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2657                 /* check duration */
2658                 /* NOTE : duration cannot be zero except live streaming.
2659                  *              Since some element could have some timing problemn with quering duration, try again.
2660                  */
2661                 if (player->duration == 0) {
2662                         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2663                                 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2664                                  * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2665                                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2666                                         player->pending_seek.is_pending = TRUE;
2667                                         player->pending_seek.format = format;
2668                                         player->pending_seek.pos = position;
2669                                         player->seek_state = MMPLAYER_SEEK_NONE;
2670                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2671                                         return MM_ERROR_NONE;
2672                                 } else {
2673                                         goto SEEK_ERROR;
2674                                 }
2675                         }
2676                         player->duration = dur_nsec;
2677                 }
2678         }
2679         LOGD("playback rate: %f\n", player->playback_rate);
2680
2681         mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
2682         if (accurated)
2683                 seek_flags |= GST_SEEK_FLAG_ACCURATE;
2684         else
2685                 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
2686
2687         /* do seek */
2688         switch (format) {
2689         case MM_PLAYER_POS_FORMAT_TIME:
2690         {
2691                 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2692                         GstQuery *query = NULL;
2693                         gboolean seekable = FALSE;
2694
2695                         /* check position is valid or not */
2696                         if (position > player->duration)
2697                                 goto INVALID_ARGS;
2698
2699                         query = gst_query_new_seeking(GST_FORMAT_TIME);
2700                         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2701                                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2702                                 gst_query_unref(query);
2703
2704                                 if (!seekable) {
2705                                         LOGW("non-seekable content");
2706                                         player->seek_state = MMPLAYER_SEEK_NONE;
2707                                         return MM_ERROR_PLAYER_NO_OP;
2708                                 }
2709                         } else {
2710                                 LOGW("failed to get seeking query");
2711                                 gst_query_unref(query); /* keep seeking operation */
2712                         }
2713
2714                         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
2715
2716                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
2717                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
2718                            This causes problem is position calculation during normal pause resume scenarios also.
2719                            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
2720                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2721                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2722                                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
2723                                         LOGW("getting current position failed in seek\n");
2724
2725                                 player->last_position = pos_nsec;
2726                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
2727                         }
2728
2729                         if (player->seek_state != MMPLAYER_SEEK_NONE) {
2730                                 LOGD("not completed seek");
2731                                 return MM_ERROR_PLAYER_DOING_SEEK;
2732                         }
2733                 }
2734
2735                 if (!internal_called)
2736                         player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
2737
2738                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
2739                         gint64 cur_time = 0;
2740
2741                         /* get current position */
2742                         gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
2743
2744                         /* flush */
2745                         GstEvent *event = gst_event_new_seek(1.0,
2746                                                         GST_FORMAT_TIME,
2747                                                         (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
2748                                                         GST_SEEK_TYPE_SET, cur_time,
2749                                                         GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2750                         if (event)
2751                                 __mmplayer_gst_send_event_to_sink(player, event);
2752
2753                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
2754                                 __mmplayer_gst_pause(player, FALSE);
2755                 }
2756
2757                 pos_nsec = position;
2758
2759                 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
2760                         that's why set position through property. */
2761                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2762                         (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
2763                         (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
2764                         (!player->videodec_linked) && (!player->audiodec_linked)) {
2765
2766                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
2767                         LOGD("[%s] set position =%"GST_TIME_FORMAT,
2768                                         GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
2769                         player->seek_state = MMPLAYER_SEEK_NONE;
2770                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2771                 } else {
2772                         ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2773                                                         GST_FORMAT_TIME, seek_flags,
2774                                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2775                 }
2776
2777                 if (!ret) {
2778                         LOGE("failed to set position.");
2779                         goto SEEK_ERROR;
2780                 }
2781         }
2782         break;
2783
2784         case MM_PLAYER_POS_FORMAT_PERCENT:
2785         {
2786                 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
2787
2788                 if (player->seek_state != MMPLAYER_SEEK_NONE) {
2789                         LOGD("not completed seek");
2790                         return MM_ERROR_PLAYER_DOING_SEEK;
2791                 }
2792
2793                 if (!internal_called)
2794                         player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
2795
2796                 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
2797                 pos_nsec = (gint64)((position * player->duration) / 100);
2798                 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
2799                                                 GST_FORMAT_TIME, seek_flags,
2800                                                 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2801                 if (!ret) {
2802                         LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
2803                         goto SEEK_ERROR;
2804                 }
2805         }
2806         break;
2807
2808         default:
2809                 goto INVALID_ARGS;
2810         }
2811
2812         /* NOTE : store last seeking point to overcome some bad operation
2813           *     (returning zero when getting current position) of some elements
2814           */
2815         player->last_position = pos_nsec;
2816
2817         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
2818         if (player->playback_rate > 1.0)
2819                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
2820
2821         if ((!internal_called) &&
2822             (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
2823                 LOGD("buffering should be reset after seeking");
2824                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
2825                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
2826         }
2827
2828         MMPLAYER_FLEAVE();
2829         return MM_ERROR_NONE;
2830
2831 PENDING:
2832         player->pending_seek.is_pending = TRUE;
2833         player->pending_seek.format = format;
2834         player->pending_seek.pos = position;
2835
2836         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
2837                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
2838                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
2839                 player->pending_seek.pos);
2840
2841         return MM_ERROR_NONE;
2842
2843 INVALID_ARGS:
2844         LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
2845         return MM_ERROR_INVALID_ARGUMENT;
2846
2847 SEEK_ERROR:
2848         player->seek_state = MMPLAYER_SEEK_NONE;
2849         return MM_ERROR_PLAYER_SEEK;
2850 }
2851
2852 int
2853 __mmplayer_gst_get_position(mm_player_t* player, int format, gint64* position)
2854 {
2855 #define TRICKPLAY_OFFSET GST_MSECOND
2856
2857         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
2858         gint64 pos_nsec = 0;
2859         gboolean ret = TRUE;
2860
2861         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
2862                 MM_ERROR_PLAYER_NOT_INITIALIZED);
2863
2864         current_state = MMPLAYER_CURRENT_STATE(player);
2865
2866         /* NOTE : query position except paused state to overcome some bad operation
2867          * please refer to below comments in details
2868          */
2869         if (current_state != MM_PLAYER_STATE_PAUSED)
2870                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
2871
2872         /* NOTE : get last point to overcome some bad operation of some elements
2873          *(returning zero when getting current position in paused state
2874          * and when failed to get postion during seeking
2875          */
2876         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
2877                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
2878
2879                 if (player->playback_rate < 0.0)
2880                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
2881                 else
2882                         pos_nsec = player->last_position;
2883
2884                 if (!ret)
2885                         pos_nsec = player->last_position;
2886                 else
2887                         player->last_position = pos_nsec;
2888
2889                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
2890
2891         } else {
2892                 if (player->duration > 0 && pos_nsec > player->duration)
2893                         pos_nsec = player->duration;
2894
2895                 player->last_position = pos_nsec;
2896         }
2897
2898         switch (format) {
2899         case MM_PLAYER_POS_FORMAT_TIME:
2900                 *position = pos_nsec;
2901                 break;
2902
2903         case MM_PLAYER_POS_FORMAT_PERCENT:
2904         {
2905                 if (player->duration <= 0) {
2906                         LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
2907                         *position = 0;
2908                 } else {
2909                         LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
2910                         *position = (gint64)(pos_nsec * 100 / player->duration);
2911                 }
2912                 break;
2913         }
2914         default:
2915                 return MM_ERROR_PLAYER_INTERNAL;
2916         }
2917
2918         return MM_ERROR_NONE;
2919 }
2920
2921 int __mmplayer_gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
2922 {
2923 #define STREAMING_IS_FINISHED   0
2924 #define BUFFERING_MAX_PER       100
2925 #define DEFAULT_PER_VALUE       -1
2926 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
2927
2928         MMPlayerGstElement *mainbin = NULL;
2929         gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
2930         gint64 buffered_total = 0;
2931         gint64 position = 0;
2932         gint buffered_sec = -1;
2933         GstBufferingMode mode = GST_BUFFERING_STREAM;
2934         gint64 content_size_time = player->duration;
2935         guint64 content_size_bytes = player->http_content_size;
2936
2937         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2938                                                 player->pipeline &&
2939                                                 player->pipeline->mainbin,
2940                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
2941
2942         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
2943
2944         *start_pos = 0;
2945         *stop_pos = 0;
2946
2947         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
2948                 /* and rtsp is not ready yet. */
2949                 LOGW("it's only used for http streaming case.\n");
2950                 return MM_ERROR_PLAYER_NO_OP;
2951         }
2952
2953         if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
2954                 LOGW("Time format is not supported yet.\n");
2955                 return MM_ERROR_INVALID_ARGUMENT;
2956         }
2957
2958         if (content_size_time <= 0 || content_size_bytes <= 0) {
2959                 LOGW("there is no content size.");
2960                 return MM_ERROR_NONE;
2961         }
2962
2963         if (__mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
2964                 LOGW("fail to get current position.");
2965                 return MM_ERROR_NONE;
2966         }
2967
2968         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
2969                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
2970
2971         mainbin = player->pipeline->mainbin;
2972         start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
2973
2974         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
2975                 GstQuery *query = NULL;
2976                 gint byte_in_rate = 0, byte_out_rate = 0;
2977                 gint64 estimated_total = 0;
2978
2979                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
2980                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
2981                         LOGW("fail to get buffering query from queue2");
2982                         if (query)
2983                                 gst_query_unref(query);
2984                         return MM_ERROR_NONE;
2985                 }
2986
2987                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
2988                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
2989
2990                 if (mode == GST_BUFFERING_STREAM) {
2991                         /* using only queue in case of push mode(ts / mp3) */
2992                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
2993                                 GST_FORMAT_BYTES, &buffered_total)) {
2994                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
2995                                 stop_per = 100 * buffered_total / content_size_bytes;
2996                         }
2997                 } else {
2998                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
2999                         guint idx = 0;
3000                         guint num_of_ranges = 0;
3001                         gint64 start_byte = 0, stop_byte = 0;
3002
3003                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3004                         if (estimated_total != STREAMING_IS_FINISHED) {
3005                                 /* buffered size info from queue2 */
3006                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3007                                 for (idx = 0; idx < num_of_ranges; idx++) {
3008                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3009                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3010
3011                                         buffered_total += (stop_byte - start_byte);
3012                                 }
3013                         } else
3014                                 stop_per = BUFFERING_MAX_PER;
3015                 }
3016                 gst_query_unref(query);
3017         }
3018
3019         if (stop_per == DEFAULT_PER_VALUE) {
3020                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3021                 if (dur_sec > 0) {
3022                         guint avg_byterate = (guint)(content_size_bytes/dur_sec);
3023
3024                         /* buffered size info from multiqueue */
3025                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3026                                 guint curr_size_bytes = 0;
3027                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3028                                         "curr-size-bytes", &curr_size_bytes, NULL);
3029                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3030                                 buffered_total += curr_size_bytes;
3031                         }
3032
3033                         if (avg_byterate > 0)
3034                                 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
3035                         else if (player->total_maximum_bitrate > 0)
3036                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
3037                         else if (player->total_bitrate > 0)
3038                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
3039
3040                         if (buffered_sec >= 0)
3041                                 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
3042                 }
3043         }
3044
3045         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3046         *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
3047
3048         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
3049                 buffered_total, buffered_sec, *start_pos, *stop_pos);
3050
3051         return MM_ERROR_NONE;
3052 }
3053