Merge tizen branch into tizen_5.5_devel
[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 <gst/app/gstappsrc.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 #include "mm_player_tracks.h"
37
38 /*===========================================================================================
39 |                                                                                                                                                                                       |
40 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
41 |                                                                                                                                                                                       |
42 ========================================================================================== */
43
44 /*---------------------------------------------------------------------------
45 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
46 ---------------------------------------------------------------------------*/
47
48 /*---------------------------------------------------------------------------
49 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
50 ---------------------------------------------------------------------------*/
51
52 /*---------------------------------------------------------------------------
53 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
54 ---------------------------------------------------------------------------*/
55
56 /*---------------------------------------------------------------------------
57 |    LOCAL #defines:                                                                                                            |
58 ---------------------------------------------------------------------------*/
59
60 /*---------------------------------------------------------------------------
61 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
62 ---------------------------------------------------------------------------*/
63
64 /*---------------------------------------------------------------------------
65 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
66 ---------------------------------------------------------------------------*/
67
68 /*---------------------------------------------------------------------------
69 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
70 ---------------------------------------------------------------------------*/
71
72 /*---------------------------------------------------------------------------
73 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
74 ---------------------------------------------------------------------------*/
75
76 /*---------------------------------------------------------------------------
77 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
78 ---------------------------------------------------------------------------*/
79
80 /*===========================================================================================
81 |                                                                                                                                                                                       |
82 |  FUNCTION DEFINITIONS                                                                                                                                         |
83 |                                                                                                                                                                                       |
84 ========================================================================================== */
85 #ifdef __DEBUG__
86 static void
87 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
88 {
89         gint i, count;
90
91         count = gst_tag_list_get_tag_size(list, tag);
92
93         LOGD("count = %d", count);
94
95         for (i = 0; i < count; i++) {
96                 gchar *str;
97
98                 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
99                         if (!gst_tag_list_get_string_index(list, tag, i, &str))
100                                 g_assert_not_reached();
101                 } else {
102                         str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
103                 }
104
105                 if (i == 0)
106                         g_print("  %15s: %s", gst_tag_get_nick(tag), str);
107                 else
108                         g_print("                 : %s", str);
109
110                 g_free(str);
111         }
112 }
113 #endif
114
115 static gboolean
116 __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name)
117 {
118         /* check whether the error is posted from not-activated track or not */
119         int msg_src_pos = 0;
120         gint active_pad_index = 0;
121
122         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE);
123
124         active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
125         LOGD("current  active pad index  -%d", active_pad_index);
126
127         if  (src_element_name) {
128                 int idx = 0;
129
130                 if (player->audio_decoders) {
131                         GList *adec = player->audio_decoders;
132                         for (; adec ; adec = g_list_next(adec)) {
133                                 gchar *name = adec->data;
134
135                                 LOGD("found audio decoder name  = %s", name);
136                                 if (g_strrstr(name, src_element_name)) {
137                                         msg_src_pos = idx;
138                                         break;
139                                 }
140                                 idx++;
141                         }
142                 }
143                 LOGD("active pad = %d, error src index = %d", active_pad_index,  msg_src_pos);
144         }
145
146         if (active_pad_index != msg_src_pos) {
147                 LOGD("skip error because error is posted from no activated track");
148                 return FALSE;
149         }
150
151         return TRUE;
152 }
153
154 static int
155 __mmplayer_gst_transform_error_decode(mmplayer_t *player, const char *klass)
156 {
157         /* Demuxer can't parse one track because it's corrupted.
158          * So, the decoder for it is not linked.
159          * But, it has one playable track.
160          */
161         if (g_strrstr(klass, "Demux")) {
162                 if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
163                         return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
164                 } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
165                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
166                 } else {
167                         if (player->pipeline->audiobin) { // PCM
168                                 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
169                         } else {
170                                 LOGD("not found any available codec. Player should be destroyed.");
171                                 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
172                         }
173                 }
174         }
175
176         return MM_ERROR_PLAYER_INVALID_STREAM;
177 }
178
179 static int
180 __mmplayer_gst_transform_error_type(mmplayer_t *player, GstElement *src_element)
181 {
182         if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
183                 LOGE("Not supported subtitle.");
184                 return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
185         }
186         return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
187 }
188
189 static int
190 __mmplayer_gst_transform_error_failed(mmplayer_t *player, const char *klass, GError *error)
191 {
192         /* Decoder Custom Message */
193         if (!strstr(error->message, "ongoing"))
194                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
195
196         if (strncasecmp(klass, "audio", 5)) {
197                 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
198                         LOGD("Video can keep playing.");
199                         return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
200                 }
201         } else if (strncasecmp(klass, "video", 5)) {
202                 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
203                         LOGD("Audio can keep playing.");
204                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
205                 }
206         }
207
208         LOGD("not found any available codec. Player should be destroyed.");
209         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
210 }
211
212 static int
213 __mmplayer_gst_transform_error_decrypt(mmplayer_t *player, GError *error)
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
224         return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
225 }
226
227 /* NOTE : decide gstreamer state whether there is some playable track or not. */
228 static gint
229 __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GError *error)
230 {
231         gchar *src_element_name = NULL;
232         GstElement *src_element = NULL;
233         GstElementFactory *factory = NULL;
234         const gchar *klass = NULL;
235
236         MMPLAYER_FENTER();
237
238         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
239         MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
240         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
241         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
242                                                                 player->pipeline &&
243                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
244
245         src_element = GST_ELEMENT_CAST(message->src);
246         if (!src_element)
247                 return MM_ERROR_PLAYER_INTERNAL;
248
249         src_element_name = GST_ELEMENT_NAME(src_element);
250         if (!src_element_name)
251                 return MM_ERROR_PLAYER_INTERNAL;
252
253         factory = gst_element_get_factory(src_element);
254         if (!factory)
255                 return MM_ERROR_PLAYER_INTERNAL;
256
257         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
258         if (!klass)
259                 return MM_ERROR_PLAYER_INTERNAL;
260
261         LOGD("error code=%d, msg=%s, src element=%s, class=%s",
262                         error->code, error->message, src_element_name, klass);
263
264         if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name))
265                 return MM_ERROR_NONE;
266
267         switch (error->code) {
268         case GST_STREAM_ERROR_DECODE:
269                 return __mmplayer_gst_transform_error_decode(player, klass);
270         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
271         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
272         case GST_STREAM_ERROR_WRONG_TYPE:
273                 return __mmplayer_gst_transform_error_type(player, src_element);
274         case GST_STREAM_ERROR_FAILED:
275                 return __mmplayer_gst_transform_error_failed(player, klass, error);
276         case GST_STREAM_ERROR_DECRYPT:
277         case GST_STREAM_ERROR_DECRYPT_NOKEY:
278                 LOGE("decryption error, [%s] failed, reason : [%s]", src_element_name, error->message);
279                 return __mmplayer_gst_transform_error_decrypt(player, error);
280         default:
281                 break;
282         }
283
284         MMPLAYER_FLEAVE();
285
286         return MM_ERROR_PLAYER_INVALID_STREAM;
287 }
288
289 gint
290 __mmplayer_gst_handle_core_error(mmplayer_t *player, int code)
291 {
292         gint trans_err = MM_ERROR_NONE;
293
294         MMPLAYER_FENTER();
295
296         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
297
298         switch (code) {
299         case GST_CORE_ERROR_MISSING_PLUGIN:
300                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
301         case GST_CORE_ERROR_STATE_CHANGE:
302         case GST_CORE_ERROR_SEEK:
303         case GST_CORE_ERROR_NOT_IMPLEMENTED:
304         case GST_CORE_ERROR_FAILED:
305         case GST_CORE_ERROR_TOO_LAZY:
306         case GST_CORE_ERROR_PAD:
307         case GST_CORE_ERROR_THREAD:
308         case GST_CORE_ERROR_NEGOTIATION:
309         case GST_CORE_ERROR_EVENT:
310         case GST_CORE_ERROR_CAPS:
311         case GST_CORE_ERROR_TAG:
312         case GST_CORE_ERROR_CLOCK:
313         case GST_CORE_ERROR_DISABLED:
314         default:
315                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
316                 break;
317         }
318
319         MMPLAYER_FLEAVE();
320
321         return trans_err;
322 }
323
324 gint
325 __mmplayer_gst_handle_library_error(mmplayer_t *player, int code)
326 {
327         gint trans_err = MM_ERROR_NONE;
328
329         MMPLAYER_FENTER();
330
331         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
332
333         switch (code) {
334         case GST_LIBRARY_ERROR_FAILED:
335         case GST_LIBRARY_ERROR_TOO_LAZY:
336         case GST_LIBRARY_ERROR_INIT:
337         case GST_LIBRARY_ERROR_SHUTDOWN:
338         case GST_LIBRARY_ERROR_SETTINGS:
339         case GST_LIBRARY_ERROR_ENCODE:
340         default:
341                 trans_err =  MM_ERROR_PLAYER_INVALID_STREAM;
342                 break;
343         }
344
345         MMPLAYER_FLEAVE();
346
347         return trans_err;
348 }
349
350 gint
351 __mmplayer_gst_handle_resource_error(mmplayer_t *player, int code, GstMessage *message)
352 {
353         gint trans_err = MM_ERROR_NONE;
354
355         MMPLAYER_FENTER();
356
357         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
358
359         switch (code) {
360         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
361                 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
362                 break;
363         case GST_RESOURCE_ERROR_NOT_FOUND:
364         case GST_RESOURCE_ERROR_OPEN_READ:
365                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
366                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
367                         trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
368                         break;
369                 }
370         case GST_RESOURCE_ERROR_READ:
371                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
372                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
373                         trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
374                         break;
375                 } else if (message != NULL && message->src != NULL) {
376                         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
377                         mmplayer_path_type_e path_type = MMPLAYER_PATH_MAX;
378
379                         if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
380                                 path_type = MMPLAYER_PATH_VOD;
381                         else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
382                                 path_type = MMPLAYER_PATH_TEXT;
383
384                         if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
385                                 /* check storage state */
386                                 storage_get_state(player->storage_info[path_type].id, &storage_state);
387                                 player->storage_info[path_type].state = storage_state;
388                                 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
389                         }
390                 } /* fall through */
391         case GST_RESOURCE_ERROR_WRITE:
392         case GST_RESOURCE_ERROR_FAILED:
393         case GST_RESOURCE_ERROR_SEEK:
394         case GST_RESOURCE_ERROR_TOO_LAZY:
395         case GST_RESOURCE_ERROR_BUSY:
396         case GST_RESOURCE_ERROR_OPEN_WRITE:
397         case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
398         case GST_RESOURCE_ERROR_CLOSE:
399         case GST_RESOURCE_ERROR_SYNC:
400         case GST_RESOURCE_ERROR_SETTINGS:
401         default:
402                 trans_err = MM_ERROR_PLAYER_INTERNAL;
403         break;
404         }
405
406         MMPLAYER_FLEAVE();
407
408         return trans_err;
409 }
410
411 gint
412 __mmplayer_gst_handle_stream_error(mmplayer_t *player, GError *error, GstMessage *message)
413 {
414         gint trans_err = MM_ERROR_NONE;
415
416         MMPLAYER_FENTER();
417
418         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
419         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
420         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
421
422         switch (error->code) {
423         case GST_STREAM_ERROR_FAILED:
424         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
425         case GST_STREAM_ERROR_DECODE:
426         case GST_STREAM_ERROR_WRONG_TYPE:
427         case GST_STREAM_ERROR_DECRYPT:
428         case GST_STREAM_ERROR_DECRYPT_NOKEY:
429         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
430                 trans_err = __mmplayer_gst_transform_gsterror(player, message, error);
431                 break;
432
433         case GST_STREAM_ERROR_NOT_IMPLEMENTED:
434         case GST_STREAM_ERROR_TOO_LAZY:
435         case GST_STREAM_ERROR_ENCODE:
436         case GST_STREAM_ERROR_DEMUX:
437         case GST_STREAM_ERROR_MUX:
438         case GST_STREAM_ERROR_FORMAT:
439         default:
440                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
441                 break;
442         }
443
444         MMPLAYER_FLEAVE();
445
446         return trans_err;
447 }
448
449 gboolean
450 __mmplayer_handle_gst_error(mmplayer_t *player, GstMessage *message, GError *error)
451 {
452         MMMessageParamType msg_param;
453         gchar *msg_src_element;
454
455         MMPLAYER_FENTER();
456
457         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
458         MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
459
460         /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
461
462         memset(&msg_param, 0, sizeof(MMMessageParamType));
463
464         if (error->domain == GST_CORE_ERROR) {
465                 msg_param.code = __mmplayer_gst_handle_core_error(player, error->code);
466         } else if (error->domain == GST_LIBRARY_ERROR) {
467                 msg_param.code = __mmplayer_gst_handle_library_error(player, error->code);
468         } else if (error->domain == GST_RESOURCE_ERROR) {
469                 msg_param.code = __mmplayer_gst_handle_resource_error(player, error->code, message);
470         } else if (error->domain == GST_STREAM_ERROR) {
471                 msg_param.code = __mmplayer_gst_handle_stream_error(player, error, message);
472         } else {
473                 LOGW("This error domain is not defined.");
474
475                 /* we treat system error as an internal error */
476                 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
477         }
478
479         if (message->src) {
480                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
481
482                 msg_param.data = (void *)error->message;
483
484                 LOGE("-Msg src : [%s]   Domain : [%s]   Error : [%s]  Code : [%d] is tranlated to error code : [0x%x]",
485                         msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
486         }
487
488         /* no error */
489         if (msg_param.code == MM_ERROR_NONE)
490                 return TRUE;
491
492         /* skip error to avoid duplicated posting */
493         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) &&
494                  (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
495                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
496                  (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
497
498                 /* The error will be handled by mused.
499                  * @ref _mmplayer_manage_external_storage_state() */
500
501                 LOGW("storage is removed, skip error post");
502                 return TRUE;
503         }
504
505         /* post error to application */
506         if (!player->msg_posted) {
507                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
508                 /* don't post more if one was sent already */
509                 player->msg_posted = TRUE;
510         } else {
511                 LOGD("skip error post because it's sent already.");
512         }
513
514         MMPLAYER_FLEAVE();
515
516         return TRUE;
517 }
518
519 static gboolean
520 __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message)
521 {
522         LOGD("\n");
523         MMMessageParamType msg_param;
524         gchar *msg_src_element = NULL;
525         GstStructure *s = NULL;
526         guint error_id = 0;
527         gchar *error_string = NULL;
528
529         MMPLAYER_FENTER();
530
531         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
532         MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
533
534         s = gst_structure_copy(gst_message_get_structure(message));
535
536
537         if (!gst_structure_get_uint(s, "error_id", &error_id))
538                 error_id = MMPLAYER_STREAMING_ERROR_NONE;
539
540         switch (error_id) {
541         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
542                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
543                 break;
544         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
545                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
546                 break;
547         case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
548                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
549                 break;
550         case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
551                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
552                 break;
553         case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
554                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
555                 break;
556         case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
557                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
558                 break;
559         case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
560                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
561                 break;
562         case MMPLAYER_STREAMING_ERROR_INVALID_URL:
563                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
564                 break;
565         case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
566                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
567                 break;
568         case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
569                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
570                 break;
571         case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
572                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
573                 break;
574         case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
575                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
576                 break;
577         case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
578                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
579                 break;
580         case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
581                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
582                 break;
583         case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
584                 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
585                 break;
586         case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
587                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
588                 break;
589         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
590                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
591                 break;
592         case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
593                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
594                 break;
595         case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
596                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
597                 break;
598         case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
599                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
600                 break;
601         case MMPLAYER_STREAMING_ERROR_GONE:
602                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
603                 break;
604         case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
605                 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
606                 break;
607         case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
608                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
609                 break;
610         case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
611                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
612                 break;
613         case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
614                 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
615                 break;
616         case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
617                 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
618                 break;
619         case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
620                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
621                 break;
622         case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
623                 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
624                 break;
625         case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
626                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
627                 break;
628         case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
629                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
630                 break;
631         case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
632                 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
633                 break;
634         case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
635                 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
636                 break;
637         case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
638                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
639                 break;
640         case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
641                 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
642                 break;
643         case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
644                 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
645                 break;
646         case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
647                 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
648                 break;
649         case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
650                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
651                 break;
652         case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
653                 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
654                 break;
655         case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
656                 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
657                 break;
658         case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
659                 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
660                 break;
661         case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
662                 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
663                 break;
664         case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
665                 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
666                 break;
667         case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
668                 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
669                 break;
670         case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
671                 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
672                 break;
673         case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
674                 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
675                 break;
676         default:
677                 {
678                         gst_structure_free(s);
679                         return MM_ERROR_PLAYER_STREAMING_FAIL;
680                 }
681         }
682
683         error_string = g_strdup(gst_structure_get_string(s, "error_string"));
684         if (error_string)
685                 msg_param.data = (void *)error_string;
686
687         if (message->src) {
688                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
689
690                 LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]",
691                         msg_src_element, msg_param.code, (char *)msg_param.data);
692         }
693
694         /* post error to application */
695         if (!player->msg_posted) {
696                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
697
698                 /* don't post more if one was sent already */
699                 player->msg_posted = TRUE;
700         } else {
701                 LOGD("skip error post because it's sent already.");
702         }
703
704         gst_structure_free(s);
705         MMPLAYER_FREEIF(error_string);
706
707         MMPLAYER_FLEAVE();
708         return TRUE;
709
710 }
711
712 static void
713 __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mmplayer_spherical_metadata_t *metadata)
714 {
715         gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
716         gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
717         gst_tag_list_get_string(tags, "stitching_software",
718                         &metadata->stitching_software);
719         gst_tag_list_get_string(tags, "projection_type",
720                         &metadata->projection_type_string);
721         gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
722         gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
723         gst_tag_list_get_int(tags, "init_view_heading",
724                         &metadata->init_view_heading);
725         gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
726         gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
727         gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
728         gst_tag_list_get_int(tags, "full_pano_width_pixels",
729                         &metadata->full_pano_width_pixels);
730         gst_tag_list_get_int(tags, "full_pano_height_pixels",
731                         &metadata->full_pano_height_pixels);
732         gst_tag_list_get_int(tags, "cropped_area_image_width",
733                         &metadata->cropped_area_image_width);
734         gst_tag_list_get_int(tags, "cropped_area_image_height",
735                         &metadata->cropped_area_image_height);
736         gst_tag_list_get_int(tags, "cropped_area_left",
737                         &metadata->cropped_area_left);
738         gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
739         gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
740         gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
741         gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
742 }
743
744 static gboolean
745 __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg)
746 {
747
748 /* macro for better code readability */
749 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \
750         do { \
751                 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
752                         if (string != NULL) { \
753                                 SECURE_LOGD("update tag string : %s", string); \
754                                 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
755                                         char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \
756                                         strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \
757                                         new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \
758                                         mm_player_set_attribute((MMHandleType)player, NULL,\
759                                                         playertag, new_string, strlen(new_string), NULL); \
760                                         MMPLAYER_FREEIF(new_string); \
761                                 } else { \
762                                         mm_player_set_attribute((MMHandleType)player, NULL,\
763                                                         playertag, string, strlen(string), NULL); \
764                                 } \
765                                 MMPLAYER_FREEIF(string); \
766                         } \
767                 } \
768         } while (0)
769
770 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \
771         do {    \
772                 GstSample *sample = NULL;\
773                 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
774                         GstMapInfo info = GST_MAP_INFO_INIT;\
775                         buffer = gst_sample_get_buffer(sample);\
776                         if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
777                                 LOGD("failed to get image data from tag");\
778                                 gst_sample_unref(sample);\
779                                 return FALSE;\
780                         } \
781                         SECURE_LOGD("update album cover data : %p, size : %zu", info.data, info.size);\
782                         MMPLAYER_FREEIF(player->album_art);\
783                         player->album_art = (gchar *)g_malloc(info.size);\
784                         if (player->album_art) {\
785                                 memcpy(player->album_art, info.data, info.size);\
786                                 mm_player_set_attribute((MMHandleType)player, NULL,\
787                                                 playertag, (void *)player->album_art, info.size, NULL); \
788                                 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
789                                         msg_param.data = (void *)player->album_art;\
790                                         msg_param.size = info.size;\
791                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
792                                         SECURE_LOGD("post message image buffer data : %p, size : %zu", info.data, info.size);\
793                                 } \
794                         } \
795                         gst_buffer_unmap(buffer, &info);\
796                         gst_sample_unref(sample);\
797                 }       \
798         } while (0)
799
800 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \
801         do {    \
802                 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
803                         if (v_uint) { \
804                                 int i = 0; \
805                                 mmplayer_track_type_e track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
806                                 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
807                                         track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
808                                 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
809                                         track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
810                                 else \
811                                         track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
812                                 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
813                                         if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
814                                                 mm_player_set_attribute((MMHandleType)player, NULL,\
815                                                                 "content_audio_bitrate", v_uint, NULL); \
816                                         player->bitrate[track_type] = v_uint; \
817                                         player->total_bitrate = 0; \
818                                         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
819                                                 player->total_bitrate += player->bitrate[i]; \
820                                         mm_player_set_attribute((MMHandleType)player, NULL,\
821                                                         playertag, player->total_bitrate, NULL); \
822                                         SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \
823                                 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
824                                         player->maximum_bitrate[track_type] = v_uint; \
825                                         player->total_maximum_bitrate = 0; \
826                                         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
827                                                 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
828                                         mm_player_set_attribute((MMHandleType)player, NULL,\
829                                                         playertag, player->total_maximum_bitrate, NULL); \
830                                         SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\
831                                 } else { \
832                                         mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \
833                                 } \
834                                 v_uint = 0;\
835                         } \
836                 } \
837         } while (0)
838
839 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \
840         do { \
841                 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
842                         if (date != NULL) {\
843                                 string = g_strdup_printf("%d", g_date_get_year(date));\
844                                 mm_player_set_attribute((MMHandleType)player, NULL,\
845                                                 playertag, string, strlen(string), NULL); \
846                                 SECURE_LOGD("metainfo year : %s", string);\
847                                 MMPLAYER_FREEIF(string);\
848                                 g_date_free(date);\
849                         } \
850                 } \
851         } while (0)
852
853 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \
854         do { \
855                 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
856                         if (datetime != NULL) {\
857                                 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
858                                 mm_player_set_attribute((MMHandleType)player, NULL,\
859                                                 playertag, string, strlen(string), NULL); \
860                                 SECURE_LOGD("metainfo year : %s", string);\
861                                 MMPLAYER_FREEIF(string);\
862                                 gst_date_time_unref(datetime);\
863                         } \
864                 } \
865         } while (0)
866
867         /* function start */
868         GstTagList *tag_list = NULL;
869
870         char *string = NULL;
871         guint v_uint = 0;
872         GDate *date = NULL;
873         GstDateTime *datetime = NULL;
874         /* album cover */
875         GstBuffer *buffer = NULL;
876         gint index = 0;
877         MMMessageParamType msg_param = {0, };
878
879         /* currently not used. but those are needed for above macro */
880         //guint64 v_uint64 = 0;
881         //gdouble v_double = 0;
882
883         MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
884
885         /* get tag list from gst message */
886         gst_message_parse_tag(msg, &tag_list);
887
888         /* store tags to player attributes */
889         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title");
890         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist");
891         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album");
892         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author");
893         MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date");
894         MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date");
895         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre");
896         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num");
897         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description");
898         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright");
899         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec");
900         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec");
901         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate");
902         MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate");
903         MMPLAYER_UPDATE_TAG_LOCK(player);
904         MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover");
905         MMPLAYER_UPDATE_TAG_UNLOCK(player);
906         MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation");
907
908         if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
909                 if (player->video360_metadata.is_spherical == -1) {
910                         __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
911                         mm_player_set_attribute((MMHandleType)player, NULL,
912                                         "content_video_is_spherical", player->video360_metadata.is_spherical, NULL);
913                         if (player->video360_metadata.is_spherical == 1) {
914                                 LOGD("This is spherical content for 360 playback.");
915                                 player->is_content_spherical = TRUE;
916                         } else {
917                                 LOGD("This is not spherical content");
918                                 player->is_content_spherical = FALSE;
919                         }
920
921                         if (player->video360_metadata.projection_type_string) {
922                                 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
923                                         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
924                                 } else {
925                                         LOGE("Projection %s: code not implemented.", player->video360_metadata.projection_type_string);
926                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
927                                 }
928                         }
929
930                         if (player->video360_metadata.stereo_mode_string) {
931                                 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
932                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
933                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
934                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
935                                 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
936                                         player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
937                                 } else {
938                                         LOGE("Stereo mode %s: code not implemented.", player->video360_metadata.stereo_mode_string);
939                                         player->is_content_spherical = player->is_video360_enabled = FALSE;
940                                 }
941                         }
942                 }
943         }
944
945         gst_tag_list_unref(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(mmplayer_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         case GST_MESSAGE_STREAM_COLLECTION:
972                 retval = TRUE;
973                 break;
974         case GST_MESSAGE_ASYNC_DONE:
975         case GST_MESSAGE_STATE_CHANGED:
976                 /* we only handle messages from pipeline */
977                 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
978                         retval = TRUE;
979                 else
980                         retval = FALSE;
981                 break;
982         case GST_MESSAGE_BUFFERING:
983         {
984                 gint buffer_percent = 0;
985
986                 retval = TRUE;
987                 gst_message_parse_buffering(message, &buffer_percent);
988                 if (buffer_percent != MAX_BUFFER_PERCENT) {
989                         LOGD("[%s] buffering msg %d%%!!", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
990                         break;
991                 }
992
993                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
994                         LOGW("can't get cmd lock, send msg to bus");
995                         break;
996                 }
997
998                 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
999                         LOGD("[%s] Buffering DONE is detected !", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
1000                         player->streamer->buffering_state |= MM_PLAYER_BUFFERING_COMPLETE;
1001                 }
1002
1003                 MMPLAYER_CMD_UNLOCK(player);
1004
1005                 break;
1006         }
1007         case GST_MESSAGE_STREAMS_SELECTED:
1008         {
1009                 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1010                         break; /* drop msg */
1011
1012                 LOGD("GST_MESSAGE_STREAMS_SELECTED");
1013                 player->no_more_pad = TRUE;
1014                 _mmplayer_pipeline_complete(NULL, player);
1015                 retval = TRUE;
1016                 break;
1017         }
1018         default:
1019                 retval = FALSE;
1020                 break;
1021         }
1022
1023         return retval;
1024 }
1025
1026 static void
1027 __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg)
1028 {
1029         guint64 data_size = 0;
1030         gint64 pos_nsec = 0;
1031
1032         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1033
1034         _mmplayer_gst_get_position(player, &pos_nsec);  /* to update player->last_position */
1035
1036         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
1037                 data_size = player->http_content_size;
1038         }
1039
1040         _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration);
1041         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
1042
1043         return;
1044 }
1045
1046 static int
1047 __mmplayer_handle_buffering_playback(mmplayer_t *player)
1048 {
1049         int ret = MM_ERROR_NONE;
1050         mmplayer_state_e prev_state = MM_PLAYER_STATE_NONE;
1051         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
1052         mmplayer_state_e target_state = MM_PLAYER_STATE_NONE;
1053         mmplayer_state_e pending_state = MM_PLAYER_STATE_NONE;
1054
1055         if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
1056                 LOGW("do nothing for buffering msg");
1057                 ret = MM_ERROR_PLAYER_INVALID_STATE;
1058                 goto exit;
1059         }
1060
1061         prev_state = MMPLAYER_PREV_STATE(player);
1062         current_state = MMPLAYER_CURRENT_STATE(player);
1063         target_state = MMPLAYER_TARGET_STATE(player);
1064         pending_state = MMPLAYER_PENDING_STATE(player);
1065
1066         LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
1067                 MMPLAYER_STATE_GET_NAME(prev_state),
1068                 MMPLAYER_STATE_GET_NAME(current_state),
1069                 MMPLAYER_STATE_GET_NAME(pending_state),
1070                 MMPLAYER_STATE_GET_NAME(target_state),
1071                 player->streamer->buffering_state);
1072
1073         if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1074                 /* NOTE : if buffering has done, player has to go to target state. */
1075                 switch (target_state) {
1076                 case MM_PLAYER_STATE_PAUSED:
1077                         {
1078                                 switch (pending_state) {
1079                                 case MM_PLAYER_STATE_PLAYING:
1080                                         _mmplayer_gst_pause(player, TRUE);
1081                                         break;
1082
1083                                 case MM_PLAYER_STATE_PAUSED:
1084                                         LOGD("player is already going to paused state, there is nothing to do.");
1085                                         break;
1086
1087                                 case MM_PLAYER_STATE_NONE:
1088                                 case MM_PLAYER_STATE_NULL:
1089                                 case MM_PLAYER_STATE_READY:
1090                                 default:
1091                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1092                                         break;
1093                                 }
1094                         }
1095                         break;
1096
1097                 case MM_PLAYER_STATE_PLAYING:
1098                         {
1099                                 switch (pending_state) {
1100                                 case MM_PLAYER_STATE_NONE:
1101                                         {
1102                                                 if (current_state != MM_PLAYER_STATE_PLAYING)
1103                                                         _mmplayer_gst_resume(player, TRUE);
1104                                         }
1105                                         break;
1106
1107                                 case MM_PLAYER_STATE_PAUSED:
1108                                         /* NOTE: It should be worked as asynchronously.
1109                                          * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
1110                                          */
1111                                         if (current_state == MM_PLAYER_STATE_PLAYING) {
1112                                                 /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet.
1113                                                  * The current state should be changed to paused purposely to prevent state conflict.
1114                                                  */
1115                                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1116                                         }
1117                                         _mmplayer_gst_resume(player, TRUE);
1118                                         break;
1119
1120                                 case MM_PLAYER_STATE_PLAYING:
1121                                         LOGD("player is already going to playing state, there is nothing to do.");
1122                                         break;
1123
1124                                 case MM_PLAYER_STATE_NULL:
1125                                 case MM_PLAYER_STATE_READY:
1126                                 default:
1127                                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1128                                         break;
1129                                 }
1130                         }
1131                         break;
1132
1133                 case MM_PLAYER_STATE_NULL:
1134                 case MM_PLAYER_STATE_READY:
1135                 case MM_PLAYER_STATE_NONE:
1136                 default:
1137                         LOGW("invalid target state [%s].", MMPLAYER_STATE_GET_NAME(target_state));
1138                         break;
1139                 }
1140         } else {
1141                 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
1142                  *      it's for stopping the pipeline clock to prevent dropping the data in sink element.
1143                  */
1144                 switch (pending_state) {
1145                 case MM_PLAYER_STATE_NONE:
1146                         {
1147                                 if (current_state != MM_PLAYER_STATE_PAUSED) {
1148                                         /* rtsp streaming pause makes rtsp server stop sending data. */
1149                                         if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
1150                                                 LOGD("set pause state during buffering");
1151                                                 _mmplayer_gst_pause(player, TRUE);
1152                                         }
1153                                 }
1154                         }
1155                         break;
1156
1157                 case MM_PLAYER_STATE_PLAYING:
1158                         /* rtsp streaming pause makes rtsp server stop sending data. */
1159                         if (!MMPLAYER_IS_RTSP_STREAMING(player))
1160                                 _mmplayer_gst_pause(player, TRUE);
1161                         break;
1162
1163                 case MM_PLAYER_STATE_PAUSED:
1164                         break;
1165
1166                 case MM_PLAYER_STATE_NULL:
1167                 case MM_PLAYER_STATE_READY:
1168                 default:
1169                         LOGW("invalid pending state [%s].", MMPLAYER_STATE_GET_NAME(pending_state));
1170                         break;
1171                 }
1172         }
1173
1174 exit:
1175         return ret;
1176 }
1177
1178 static stream_variant_t *
1179 __mmplayer_adaptive_var_info(const stream_variant_t *self, gpointer user_data)
1180 {
1181         stream_variant_t *var_info = NULL;
1182         g_return_val_if_fail(self != NULL, NULL);
1183
1184         var_info = g_new0(stream_variant_t, 1);
1185         if (!var_info) return NULL;
1186         var_info->bandwidth = self->bandwidth;
1187         var_info->width = self->width;
1188         var_info->height = self->height;
1189         return var_info;
1190 }
1191
1192 static gboolean
1193 __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg)
1194 {
1195         gint64 bytes = 0;
1196
1197         MMPLAYER_FENTER();
1198
1199         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1200         MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1201
1202         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1203                 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1204                 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1205
1206                 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1207                         LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1208                         player->http_content_size = (bytes > 0) ? bytes : 0;
1209                 }
1210         } else {
1211                 /* handling audio clip which has vbr. means duration is keep changing */
1212                 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1213         }
1214
1215         MMPLAYER_FLEAVE();
1216
1217         return TRUE;
1218 }
1219
1220 static gboolean
1221 __mmplayer_eos_timer_cb(gpointer u_data)
1222 {
1223         mmplayer_t *player = NULL;
1224         MMHandleType attrs = 0;
1225         int count = 0;
1226
1227         MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
1228
1229         player = (mmplayer_t *)u_data;
1230         attrs = MMPLAYER_GET_ATTRS(player);
1231
1232         mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1233
1234         if (count == -1) {
1235                 gint ret_value = 0;
1236                 ret_value = _mmplayer_gst_set_position(player, 0, TRUE);
1237                 if (ret_value != MM_ERROR_NONE)
1238                         LOGE("seeking to 0 failed in repeat play");
1239         } else {
1240                 /* posting eos */
1241                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1242         }
1243
1244         /* we are returning FALSE as we need only one posting */
1245         return FALSE;
1246 }
1247
1248 static void
1249 __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms)
1250 {
1251         MMPLAYER_RETURN_IF_FAIL(player);
1252
1253         /* post now if delay is zero */
1254         if (delay_in_ms == 0 || player->audio_decoded_cb) {
1255                 LOGD("eos delay is zero. posting EOS now");
1256                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1257
1258                 if (player->audio_decoded_cb)
1259                         _mmplayer_cancel_eos_timer(player);
1260
1261                 return;
1262         }
1263
1264         /* cancel if existing */
1265         _mmplayer_cancel_eos_timer(player);
1266
1267         /* init new timeout */
1268         /* NOTE : consider give high priority to this timer */
1269         LOGD("posting EOS message after [%d] msec", delay_in_ms);
1270
1271         player->eos_timer = g_timeout_add(delay_in_ms,
1272                 __mmplayer_eos_timer_cb, player);
1273
1274         player->context.global_default = g_main_context_default();
1275         LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
1276
1277         /* check timer is valid. if not, send EOS now */
1278         if (player->eos_timer == 0) {
1279                 LOGW("creating timer for delayed EOS has failed. sending EOS now");
1280                 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
1281         }
1282 }
1283
1284 static int
1285 __mmplayer_gst_pending_seek(mmplayer_t *player)
1286 {
1287         mmplayer_state_e 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.");
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. ",
1304                         MMPLAYER_STATE_GET_NAME(current_state));
1305                 return ret;
1306         }
1307
1308         LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1309
1310         ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE);
1311         if (ret != MM_ERROR_NONE)
1312                 LOGE("failed to seek pending postion. just keep staying current position.");
1313
1314         player->pending_seek.is_pending = false;
1315
1316         MMPLAYER_FLEAVE();
1317
1318         return ret;
1319 }
1320
1321 static void
1322 __mmplayer_gst_set_async(mmplayer_t *player, gboolean async, enum mmplayer_sink_type  type)
1323 {
1324         mmplayer_gst_element_t *videobin = NULL, *audiobin = NULL, *textbin = NULL;
1325
1326         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
1327
1328         audiobin = player->pipeline->audiobin; /* can be null */
1329         videobin = player->pipeline->videobin; /* can be null */
1330         textbin = player->pipeline->textbin;   /* can be null */
1331
1332         LOGD("Async will be set to %d about 0x%X type sink", async, type);
1333
1334         if ((type & MMPLAYER_AUDIO_SINK) && audiobin && audiobin[MMPLAYER_A_SINK].gst)
1335                 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "async", async, NULL);
1336
1337         if ((type & MMPLAYER_VIDEO_SINK) && videobin && videobin[MMPLAYER_V_SINK].gst)
1338                 g_object_set(videobin[MMPLAYER_V_SINK].gst, "async", async, NULL);
1339
1340         if ((type & MMPLAYER_TEXT_SINK) && textbin && textbin[MMPLAYER_T_FAKE_SINK].gst)
1341                 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", async, NULL);
1342
1343         return;
1344 }
1345
1346 static void
1347 __mmplayer_drop_subtitle(mmplayer_t *player, gboolean is_drop)
1348 {
1349         mmplayer_gst_element_t *textbin;
1350         MMPLAYER_FENTER();
1351
1352         MMPLAYER_RETURN_IF_FAIL(player &&
1353                                         player->pipeline &&
1354                                         player->pipeline->textbin);
1355
1356         MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
1357
1358         textbin = player->pipeline->textbin;
1359
1360         if (is_drop) {
1361                 LOGD("Drop subtitle text after getting EOS");
1362
1363                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_TEXT_SINK);
1364                 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
1365
1366                 player->is_subtitle_force_drop = TRUE;
1367         } else {
1368                 if (player->is_subtitle_force_drop == TRUE) {
1369                         LOGD("Enable subtitle data path without drop");
1370
1371                         g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
1372                         __mmplayer_gst_set_async(player, TRUE, MMPLAYER_TEXT_SINK);
1373
1374                         LOGD("non-connected with external display");
1375
1376                         player->is_subtitle_force_drop = FALSE;
1377                 }
1378         }
1379 }
1380
1381 static void
1382 __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg)
1383 {
1384         MMHandleType attrs = 0;
1385         gint count = 0;
1386
1387         MMPLAYER_FENTER();
1388
1389         /* NOTE : EOS event is comming multiple time. watch out it */
1390         /* check state. we only process EOS when pipeline state goes to PLAYING */
1391         if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1392                 LOGD("EOS received on non-playing state. ignoring it");
1393                 return;
1394         }
1395
1396         if (player->pipeline && player->pipeline->textbin)
1397                 __mmplayer_drop_subtitle(player, TRUE);
1398
1399         if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
1400                 _mmplayer_audio_stream_clear_buffer(player, TRUE);
1401
1402         /* rewind if repeat count is greater then zero */
1403         /* get play count */
1404         attrs = MMPLAYER_GET_ATTRS(player);
1405         if (attrs) {
1406                 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1407
1408                 LOGD("play count: %d, playback rate: %f", count, player->playback_rate);
1409
1410                 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1411                         if (player->playback_rate < 0.0) {
1412                                 player->resumed_by_rewind = TRUE;
1413                                 _mmplayer_set_mute((MMHandleType)player, false);
1414                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1415                         }
1416
1417                         __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1418
1419                         /* initialize */
1420                         player->sent_bos = FALSE;
1421
1422                         LOGD("do not post eos msg for repeating");
1423                         return;
1424                 }
1425         }
1426
1427         if (player->pipeline)
1428                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1429
1430         /* post eos message to application */
1431         __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1432
1433         /* reset last position */
1434         player->last_position = 0;
1435
1436         MMPLAYER_FLEAVE();
1437         return;
1438 }
1439
1440 static void
1441 __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg)
1442 {
1443         GError *error = NULL;
1444         gchar *debug = NULL;
1445
1446         MMPLAYER_FENTER();
1447
1448         /* generating debug info before returning error */
1449         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1450
1451         /* get error code */
1452         gst_message_parse_error(msg, &error, &debug);
1453
1454         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1455                 /* Note : the streaming error from the streaming source is handled
1456                  *       using __mmplayer_handle_streaming_error.
1457                  */
1458                 __mmplayer_handle_streaming_error(player, msg);
1459
1460                 /* dump state of all element */
1461                 _mmplayer_dump_pipeline_state(player);
1462         } else {
1463                 /* traslate gst error code to msl error code. then post it
1464                  * to application if needed
1465                  */
1466                 __mmplayer_handle_gst_error(player, msg, error);
1467
1468                 if (debug)
1469                         LOGE("error debug : %s", debug);
1470         }
1471
1472         MMPLAYER_FREEIF(debug);
1473         g_error_free(error);
1474
1475         MMPLAYER_FLEAVE();
1476         return;
1477 }
1478
1479 static void
1480 __mmplayer_gst_handle_buffering_message(mmplayer_t *player, GstMessage *msg)
1481 {
1482         MMMessageParamType msg_param = {0, };
1483         int bRet = MM_ERROR_NONE;
1484
1485         MMPLAYER_FENTER();
1486         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1487
1488         if (!MMPLAYER_IS_STREAMING(player)) {
1489                 LOGW("this is not streaming playback.");
1490                 return;
1491         }
1492
1493         MMPLAYER_CMD_LOCK(player);
1494
1495         if (!player->streamer) {
1496                 LOGW("Pipeline is shutting down");
1497                 MMPLAYER_CMD_UNLOCK(player);
1498                 return;
1499         }
1500
1501         /* ignore the remained buffering message till getting 100% msg */
1502         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1503                 gint buffer_percent = 0;
1504
1505                 gst_message_parse_buffering(msg, &buffer_percent);
1506
1507                 if (buffer_percent == MAX_BUFFER_PERCENT) {
1508                         LOGD("Ignored all the previous buffering msg!(got %d%%)", buffer_percent);
1509                         __mmplayer_update_buffer_setting(player, NULL); /* update buffering size for next buffering */
1510                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1511                 }
1512                 MMPLAYER_CMD_UNLOCK(player);
1513                 return;
1514         }
1515
1516         /* ignore the remained buffering message */
1517         if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1518                 gint buffer_percent = 0;
1519
1520                 gst_message_parse_buffering(msg, &buffer_percent);
1521
1522                 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1523                                         player->streamer->buffering_percent, buffer_percent);
1524
1525                 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1526                         player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1527                         player->streamer->buffering_req.is_pre_buffering = FALSE;
1528
1529                         LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1530                 } else {
1531                         LOGD("interrupted buffering - ignored the remained buffering msg!");
1532                         MMPLAYER_CMD_UNLOCK(player);
1533                         return;
1534                 }
1535         }
1536
1537         __mmplayer_update_buffer_setting(player, msg);
1538
1539         bRet = __mmplayer_handle_buffering_playback(player); /* playback control */
1540
1541         if (bRet == MM_ERROR_NONE) {
1542                 msg_param.connection.buffering = player->streamer->buffering_percent;
1543                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1544
1545                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1546                         player->pending_resume &&
1547                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1548
1549                         player->is_external_subtitle_added_now = FALSE;
1550                         player->pending_resume = FALSE;
1551                         _mmplayer_resume((MMHandleType)player);
1552                 }
1553
1554                 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1555                         (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1556
1557                         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1558                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1559                                         player->seek_state = MMPLAYER_SEEK_NONE;
1560                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1561                                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1562                                         /* Considering the async state trasition in case of RTSP.
1563                                            After getting state change gst msg, seek cmpleted msg will be posted. */
1564                                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1565                                 }
1566                         }
1567                 }
1568         } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1569                 if (!player->streamer) {
1570                         LOGW("player->streamer is NULL, so discarding the buffering percent update");
1571                         MMPLAYER_CMD_UNLOCK(player);
1572                         return;
1573                 }
1574
1575                 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1576
1577                         LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d",
1578                                         GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1579
1580                         if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1581                                 msg_param.connection.buffering = player->streamer->buffering_percent;
1582                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1583                         } else {
1584                                 LOGD("Not updating Buffering Message for Live RTSP case !!!");
1585                         }
1586                 } else {
1587                         msg_param.connection.buffering = player->streamer->buffering_percent;
1588                         MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1589                 }
1590         }
1591         MMPLAYER_CMD_UNLOCK(player);
1592
1593         MMPLAYER_FLEAVE();
1594         return;
1595
1596 }
1597
1598 static void
1599 __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg)
1600 {
1601         mmplayer_gst_element_t *mainbin;
1602         const GValue *voldstate, *vnewstate, *vpending;
1603         GstState oldstate = GST_STATE_NULL;
1604         GstState newstate = GST_STATE_NULL;
1605         GstState pending = GST_STATE_NULL;
1606
1607         MMPLAYER_FENTER();
1608         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1609
1610         mainbin = player->pipeline->mainbin;
1611
1612         /* we only handle messages from pipeline */
1613         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1614                 return;
1615
1616         /* get state info from msg */
1617         voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1618         vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1619         vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1620
1621         if (!voldstate || !vnewstate) {
1622                 LOGE("received msg has wrong format.");
1623                 return;
1624         }
1625
1626         oldstate = (GstState)voldstate->data[0].v_int;
1627         newstate = (GstState)vnewstate->data[0].v_int;
1628         if (vpending)
1629                 pending = (GstState)vpending->data[0].v_int;
1630
1631         LOGD("state changed [%s] : %s ---> %s     final : %s",
1632                 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1633                 gst_element_state_get_name((GstState)oldstate),
1634                 gst_element_state_get_name((GstState)newstate),
1635                 gst_element_state_get_name((GstState)pending));
1636
1637         if (newstate == GST_STATE_PLAYING) {
1638                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1639
1640                         int retVal = MM_ERROR_NONE;
1641                         LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos);
1642
1643                         retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE);
1644
1645                         if (MM_ERROR_NONE != retVal)
1646                                 LOGE("failed to seek pending postion. just keep staying current position.");
1647
1648                         player->pending_seek.is_pending = false;
1649                 }
1650         }
1651
1652         if (oldstate == newstate) {
1653                 LOGD("pipeline reports state transition to old state");
1654                 return;
1655         }
1656
1657         switch (newstate) {
1658         case GST_STATE_PAUSED:
1659                 {
1660                         gboolean prepare_async = FALSE;
1661
1662                         if (!player->sent_bos && oldstate == GST_STATE_READY) {
1663                                 // managed prepare async case
1664                                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1665                                 LOGD("checking prepare mode for async transition - %d", prepare_async);
1666                         }
1667
1668                         if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1669                                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1670
1671                                 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1672                                         _mm_player_streaming_set_content_bitrate(player->streamer,
1673                                                 player->total_maximum_bitrate, player->total_bitrate);
1674
1675                                 if (player->pending_seek.is_pending) {
1676                                         LOGW("trying to do pending seek");
1677                                         MMPLAYER_CMD_LOCK(player);
1678                                         __mmplayer_gst_pending_seek(player);
1679                                         MMPLAYER_CMD_UNLOCK(player);
1680                                 }
1681                         }
1682                 }
1683                 break;
1684
1685         case GST_STATE_PLAYING:
1686                 {
1687                         if (MMPLAYER_IS_STREAMING(player)) {
1688                                 // managed prepare async case when buffering is completed
1689                                 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1690                                 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1691                                         (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1692                                         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1693
1694                                 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1695
1696                                         LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1697                                         if (player->streamer->buffering_percent < 100) {
1698
1699                                                 MMMessageParamType msg_param = {0, };
1700                                                 LOGW("Posting Buffering Completed Message to Application !!!");
1701
1702                                                 msg_param.connection.buffering = 100;
1703                                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1704                                         }
1705                                 }
1706                         }
1707
1708                         if (player->gapless.stream_changed) {
1709                                 _mmplayer_update_content_attrs(player, ATTR_ALL);
1710                                 player->gapless.stream_changed = FALSE;
1711                         }
1712
1713                         if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1714                                 player->seek_state = MMPLAYER_SEEK_NONE;
1715                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1716                         }
1717                 }
1718                 break;
1719         case GST_STATE_VOID_PENDING:
1720         case GST_STATE_NULL:
1721         case GST_STATE_READY:
1722         default:
1723                 break;
1724         }
1725
1726         MMPLAYER_FLEAVE();
1727         return;
1728 }
1729
1730 static void
1731 __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg)
1732 {
1733         const gchar *structure_name;
1734         gint count = 0, idx = 0;
1735
1736         MMPLAYER_FENTER();
1737         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1738
1739         if (gst_message_get_structure(msg) == NULL)
1740                 return;
1741
1742         structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1743         if (!structure_name)
1744                 return;
1745
1746         LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1747
1748         if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1749                 const GValue *var_info = NULL;
1750
1751                 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1752                 if (var_info != NULL) {
1753                         if (player->adaptive_info.var_list)
1754                                 g_list_free_full(player->adaptive_info.var_list, g_free);
1755
1756                         /* share addr or copy the list */
1757                         player->adaptive_info.var_list =
1758                                 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1759
1760                         count = g_list_length(player->adaptive_info.var_list);
1761                         if (count > 0) {
1762                                 stream_variant_t *temp = NULL;
1763
1764                                 /* print out for debug */
1765                                 LOGD("num of variant_info %d", count);
1766                                 for (idx = 0; idx < count; idx++) {
1767                                         temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1768                                         if (temp)
1769                                                 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1770                                 }
1771                         }
1772                 }
1773         }
1774
1775         if (!strcmp(structure_name, "prepare-decode-buffers")) {
1776                 gint num_buffers = 0;
1777                 gint extra_num_buffers = 0;
1778
1779                 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1780                         LOGD("video_num_buffers : %d", num_buffers);
1781                         mm_player_set_attribute((MMHandleType)player, NULL,
1782                                         MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL);
1783                 }
1784
1785                 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1786                         LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1787                         mm_player_set_attribute((MMHandleType)player, NULL,
1788                                         MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL);
1789                 }
1790                 return;
1791         }
1792
1793         if (!strcmp(structure_name, "Ext_Sub_Language_List"))
1794                 _mmplayer_track_update_text_attr_info(player, msg);
1795
1796         /* custom message */
1797         if (!strcmp(structure_name, "audio_codec_not_supported")) {
1798                 MMMessageParamType msg_param = {0,};
1799                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1800                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1801         }
1802
1803         /* custom message for RTSP attribute :
1804                 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1805                 sdp which has contents info is received when rtsp connection is opened.
1806                 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1807         if (!strcmp(structure_name, "rtspsrc_properties")) {
1808                 gchar *audio_codec = NULL;
1809                 gchar *video_codec = NULL;
1810                 gchar *video_frame_size = NULL;
1811
1812                 gst_structure_get(gst_message_get_structure(msg),
1813                                         "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1814                 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1815                 player->streaming_type = _mmplayer_get_stream_service_type(player);
1816
1817                 gst_structure_get(gst_message_get_structure(msg),
1818                                         "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1819                 LOGD("rtsp_audio_codec : %s", audio_codec);
1820                 if (audio_codec)
1821                         mm_player_set_attribute((MMHandleType)player, NULL,
1822                                         "content_audio_codec", audio_codec, strlen(audio_codec), NULL);
1823
1824                 gst_structure_get(gst_message_get_structure(msg),
1825                                         "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1826                 LOGD("rtsp_video_codec : %s", video_codec);
1827                 if (video_codec)
1828                         mm_player_set_attribute((MMHandleType)player, NULL,
1829                                         "content_video_codec", video_codec, strlen(video_codec), NULL);
1830
1831                 gst_structure_get(gst_message_get_structure(msg),
1832                                         "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1833                 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1834                 if (video_frame_size) {
1835                         char *seperator = strchr(video_frame_size, '-');
1836                         if (seperator) {
1837                                 char video_width[10] = {0,};
1838                                 int frame_size_len = strlen(video_frame_size);
1839                                 int separtor_len = strlen(seperator);
1840
1841                                 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1842                                 seperator++;
1843
1844                                 mm_player_set_attribute((MMHandleType)player, NULL, MM_PLAYER_VIDEO_WIDTH,
1845                                                 atoi(video_width), MM_PLAYER_VIDEO_HEIGHT, atoi(seperator), NULL);
1846                         }
1847                 }
1848         }
1849
1850         MMPLAYER_FLEAVE();
1851         return;
1852 }
1853
1854 static void
1855 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1856 {
1857         mmplayer_gst_element_t *mainbin;
1858
1859         MMPLAYER_FENTER();
1860         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1861
1862         mainbin = player->pipeline->mainbin;
1863
1864         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1865
1866         /* we only handle messages from pipeline */
1867         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1868                 return;
1869
1870         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1871                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1872                         player->seek_state = MMPLAYER_SEEK_NONE;
1873                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1874                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1875                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1876                                 LOGD("sync %s state(%s) with parent state(%s)",
1877                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1878                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1879                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1880
1881                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1882                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1883                                    Because the buffering state is controlled according to the state transition for force resume,
1884                                    the decodebin state should be paused as player state. */
1885                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1886                         }
1887
1888                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1889                                 (player->streamer) &&
1890                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1891                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1892                                 GstQuery *query = NULL;
1893                                 gboolean busy = FALSE;
1894                                 gint percent = 0;
1895
1896                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1897                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1898                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1899                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1900                                         gst_query_unref(query);
1901
1902                                         LOGD("buffered percent(%s): %d",
1903                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1904                                 }
1905
1906                                 if (percent >= 100)
1907                                         __mmplayer_handle_buffering_playback(player);
1908                         }
1909
1910                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1911                 }
1912         }
1913
1914         MMPLAYER_FLEAVE();
1915         return;
1916 }
1917
1918 static void
1919 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1920 {
1921         mmplayer_t *player = (mmplayer_t *)(data);
1922
1923         MMPLAYER_RETURN_IF_FAIL(player);
1924         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1925
1926         switch (GST_MESSAGE_TYPE(msg)) {
1927         case GST_MESSAGE_UNKNOWN:
1928                 LOGD("unknown message received");
1929                 break;
1930
1931         case GST_MESSAGE_EOS:
1932                 LOGD("GST_MESSAGE_EOS received");
1933                 __mmplayer_gst_handle_eos_message(player, msg);
1934                 break;
1935
1936         case GST_MESSAGE_ERROR:
1937                 __mmplayer_gst_handle_error_message(player, msg);
1938                 break;
1939
1940         case GST_MESSAGE_WARNING:
1941                 {
1942                         char *debug = NULL;
1943                         GError *error = NULL;
1944
1945                         gst_message_parse_warning(msg, &error, &debug);
1946
1947                         LOGD("warning : %s", error->message);
1948                         LOGD("debug : %s", debug);
1949
1950                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1951
1952                         MMPLAYER_FREEIF(debug);
1953                         g_error_free(error);
1954                 }
1955                 break;
1956
1957         case GST_MESSAGE_TAG:
1958                 {
1959                         LOGD("GST_MESSAGE_TAG");
1960                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1961                                 LOGW("failed to extract tags from gstmessage");
1962                 }
1963                 break;
1964
1965         case GST_MESSAGE_BUFFERING:
1966                 __mmplayer_gst_handle_buffering_message(player, msg);
1967                 break;
1968
1969         case GST_MESSAGE_STATE_CHANGED:
1970                 __mmplayer_gst_handle_state_message(player, msg);
1971                 break;
1972
1973         case GST_MESSAGE_CLOCK_LOST:
1974                         {
1975                                 GstClock *clock = NULL;
1976                                 gboolean need_new_clock = FALSE;
1977
1978                                 gst_message_parse_clock_lost(msg, &clock);
1979                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1980
1981                                 if (!player->videodec_linked)
1982                                         need_new_clock = TRUE;
1983                                 else if (!player->ini.use_system_clock)
1984                                         need_new_clock = TRUE;
1985
1986                                 if (need_new_clock) {
1987                                         LOGD("Provide clock is TRUE, do pause->resume");
1988                                         _mmplayer_gst_pause(player, FALSE);
1989                                         _mmplayer_gst_resume(player, FALSE);
1990                                 }
1991                         }
1992                         break;
1993
1994         case GST_MESSAGE_NEW_CLOCK:
1995                         {
1996                                 GstClock *clock = NULL;
1997                                 gst_message_parse_new_clock(msg, &clock);
1998                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1999                         }
2000                         break;
2001
2002         case GST_MESSAGE_ELEMENT:
2003                 __mmplayer_gst_handle_element_message(player, msg);
2004                         break;
2005
2006         case GST_MESSAGE_DURATION_CHANGED:
2007                 {
2008                         LOGD("GST_MESSAGE_DURATION_CHANGED");
2009                         if (!__mmplayer_gst_handle_duration(player, msg))
2010                                 LOGW("failed to update duration");
2011                 }
2012                 break;
2013
2014         case GST_MESSAGE_ASYNC_START:
2015                         LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2016                 break;
2017
2018         case GST_MESSAGE_ASYNC_DONE:
2019                 __mmplayer_gst_handle_async_done_message(player, msg);
2020                 break;
2021         case GST_MESSAGE_STREAM_COLLECTION:
2022                 LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2023                 break;
2024         case GST_MESSAGE_STREAMS_SELECTED:
2025                 LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2026                 break;
2027
2028 #ifdef __DEBUG__
2029         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2030         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START"); break;
2031         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS"); break;
2032         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS"); break;
2033         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY"); break;
2034         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2035         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2036         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE"); break;
2037         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2038         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2039         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2040         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION"); break;
2041         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START"); break;
2042         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2043         case GST_MESSAGE_LATENCY:                       LOGD("GST_MESSAGE_LATENCY"); break;
2044 #endif
2045
2046         default:
2047                 break;
2048         }
2049
2050         /* should not call 'gst_message_unref(msg)' */
2051         return;
2052 }
2053
2054 static GstBusSyncReply
2055 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2056 {
2057         mmplayer_t *player = (mmplayer_t *)data;
2058         GstBusSyncReply reply = GST_BUS_DROP;
2059
2060         if (!(player->pipeline && player->pipeline->mainbin)) {
2061                 LOGE("player pipeline handle is null");
2062                 return GST_BUS_PASS;
2063         }
2064
2065         if (!__mmplayer_gst_check_useful_message(player, message)) {
2066                 gst_message_unref(message);
2067                 return GST_BUS_DROP;
2068         }
2069
2070         switch (GST_MESSAGE_TYPE(message)) {
2071         case GST_MESSAGE_TAG:
2072                 __mmplayer_gst_extract_tag_from_msg(player, message);
2073
2074 #ifdef __DEBUG__
2075                 {
2076                         GstTagList *tags = NULL;
2077
2078                         gst_message_parse_tag(message, &tags);
2079                         if (tags) {
2080                                 LOGE("TAGS received from element \"%s\".",
2081                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2082
2083                                 gst_tag_list_foreach(tags, print_tag, NULL);
2084                                 gst_tag_list_unref(tags);
2085                                 tags = NULL;
2086                         }
2087                         break;
2088                 }
2089 #endif
2090                 break;
2091
2092         case GST_MESSAGE_DURATION_CHANGED:
2093                 __mmplayer_gst_handle_duration(player, message);
2094                 break;
2095         case GST_MESSAGE_ASYNC_DONE:
2096                 /* NOTE:Don't call gst_callback directly
2097                  * because previous frame can be showed even though this message is received for seek.
2098                  */
2099         default:
2100                 reply = GST_BUS_PASS;
2101                 break;
2102         }
2103
2104         if (reply == GST_BUS_DROP)
2105                 gst_message_unref(message);
2106
2107         return reply;
2108 }
2109
2110 static void
2111 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2112 {
2113         GstElement *appsrc = element;
2114         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2115         GstBuffer *buffer = NULL;
2116         GstFlowReturn ret = GST_FLOW_OK;
2117         gint len = size;
2118
2119         MMPLAYER_RETURN_IF_FAIL(element);
2120         MMPLAYER_RETURN_IF_FAIL(buf);
2121
2122         buffer = gst_buffer_new();
2123
2124         if (buf->offset < 0 || buf->len < 0) {
2125                 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2126                 return;
2127         }
2128
2129         if (buf->offset >= buf->len) {
2130                 LOGD("call eos appsrc");
2131                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2132                 return;
2133         }
2134
2135         if (buf->len - buf->offset < size)
2136                 len = buf->len - buf->offset;
2137
2138         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2139         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2140         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2141
2142 #ifdef __DEBUG__
2143         LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2144 #endif
2145         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2146
2147         buf->offset += len;
2148 }
2149
2150 static gboolean
2151 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2152 {
2153         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2154
2155         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2156
2157         buf->offset  = (int)size;
2158
2159         return TRUE;
2160 }
2161
2162 void
2163 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2164 {
2165         mmplayer_t *player  = (mmplayer_t *)user_data;
2166         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2167         MMMessageParamType msg_param = {0,};
2168         guint64 current_level_bytes = 0;
2169
2170         MMPLAYER_RETURN_IF_FAIL(player);
2171
2172         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2173                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2174         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2175                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2176         } else {
2177                 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2178                 return;
2179         }
2180
2181         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2182
2183         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2184
2185         msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2186         msg_param.buffer_status.stream_type = stream_type;
2187         msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2188         msg_param.buffer_status.bytes = current_level_bytes;
2189
2190         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2191 }
2192
2193 void
2194 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2195 {
2196         mmplayer_t *player  = (mmplayer_t *)user_data;
2197         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2198         MMMessageParamType msg_param = {0,};
2199         guint64 current_level_bytes = 0;
2200
2201         MMPLAYER_RETURN_IF_FAIL(player);
2202
2203         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2204                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2205         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2206                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2207         } else {
2208                 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2209                 return;
2210         }
2211
2212         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2213
2214         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2215
2216         msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2217         msg_param.buffer_status.stream_type = stream_type;
2218         msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2219         msg_param.buffer_status.bytes = current_level_bytes;
2220
2221         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2222 }
2223
2224 gboolean
2225 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2226 {
2227         mmplayer_t *player  = (mmplayer_t *)user_data;
2228         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2229         MMMessageParamType msg_param = {0,};
2230
2231         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2232
2233         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2234                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2235         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2236                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2237         } else {
2238                 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2239                 return TRUE;
2240         }
2241
2242         LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2243
2244         msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2245         msg_param.seek_data.stream_type = stream_type;
2246         msg_param.seek_data.offset = position;
2247
2248         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2249
2250         return TRUE;
2251 }
2252
2253 static gboolean
2254 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2255 {
2256 #define MAX_LEN_NAME 20
2257
2258         gboolean ret = FALSE;
2259         GstPad *sinkpad = NULL;
2260         gchar *prefix = NULL;
2261         gchar dec_name[MAX_LEN_NAME] = {0, };
2262         main_element_id_e elem_id = MMPLAYER_M_NUM;
2263
2264         mmplayer_gst_element_t *mainbin = NULL;
2265         GstElement *decodebin = NULL;
2266         GstCaps *dec_caps = NULL;
2267
2268         MMPLAYER_FENTER();
2269
2270         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2271                                                 player->pipeline &&
2272                                                 player->pipeline->mainbin, FALSE);
2273         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2274
2275         mainbin = player->pipeline->mainbin;
2276         switch (type) {
2277         case MM_PLAYER_STREAM_TYPE_AUDIO:
2278                 prefix = "audio";
2279                 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2280         break;
2281         case MM_PLAYER_STREAM_TYPE_VIDEO:
2282                 prefix = "video";
2283                 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2284         break;
2285         default:
2286                 LOGE("invalid type %d", type);
2287                 return FALSE;
2288         }
2289
2290         if (mainbin[elem_id].gst) {
2291                 LOGE("elem(%d) is already created", elem_id);
2292                 return FALSE;
2293         }
2294
2295         snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2296
2297         /* create decodebin */
2298         decodebin = gst_element_factory_make("decodebin", dec_name);
2299         if (!decodebin) {
2300                 LOGE("failed to create %s", dec_name);
2301                 return FALSE;
2302         }
2303
2304         mainbin[elem_id].id = elem_id;
2305         mainbin[elem_id].gst = decodebin;
2306
2307         /* raw pad handling signal */
2308         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2309                                                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2310
2311         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2312         before looking for any elements that can handle that stream.*/
2313         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2314                                                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2315
2316         /* This signal is emitted when a element is added to the bin.*/
2317         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2318                                                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2319
2320         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2321                 LOGE("failed to add new decodebin");
2322                 return FALSE;
2323         }
2324
2325         dec_caps = gst_pad_query_caps(srcpad, NULL);
2326         if (dec_caps) {
2327 #ifdef __DEBUG__
2328                 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2329 #endif
2330                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2331                 gst_caps_unref(dec_caps);
2332         }
2333
2334         sinkpad = gst_element_get_static_pad(decodebin, "sink");
2335
2336         if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2337                 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2338                 goto ERROR;
2339         }
2340         gst_object_unref(GST_OBJECT(sinkpad));
2341
2342         gst_element_sync_state_with_parent(decodebin);
2343         MMPLAYER_FLEAVE();
2344         return TRUE;
2345
2346 ERROR:
2347         if (sinkpad)
2348                 gst_object_unref(GST_OBJECT(sinkpad));
2349
2350         if (mainbin[elem_id].gst) {
2351                 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2352                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2353                 gst_object_unref(mainbin[elem_id].gst);
2354                 mainbin[elem_id].gst = NULL;
2355         }
2356
2357         MMPLAYER_FLEAVE();
2358         return ret;
2359 }
2360
2361 static gboolean
2362 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2363 {
2364 #define MAX_LEN_NAME 20
2365         mmplayer_gst_element_t *mainbin = NULL;
2366         gchar *prefix = NULL;
2367         main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2368
2369         gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2370         GstElement *src = NULL, *queue = NULL;
2371         GstPad *srcpad = NULL;
2372
2373         MMPLAYER_FENTER();
2374         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2375                                 player->pipeline->mainbin, FALSE);
2376
2377         mainbin = player->pipeline->mainbin;
2378
2379         LOGD("type(%d) path is creating", type);
2380         switch (type) {
2381         case MM_PLAYER_STREAM_TYPE_AUDIO:
2382                 prefix = "audio";
2383                 if (mainbin[MMPLAYER_M_SRC].gst)
2384                         src_id = MMPLAYER_M_2ND_SRC;
2385                 else
2386                         src_id = MMPLAYER_M_SRC;
2387                 queue_id = MMPLAYER_M_A_BUFFER;
2388         break;
2389         case MM_PLAYER_STREAM_TYPE_VIDEO:
2390                 prefix = "video";
2391                 src_id = MMPLAYER_M_SRC;
2392                 queue_id = MMPLAYER_M_V_BUFFER;
2393         break;
2394         case MM_PLAYER_STREAM_TYPE_TEXT:
2395                 prefix = "subtitle";
2396                 src_id = MMPLAYER_M_SUBSRC;
2397                 queue_id = MMPLAYER_M_S_BUFFER;
2398         break;
2399         default:
2400                 LOGE("invalid type %d", type);
2401                 return FALSE;
2402         }
2403
2404         snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2405         snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2406
2407         /* create source */
2408         src = gst_element_factory_make("appsrc", src_name);
2409         if (!src) {
2410                 LOGF("failed to create %s", src_name);
2411                 goto ERROR;
2412         }
2413
2414         mainbin[src_id].id = src_id;
2415         mainbin[src_id].gst = src;
2416
2417         g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2418                                                                 "caps", caps, NULL);
2419
2420         /* size of many video frames are larger than default blocksize as 4096 */
2421         if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2422                 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2423
2424         if (player->media_stream_buffer_max_size[type] > 0)
2425                 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2426
2427         if (player->media_stream_buffer_min_percent[type] > 0)
2428                 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2429
2430         /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2431         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2432
2433         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2434                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2435         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2436                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2437         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2438                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2439
2440         /* create queue */
2441         queue = gst_element_factory_make("queue2", queue_name);
2442         if (!queue) {
2443                 LOGE("failed to create %s", queue_name);
2444                 goto ERROR;
2445         }
2446         g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2447
2448         mainbin[queue_id].id = queue_id;
2449         mainbin[queue_id].gst = queue;
2450
2451         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2452                 LOGE("failed to add src");
2453                 goto ERROR;
2454         }
2455
2456         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2457                 LOGE("failed to add queue");
2458                 goto ERROR;
2459         }
2460
2461         if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2462                 LOGE("failed to link src and queue");
2463                 goto ERROR;
2464         }
2465
2466         /* create decoder */
2467         srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2468         if (!srcpad) {
2469                 LOGE("failed to get srcpad of queue");
2470                 goto ERROR;
2471         }
2472
2473         if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2474                 _mmplayer_gst_create_decoder(player, srcpad, caps);
2475         } else {
2476                 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2477                         LOGE("failed to create decoder");
2478                         gst_object_unref(GST_OBJECT(srcpad));
2479                         goto ERROR;
2480                 }
2481         }
2482         gst_object_unref(GST_OBJECT(srcpad));
2483         return TRUE;
2484
2485 ERROR:
2486         if (mainbin[src_id].gst) {
2487                 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2488                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2489                 gst_object_unref(mainbin[src_id].gst);
2490                 mainbin[src_id].gst = NULL;
2491         }
2492
2493         if (mainbin[queue_id].gst) {
2494                 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2495                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2496                 gst_object_unref(mainbin[queue_id].gst);
2497                 mainbin[queue_id].gst = NULL;
2498         }
2499
2500         return FALSE;
2501 }
2502
2503 static void
2504 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2505 {
2506         GstPad *sinkpad = NULL;
2507         GstCaps *caps = NULL;
2508         GstElement *new_element = NULL;
2509         GstStructure *str = NULL;
2510         const gchar *name = NULL;
2511
2512         mmplayer_t *player = (mmplayer_t *)data;
2513
2514         MMPLAYER_FENTER();
2515
2516         MMPLAYER_RETURN_IF_FAIL(element && pad);
2517         MMPLAYER_RETURN_IF_FAIL(player &&
2518                                         player->pipeline &&
2519                                         player->pipeline->mainbin);
2520
2521         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2522          * num_dynamic_pad will decreased after creating a sinkbin.
2523          */
2524         player->num_dynamic_pad++;
2525         LOGD("stream count inc : %d", player->num_dynamic_pad);
2526
2527         caps = gst_pad_query_caps(pad, NULL);
2528         MMPLAYER_CHECK_NULL(caps);
2529
2530         str = gst_caps_get_structure(caps, 0);
2531         name = gst_structure_get_string(str, "media");
2532         if (!name) {
2533                 LOGE("cannot get mimetype from structure.");
2534                 goto ERROR;
2535         }
2536
2537         if (strstr(name, "video")) {
2538                 gint stype = 0;
2539                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2540
2541                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2542                         if (player->v_stream_caps) {
2543                                 gst_caps_unref(player->v_stream_caps);
2544                                 player->v_stream_caps = NULL;
2545                         }
2546
2547                         new_element = gst_element_factory_make("fakesink", NULL);
2548                         player->num_dynamic_pad--;
2549                         goto NEW_ELEMENT;
2550                 }
2551         }
2552
2553         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2554                 LOGE("failed to autoplug for caps");
2555                 goto ERROR;
2556         }
2557
2558         gst_caps_unref(caps);
2559         caps = NULL;
2560
2561 NEW_ELEMENT:
2562
2563         /* excute new_element if created*/
2564         if (new_element) {
2565                 LOGD("adding new element to pipeline");
2566
2567                 /* set state to READY before add to bin */
2568                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2569
2570                 /* add new element to the pipeline */
2571                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2572                         LOGE("failed to add autoplug element to bin");
2573                         goto ERROR;
2574                 }
2575
2576                 /* get pad from element */
2577                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2578                 if (!sinkpad) {
2579                         LOGE("failed to get sinkpad from autoplug element");
2580                         goto ERROR;
2581                 }
2582
2583                 /* link it */
2584                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2585                         LOGE("failed to link autoplug element");
2586                         goto ERROR;
2587                 }
2588
2589                 gst_object_unref(sinkpad);
2590                 sinkpad = NULL;
2591
2592                 /* run. setting PLAYING here since streamming source is live source */
2593                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2594         }
2595
2596         if (caps)
2597                 gst_caps_unref(caps);
2598
2599         MMPLAYER_FLEAVE();
2600
2601         return;
2602
2603 STATE_CHANGE_FAILED:
2604 ERROR:
2605         /* FIXIT : take care if new_element has already added to pipeline */
2606         if (new_element)
2607                 gst_object_unref(GST_OBJECT(new_element));
2608
2609         if (sinkpad)
2610                 gst_object_unref(GST_OBJECT(sinkpad));
2611
2612         if (caps)
2613                 gst_caps_unref(caps);
2614
2615         /* FIXIT : how to inform this error to MSL ????? */
2616         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2617          * then post an error to application
2618          */
2619 }
2620
2621 static void
2622 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2623 {
2624         mmplayer_t *player = (mmplayer_t *)data;
2625
2626         MMPLAYER_FENTER();
2627
2628         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2629          * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2630          * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2631          * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2632
2633          * [1] audio and video will be dumped with filesink.
2634          * [2] autoplugging is done by just using pad caps.
2635          * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2636          * and the video will be dumped via filesink.
2637          */
2638         if (player->num_dynamic_pad == 0) {
2639                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2640
2641                 if (!_mmplayer_gst_remove_fakesink(player,
2642                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2643                         /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
2644                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2645                          * source element are not same. To overcome this situation, this function will called
2646                          * several places and several times. Therefore, this is not an error case.
2647                          */
2648                         return;
2649         }
2650
2651         /* create dot before error-return. for debugging */
2652         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2653
2654         player->no_more_pad = TRUE;
2655
2656         MMPLAYER_FLEAVE();
2657 }
2658
2659 static GstElement *
2660 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2661 {
2662         GstElement *element = NULL;
2663         gchar *user_agent = NULL;
2664         MMHandleType attrs = 0;
2665
2666         MMPLAYER_FENTER();
2667         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2668
2669         /* get profile attribute */
2670         attrs = MMPLAYER_GET_ATTRS(player);
2671         if (!attrs) {
2672                 LOGE("failed to get content attribute");
2673                 return NULL;
2674         }
2675
2676         element = gst_element_factory_make("rtspsrc", "rtsp source");
2677         if (!element) {
2678                 LOGE("failed to create rtspsrc element");
2679                 return NULL;
2680         }
2681
2682         /* get attribute */
2683         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2684
2685         SECURE_LOGD("user_agent : %s", user_agent);
2686
2687         /* setting property to streaming source */
2688         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2689         if (user_agent)
2690                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2691
2692         _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2693                                                                         G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2694         _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2695                                                                         G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2696
2697         MMPLAYER_FLEAVE();
2698         return element;
2699 }
2700
2701 void __mmplayer_http_src_setup(GstElement *element, GstElement *source, gpointer data)
2702 {
2703 #define HTTP_SOURCE_BLOCK_SIZE (64 * 1024)
2704
2705         mmplayer_t *player = (mmplayer_t *)data;
2706         MMHandleType attrs = 0;
2707         gchar *user_agent, *cookies, **cookie_list;
2708         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2709         user_agent = cookies = NULL;
2710         cookie_list = NULL;
2711
2712         MMPLAYER_FENTER();
2713         MMPLAYER_RETURN_IF_FAIL(player);
2714
2715         LOGD("source element %s", GST_ELEMENT_NAME(source));
2716
2717         /* get profile attribute */
2718         attrs = MMPLAYER_GET_ATTRS(player);
2719         if (!attrs) {
2720                 LOGE("failed to get content attribute");
2721                 return;
2722         }
2723
2724         player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
2725         player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source;
2726
2727         /* get attribute */
2728         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2729         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2730
2731         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2732                 http_timeout = player->ini.http_timeout;
2733
2734         /* get attribute */
2735         SECURE_LOGD("cookies : %s", cookies);
2736         SECURE_LOGD("user_agent :  %s", user_agent);
2737         LOGD("timeout : %d", http_timeout);
2738
2739         /* setting property to streaming source */
2740         g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL);
2741
2742         /* parsing cookies */
2743         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2744                 g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL);
2745                 g_strfreev(cookie_list);
2746         }
2747
2748         if (user_agent)
2749                 g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL);
2750
2751         MMPLAYER_FLEAVE();
2752         return;
2753 }
2754
2755 gint __mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection,
2756     GstStream * stream, gpointer data)
2757 {
2758         GstStreamType stype = gst_stream_get_stream_type (stream);
2759
2760         if (stype & GST_STREAM_TYPE_AUDIO)
2761                 LOGW("AUDIO type 0x%X", stype);
2762         else if (stype & GST_STREAM_TYPE_VIDEO)
2763                 LOGW("VIDEO type 0x%X", stype);
2764         else if (stype & GST_STREAM_TYPE_TEXT)
2765                 LOGW("TEXT type 0x%X", stype);
2766
2767         return 1;
2768 }
2769
2770 void
2771 __mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2772 {
2773         gchar *factory_name = NULL;
2774         mmplayer_t *player = (mmplayer_t *)data;
2775
2776         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
2777
2778         LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child),
2779                 factory_name, GST_ELEMENT_NAME(element));
2780
2781         /* keep the first typefind reference only */
2782         if (!player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) {
2783                 player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND;
2784                 player->pipeline->mainbin[MMPLAYER_M_TYPEFIND].gst = element;
2785
2786                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2787                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
2788         } else if (g_strrstr(factory_name, "parsebin")) {
2789                 player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN;
2790                 player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element;
2791                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2792                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
2793
2794                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2795                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
2796
2797                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
2798                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2799         } else {
2800                 _mmplayer_gst_element_added((GstElement *)child, element, data);
2801         }
2802
2803         return;
2804 }
2805
2806 void
2807 __mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data)
2808 {
2809         LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element));
2810         return;
2811 }
2812
2813 static GstElement *
2814 __mmplayer_gst_make_uridecodebin(mmplayer_t *player)
2815 {
2816         GstElement *uridecodebin3 = NULL;
2817         GstElement *decodebin3 = NULL, *multiqueue = NULL;
2818
2819         MMPLAYER_FENTER();
2820         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2821
2822         uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3");
2823         if (!uridecodebin3) {
2824                 LOGE("failed to create uridecodebin3");
2825                 return NULL;
2826         }
2827
2828         /* get attribute */
2829         SECURE_LOGD("uri : %s", player->profile.uri);
2830
2831         decodebin3 = gst_bin_get_by_name((GstBin *)uridecodebin3, "decodebin3-0");
2832
2833         if (decodebin3) {
2834                 g_object_set(G_OBJECT(decodebin3), "message-forward", TRUE, NULL);
2835                 multiqueue = gst_bin_get_by_name((GstBin *)decodebin3, "multiqueue0");
2836         }
2837
2838         if (multiqueue) {
2839                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
2840                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = multiqueue;
2841
2842                 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */
2843                 _mm_player_streaming_set_multiqueue(player->streamer, multiqueue);
2844         }
2845
2846         /* setting property to streaming source */
2847         g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri, "message-forward", TRUE, NULL);
2848
2849         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2850                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "source-setup", G_CALLBACK(__mmplayer_http_src_setup), (gpointer)player);
2851
2852         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2853                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2854
2855         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2856                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
2857
2858         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2859                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
2860
2861         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2862                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player);
2863
2864 /* FIXME: need to be added for gapless playback
2865         _mmplayer_add_signal_connection(player, G_OBJECT(element),
2866                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
2867 */
2868
2869         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2870                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player);
2871
2872         _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3),
2873                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player);
2874
2875         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2876                 LOGW("[DASH] this is still experimental feature");
2877
2878         MMPLAYER_FLEAVE();
2879         return uridecodebin3;
2880 }
2881
2882 static GstElement *
2883 __mmplayer_gst_make_http_src(mmplayer_t *player)
2884 {
2885 #define MAX_RETRY_COUNT 10
2886         GstElement *element = NULL;
2887         MMHandleType attrs = 0;
2888         gchar *user_agent, *cookies, **cookie_list;
2889         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2890
2891         user_agent = cookies = NULL;
2892         cookie_list = NULL;
2893
2894         MMPLAYER_FENTER();
2895         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2896
2897         /* get profile attribute */
2898         attrs = MMPLAYER_GET_ATTRS(player);
2899         if (!attrs) {
2900                 LOGE("failed to get content attribute");
2901                 return NULL;
2902         }
2903
2904         LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2905
2906         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2907         if (!element) {
2908                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2909                 return NULL;
2910         }
2911
2912         /* get attribute */
2913         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2914         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2915
2916         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2917                 http_timeout = player->ini.http_timeout;
2918
2919         /* get attribute */
2920         SECURE_LOGD("location : %s", player->profile.uri);
2921         SECURE_LOGD("cookies : %s", cookies);
2922         SECURE_LOGD("user_agent :  %s", user_agent);
2923         LOGD("timeout : %d", http_timeout);
2924
2925         /* setting property to streaming source */
2926         g_object_set(G_OBJECT(element), "location", player->profile.uri,
2927                                 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
2928                                 "retries", MAX_RETRY_COUNT, NULL);
2929
2930         /* parsing cookies */
2931         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2932                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2933                 g_strfreev(cookie_list);
2934         }
2935
2936         if (user_agent)
2937                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2938
2939         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2940                 LOGW("[DASH] this is still experimental feature");
2941
2942         MMPLAYER_FLEAVE();
2943         return element;
2944 }
2945
2946 static GstElement *
2947 __mmplayer_gst_make_file_src(mmplayer_t *player)
2948 {
2949         GstElement *element = NULL;
2950
2951         MMPLAYER_FENTER();
2952         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2953
2954         LOGD("using filesrc for 'file://' handler");
2955         if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2956                 LOGE("failed to get storage info");
2957                 return NULL;
2958         }
2959
2960         element = gst_element_factory_make("filesrc", "source");
2961         if (!element) {
2962                 LOGE("failed to create filesrc");
2963                 return NULL;
2964         }
2965
2966         g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2967
2968         MMPLAYER_FLEAVE();
2969         return element;
2970 }
2971
2972 static gboolean
2973 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2974 {
2975         mmplayer_t *player = (mmplayer_t *)data;
2976
2977         g_return_val_if_fail(player, FALSE);
2978         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2979
2980         gst_message_ref(msg);
2981
2982         g_mutex_lock(&player->bus_msg_q_lock);
2983         g_queue_push_tail(player->bus_msg_q, msg);
2984         g_mutex_unlock(&player->bus_msg_q_lock);
2985
2986         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2987         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2988         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2989         return TRUE;
2990 }
2991
2992 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2993 {
2994         mmplayer_t *player = (mmplayer_t *)(data);
2995         GstMessage *msg = NULL;
2996         GstBus *bus = NULL;
2997
2998         MMPLAYER_FENTER();
2999         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3000                                                 player->pipeline &&
3001                                                 player->pipeline->mainbin &&
3002                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
3003                                                 NULL);
3004
3005         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3006         if (!bus) {
3007                 LOGE("cannot get BUS from the pipeline");
3008                 return NULL;
3009         }
3010
3011         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3012
3013         LOGD("[handle: %p] gst bus msg thread will be started.", player);
3014         while (!player->bus_msg_thread_exit) {
3015                 g_mutex_lock(&player->bus_msg_q_lock);
3016                 msg = g_queue_pop_head(player->bus_msg_q);
3017                 g_mutex_unlock(&player->bus_msg_q_lock);
3018                 if (msg == NULL) {
3019                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
3020                         continue;
3021                 }
3022                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3023                 /* handle the gst msg */
3024                 __mmplayer_gst_bus_msg_callback(msg, player);
3025                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
3026                 gst_message_unref(msg);
3027         }
3028
3029         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
3030         gst_object_unref(GST_OBJECT(bus));
3031
3032         MMPLAYER_FLEAVE();
3033         return NULL;
3034 }
3035
3036 static int
3037 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
3038 {
3039         gint64 dur_nsec = 0;
3040
3041         MMPLAYER_FENTER();
3042         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3043
3044         if (MMPLAYER_IS_MS_BUFF_SRC(player))
3045                 return MM_ERROR_NONE;
3046
3047         /* NOTE : duration cannot be zero except live streaming.
3048          *              Since some element could have some timing problemn with quering duration, try again.
3049          */
3050         if (player->duration == 0) {
3051                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
3052                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
3053                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
3054                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3055                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3056                                 player->pending_seek.is_pending = true;
3057                                 player->pending_seek.pos = position;
3058                                 player->seek_state = MMPLAYER_SEEK_NONE;
3059                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3060                                 return MM_ERROR_PLAYER_NO_OP;
3061                         } else {
3062                                 player->seek_state = MMPLAYER_SEEK_NONE;
3063                                 return MM_ERROR_PLAYER_SEEK;
3064                         }
3065                 }
3066                 player->duration = dur_nsec;
3067         }
3068
3069         if (player->duration > 0 && player->duration < position) {
3070                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
3071                 return MM_ERROR_INVALID_ARGUMENT;
3072         }
3073
3074         MMPLAYER_FLEAVE();
3075         return MM_ERROR_NONE;
3076 }
3077
3078 static gboolean
3079 __mmplayer_gst_check_seekable(mmplayer_t *player)
3080 {
3081         GstQuery *query = NULL;
3082         gboolean seekable = FALSE;
3083
3084         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3085                 return TRUE;
3086         }
3087
3088         query = gst_query_new_seeking(GST_FORMAT_TIME);
3089         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
3090                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
3091                 gst_query_unref(query);
3092
3093                 if (!seekable) {
3094                         LOGW("non-seekable content");
3095                         player->seek_state = MMPLAYER_SEEK_NONE;
3096                         return FALSE;
3097                 }
3098         } else {
3099                 LOGW("failed to get seeking query");
3100                 gst_query_unref(query); /* keep seeking operation */
3101         }
3102
3103         return TRUE;
3104 }
3105
3106 int
3107 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element,  GstState state, gboolean async, gint timeout)
3108 {
3109         GstState element_state = GST_STATE_VOID_PENDING;
3110         GstState element_pending_state = GST_STATE_VOID_PENDING;
3111         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
3112
3113         MMPLAYER_FENTER();
3114
3115         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3116         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
3117
3118         LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
3119
3120         /* set state */
3121         ret = gst_element_set_state(element, state);
3122         if (ret == GST_STATE_CHANGE_FAILURE) {
3123                 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
3124
3125                 /* dump state of all element */
3126                 _mmplayer_dump_pipeline_state(player);
3127
3128                 return MM_ERROR_PLAYER_INTERNAL;
3129         }
3130
3131         /* return here so state transition to be done in async mode */
3132         if (async) {
3133                 LOGD("async state transition. not waiting for state complete.");
3134                 return MM_ERROR_NONE;
3135         }
3136
3137         /* wait for state transition */
3138         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
3139         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
3140                 LOGE("failed to change [%s] element state to [%s] within %d sec",
3141                         GST_ELEMENT_NAME(element),
3142                         gst_element_state_get_name(state), timeout);
3143
3144                 LOGE(" [%s] state : %s   pending : %s",
3145                         GST_ELEMENT_NAME(element),
3146                         gst_element_state_get_name(element_state),
3147                         gst_element_state_get_name(element_pending_state));
3148
3149                 /* dump state of all element */
3150                 _mmplayer_dump_pipeline_state(player);
3151
3152                 return MM_ERROR_PLAYER_INTERNAL;
3153         }
3154
3155         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
3156
3157         MMPLAYER_FLEAVE();
3158
3159         return MM_ERROR_NONE;
3160 }
3161
3162 int
3163 _mmplayer_gst_start(mmplayer_t *player)
3164 {
3165         int ret = MM_ERROR_NONE;
3166         gboolean async = FALSE;
3167
3168         MMPLAYER_FENTER();
3169
3170         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3171
3172         /* NOTE : if SetPosition was called before Start. do it now
3173          * streaming doesn't support it. so it should be always sync
3174          * !!create one more api to check if there is pending seek rather than checking variables
3175          */
3176         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
3177                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
3178                 ret = _mmplayer_gst_pause(player, FALSE);
3179                 if (ret != MM_ERROR_NONE) {
3180                         LOGE("failed to set state to PAUSED for pending seek");
3181                         return ret;
3182                 }
3183
3184                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3185                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3186                                 LOGW("failed to seek pending postion. starting from the begin of content");
3187         }
3188
3189         LOGD("current state before doing transition");
3190         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3191         MMPLAYER_PRINT_STATE(player);
3192
3193         /* set pipeline state to PLAYING  */
3194         ret = _mmplayer_gst_set_state(player,
3195                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3196         if (ret != MM_ERROR_NONE) {
3197                 LOGE("failed to set state to PLAYING");
3198                 return ret;
3199         }
3200
3201         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3202
3203         /* generating debug info before returning error */
3204         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3205
3206         MMPLAYER_FLEAVE();
3207
3208         return ret;
3209 }
3210
3211 int
3212 _mmplayer_gst_stop(mmplayer_t *player)
3213 {
3214         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3215         MMHandleType attrs = 0;
3216         gboolean rewind = FALSE;
3217         gint timeout = 0;
3218         int ret = MM_ERROR_NONE;
3219
3220         MMPLAYER_FENTER();
3221
3222         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3223         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3224
3225         LOGD("current state before doing transition");
3226         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3227         MMPLAYER_PRINT_STATE(player);
3228
3229         attrs = MMPLAYER_GET_ATTRS(player);
3230         if (!attrs) {
3231                 LOGE("cannot get content attribute");
3232                 return MM_ERROR_PLAYER_INTERNAL;
3233         }
3234
3235         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3236         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3237
3238         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3239                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3240                 rewind = TRUE;
3241
3242         if (player->es_player_push_mode)
3243                 /* disable the async state transition because there could be no data in the pipeline */
3244                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3245
3246         /* set gst state */
3247         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3248
3249         if (player->es_player_push_mode) {
3250                 /* enable the async state transition as default operation */
3251                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3252         }
3253
3254         /* return if set_state has failed */
3255         if (ret != MM_ERROR_NONE) {
3256                 LOGE("failed to set state.");
3257                 return ret;
3258         }
3259
3260         /* rewind */
3261         if (rewind) {
3262                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3263                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3264                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3265                         LOGW("failed to rewind");
3266                         ret = MM_ERROR_PLAYER_SEEK;
3267                 }
3268         }
3269
3270         /* initialize */
3271         player->sent_bos = FALSE;
3272
3273         if (player->es_player_push_mode) //for cloudgame
3274                 timeout = 0;
3275
3276         /* wait for seek to complete */
3277         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3278         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3279                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3280         } else {
3281                 LOGE("fail to stop player.");
3282                 ret = MM_ERROR_PLAYER_INTERNAL;
3283                 _mmplayer_dump_pipeline_state(player);
3284         }
3285
3286         /* generate dot file if enabled */
3287         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3288
3289         MMPLAYER_FLEAVE();
3290
3291         return ret;
3292 }
3293
3294 int
3295 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3296 {
3297         int ret = MM_ERROR_NONE;
3298
3299         MMPLAYER_FENTER();
3300
3301         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3302         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3303
3304         LOGD("current state before doing transition");
3305         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3306         MMPLAYER_PRINT_STATE(player);
3307
3308         /* set pipeline status to PAUSED */
3309         ret = _mmplayer_gst_set_state(player,
3310                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3311
3312         if (async)
3313                 goto EXIT;
3314
3315         if (ret != MM_ERROR_NONE) {
3316                 GstMessage *msg = NULL;
3317                 GTimer *timer = NULL;
3318                 gdouble MAX_TIMEOUT_SEC = 3;
3319
3320                 LOGE("failed to set state to PAUSED");
3321
3322                 if (!player->bus_watcher) {
3323                         LOGE("there is no bus msg thread. pipeline is shutting down.");
3324                         return ret;
3325                 }
3326
3327                 if (player->msg_posted) {
3328                         LOGE("error msg is already posted.");
3329                         return ret;
3330                 }
3331
3332                 timer = g_timer_new();
3333                 g_timer_start(timer);
3334
3335                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3336
3337                 do {
3338                         msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3339                         if (msg) {
3340                                 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3341                                         GError *error = NULL;
3342
3343                                         /* parse error code */
3344                                         gst_message_parse_error(msg, &error, NULL);
3345
3346                                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3347                                                 /* Note : the streaming error from the streaming source is handled
3348                                                         *   using __mmplayer_handle_streaming_error.
3349                                                         */
3350                                                 __mmplayer_handle_streaming_error(player, msg);
3351
3352                                         } else if (error) {
3353                                                 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3354
3355                                                 if (error->domain == GST_STREAM_ERROR)
3356                                                         ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3357                                                 else if (error->domain == GST_RESOURCE_ERROR)
3358                                                         ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3359                                                 else if (error->domain == GST_LIBRARY_ERROR)
3360                                                         ret = __mmplayer_gst_handle_library_error(player, error->code);
3361                                                 else if (error->domain == GST_CORE_ERROR)
3362                                                         ret = __mmplayer_gst_handle_core_error(player, error->code);
3363
3364                                                 g_error_free(error);
3365                                         }
3366                                         player->msg_posted = TRUE;
3367                                 }
3368                                 gst_message_unref(msg);
3369                         }
3370                 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3371                 /* clean */
3372                 gst_object_unref(bus);
3373                 g_timer_stop(timer);
3374                 g_timer_destroy(timer);
3375
3376                 return ret;
3377         }
3378
3379         if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
3380                 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3381                         (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3382                         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3383         }
3384
3385         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3386
3387 EXIT:
3388         /* generate dot file before returning error */
3389         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3390
3391         MMPLAYER_FLEAVE();
3392
3393         return ret;
3394 }
3395
3396 int
3397 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3398 {
3399         int ret = MM_ERROR_NONE;
3400         gint timeout = 0;
3401
3402         MMPLAYER_FENTER();
3403
3404         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3405                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3406
3407         LOGD("current state before doing transition");
3408         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3409         MMPLAYER_PRINT_STATE(player);
3410
3411         if (async)
3412                 LOGD("do async state transition to PLAYING");
3413
3414         /* set pipeline state to PLAYING */
3415         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3416
3417         ret = _mmplayer_gst_set_state(player,
3418                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3419         if (ret != MM_ERROR_NONE) {
3420                 LOGE("failed to set state to PLAYING");
3421                 goto EXIT;
3422         }
3423
3424         if (!async)
3425                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3426
3427 EXIT:
3428         /* generate dot file */
3429         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3430
3431         MMPLAYER_FLEAVE();
3432
3433         return ret;
3434 }
3435
3436 /* sending event to one of sinkelements */
3437 gboolean
3438 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3439 {
3440         GstEvent *event2 = NULL;
3441         GList *sinks = NULL;
3442         gboolean res = FALSE;
3443         MMPLAYER_FENTER();
3444
3445         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3446         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3447
3448         /* While adding subtitles in live feeds seek is getting called.
3449            Adding defensive check in framework layer.*/
3450         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3451                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3452                         LOGE("Should not send seek event during live playback");
3453                         return TRUE;
3454                 }
3455         }
3456
3457         if (player->play_subtitle)
3458                 event2 = gst_event_copy((const GstEvent *)event);
3459
3460         sinks = player->sink_elements;
3461         while (sinks) {
3462                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3463
3464                 if (GST_IS_ELEMENT(sink)) {
3465                         /* keep ref to the event */
3466                         gst_event_ref(event);
3467
3468                         if ((res = gst_element_send_event(sink, event))) {
3469                                 LOGD("sending event[%s] to sink element [%s] success!",
3470                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3471
3472                                 /* rtsp case, asyn_done is not called after seek during pause state */
3473                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3474                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3475                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3476                                                         LOGD("RTSP seek completed, after pause state..");
3477                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3478                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3479                                                 }
3480
3481                                         }
3482                                 }
3483
3484                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3485                                         sinks = g_list_next(sinks);
3486                                         continue;
3487                                 } else {
3488                                         break;
3489                                 }
3490                         }
3491
3492                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3493                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3494                 }
3495
3496                 sinks = g_list_next(sinks);
3497         }
3498
3499         /* Note : Textbin is not linked to the video or audio bin.
3500          * It needs to send the event to the text sink seperatelly.
3501          */
3502         if (player->play_subtitle && player->pipeline) {
3503                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3504
3505                 if (GST_IS_ELEMENT(text_sink)) {
3506                         /* keep ref to the event */
3507                         gst_event_ref(event2);
3508
3509                         if ((res = gst_element_send_event(text_sink, event2)))
3510                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3511                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3512                         else
3513                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3514                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3515
3516                         gst_event_unref(event2);
3517                 }
3518         }
3519
3520         gst_event_unref(event);
3521
3522         MMPLAYER_FLEAVE();
3523
3524         return res;
3525 }
3526
3527 gboolean
3528 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3529                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3530                         gint64 cur, GstSeekType stop_type, gint64 stop)
3531 {
3532         GstEvent *event = NULL;
3533         gboolean result = FALSE;
3534
3535         MMPLAYER_FENTER();
3536
3537         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3538
3539         if (player->pipeline && player->pipeline->textbin)
3540                 __mmplayer_drop_subtitle(player, FALSE);
3541
3542         event = gst_event_new_seek(rate, format, flags, cur_type,
3543                 cur, stop_type, stop);
3544
3545         result = _mmplayer_gst_send_event_to_sink(player, event);
3546
3547         MMPLAYER_FLEAVE();
3548
3549         return result;
3550 }
3551
3552 int
3553 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3554 {
3555         int ret = MM_ERROR_NONE;
3556         gint64 pos_nsec = 0;
3557         gboolean accurated = FALSE;
3558         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3559
3560         MMPLAYER_FENTER();
3561         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3562         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3563
3564         if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3565                 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3566                 goto PENDING;
3567
3568         ret = __mmplayer_gst_check_duration(player, position);
3569         if (ret != MM_ERROR_NONE) {
3570                 LOGE("failed to check duration 0x%X", ret);
3571                 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3572         }
3573
3574         if (!__mmplayer_gst_check_seekable(player))
3575                 return MM_ERROR_PLAYER_NO_OP;
3576
3577         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3578                                 position, player->playback_rate, player->duration);
3579
3580         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3581            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3582            This causes problem is position calculation during normal pause resume scenarios also.
3583            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3584         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3585                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3586                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3587                         LOGW("getting current position failed in seek");
3588
3589                 player->last_position = pos_nsec;
3590                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3591         }
3592
3593         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3594                 LOGD("not completed seek");
3595                 return MM_ERROR_PLAYER_DOING_SEEK;
3596         }
3597
3598         if (!internal_called)
3599                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3600
3601         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3602                 that's why set position through property. */
3603         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3604                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3605                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3606                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3607
3608                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3609                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3610
3611                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3612                 player->seek_state = MMPLAYER_SEEK_NONE;
3613                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3614         } else {
3615                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3616                 if (accurated)
3617                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3618                 else
3619                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3620
3621                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3622                                                 GST_FORMAT_TIME, seek_flags,
3623                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3624                         LOGE("failed to set position");
3625                         goto SEEK_ERROR;
3626                 }
3627         }
3628
3629         /* NOTE : store last seeking point to overcome some bad operation
3630          *     (returning zero when getting current position) of some elements
3631          */
3632         player->last_position = position;
3633
3634         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3635         if (player->playback_rate > 1.0)
3636                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3637
3638         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3639                 LOGD("buffering should be reset after seeking");
3640                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3641                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3642         }
3643
3644         MMPLAYER_FLEAVE();
3645         return MM_ERROR_NONE;
3646
3647 PENDING:
3648         player->pending_seek.is_pending = true;
3649         player->pending_seek.pos = position;
3650
3651         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3652                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3653                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3654                 player->pending_seek.pos);
3655
3656         return MM_ERROR_NONE;
3657
3658 SEEK_ERROR:
3659         player->seek_state = MMPLAYER_SEEK_NONE;
3660         return MM_ERROR_PLAYER_SEEK;
3661 }
3662
3663 int
3664 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3665 {
3666 #define TRICKPLAY_OFFSET GST_MSECOND
3667
3668         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3669         gint64 pos_nsec = 0;
3670         gboolean ret = TRUE;
3671
3672         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3673                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3674
3675         current_state = MMPLAYER_CURRENT_STATE(player);
3676
3677         /* NOTE : query position except paused state to overcome some bad operation
3678          * please refer to below comments in details
3679          */
3680         if (current_state != MM_PLAYER_STATE_PAUSED)
3681                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3682
3683         /* NOTE : get last point to overcome some bad operation of some elements
3684          *(returning zero when getting current position in paused state
3685          * and when failed to get postion during seeking
3686          */
3687         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3688                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3689
3690                 if (player->playback_rate < 0.0)
3691                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3692                 else
3693                         pos_nsec = player->last_position;
3694
3695                 if (!ret)
3696                         pos_nsec = player->last_position;
3697                 else
3698                         player->last_position = pos_nsec;
3699
3700                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3701
3702         } else {
3703                 if (player->duration > 0 && pos_nsec > player->duration)
3704                         pos_nsec = player->duration;
3705
3706                 player->last_position = pos_nsec;
3707         }
3708
3709         *position = pos_nsec;
3710
3711         return MM_ERROR_NONE;
3712 }
3713
3714 int
3715 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3716 {
3717 #define STREAMING_IS_FINISHED   0
3718 #define BUFFERING_MAX_PER       100
3719 #define DEFAULT_PER_VALUE       -1
3720 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3721
3722         mmplayer_gst_element_t *mainbin = NULL;
3723         gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3724         gint64 buffered_total = 0;
3725         gint64 position = 0;
3726         gint buffered_sec = -1;
3727         GstBufferingMode mode = GST_BUFFERING_STREAM;
3728         gint64 content_size_time = player->duration;
3729         guint64 content_size_bytes = player->http_content_size;
3730
3731         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3732                                                 player->pipeline &&
3733                                                 player->pipeline->mainbin,
3734                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3735
3736         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3737
3738         *start_pos = 0;
3739         *end_pos = 0;
3740
3741         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3742                 /* and rtsp is not ready yet. */
3743                 LOGW("it's only used for http streaming case");
3744                 return MM_ERROR_PLAYER_NO_OP;
3745         }
3746
3747         if (content_size_time <= 0 || content_size_bytes <= 0) {
3748                 LOGW("there is no content size");
3749                 return MM_ERROR_NONE;
3750         }
3751
3752         if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3753                 LOGW("fail to get current position");
3754                 return MM_ERROR_NONE;
3755         }
3756
3757         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3758                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3759
3760         mainbin = player->pipeline->mainbin;
3761         start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3762
3763         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3764                 GstQuery *query = NULL;
3765                 gint byte_in_rate = 0, byte_out_rate = 0;
3766                 gint64 estimated_total = 0;
3767
3768                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3769                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3770                         LOGW("fail to get buffering query from queue2");
3771                         if (query)
3772                                 gst_query_unref(query);
3773                         return MM_ERROR_NONE;
3774                 }
3775
3776                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3777                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3778
3779                 if (mode == GST_BUFFERING_STREAM) {
3780                         /* using only queue in case of push mode(ts / mp3) */
3781                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3782                                 GST_FORMAT_BYTES, &buffered_total)) {
3783                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3784                                 end_per = 100 * buffered_total / content_size_bytes;
3785                         }
3786                 } else {
3787                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3788                         guint idx = 0;
3789                         guint num_of_ranges = 0;
3790                         gint64 start_byte = 0, stop_byte = 0;
3791
3792                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3793                         if (estimated_total != STREAMING_IS_FINISHED) {
3794                                 /* buffered size info from queue2 */
3795                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3796                                 for (idx = 0; idx < num_of_ranges; idx++) {
3797                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3798                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3799
3800                                         buffered_total += (stop_byte - start_byte);
3801                                 }
3802                         } else {
3803                                 end_per = BUFFERING_MAX_PER;
3804                         }
3805                 }
3806                 gst_query_unref(query);
3807         }
3808
3809         if (end_per == DEFAULT_PER_VALUE) {
3810                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3811                 if (dur_sec > 0) {
3812                         guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3813
3814                         /* buffered size info from multiqueue */
3815                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3816                                 guint curr_size_bytes = 0;
3817                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3818                                         "curr-size-bytes", &curr_size_bytes, NULL);
3819                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3820                                 buffered_total += curr_size_bytes;
3821                         }
3822
3823                         if (avg_byterate > 0)
3824                                 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3825                         else if (player->total_maximum_bitrate > 0)
3826                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3827                         else if (player->total_bitrate > 0)
3828                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3829
3830                         if (buffered_sec >= 0)
3831                                 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3832                 }
3833         }
3834
3835         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3836         *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3837
3838         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3839                 buffered_total, buffered_sec, *start_pos, *end_pos);
3840
3841         return MM_ERROR_NONE;
3842 }
3843
3844 GstElement *
3845 _mmplayer_gst_create_source(mmplayer_t *player)
3846 {
3847         GstElement *element = NULL;
3848
3849         MMPLAYER_FENTER();
3850         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3851                                 player->pipeline->mainbin, NULL);
3852
3853         /* setup source for gapless play */
3854         switch (player->profile.uri_type) {
3855         /* file source */
3856         case MM_PLAYER_URI_TYPE_FILE:
3857                 element = __mmplayer_gst_make_file_src(player);
3858                 break;
3859         case MM_PLAYER_URI_TYPE_URL_HTTP:
3860                 element = __mmplayer_gst_make_http_src(player);
3861                 break;
3862         default:
3863                 LOGE("not support uri type %d", player->profile.uri_type);
3864                 break;
3865         }
3866
3867         if (!element) {
3868                 LOGE("failed to create source element");
3869                 return NULL;
3870         }
3871
3872         MMPLAYER_FLEAVE();
3873         return element;
3874 }
3875
3876 int
3877 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3878 {
3879         MMPLAYER_FENTER();
3880         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3881                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3882
3883         SECURE_LOGD("uri : %s", player->profile.uri);
3884
3885         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
3886
3887         if ((player->v_stream_caps) &&
3888                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
3889                 return MM_ERROR_PLAYER_INTERNAL;
3890
3891         if ((player->a_stream_caps) &&
3892                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
3893                 return MM_ERROR_PLAYER_INTERNAL;
3894
3895         if ((player->s_stream_caps) &&
3896                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
3897                 return MM_ERROR_PLAYER_INTERNAL;
3898
3899         MMPLAYER_FLEAVE();
3900         return MM_ERROR_NONE;
3901 }
3902
3903 int
3904 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3905 {
3906         mmplayer_gst_element_t *mainbin = NULL;
3907         GstElement *src_elem = NULL;
3908         GstElement *autoplug_elem = NULL;
3909         GList *element_bucket = NULL;
3910         main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3911
3912         MMPLAYER_FENTER();
3913         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3914                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3915
3916         mainbin = player->pipeline->mainbin;
3917
3918         LOGD("uri type %d", player->profile.uri_type);
3919
3920         /* create source element */
3921         switch (player->profile.uri_type) {
3922         case MM_PLAYER_URI_TYPE_URL_RTSP:
3923                 src_elem = __mmplayer_gst_make_rtsp_src(player);
3924                 break;
3925         case MM_PLAYER_URI_TYPE_URL_HTTP:
3926                 if (player->ini.use_uridecodebin3) { /* or MMPLAYER_USE_URIDECODEBIN3(player) */
3927                         LOGD("uridecodebin include src element.");
3928                         goto ADD_DECODEBIN;
3929                 }
3930                 src_elem = __mmplayer_gst_make_http_src(player);
3931                 break;
3932         case MM_PLAYER_URI_TYPE_FILE:
3933                 src_elem = __mmplayer_gst_make_file_src(player);
3934                 break;
3935         case MM_PLAYER_URI_TYPE_SS:
3936                 {
3937                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3938                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3939                         if (!src_elem) {
3940                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3941                                 break;
3942                         }
3943
3944                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3945                                 LOGD("get timeout from ini");
3946                                 http_timeout = player->ini.http_timeout;
3947                         }
3948
3949                         /* setting property to streaming source */
3950                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3951                 }
3952                 break;
3953         case MM_PLAYER_URI_TYPE_MEM:
3954                 {
3955                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3956
3957                         src_elem = gst_element_factory_make("appsrc", "mem-source");
3958                         if (!src_elem) {
3959                                 LOGE("failed to create appsrc element");
3960                                 break;
3961                         }
3962
3963                         g_object_set(src_elem, "stream-type", stream_type,
3964                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3965
3966                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3967                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3968                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3969                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3970                 }
3971                 break;
3972         default:
3973                 LOGE("not support uri type");
3974                 break;
3975         }
3976
3977         if (!src_elem) {
3978                 LOGE("failed to create source element");
3979                 return MM_ERROR_PLAYER_INTERNAL;
3980         }
3981
3982         /* take source element */
3983         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3984
3985         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3986         mainbin[MMPLAYER_M_SRC].gst = src_elem;
3987         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3988
3989 ADD_DECODEBIN: /* create next element for auto-plugging */
3990         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3991                 if (!src_elem) { /* make uridecodebin3 which include src element */
3992                         autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3993                         autoplug_elem = __mmplayer_gst_make_uridecodebin(player);
3994                         if (!autoplug_elem) {
3995                                 LOGE("failed to create uridecodebin3 element");
3996                                 goto ERROR;
3997                         }
3998                 } else {
3999                         autoplug_elem_id = MMPLAYER_M_TYPEFIND;
4000                         autoplug_elem = gst_element_factory_make("typefind", "typefinder");
4001                         if (!autoplug_elem) {
4002                                 LOGE("failed to create typefind element");
4003                                 goto ERROR;
4004                         }
4005                         _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
4006                                                                                 G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4007                 }
4008         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
4009                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
4010                 autoplug_elem = _mmplayer_gst_make_decodebin(player);
4011                 if (!autoplug_elem) {
4012                         LOGE("failed to create decodebin");
4013                         goto ERROR;
4014                 }
4015
4016                 /* default size of mq in decodebin is 2M
4017                  * but it can cause blocking issue during seeking depends on content. */
4018                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
4019         }
4020
4021         if (autoplug_elem) {
4022                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
4023                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
4024                 mainbin[autoplug_elem_id].gst = autoplug_elem;
4025
4026                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
4027         }
4028
4029         /* add elements to pipeline */
4030         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
4031                 LOGE("failed to add elements to pipeline");
4032                 goto ERROR;
4033         }
4034
4035         /* linking elements in the bucket by added order. */
4036         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4037                 LOGE("failed to link some elements");
4038                 goto ERROR;
4039         }
4040
4041         /* FIXME: need to check whether this is required or not. */
4042         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
4043                 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
4044                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
4045                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
4046                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
4047
4048                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
4049                         LOGE("failed to create fakesink");
4050                         goto ERROR;
4051                 }
4052                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
4053
4054                 /* take ownership of fakesink. we are reusing it */
4055                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4056
4057                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
4058                         LOGE("failed to add fakesink to bin");
4059                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
4060                         goto ERROR;
4061                 }
4062         }
4063
4064         g_list_free(element_bucket);
4065
4066         MMPLAYER_FLEAVE();
4067         return MM_ERROR_NONE;
4068
4069 ERROR:
4070         g_list_free(element_bucket);
4071
4072         if (mainbin[MMPLAYER_M_SRC].gst)
4073                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
4074
4075         if (mainbin[autoplug_elem_id].gst)
4076                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
4077
4078         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4079                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4080
4081         mainbin[MMPLAYER_M_SRC].gst = NULL;
4082         mainbin[autoplug_elem_id].gst = NULL;
4083         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
4084
4085         return MM_ERROR_PLAYER_INTERNAL;
4086 }
4087
4088 int
4089 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
4090 {
4091         GstBus  *bus = NULL;
4092         mmplayer_gst_element_t *mainbin = NULL;
4093
4094         MMPLAYER_FENTER();
4095         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
4096                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4097
4098         mainbin = player->pipeline->mainbin;
4099
4100         /* connect bus callback */
4101         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4102         if (!bus) {
4103                 LOGE("cannot get bus from pipeline");
4104                 return MM_ERROR_PLAYER_INTERNAL;
4105         }
4106
4107         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
4108         player->context.thread_default = g_main_context_get_thread_default();
4109         if (player->context.thread_default == NULL) {
4110                 player->context.thread_default = g_main_context_default();
4111                 LOGD("thread-default context is the global default context");
4112         }
4113         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
4114
4115         /* set sync handler to get tag synchronously */
4116         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
4117         gst_object_unref(GST_OBJECT(bus));
4118
4119         /* create gst bus_msb_cb thread */
4120         g_mutex_init(&player->bus_msg_thread_mutex);
4121         g_cond_init(&player->bus_msg_thread_cond);
4122         player->bus_msg_thread_exit = FALSE;
4123         player->bus_msg_thread =
4124                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
4125         if (!player->bus_msg_thread) {
4126                 LOGE("failed to create gst BUS msg thread");
4127                 g_mutex_clear(&player->bus_msg_thread_mutex);
4128                 g_cond_clear(&player->bus_msg_thread_cond);
4129                 return MM_ERROR_PLAYER_INTERNAL;
4130         }
4131
4132         MMPLAYER_FLEAVE();
4133         return MM_ERROR_NONE;
4134 }
4135
4136 void
4137 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
4138 {
4139         mmplayer_gst_element_t *mainbin = NULL;
4140         MMMessageParamType msg_param = {0,};
4141         GstElement *element = NULL;
4142         MMHandleType attrs = 0;
4143         char *uri = NULL;
4144         main_element_id_e elem_idx = MMPLAYER_M_NUM;
4145
4146         MMPLAYER_FENTER();
4147
4148         if (!player || !player->pipeline || !player->pipeline->mainbin) {
4149                 LOGE("player is not initialized");
4150                 goto ERROR;
4151         }
4152
4153         mainbin = player->pipeline->mainbin;
4154         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
4155
4156         attrs = MMPLAYER_GET_ATTRS(player);
4157         if (!attrs) {
4158                 LOGE("fail to get attributes");
4159                 goto ERROR;
4160         }
4161
4162         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4163
4164         if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
4165                 LOGE("failed to parse profile");
4166                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4167                 goto ERROR;
4168         }
4169
4170         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
4171                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
4172                 LOGE("dash or hls is not supportable");
4173                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
4174                 goto ERROR;
4175         }
4176
4177         element = _mmplayer_gst_create_source(player);
4178         if (!element) {
4179                 LOGE("no source element was created");
4180                 goto ERROR;
4181         }
4182
4183         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4184                 LOGE("failed to add source element to pipeline");
4185                 gst_object_unref(GST_OBJECT(element));
4186                 element = NULL;
4187                 goto ERROR;
4188         }
4189
4190         /* take source element */
4191         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
4192         mainbin[MMPLAYER_M_SRC].gst = element;
4193
4194         element = NULL;
4195
4196         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4197                 if (player->streamer == NULL) {
4198                         player->streamer = _mm_player_streaming_create();
4199                         _mm_player_streaming_initialize(player->streamer, TRUE);
4200                 }
4201
4202                 elem_idx = MMPLAYER_M_TYPEFIND;
4203                 element = gst_element_factory_make("typefind", "typefinder");
4204                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4205                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4206         } else {
4207                 elem_idx = MMPLAYER_M_AUTOPLUG;
4208                 element = _mmplayer_gst_make_decodebin(player);
4209         }
4210
4211         /* check autoplug element is OK */
4212         if (!element) {
4213                 LOGE("can not create element(%d)", elem_idx);
4214                 goto ERROR;
4215         }
4216
4217         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4218                 LOGE("failed to add sinkbin to pipeline");
4219                 gst_object_unref(GST_OBJECT(element));
4220                 element = NULL;
4221                 goto ERROR;
4222         }
4223
4224         mainbin[elem_idx].id = elem_idx;
4225         mainbin[elem_idx].gst = element;
4226
4227         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4228                 LOGE("Failed to link src - autoplug(or typefind)");
4229                 goto ERROR;
4230         }
4231
4232         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4233                 LOGE("Failed to change state of src element");
4234                 goto ERROR;
4235         }
4236
4237         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4238                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4239                         LOGE("Failed to change state of decodebin");
4240                         goto ERROR;
4241                 }
4242         } else {
4243                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4244                         LOGE("Failed to change state of src element");
4245                         goto ERROR;
4246                 }
4247         }
4248
4249         player->gapless.stream_changed = TRUE;
4250         player->gapless.running = TRUE;
4251         MMPLAYER_FLEAVE();
4252         return;
4253
4254 ERROR:
4255         if (player) {
4256                 MMPLAYER_PLAYBACK_UNLOCK(player);
4257
4258                 if (!player->msg_posted) {
4259                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4260                         player->msg_posted = TRUE;
4261                 }
4262         }
4263         return;
4264 }