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