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