[0.6.207] use reconfigure lock to sync operation
[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                         char *seperator = strchr(video_frame_size, '-');
1824                         if (seperator) {
1825                                 char video_width[10] = {0,};
1826                                 int frame_size_len = strlen(video_frame_size);
1827                                 int separtor_len = strlen(seperator);
1828
1829                                 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1830                                 seperator++;
1831
1832                                 mm_player_set_attribute((MMHandleType)player, NULL, MM_PLAYER_VIDEO_WIDTH,
1833                                                 atoi(video_width), MM_PLAYER_VIDEO_HEIGHT, atoi(seperator), NULL);
1834                         }
1835                 }
1836         }
1837
1838         MMPLAYER_FLEAVE();
1839         return;
1840 }
1841
1842 static void
1843 __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg)
1844 {
1845         mmplayer_gst_element_t *mainbin;
1846
1847         MMPLAYER_FENTER();
1848         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1849
1850         mainbin = player->pipeline->mainbin;
1851
1852         LOGD("GST_MESSAGE_ASYNC_DONE : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1853
1854         /* we only handle messages from pipeline */
1855         if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1856                 return;
1857
1858         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1859                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1860                         player->seek_state = MMPLAYER_SEEK_NONE;
1861                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1862                 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1863                         if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1864                                 LOGD("sync %s state(%s) with parent state(%s)",
1865                                         GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1866                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1867                                         gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1868
1869                                 /* In case of streaming, pause is required before finishing seeking by buffering.
1870                                    After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1871                                    Because the buffering state is controlled according to the state transition for force resume,
1872                                    the decodebin state should be paused as player state. */
1873                                 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1874                         }
1875
1876                         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1877                                 (player->streamer) &&
1878                                 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1879                                 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1880                                 GstQuery *query = NULL;
1881                                 gboolean busy = FALSE;
1882                                 gint percent = 0;
1883
1884                                 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1885                                         query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1886                                         if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1887                                                 gst_query_parse_buffering_percent(query, &busy, &percent);
1888                                         gst_query_unref(query);
1889
1890                                         LOGD("buffered percent(%s): %d",
1891                                                 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1892                                 }
1893
1894                                 if (percent >= 100)
1895                                         __mmplayer_handle_buffering_playback(player);
1896                         }
1897
1898                         player->seek_state = MMPLAYER_SEEK_COMPLETED;
1899                 }
1900         }
1901
1902         MMPLAYER_FLEAVE();
1903         return;
1904 }
1905
1906 static void
1907 __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data)
1908 {
1909         mmplayer_t *player = (mmplayer_t *)(data);
1910
1911         MMPLAYER_RETURN_IF_FAIL(player);
1912         MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1913
1914         switch (GST_MESSAGE_TYPE(msg)) {
1915         case GST_MESSAGE_UNKNOWN:
1916                 LOGD("unknown message received");
1917                 break;
1918
1919         case GST_MESSAGE_EOS:
1920                 LOGD("GST_MESSAGE_EOS received");
1921                 __mmplayer_gst_handle_eos_message(player, msg);
1922                 break;
1923
1924         case GST_MESSAGE_ERROR:
1925                 _mmplayer_set_reconfigure_state(player, FALSE);
1926                 __mmplayer_gst_handle_error_message(player, msg);
1927                 break;
1928
1929         case GST_MESSAGE_WARNING:
1930                 {
1931                         char *debug = NULL;
1932                         GError *error = NULL;
1933
1934                         gst_message_parse_warning(msg, &error, &debug);
1935
1936                         LOGD("warning : %s", error->message);
1937                         LOGD("debug : %s", debug);
1938
1939                         MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1940
1941                         MMPLAYER_FREEIF(debug);
1942                         g_error_free(error);
1943                 }
1944                 break;
1945
1946         case GST_MESSAGE_TAG:
1947                 {
1948                         LOGD("GST_MESSAGE_TAG");
1949                         if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1950                                 LOGW("failed to extract tags from gstmessage");
1951                 }
1952                 break;
1953
1954         case GST_MESSAGE_BUFFERING:
1955                 __mmplayer_gst_handle_buffering_message(player, msg);
1956                 break;
1957
1958         case GST_MESSAGE_STATE_CHANGED:
1959                 __mmplayer_gst_handle_state_message(player, msg);
1960                 break;
1961
1962         case GST_MESSAGE_CLOCK_LOST:
1963                         {
1964                                 GstClock *clock = NULL;
1965                                 gboolean need_new_clock = FALSE;
1966
1967                                 gst_message_parse_clock_lost(msg, &clock);
1968                                 LOGD("GST_MESSAGE_CLOCK_LOST : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1969
1970                                 if (!player->videodec_linked)
1971                                         need_new_clock = TRUE;
1972                                 else if (!player->ini.use_system_clock)
1973                                         need_new_clock = TRUE;
1974
1975                                 if (need_new_clock) {
1976                                         LOGD("Provide clock is TRUE, do pause->resume");
1977                                         _mmplayer_gst_pause(player, FALSE);
1978                                         _mmplayer_gst_resume(player, FALSE);
1979                                 }
1980                         }
1981                         break;
1982
1983         case GST_MESSAGE_NEW_CLOCK:
1984                         {
1985                                 GstClock *clock = NULL;
1986                                 gst_message_parse_new_clock(msg, &clock);
1987                                 LOGD("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1988                         }
1989                         break;
1990
1991         case GST_MESSAGE_ELEMENT:
1992                 __mmplayer_gst_handle_element_message(player, msg);
1993                         break;
1994
1995         case GST_MESSAGE_DURATION_CHANGED:
1996                 {
1997                         LOGD("GST_MESSAGE_DURATION_CHANGED");
1998                         if (!__mmplayer_gst_handle_duration(player, msg))
1999                                 LOGW("failed to update duration");
2000                 }
2001                 break;
2002
2003         case GST_MESSAGE_ASYNC_START:
2004                         LOGD("GST_MESSAGE_ASYNC_START : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
2005                 break;
2006
2007         case GST_MESSAGE_ASYNC_DONE:
2008                 __mmplayer_gst_handle_async_done_message(player, msg);
2009                 break;
2010
2011 #ifdef __DEBUG__
2012         case GST_MESSAGE_REQUEST_STATE:         LOGD("GST_MESSAGE_REQUEST_STATE"); break;
2013         case GST_MESSAGE_STEP_START:            LOGD("GST_MESSAGE_STEP_START"); break;
2014         case GST_MESSAGE_QOS:                           LOGD("GST_MESSAGE_QOS"); break;
2015         case GST_MESSAGE_PROGRESS:                      LOGD("GST_MESSAGE_PROGRESS"); break;
2016         case GST_MESSAGE_ANY:                           LOGD("GST_MESSAGE_ANY"); break;
2017         case GST_MESSAGE_INFO:                          LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2018         case GST_MESSAGE_STATE_DIRTY:           LOGD("GST_MESSAGE_STATE_DIRTY"); break;
2019         case GST_MESSAGE_STEP_DONE:                     LOGD("GST_MESSAGE_STEP_DONE"); break;
2020         case GST_MESSAGE_CLOCK_PROVIDE:         LOGD("GST_MESSAGE_CLOCK_PROVIDE"); break;
2021         case GST_MESSAGE_STRUCTURE_CHANGE:      LOGD("GST_MESSAGE_STRUCTURE_CHANGE"); break;
2022         case GST_MESSAGE_STREAM_STATUS:         LOGD("GST_MESSAGE_STREAM_STATUS"); break;
2023         case GST_MESSAGE_APPLICATION:           LOGD("GST_MESSAGE_APPLICATION"); break;
2024         case GST_MESSAGE_SEGMENT_START:         LOGD("GST_MESSAGE_SEGMENT_START"); break;
2025         case GST_MESSAGE_SEGMENT_DONE:          LOGD("GST_MESSAGE_SEGMENT_DONE"); break;
2026         case GST_MESSAGE_LATENCY:                       LOGD("GST_MESSAGE_LATENCY"); break;
2027 #endif
2028
2029         default:
2030                 break;
2031         }
2032
2033         /* should not call 'gst_message_unref(msg)' */
2034         return;
2035 }
2036
2037 static GstBusSyncReply
2038 __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
2039 {
2040         mmplayer_t *player = (mmplayer_t *)data;
2041         GstBusSyncReply reply = GST_BUS_DROP;
2042
2043         if (!(player->pipeline && player->pipeline->mainbin)) {
2044                 LOGE("player pipeline handle is null");
2045                 return GST_BUS_PASS;
2046         }
2047
2048         if (!__mmplayer_gst_check_useful_message(player, message)) {
2049                 gst_message_unref(message);
2050                 return GST_BUS_DROP;
2051         }
2052
2053         switch (GST_MESSAGE_TYPE(message)) {
2054         case GST_MESSAGE_TAG:
2055                 __mmplayer_gst_extract_tag_from_msg(player, message);
2056
2057 #ifdef __DEBUG__
2058                 {
2059                         GstTagList *tags = NULL;
2060
2061                         gst_message_parse_tag(message, &tags);
2062                         if (tags) {
2063                                 LOGE("TAGS received from element \"%s\".",
2064                                 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
2065
2066                                 gst_tag_list_foreach(tags, print_tag, NULL);
2067                                 gst_tag_list_unref(tags);
2068                                 tags = NULL;
2069                         }
2070                         break;
2071                 }
2072 #endif
2073                 break;
2074
2075         case GST_MESSAGE_DURATION_CHANGED:
2076                 __mmplayer_gst_handle_duration(player, message);
2077                 break;
2078         case GST_MESSAGE_ELEMENT:
2079                 {
2080                         const gchar *klass = NULL;
2081                         klass = gst_element_factory_get_metadata
2082                                 (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS);
2083                         if (!klass || !g_strrstr(klass, "Codec/Decoder")) {
2084                                 reply = GST_BUS_PASS;
2085                                 break;
2086                         }
2087                         __mmplayer_gst_handle_element_message(player, message);
2088                 }
2089                 break;
2090         case GST_MESSAGE_ASYNC_DONE:
2091                 /* NOTE:Don't call gst_callback directly
2092                  * because previous frame can be showed even though this message is received for seek.
2093                  */
2094         default:
2095                 reply = GST_BUS_PASS;
2096                 break;
2097         }
2098
2099         if (reply == GST_BUS_DROP)
2100                 gst_message_unref(message);
2101
2102         return reply;
2103 }
2104
2105 static void
2106 __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
2107 {
2108         GstElement *appsrc = element;
2109         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2110         GstBuffer *buffer = NULL;
2111         GstFlowReturn ret = GST_FLOW_OK;
2112         gint len = size;
2113
2114         MMPLAYER_RETURN_IF_FAIL(element);
2115         MMPLAYER_RETURN_IF_FAIL(buf);
2116
2117         buffer = gst_buffer_new();
2118
2119         if (buf->offset < 0 || buf->len < 0) {
2120                 LOGE("invalid buf info %d %d", buf->offset, buf->len);
2121                 return;
2122         }
2123
2124         if (buf->offset >= buf->len) {
2125                 LOGD("call eos appsrc");
2126                 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
2127                 return;
2128         }
2129
2130         if (buf->len - buf->offset < size)
2131                 len = buf->len - buf->offset;
2132
2133         gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
2134         GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
2135         GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
2136
2137 #ifdef __DEBUG__
2138         LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
2139 #endif
2140         g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
2141
2142         buf->offset += len;
2143 }
2144
2145 static gboolean
2146 __mmplayer_gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
2147 {
2148         mmplayer_input_buffer_t *buf = (mmplayer_input_buffer_t *)user_data;
2149
2150         MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
2151
2152         buf->offset  = (int)size;
2153
2154         return TRUE;
2155 }
2156
2157 void
2158 __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data)
2159 {
2160         mmplayer_t *player  = (mmplayer_t *)user_data;
2161         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2162         MMMessageParamType msg_param = {0,};
2163         guint64 current_level_bytes = 0;
2164
2165         MMPLAYER_RETURN_IF_FAIL(player);
2166
2167         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2168                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2169         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2170                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2171         } else {
2172                 LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element));
2173                 return;
2174         }
2175
2176         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2177
2178         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2179
2180         msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2181         msg_param.buffer_status.stream_type = stream_type;
2182         msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN;
2183         msg_param.buffer_status.bytes = current_level_bytes;
2184
2185         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2186 }
2187
2188 void
2189 __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data)
2190 {
2191         mmplayer_t *player  = (mmplayer_t *)user_data;
2192         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2193         MMMessageParamType msg_param = {0,};
2194         guint64 current_level_bytes = 0;
2195
2196         MMPLAYER_RETURN_IF_FAIL(player);
2197
2198         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2199                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2200         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2201                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2202         } else {
2203                 LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element));
2204                 return;
2205         }
2206
2207         g_object_get(G_OBJECT(element), "current-level-bytes", &current_level_bytes, NULL);
2208
2209         LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes);
2210
2211         msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS;
2212         msg_param.buffer_status.stream_type = stream_type;
2213         msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW;
2214         msg_param.buffer_status.bytes = current_level_bytes;
2215
2216         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param);
2217 }
2218
2219 gboolean
2220 __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data)
2221 {
2222         mmplayer_t *player  = (mmplayer_t *)user_data;
2223         mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT;
2224         MMMessageParamType msg_param = {0,};
2225
2226         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2227
2228         if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) {
2229                 stream_type = MM_PLAYER_STREAM_TYPE_AUDIO;
2230         } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) {
2231                 stream_type = MM_PLAYER_STREAM_TYPE_VIDEO;
2232         } else {
2233                 LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element));
2234                 return TRUE;
2235         }
2236
2237         LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position);
2238
2239         msg_param.union_type = MM_MSG_UNION_SEEK_DATA;
2240         msg_param.seek_data.stream_type = stream_type;
2241         msg_param.seek_data.offset = position;
2242
2243         MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param);
2244
2245         return TRUE;
2246 }
2247
2248 static gboolean
2249 __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type, GstPad *srcpad)
2250 {
2251 #define MAX_LEN_NAME 20
2252
2253         gboolean ret = FALSE;
2254         GstPad *sinkpad = NULL;
2255         gchar *prefix = NULL;
2256         gchar dec_name[MAX_LEN_NAME] = {0, };
2257         main_element_id_e elem_id = MMPLAYER_M_NUM;
2258
2259         mmplayer_gst_element_t *mainbin = NULL;
2260         GstElement *decodebin = NULL;
2261         GstCaps *dec_caps = NULL;
2262
2263         MMPLAYER_FENTER();
2264
2265         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2266                                                 player->pipeline &&
2267                                                 player->pipeline->mainbin, FALSE);
2268         MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
2269
2270         mainbin = player->pipeline->mainbin;
2271         switch (type) {
2272         case MM_PLAYER_STREAM_TYPE_AUDIO:
2273                 prefix = "audio";
2274                 elem_id = MMPLAYER_M_AUTOPLUG_A_DEC;
2275         break;
2276         case MM_PLAYER_STREAM_TYPE_VIDEO:
2277                 prefix = "video";
2278                 elem_id = MMPLAYER_M_AUTOPLUG_V_DEC;
2279         break;
2280         default:
2281                 LOGE("invalid type %d", type);
2282                 return FALSE;
2283         }
2284
2285         if (mainbin[elem_id].gst) {
2286                 LOGE("elem(%d) is already created", elem_id);
2287                 return FALSE;
2288         }
2289
2290         snprintf(dec_name, sizeof(dec_name), "%s_decodebin", prefix);
2291
2292         /* create decodebin */
2293         decodebin = gst_element_factory_make("decodebin", dec_name);
2294         if (!decodebin) {
2295                 LOGE("failed to create %s", dec_name);
2296                 return FALSE;
2297         }
2298
2299         mainbin[elem_id].id = elem_id;
2300         mainbin[elem_id].gst = decodebin;
2301
2302         /* raw pad handling signal */
2303         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2304                                                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
2305
2306         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
2307         before looking for any elements that can handle that stream.*/
2308         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
2309                                                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
2310
2311         if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
2312                 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
2313                                                         G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
2314
2315         /* This signal is emitted when a element is added to the bin.*/
2316         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
2317                                                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
2318
2319         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
2320                 LOGE("failed to add new decodebin");
2321                 return FALSE;
2322         }
2323
2324         dec_caps = gst_pad_query_caps(srcpad, NULL);
2325         if (dec_caps) {
2326 #ifdef __DEBUG__
2327                 LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
2328 #endif
2329                 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
2330                 gst_caps_unref(dec_caps);
2331         }
2332
2333         sinkpad = gst_element_get_static_pad(decodebin, "sink");
2334
2335         if (!sinkpad || gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
2336                 LOGE("failed to link [%s:%s] to decoder", GST_DEBUG_PAD_NAME(srcpad));
2337                 goto ERROR;
2338         }
2339         gst_object_unref(GST_OBJECT(sinkpad));
2340
2341         gst_element_sync_state_with_parent(decodebin);
2342         MMPLAYER_FLEAVE();
2343         return TRUE;
2344
2345 ERROR:
2346         if (sinkpad)
2347                 gst_object_unref(GST_OBJECT(sinkpad));
2348
2349         if (mainbin[elem_id].gst) {
2350                 gst_element_set_state(mainbin[elem_id].gst, GST_STATE_NULL);
2351                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[elem_id].gst);
2352                 gst_object_unref(mainbin[elem_id].gst);
2353                 mainbin[elem_id].gst = NULL;
2354         }
2355
2356         MMPLAYER_FLEAVE();
2357         return ret;
2358 }
2359
2360 static gboolean
2361 __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, GstCaps *caps)
2362 {
2363 #define MAX_LEN_NAME 20
2364         mmplayer_gst_element_t *mainbin = NULL;
2365         gchar *prefix = NULL;
2366         main_element_id_e src_id = MMPLAYER_M_NUM, queue_id = MMPLAYER_M_NUM;
2367
2368         gchar src_name[MAX_LEN_NAME] = {0, }, queue_name[MAX_LEN_NAME] = {0, };
2369         GstElement *src = NULL, *queue = NULL;
2370         GstPad *srcpad = NULL;
2371
2372         MMPLAYER_FENTER();
2373         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2374                                 player->pipeline->mainbin, FALSE);
2375
2376         mainbin = player->pipeline->mainbin;
2377
2378         LOGD("type(%d) path is creating", type);
2379         switch (type) {
2380         case MM_PLAYER_STREAM_TYPE_AUDIO:
2381                 prefix = "audio";
2382                 if (mainbin[MMPLAYER_M_SRC].gst)
2383                         src_id = MMPLAYER_M_2ND_SRC;
2384                 else
2385                         src_id = MMPLAYER_M_SRC;
2386                 queue_id = MMPLAYER_M_A_BUFFER;
2387         break;
2388         case MM_PLAYER_STREAM_TYPE_VIDEO:
2389                 prefix = "video";
2390                 src_id = MMPLAYER_M_SRC;
2391                 queue_id = MMPLAYER_M_V_BUFFER;
2392         break;
2393         case MM_PLAYER_STREAM_TYPE_TEXT:
2394                 prefix = "subtitle";
2395                 src_id = MMPLAYER_M_SUBSRC;
2396                 queue_id = MMPLAYER_M_S_BUFFER;
2397         break;
2398         default:
2399                 LOGE("invalid type %d", type);
2400                 return FALSE;
2401         }
2402
2403         snprintf(src_name, sizeof(src_name), "%s_appsrc", prefix);
2404         snprintf(queue_name, sizeof(queue_name), "%s_queue", prefix);
2405
2406         /* create source */
2407         src = gst_element_factory_make("appsrc", src_name);
2408         if (!src) {
2409                 LOGF("failed to create %s", src_name);
2410                 goto ERROR;
2411         }
2412
2413         mainbin[src_id].id = src_id;
2414         mainbin[src_id].gst = src;
2415
2416         g_object_set(G_OBJECT(src), "format", GST_FORMAT_TIME,
2417                                                                 "caps", caps, NULL);
2418
2419         /* size of many video frames are larger than default blocksize as 4096 */
2420         if (type == MM_PLAYER_STREAM_TYPE_VIDEO)
2421                 g_object_set(G_OBJECT(src), "blocksize", (guint)1048576, NULL);
2422
2423         if (player->media_stream_buffer_max_size[type] > 0)
2424                 g_object_set(G_OBJECT(src), "max-bytes", player->media_stream_buffer_max_size[type], NULL);
2425
2426         if (player->media_stream_buffer_min_percent[type] > 0)
2427                 g_object_set(G_OBJECT(src), "min-percent", player->media_stream_buffer_min_percent[type], NULL);
2428
2429         /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
2430         gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE);
2431
2432         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
2433                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player);
2434         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
2435                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player);
2436         _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
2437                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player);
2438
2439         /* create queue */
2440         queue = gst_element_factory_make("queue2", queue_name);
2441         if (!queue) {
2442                 LOGE("failed to create %s", queue_name);
2443                 goto ERROR;
2444         }
2445         g_object_set(G_OBJECT(queue), "max-size-buffers", 2, NULL);
2446
2447         mainbin[queue_id].id = queue_id;
2448         mainbin[queue_id].gst = queue;
2449
2450         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst)) {
2451                 LOGE("failed to add src");
2452                 goto ERROR;
2453         }
2454
2455         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst)) {
2456                 LOGE("failed to add queue");
2457                 goto ERROR;
2458         }
2459
2460         if (!gst_element_link(mainbin[src_id].gst, mainbin[queue_id].gst)) {
2461                 LOGE("failed to link src and queue");
2462                 goto ERROR;
2463         }
2464
2465         /* create decoder */
2466         srcpad = gst_element_get_static_pad(mainbin[queue_id].gst, "src");
2467         if (!srcpad) {
2468                 LOGE("failed to get srcpad of queue");
2469                 goto ERROR;
2470         }
2471
2472         if (type == MM_PLAYER_STREAM_TYPE_TEXT) {
2473                 _mmplayer_gst_create_decoder(player, srcpad, caps);
2474         } else {
2475                 if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) {
2476                         LOGE("failed to create decoder");
2477                         gst_object_unref(GST_OBJECT(srcpad));
2478                         goto ERROR;
2479                 }
2480         }
2481         gst_object_unref(GST_OBJECT(srcpad));
2482         return TRUE;
2483
2484 ERROR:
2485         if (mainbin[src_id].gst) {
2486                 gst_element_set_state(mainbin[src_id].gst, GST_STATE_NULL);
2487                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[src_id].gst);
2488                 gst_object_unref(mainbin[src_id].gst);
2489                 mainbin[src_id].gst = NULL;
2490         }
2491
2492         if (mainbin[queue_id].gst) {
2493                 gst_element_set_state(mainbin[queue_id].gst, GST_STATE_NULL);
2494                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[queue_id].gst);
2495                 gst_object_unref(mainbin[queue_id].gst);
2496                 mainbin[queue_id].gst = NULL;
2497         }
2498
2499         return FALSE;
2500 }
2501
2502 static void
2503 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2504 {
2505         GstPad *sinkpad = NULL;
2506         GstCaps *caps = NULL;
2507         GstElement *new_element = NULL;
2508         GstStructure *str = NULL;
2509         const gchar *name = NULL;
2510
2511         mmplayer_t *player = (mmplayer_t *)data;
2512
2513         MMPLAYER_FENTER();
2514
2515         MMPLAYER_RETURN_IF_FAIL(element && pad);
2516         MMPLAYER_RETURN_IF_FAIL(player &&
2517                                         player->pipeline &&
2518                                         player->pipeline->mainbin);
2519
2520         /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2521          * num_dynamic_pad will decreased after creating a sinkbin.
2522          */
2523         player->num_dynamic_pad++;
2524         LOGD("stream count inc : %d", player->num_dynamic_pad);
2525
2526         caps = gst_pad_query_caps(pad, NULL);
2527         MMPLAYER_CHECK_NULL(caps);
2528
2529         str = gst_caps_get_structure(caps, 0);
2530         name = gst_structure_get_string(str, "media");
2531         if (!name) {
2532                 LOGE("cannot get mimetype from structure.");
2533                 goto ERROR;
2534         }
2535
2536         if (strstr(name, "video")) {
2537                 gint stype = 0;
2538                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2539
2540                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
2541                         if (player->v_stream_caps) {
2542                                 gst_caps_unref(player->v_stream_caps);
2543                                 player->v_stream_caps = NULL;
2544                         }
2545
2546                         new_element = gst_element_factory_make("fakesink", NULL);
2547                         player->num_dynamic_pad--;
2548                         goto NEW_ELEMENT;
2549                 }
2550         }
2551
2552         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
2553                 LOGE("failed to autoplug for caps");
2554                 goto ERROR;
2555         }
2556
2557         gst_caps_unref(caps);
2558         caps = NULL;
2559
2560 NEW_ELEMENT:
2561
2562         /* excute new_element if created*/
2563         if (new_element) {
2564                 LOGD("adding new element to pipeline");
2565
2566                 /* set state to READY before add to bin */
2567                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2568
2569                 /* add new element to the pipeline */
2570                 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2571                         LOGE("failed to add autoplug element to bin");
2572                         goto ERROR;
2573                 }
2574
2575                 /* get pad from element */
2576                 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2577                 if (!sinkpad) {
2578                         LOGE("failed to get sinkpad from autoplug element");
2579                         goto ERROR;
2580                 }
2581
2582                 /* link it */
2583                 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2584                         LOGE("failed to link autoplug element");
2585                         goto ERROR;
2586                 }
2587
2588                 gst_object_unref(sinkpad);
2589                 sinkpad = NULL;
2590
2591                 /* run. setting PLAYING here since streamming source is live source */
2592                 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2593         }
2594
2595         if (caps)
2596                 gst_caps_unref(caps);
2597
2598         MMPLAYER_FLEAVE();
2599
2600         return;
2601
2602 STATE_CHANGE_FAILED:
2603 ERROR:
2604         /* FIXIT : take care if new_element has already added to pipeline */
2605         if (new_element)
2606                 gst_object_unref(GST_OBJECT(new_element));
2607
2608         if (sinkpad)
2609                 gst_object_unref(GST_OBJECT(sinkpad));
2610
2611         if (caps)
2612                 gst_caps_unref(caps);
2613
2614         /* FIXIT : how to inform this error to MSL ????? */
2615         /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2616          * then post an error to application
2617          */
2618 }
2619
2620 static void
2621 __mmplayer_gst_rtp_no_more_pads(GstElement *element,  gpointer data)
2622 {
2623         mmplayer_t *player = (mmplayer_t *)data;
2624
2625         MMPLAYER_FENTER();
2626
2627         /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2628          * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2629          * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2630          * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2631
2632          * [1] audio and video will be dumped with filesink.
2633          * [2] autoplugging is done by just using pad caps.
2634          * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2635          * and the video will be dumped via filesink.
2636          */
2637         if (player->num_dynamic_pad == 0) {
2638                 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now");
2639
2640                 if (!_mmplayer_gst_remove_fakesink(player,
2641                         &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2642                         /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2643                          * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2644                          * source element are not same. To overcome this situation, this function will called
2645                          * several places and several times. Therefore, this is not an error case.
2646                          */
2647                         return;
2648         }
2649
2650         /* create dot before error-return. for debugging */
2651         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2652
2653         player->no_more_pad = TRUE;
2654
2655         MMPLAYER_FLEAVE();
2656 }
2657
2658 static GstElement *
2659 __mmplayer_gst_make_rtsp_src(mmplayer_t *player)
2660 {
2661         GstElement *element = NULL;
2662         gchar *user_agent = NULL;
2663         MMHandleType attrs = 0;
2664
2665         MMPLAYER_FENTER();
2666         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2667
2668         /* get profile attribute */
2669         attrs = MMPLAYER_GET_ATTRS(player);
2670         if (!attrs) {
2671                 LOGE("failed to get content attribute");
2672                 return NULL;
2673         }
2674
2675         element = gst_element_factory_make("rtspsrc", "rtsp source");
2676         if (!element) {
2677                 LOGE("failed to create rtspsrc element");
2678                 return NULL;
2679         }
2680
2681         /* get attribute */
2682         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2683
2684         SECURE_LOGD("user_agent : %s", user_agent);
2685
2686         /* setting property to streaming source */
2687         g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
2688         if (user_agent)
2689                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2690
2691         _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2692                                                                         G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player);
2693         _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2694                                                                         G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player);
2695
2696         MMPLAYER_FLEAVE();
2697         return element;
2698 }
2699
2700 static GstElement *
2701 __mmplayer_gst_make_http_src(mmplayer_t *player)
2702 {
2703 #define MAX_RETRY_COUNT 10
2704         GstElement *element = NULL;
2705         MMHandleType attrs = 0;
2706         gchar *user_agent, *cookies, **cookie_list;
2707         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
2708
2709         user_agent = cookies = NULL;
2710         cookie_list = NULL;
2711
2712         MMPLAYER_FENTER();
2713         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2714
2715         /* get profile attribute */
2716         attrs = MMPLAYER_GET_ATTRS(player);
2717         if (!attrs) {
2718                 LOGE("failed to get content attribute");
2719                 return NULL;
2720         }
2721
2722         LOGD("using http streamming source [%s]", player->ini.httpsrc_element);
2723
2724         element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
2725         if (!element) {
2726                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
2727                 return NULL;
2728         }
2729
2730         /* get attribute */
2731         mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
2732         mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
2733
2734         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT)
2735                 http_timeout = player->ini.http_timeout;
2736
2737         /* get attribute */
2738         SECURE_LOGD("location : %s", player->profile.uri);
2739         SECURE_LOGD("cookies : %s", cookies);
2740         SECURE_LOGD("user_agent :  %s", user_agent);
2741         LOGD("timeout : %d", http_timeout);
2742
2743         /* setting property to streaming source */
2744         g_object_set(G_OBJECT(element), "location", player->profile.uri,
2745                                 "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024),
2746                                 "retries", MAX_RETRY_COUNT, NULL);
2747
2748         /* parsing cookies */
2749         if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) {
2750                 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
2751                 g_strfreev(cookie_list);
2752         }
2753
2754         if (user_agent)
2755                 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
2756
2757         if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
2758                 LOGW("[DASH] this is still experimental feature");
2759
2760         MMPLAYER_FLEAVE();
2761         return element;
2762 }
2763
2764 static GstElement *
2765 __mmplayer_gst_make_file_src(mmplayer_t *player)
2766 {
2767         GstElement *element = NULL;
2768
2769         MMPLAYER_FENTER();
2770         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2771
2772         LOGD("using filesrc for 'file://' handler");
2773         if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
2774                 LOGE("failed to get storage info");
2775                 return NULL;
2776         }
2777
2778         element = gst_element_factory_make("filesrc", "source");
2779         if (!element) {
2780                 LOGE("failed to create filesrc");
2781                 return NULL;
2782         }
2783
2784         g_object_set(G_OBJECT(element), "location", (player->profile.uri) + 7, NULL); /* uri+7 -> remove "file:// */
2785
2786         MMPLAYER_FLEAVE();
2787         return element;
2788 }
2789
2790 static gboolean
2791 __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
2792 {
2793         mmplayer_t *player = (mmplayer_t *)data;
2794
2795         g_return_val_if_fail(player, FALSE);
2796         g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
2797
2798         gst_message_ref(msg);
2799
2800         g_mutex_lock(&player->bus_msg_q_lock);
2801         g_queue_push_tail(player->bus_msg_q, msg);
2802         g_mutex_unlock(&player->bus_msg_q_lock);
2803
2804         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2805         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
2806         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2807         return TRUE;
2808 }
2809
2810 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
2811 {
2812         mmplayer_t *player = (mmplayer_t *)(data);
2813         GstMessage *msg = NULL;
2814         GstBus *bus = NULL;
2815
2816         MMPLAYER_FENTER();
2817         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2818                                                 player->pipeline &&
2819                                                 player->pipeline->mainbin &&
2820                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
2821                                                 NULL);
2822
2823         bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
2824         if (!bus) {
2825                 LOGE("cannot get BUS from the pipeline");
2826                 return NULL;
2827         }
2828
2829         MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2830
2831         LOGD("[handle: %p] gst bus msg thread will be started.", player);
2832         while (!player->bus_msg_thread_exit) {
2833                 g_mutex_lock(&player->bus_msg_q_lock);
2834                 msg = g_queue_pop_head(player->bus_msg_q);
2835                 g_mutex_unlock(&player->bus_msg_q_lock);
2836                 if (msg == NULL) {
2837                         MMPLAYER_BUS_MSG_THREAD_WAIT(player);
2838                         continue;
2839                 }
2840                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2841                 /* handle the gst msg */
2842                 __mmplayer_gst_bus_msg_callback(msg, player);
2843                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
2844                 gst_message_unref(msg);
2845         }
2846
2847         MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
2848         gst_object_unref(GST_OBJECT(bus));
2849
2850         MMPLAYER_FLEAVE();
2851         return NULL;
2852 }
2853
2854 static int
2855 __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position)
2856 {
2857         gint64 dur_nsec = 0;
2858
2859         MMPLAYER_FENTER();
2860         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2861
2862         if (MMPLAYER_IS_MS_BUFF_SRC(player))
2863                 return MM_ERROR_NONE;
2864
2865         /* NOTE : duration cannot be zero except live streaming.
2866          *              Since some element could have some timing problemn with quering duration, try again.
2867          */
2868         if (player->duration == 0) {
2869                 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
2870                         /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
2871                          * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
2872                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
2873                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
2874                                 player->pending_seek.is_pending = true;
2875                                 player->pending_seek.pos = position;
2876                                 player->seek_state = MMPLAYER_SEEK_NONE;
2877                                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
2878                                 return MM_ERROR_PLAYER_NO_OP;
2879                         } else {
2880                                 player->seek_state = MMPLAYER_SEEK_NONE;
2881                                 return MM_ERROR_PLAYER_SEEK;
2882                         }
2883                 }
2884                 player->duration = dur_nsec;
2885         }
2886
2887         if (player->duration > 0 && player->duration < position) {
2888                 LOGE("invalid pos %"G_GINT64_FORMAT", dur: %"G_GINT64_FORMAT, position, player->duration);
2889                 return MM_ERROR_INVALID_ARGUMENT;
2890         }
2891
2892         MMPLAYER_FLEAVE();
2893         return MM_ERROR_NONE;
2894 }
2895
2896 static gboolean
2897 __mmplayer_gst_check_seekable(mmplayer_t *player)
2898 {
2899         GstQuery *query = NULL;
2900         gboolean seekable = FALSE;
2901
2902         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2903                 return TRUE;
2904         }
2905
2906         query = gst_query_new_seeking(GST_FORMAT_TIME);
2907         if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
2908                 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
2909                 gst_query_unref(query);
2910
2911                 if (!seekable) {
2912                         LOGW("non-seekable content");
2913                         player->seek_state = MMPLAYER_SEEK_NONE;
2914                         return FALSE;
2915                 }
2916         } else {
2917                 LOGW("failed to get seeking query");
2918                 gst_query_unref(query); /* keep seeking operation */
2919         }
2920
2921         return TRUE;
2922 }
2923
2924 int
2925 _mmplayer_gst_set_state(mmplayer_t *player, GstElement *element,  GstState state, gboolean async, gint timeout)
2926 {
2927         GstState element_state = GST_STATE_VOID_PENDING;
2928         GstState element_pending_state = GST_STATE_VOID_PENDING;
2929         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
2930
2931         MMPLAYER_FENTER();
2932
2933         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2934         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
2935
2936         LOGD("setting [%s] element state to : %s", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
2937
2938         /* set state */
2939         ret = gst_element_set_state(element, state);
2940         if (ret == GST_STATE_CHANGE_FAILURE) {
2941                 LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element));
2942
2943                 /* dump state of all element */
2944                 _mmplayer_dump_pipeline_state(player);
2945
2946                 return MM_ERROR_PLAYER_INTERNAL;
2947         }
2948
2949         /* return here so state transition to be done in async mode */
2950         if (async) {
2951                 LOGD("async state transition. not waiting for state complete.");
2952                 return MM_ERROR_NONE;
2953         }
2954
2955         /* wait for state transition */
2956         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
2957         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
2958                 LOGE("failed to change [%s] element state to [%s] within %d sec",
2959                         GST_ELEMENT_NAME(element),
2960                         gst_element_state_get_name(state), timeout);
2961
2962                 LOGE(" [%s] state : %s   pending : %s",
2963                         GST_ELEMENT_NAME(element),
2964                         gst_element_state_get_name(element_state),
2965                         gst_element_state_get_name(element_pending_state));
2966
2967                 /* dump state of all element */
2968                 _mmplayer_dump_pipeline_state(player);
2969
2970                 return MM_ERROR_PLAYER_INTERNAL;
2971         }
2972
2973         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
2974
2975         MMPLAYER_FLEAVE();
2976
2977         return MM_ERROR_NONE;
2978 }
2979
2980 int
2981 _mmplayer_gst_start(mmplayer_t *player)
2982 {
2983         int ret = MM_ERROR_NONE;
2984         gboolean async = FALSE;
2985
2986         MMPLAYER_FENTER();
2987
2988         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2989
2990         /* NOTE : if SetPosition was called before Start. do it now
2991          * streaming doesn't support it. so it should be always sync
2992          * !!create one more api to check if there is pending seek rather than checking variables
2993          */
2994         if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) {
2995                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
2996                 ret = _mmplayer_gst_pause(player, FALSE);
2997                 if (ret != MM_ERROR_NONE) {
2998                         LOGE("failed to set state to PAUSED for pending seek");
2999                         return ret;
3000                 }
3001
3002                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
3003                 if (__mmplayer_gst_pending_seek(player) != MM_ERROR_NONE)
3004                                 LOGW("failed to seek pending postion. starting from the begin of content");
3005         }
3006
3007         LOGD("current state before doing transition");
3008         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3009         MMPLAYER_PRINT_STATE(player);
3010
3011         /* set pipeline state to PLAYING  */
3012         ret = _mmplayer_gst_set_state(player,
3013                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3014         if (ret != MM_ERROR_NONE) {
3015                 LOGE("failed to set state to PLAYING");
3016                 return ret;
3017         }
3018
3019         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3020
3021         /* generating debug info before returning error */
3022         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
3023
3024         MMPLAYER_FLEAVE();
3025
3026         return ret;
3027 }
3028
3029 int
3030 _mmplayer_gst_stop(mmplayer_t *player)
3031 {
3032         GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
3033         MMHandleType attrs = 0;
3034         gboolean rewind = FALSE;
3035         gint timeout = 0;
3036         int ret = MM_ERROR_NONE;
3037
3038         MMPLAYER_FENTER();
3039
3040         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3041         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3042
3043         LOGD("current state before doing transition");
3044         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
3045         MMPLAYER_PRINT_STATE(player);
3046
3047         attrs = MMPLAYER_GET_ATTRS(player);
3048         if (!attrs) {
3049                 LOGE("cannot get content attribute");
3050                 return MM_ERROR_PLAYER_INTERNAL;
3051         }
3052
3053         /* Just set state to PAUESED and the rewind. it's usual player behavior. */
3054         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3055
3056         if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
3057                 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
3058                 rewind = TRUE;
3059
3060         if (player->es_player_push_mode)
3061                 /* disable the async state transition because there could be no data in the pipeline */
3062                 __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL);
3063
3064         /* set gst state */
3065         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout);
3066
3067         if (player->es_player_push_mode) {
3068                 /* enable the async state transition as default operation */
3069                 __mmplayer_gst_set_async(player, TRUE, MMPLAYER_SINK_ALL);
3070         }
3071
3072         /* return if set_state has failed */
3073         if (ret != MM_ERROR_NONE) {
3074                 LOGE("failed to set state.");
3075                 return ret;
3076         }
3077
3078         /* rewind */
3079         if (rewind) {
3080                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3081                                 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
3082                                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3083                         LOGW("failed to rewind");
3084                         ret = MM_ERROR_PLAYER_SEEK;
3085                 }
3086         }
3087
3088         /* initialize */
3089         player->sent_bos = FALSE;
3090
3091         if (player->es_player_push_mode) //for cloudgame
3092                 timeout = 0;
3093
3094         /* wait for seek to complete */
3095         change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
3096         if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
3097                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
3098         } else {
3099                 LOGE("fail to stop player.");
3100                 ret = MM_ERROR_PLAYER_INTERNAL;
3101                 _mmplayer_dump_pipeline_state(player);
3102         }
3103
3104         /* generate dot file if enabled */
3105         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
3106
3107         MMPLAYER_FLEAVE();
3108
3109         return ret;
3110 }
3111
3112 int
3113 _mmplayer_gst_pause(mmplayer_t *player, gboolean async)
3114 {
3115         int ret = MM_ERROR_NONE;
3116
3117         MMPLAYER_FENTER();
3118
3119         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3120         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3121
3122         LOGD("current state before doing transition");
3123         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
3124         MMPLAYER_PRINT_STATE(player);
3125
3126         /* set pipeline status to PAUSED */
3127         ret = _mmplayer_gst_set_state(player,
3128                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
3129
3130         if (async)
3131                 goto EXIT;
3132
3133         if (ret != MM_ERROR_NONE) {
3134                 GstMessage *msg = NULL;
3135                 GTimer *timer = NULL;
3136                 gdouble MAX_TIMEOUT_SEC = 3;
3137
3138                 LOGE("failed to set state to PAUSED");
3139
3140                 if (!player->bus_watcher) {
3141                         LOGE("there is no bus msg thread. pipeline is shutting down.");
3142                         return ret;
3143                 }
3144
3145                 if (player->msg_posted) {
3146                         LOGE("error msg is already posted.");
3147                         return ret;
3148                 }
3149
3150                 timer = g_timer_new();
3151                 g_timer_start(timer);
3152
3153                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
3154
3155                 do {
3156                         msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
3157                         if (msg) {
3158                                 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
3159                                         GError *error = NULL;
3160
3161                                         /* parse error code */
3162                                         gst_message_parse_error(msg, &error, NULL);
3163
3164                                         if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
3165                                                 /* Note : the streaming error from the streaming source is handled
3166                                                         *   using __mmplayer_handle_streaming_error.
3167                                                         */
3168                                                 __mmplayer_handle_streaming_error(player, msg);
3169
3170                                         } else if (error) {
3171                                                 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
3172
3173                                                 if (error->domain == GST_STREAM_ERROR)
3174                                                         ret = __mmplayer_gst_handle_stream_error(player, error, msg);
3175                                                 else if (error->domain == GST_RESOURCE_ERROR)
3176                                                         ret = __mmplayer_gst_handle_resource_error(player, error->code, NULL);
3177                                                 else if (error->domain == GST_LIBRARY_ERROR)
3178                                                         ret = __mmplayer_gst_handle_library_error(player, error->code);
3179                                                 else if (error->domain == GST_CORE_ERROR)
3180                                                         ret = __mmplayer_gst_handle_core_error(player, error->code);
3181
3182                                                 g_error_free(error);
3183                                         }
3184                                         player->msg_posted = TRUE;
3185                                 }
3186                                 gst_message_unref(msg);
3187                         }
3188                 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
3189                 /* clean */
3190                 gst_object_unref(bus);
3191                 g_timer_stop(timer);
3192                 g_timer_destroy(timer);
3193
3194                 return ret;
3195         }
3196
3197         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) &&
3198                 (!player->pipeline->videobin) && (!player->pipeline->audiobin))
3199                 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
3200
3201         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
3202
3203 EXIT:
3204         /* generate dot file before returning error */
3205         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
3206
3207         MMPLAYER_FLEAVE();
3208
3209         return ret;
3210 }
3211
3212 int
3213 _mmplayer_gst_resume(mmplayer_t *player, gboolean async)
3214 {
3215         int ret = MM_ERROR_NONE;
3216         gint timeout = 0;
3217
3218         MMPLAYER_FENTER();
3219
3220         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
3221                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3222
3223         LOGD("current state before doing transition");
3224         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
3225         MMPLAYER_PRINT_STATE(player);
3226
3227         if (async)
3228                 LOGD("do async state transition to PLAYING");
3229
3230         /* set pipeline state to PLAYING */
3231         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
3232
3233         ret = _mmplayer_gst_set_state(player,
3234                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
3235         if (ret != MM_ERROR_NONE) {
3236                 LOGE("failed to set state to PLAYING");
3237                 goto EXIT;
3238         }
3239
3240         if (!async)
3241                 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
3242
3243 EXIT:
3244         /* generate dot file */
3245         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
3246
3247         MMPLAYER_FLEAVE();
3248
3249         return ret;
3250 }
3251
3252 /* sending event to one of sinkelements */
3253 gboolean
3254 _mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event)
3255 {
3256         GstEvent *event2 = NULL;
3257         GList *sinks = NULL;
3258         gboolean res = FALSE;
3259         MMPLAYER_FENTER();
3260
3261         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3262         MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
3263
3264         /* While adding subtitles in live feeds seek is getting called.
3265            Adding defensive check in framework layer.*/
3266         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3267                 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
3268                         LOGE("Should not send seek event during live playback");
3269                         return TRUE;
3270                 }
3271         }
3272
3273         if (player->play_subtitle)
3274                 event2 = gst_event_copy((const GstEvent *)event);
3275
3276         sinks = player->sink_elements;
3277         while (sinks) {
3278                 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
3279
3280                 if (GST_IS_ELEMENT(sink)) {
3281                         /* keep ref to the event */
3282                         gst_event_ref(event);
3283
3284                         if ((res = gst_element_send_event(sink, event))) {
3285                                 LOGD("sending event[%s] to sink element [%s] success!",
3286                                         GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3287
3288                                 /* rtsp case, asyn_done is not called after seek during pause state */
3289                                 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
3290                                         if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
3291                                                 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
3292                                                         LOGD("RTSP seek completed, after pause state..");
3293                                                         player->seek_state = MMPLAYER_SEEK_NONE;
3294                                                         MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3295                                                 }
3296
3297                                         }
3298                                 }
3299
3300                                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3301                                         sinks = g_list_next(sinks);
3302                                         continue;
3303                                 } else {
3304                                         break;
3305                                 }
3306                         }
3307
3308                         LOGD("sending event[%s] to sink element [%s] failed. try with next one.",
3309                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
3310                 }
3311
3312                 sinks = g_list_next(sinks);
3313         }
3314
3315         /* Note : Textbin is not linked to the video or audio bin.
3316          * It needs to send the event to the text sink seperatelly.
3317          */
3318         if (player->play_subtitle && player->pipeline) {
3319                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
3320
3321                 if (GST_IS_ELEMENT(text_sink)) {
3322                         /* keep ref to the event */
3323                         gst_event_ref(event2);
3324
3325                         if ((res = gst_element_send_event(text_sink, event2)))
3326                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
3327                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3328                         else
3329                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
3330                                                 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
3331
3332                         gst_event_unref(event2);
3333                 }
3334         }
3335
3336         gst_event_unref(event);
3337
3338         MMPLAYER_FLEAVE();
3339
3340         return res;
3341 }
3342
3343 gboolean
3344 _mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate,
3345                         GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
3346                         gint64 cur, GstSeekType stop_type, gint64 stop)
3347 {
3348         GstEvent *event = NULL;
3349         gboolean result = FALSE;
3350
3351         MMPLAYER_FENTER();
3352
3353         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3354
3355         if (player->pipeline && player->pipeline->textbin)
3356                 __mmplayer_drop_subtitle(player, FALSE);
3357
3358         event = gst_event_new_seek(rate, format, flags, cur_type,
3359                 cur, stop_type, stop);
3360
3361         result = _mmplayer_gst_send_event_to_sink(player, event);
3362
3363         MMPLAYER_FLEAVE();
3364
3365         return result;
3366 }
3367
3368 int
3369 _mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called)
3370 {
3371         int ret = MM_ERROR_NONE;
3372         gint64 pos_nsec = 0;
3373         gboolean accurated = FALSE;
3374         GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
3375
3376         MMPLAYER_FENTER();
3377         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3378         MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
3379
3380         if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING)
3381                 && (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED))
3382                 goto PENDING;
3383
3384         ret = __mmplayer_gst_check_duration(player, position);
3385         if (ret != MM_ERROR_NONE) {
3386                 LOGE("failed to check duration 0x%X", ret);
3387                 return (ret == MM_ERROR_PLAYER_NO_OP) ? MM_ERROR_NONE : ret;
3388         }
3389
3390         if (!__mmplayer_gst_check_seekable(player))
3391                 return MM_ERROR_PLAYER_NO_OP;
3392
3393         LOGD("seeking to(%"G_GINT64_FORMAT") nsec, rate: %f, dur: %"G_GINT64_FORMAT" nsec",
3394                                 position, player->playback_rate, player->duration);
3395
3396         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
3397            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
3398            This causes problem is position calculation during normal pause resume scenarios also.
3399            Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
3400         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3401                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
3402                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
3403                         LOGW("getting current position failed in seek");
3404
3405                 player->last_position = pos_nsec;
3406                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
3407         }
3408
3409         if (player->seek_state != MMPLAYER_SEEK_NONE) {
3410                 LOGD("not completed seek");
3411                 return MM_ERROR_PLAYER_DOING_SEEK;
3412         }
3413
3414         if (!internal_called)
3415                 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
3416
3417         /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
3418                 that's why set position through property. */
3419         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
3420                 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
3421                 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
3422                 (!player->videodec_linked) && (!player->audiodec_linked)) {
3423
3424                 LOGD("[%s] set position =%"GST_TIME_FORMAT,
3425                                 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(position));
3426
3427                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", position, NULL);
3428                 player->seek_state = MMPLAYER_SEEK_NONE;
3429                 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
3430         } else {
3431                 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
3432                 if (accurated)
3433                         seek_flags |= GST_SEEK_FLAG_ACCURATE;
3434                 else
3435                         seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
3436
3437                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
3438                                                 GST_FORMAT_TIME, seek_flags,
3439                                                 GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
3440                         LOGE("failed to set position");
3441                         goto SEEK_ERROR;
3442                 }
3443         }
3444
3445         /* NOTE : store last seeking point to overcome some bad operation
3446          *     (returning zero when getting current position) of some elements
3447          */
3448         player->last_position = position;
3449
3450         /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
3451         if (player->playback_rate > 1.0)
3452                 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
3453
3454         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
3455                 LOGD("buffering should be reset after seeking");
3456                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
3457                 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
3458         }
3459
3460         MMPLAYER_FLEAVE();
3461         return MM_ERROR_NONE;
3462
3463 PENDING:
3464         player->pending_seek.is_pending = true;
3465         player->pending_seek.pos = position;
3466
3467         LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT")",
3468                 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
3469                 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
3470                 player->pending_seek.pos);
3471
3472         return MM_ERROR_NONE;
3473
3474 SEEK_ERROR:
3475         player->seek_state = MMPLAYER_SEEK_NONE;
3476         return MM_ERROR_PLAYER_SEEK;
3477 }
3478
3479 int
3480 _mmplayer_gst_get_position(mmplayer_t *player, gint64 *position)
3481 {
3482 #define TRICKPLAY_OFFSET GST_MSECOND
3483
3484         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
3485         gint64 pos_nsec = 0;
3486         gboolean ret = TRUE;
3487
3488         MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
3489                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3490
3491         current_state = MMPLAYER_CURRENT_STATE(player);
3492
3493         /* NOTE : query position except paused state to overcome some bad operation
3494          * please refer to below comments in details
3495          */
3496         if (current_state != MM_PLAYER_STATE_PAUSED)
3497                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
3498
3499         /* NOTE : get last point to overcome some bad operation of some elements
3500          *(returning zero when getting current position in paused state
3501          * and when failed to get postion during seeking
3502          */
3503         if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
3504                 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
3505
3506                 if (player->playback_rate < 0.0)
3507                         pos_nsec = player->last_position - TRICKPLAY_OFFSET;
3508                 else
3509                         pos_nsec = player->last_position;
3510
3511                 if (!ret)
3512                         pos_nsec = player->last_position;
3513                 else
3514                         player->last_position = pos_nsec;
3515
3516                 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
3517
3518         } else {
3519                 if (player->duration > 0 && pos_nsec > player->duration)
3520                         pos_nsec = player->duration;
3521
3522                 player->last_position = pos_nsec;
3523         }
3524
3525         *position = pos_nsec;
3526
3527         return MM_ERROR_NONE;
3528 }
3529
3530 int
3531 _mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos)
3532 {
3533 #define STREAMING_IS_FINISHED   0
3534 #define BUFFERING_MAX_PER       100
3535 #define DEFAULT_PER_VALUE       -1
3536 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
3537
3538         mmplayer_gst_element_t *mainbin = NULL;
3539         gint start_per = DEFAULT_PER_VALUE, end_per = DEFAULT_PER_VALUE;
3540         gint64 buffered_total = 0;
3541         gint64 position = 0;
3542         gint buffered_sec = -1;
3543         GstBufferingMode mode = GST_BUFFERING_STREAM;
3544         gint64 content_size_time = player->duration;
3545         guint64 content_size_bytes = player->http_content_size;
3546
3547         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3548                                                 player->pipeline &&
3549                                                 player->pipeline->mainbin,
3550                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
3551
3552         MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && end_pos, MM_ERROR_INVALID_ARGUMENT);
3553
3554         *start_pos = 0;
3555         *end_pos = 0;
3556
3557         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
3558                 /* and rtsp is not ready yet. */
3559                 LOGW("it's only used for http streaming case");
3560                 return MM_ERROR_PLAYER_NO_OP;
3561         }
3562
3563         if (content_size_time <= 0 || content_size_bytes <= 0) {
3564                 LOGW("there is no content size");
3565                 return MM_ERROR_NONE;
3566         }
3567
3568         if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) {
3569                 LOGW("fail to get current position");
3570                 return MM_ERROR_NONE;
3571         }
3572
3573         LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
3574                 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
3575
3576         mainbin = player->pipeline->mainbin;
3577         start_per = (gint)(floor(100 * (gdouble)position / (gdouble)content_size_time));
3578
3579         if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
3580                 GstQuery *query = NULL;
3581                 gint byte_in_rate = 0, byte_out_rate = 0;
3582                 gint64 estimated_total = 0;
3583
3584                 query = gst_query_new_buffering(GST_FORMAT_BYTES);
3585                 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
3586                         LOGW("fail to get buffering query from queue2");
3587                         if (query)
3588                                 gst_query_unref(query);
3589                         return MM_ERROR_NONE;
3590                 }
3591
3592                 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
3593                 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
3594
3595                 if (mode == GST_BUFFERING_STREAM) {
3596                         /* using only queue in case of push mode(ts / mp3) */
3597                         if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
3598                                 GST_FORMAT_BYTES, &buffered_total)) {
3599                                 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
3600                                 end_per = 100 * buffered_total / content_size_bytes;
3601                         }
3602                 } else {
3603                         /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
3604                         guint idx = 0;
3605                         guint num_of_ranges = 0;
3606                         gint64 start_byte = 0, stop_byte = 0;
3607
3608                         gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
3609                         if (estimated_total != STREAMING_IS_FINISHED) {
3610                                 /* buffered size info from queue2 */
3611                                 num_of_ranges = gst_query_get_n_buffering_ranges(query);
3612                                 for (idx = 0; idx < num_of_ranges; idx++) {
3613                                         gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
3614                                         LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
3615
3616                                         buffered_total += (stop_byte - start_byte);
3617                                 }
3618                         } else {
3619                                 end_per = BUFFERING_MAX_PER;
3620                         }
3621                 }
3622                 gst_query_unref(query);
3623         }
3624
3625         if (end_per == DEFAULT_PER_VALUE) {
3626                 guint dur_sec = (guint)(content_size_time/GST_SECOND);
3627                 if (dur_sec > 0) {
3628                         guint avg_byterate = (guint)(content_size_bytes / dur_sec);
3629
3630                         /* buffered size info from multiqueue */
3631                         if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
3632                                 guint curr_size_bytes = 0;
3633                                 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
3634                                         "curr-size-bytes", &curr_size_bytes, NULL);
3635                                 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
3636                                 buffered_total += curr_size_bytes;
3637                         }
3638
3639                         if (avg_byterate > 0)
3640                                 buffered_sec = (gint)(ceil((gdouble)buffered_total / (gdouble)avg_byterate));
3641                         else if (player->total_maximum_bitrate > 0)
3642                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_maximum_bitrate));
3643                         else if (player->total_bitrate > 0)
3644                                 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total) / (gdouble)player->total_bitrate));
3645
3646                         if (buffered_sec >= 0)
3647                                 end_per = start_per + (gint)(ceil)(100 * (gdouble)buffered_sec / (gdouble)dur_sec);
3648                 }
3649         }
3650
3651         *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
3652         *end_pos = CHECK_PERCENT_VALUE(end_per, *start_pos, 100);
3653
3654         LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %d~%d",
3655                 buffered_total, buffered_sec, *start_pos, *end_pos);
3656
3657         return MM_ERROR_NONE;
3658 }
3659
3660 GstElement *
3661 _mmplayer_gst_create_source(mmplayer_t *player)
3662 {
3663         GstElement *element = NULL;
3664
3665         MMPLAYER_FENTER();
3666         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3667                                 player->pipeline->mainbin, NULL);
3668
3669         /* setup source for gapless play */
3670         switch (player->profile.uri_type) {
3671         /* file source */
3672         case MM_PLAYER_URI_TYPE_FILE:
3673                 element = __mmplayer_gst_make_file_src(player);
3674                 break;
3675         case MM_PLAYER_URI_TYPE_URL_HTTP:
3676                 element = __mmplayer_gst_make_http_src(player);
3677                 break;
3678         default:
3679                 LOGE("not support uri type %d", player->profile.uri_type);
3680                 break;
3681         }
3682
3683         if (!element) {
3684                 LOGE("failed to create source element");
3685                 return NULL;
3686         }
3687
3688         MMPLAYER_FLEAVE();
3689         return element;
3690 }
3691
3692 int
3693 _mmplayer_gst_build_es_pipeline(mmplayer_t *player)
3694 {
3695         MMPLAYER_FENTER();
3696         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3697                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3698
3699         SECURE_LOGD("uri : %s", player->profile.uri);
3700
3701         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
3702
3703         if ((player->v_stream_caps) &&
3704                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)))
3705                 return MM_ERROR_PLAYER_INTERNAL;
3706
3707         if ((player->a_stream_caps) &&
3708                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)))
3709                 return MM_ERROR_PLAYER_INTERNAL;
3710
3711         if ((player->s_stream_caps) &&
3712                 !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)))
3713                 return MM_ERROR_PLAYER_INTERNAL;
3714
3715         MMPLAYER_FLEAVE();
3716         return MM_ERROR_NONE;
3717 }
3718
3719 int
3720 _mmplayer_gst_build_pipeline(mmplayer_t *player)
3721 {
3722         mmplayer_gst_element_t *mainbin = NULL;
3723         GstElement *src_elem = NULL;
3724         GstElement *autoplug_elem = NULL;
3725         GList *element_bucket = NULL;
3726         main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM;
3727
3728         MMPLAYER_FENTER();
3729         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3730                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3731
3732         LOGD("uri type %d", player->profile.uri_type);
3733
3734         /* create source element */
3735         switch (player->profile.uri_type) {
3736         case MM_PLAYER_URI_TYPE_URL_RTSP:
3737                 src_elem = __mmplayer_gst_make_rtsp_src(player);
3738                 break;
3739         case MM_PLAYER_URI_TYPE_URL_HTTP:
3740                 src_elem = __mmplayer_gst_make_http_src(player);
3741                 break;
3742         case MM_PLAYER_URI_TYPE_FILE:
3743                 src_elem = __mmplayer_gst_make_file_src(player);
3744                 break;
3745         case MM_PLAYER_URI_TYPE_SS:
3746                 {
3747                         gint http_timeout = DEFAULT_HTTP_TIMEOUT;
3748                         src_elem = gst_element_factory_make("souphttpsrc", "http streaming source");
3749                         if (!src_elem) {
3750                                 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
3751                                 break;
3752                         }
3753
3754                         if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
3755                                 LOGD("get timeout from ini");
3756                                 http_timeout = player->ini.http_timeout;
3757                         }
3758
3759                         /* setting property to streaming source */
3760                         g_object_set(G_OBJECT(src_elem), "location", player->profile.uri, "timeout", http_timeout, NULL);
3761                 }
3762                 break;
3763         case MM_PLAYER_URI_TYPE_MEM:
3764                 {
3765                         GstAppStreamType stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
3766
3767                         src_elem = gst_element_factory_make("appsrc", "mem-source");
3768                         if (!src_elem) {
3769                                 LOGE("failed to create appsrc element");
3770                                 break;
3771                         }
3772
3773                         g_object_set(src_elem, "stream-type", stream_type,
3774                                 "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL);
3775
3776                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
3777                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem);
3778                         _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
3779                                                                                         G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem);
3780                 }
3781                 break;
3782         default:
3783                 LOGE("not support uri type");
3784                 break;
3785         }
3786
3787         if (!src_elem) {
3788                 LOGE("failed to create source element");
3789                 return MM_ERROR_PLAYER_INTERNAL;
3790         }
3791
3792         mainbin = player->pipeline->mainbin;
3793
3794         /* take source element */
3795         LOGD("source elem is created %s", GST_ELEMENT_NAME(src_elem));
3796
3797         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3798         mainbin[MMPLAYER_M_SRC].gst = src_elem;
3799         element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
3800
3801         /* create next element for auto-plugging */
3802         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
3803                 autoplug_elem_id = MMPLAYER_M_TYPEFIND;
3804                 autoplug_elem = gst_element_factory_make("typefind", "typefinder");
3805                 if (!autoplug_elem) {
3806                         LOGE("failed to create typefind element");
3807                         goto ERROR;
3808                 }
3809
3810                 _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
3811                                                                         G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
3812         } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
3813                 autoplug_elem_id = MMPLAYER_M_AUTOPLUG;
3814                 autoplug_elem = _mmplayer_gst_make_decodebin(player);
3815                 if (!autoplug_elem) {
3816                         LOGE("failed to create decodebin");
3817                         goto ERROR;
3818                 }
3819
3820                 /* default size of mq in decodebin is 2M
3821                  * but it can cause blocking issue during seeking depends on content. */
3822                 g_object_set(G_OBJECT(autoplug_elem), "max-size-bytes", (5 * 1024 * 1024), NULL);
3823         }
3824
3825         if (autoplug_elem) {
3826                 LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem));
3827                 mainbin[autoplug_elem_id].id = autoplug_elem_id;
3828                 mainbin[autoplug_elem_id].gst = autoplug_elem;
3829
3830                 element_bucket = g_list_append(element_bucket, &mainbin[autoplug_elem_id]);
3831         }
3832
3833         /* add elements to pipeline */
3834         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
3835                 LOGE("failed to add elements to pipeline");
3836                 goto ERROR;
3837         }
3838
3839         /* linking elements in the bucket by added order. */
3840         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3841                 LOGE("failed to link some elements");
3842                 goto ERROR;
3843         }
3844
3845         /* FIXME: need to check whether this is required or not. */
3846         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) ||
3847                 (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) {
3848                 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
3849                 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
3850                 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
3851
3852                 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
3853                         LOGE("failed to create fakesink");
3854                         goto ERROR;
3855                 }
3856                 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
3857
3858                 /* take ownership of fakesink. we are reusing it */
3859                 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3860
3861                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
3862                         LOGE("failed to add fakesink to bin");
3863                         gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
3864                         goto ERROR;
3865                 }
3866         }
3867
3868         g_list_free(element_bucket);
3869
3870         MMPLAYER_FLEAVE();
3871         return MM_ERROR_NONE;
3872
3873 ERROR:
3874         g_list_free(element_bucket);
3875
3876         if (mainbin[MMPLAYER_M_SRC].gst)
3877                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC].gst));
3878
3879         if (mainbin[autoplug_elem_id].gst)
3880                 gst_object_unref(GST_OBJECT(mainbin[autoplug_elem_id].gst));
3881
3882         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
3883                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
3884
3885         mainbin[MMPLAYER_M_SRC].gst = NULL;
3886         mainbin[autoplug_elem_id].gst = NULL;
3887         mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL;
3888
3889         return MM_ERROR_PLAYER_INTERNAL;
3890 }
3891
3892 int
3893 _mmplayer_gst_add_bus_watch(mmplayer_t *player)
3894 {
3895         GstBus  *bus = NULL;
3896         mmplayer_gst_element_t *mainbin = NULL;
3897
3898         MMPLAYER_FENTER();
3899         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3900                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3901
3902         mainbin = player->pipeline->mainbin;
3903
3904         /* connect bus callback */
3905         bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
3906         if (!bus) {
3907                 LOGE("cannot get bus from pipeline");
3908                 return MM_ERROR_PLAYER_INTERNAL;
3909         }
3910
3911         player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
3912         player->context.thread_default = g_main_context_get_thread_default();
3913         if (player->context.thread_default == NULL) {
3914                 player->context.thread_default = g_main_context_default();
3915                 LOGD("thread-default context is the global default context");
3916         }
3917         LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
3918
3919         /* set sync handler to get tag synchronously */
3920         gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
3921         gst_object_unref(GST_OBJECT(bus));
3922
3923         /* create gst bus_msb_cb thread */
3924         g_mutex_init(&player->bus_msg_thread_mutex);
3925         g_cond_init(&player->bus_msg_thread_cond);
3926         player->bus_msg_thread_exit = FALSE;
3927         player->bus_msg_thread =
3928                 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
3929         if (!player->bus_msg_thread) {
3930                 LOGE("failed to create gst BUS msg thread");
3931                 g_mutex_clear(&player->bus_msg_thread_mutex);
3932                 g_cond_clear(&player->bus_msg_thread_cond);
3933                 return MM_ERROR_PLAYER_INTERNAL;
3934         }
3935
3936         MMPLAYER_FLEAVE();
3937         return MM_ERROR_NONE;
3938 }
3939
3940 void
3941 _mmplayer_activate_next_source(mmplayer_t *player, GstState target)
3942 {
3943         mmplayer_gst_element_t *mainbin = NULL;
3944         MMMessageParamType msg_param = {0,};
3945         GstElement *element = NULL;
3946         MMHandleType attrs = 0;
3947         char *uri = NULL;
3948         main_element_id_e elem_idx = MMPLAYER_M_NUM;
3949
3950         MMPLAYER_FENTER();
3951
3952         if (!player || !player->pipeline || !player->pipeline->mainbin) {
3953                 LOGE("player is not initialized");
3954                 goto ERROR;
3955         }
3956
3957         mainbin = player->pipeline->mainbin;
3958         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
3959
3960         attrs = MMPLAYER_GET_ATTRS(player);
3961         if (!attrs) {
3962                 LOGE("fail to get attributes");
3963                 goto ERROR;
3964         }
3965
3966         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
3967
3968         if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
3969                 LOGE("failed to parse profile");
3970                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
3971                 goto ERROR;
3972         }
3973
3974         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
3975                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
3976                 LOGE("dash or hls is not supportable");
3977                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
3978                 goto ERROR;
3979         }
3980
3981         element = _mmplayer_gst_create_source(player);
3982         if (!element) {
3983                 LOGE("no source element was created");
3984                 goto ERROR;
3985         }
3986
3987         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
3988                 LOGE("failed to add source element to pipeline");
3989                 gst_object_unref(GST_OBJECT(element));
3990                 element = NULL;
3991                 goto ERROR;
3992         }
3993
3994         /* take source element */
3995         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
3996         mainbin[MMPLAYER_M_SRC].gst = element;
3997
3998         element = NULL;
3999
4000         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
4001                 if (player->streamer == NULL) {
4002                         player->streamer = _mm_player_streaming_create();
4003                         _mm_player_streaming_initialize(player->streamer, TRUE);
4004                 }
4005
4006                 elem_idx = MMPLAYER_M_TYPEFIND;
4007                 element = gst_element_factory_make("typefind", "typefinder");
4008                 _mmplayer_add_signal_connection(player, G_OBJECT(element),
4009                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player);
4010         } else {
4011                 elem_idx = MMPLAYER_M_AUTOPLUG;
4012                 element = _mmplayer_gst_make_decodebin(player);
4013         }
4014
4015         /* check autoplug element is OK */
4016         if (!element) {
4017                 LOGE("can not create element(%d)", elem_idx);
4018                 goto ERROR;
4019         }
4020
4021         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
4022                 LOGE("failed to add sinkbin to pipeline");
4023                 gst_object_unref(GST_OBJECT(element));
4024                 element = NULL;
4025                 goto ERROR;
4026         }
4027
4028         mainbin[elem_idx].id = elem_idx;
4029         mainbin[elem_idx].gst = element;
4030
4031         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
4032                 LOGE("Failed to link src - autoplug(or typefind)");
4033                 goto ERROR;
4034         }
4035
4036         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
4037                 LOGE("Failed to change state of src element");
4038                 goto ERROR;
4039         }
4040
4041         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
4042                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
4043                         LOGE("Failed to change state of decodebin");
4044                         goto ERROR;
4045                 }
4046         } else {
4047                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
4048                         LOGE("Failed to change state of src element");
4049                         goto ERROR;
4050                 }
4051         }
4052
4053         player->gapless.stream_changed = TRUE;
4054         player->gapless.running = TRUE;
4055         MMPLAYER_FLEAVE();
4056         return;
4057
4058 ERROR:
4059         if (player) {
4060                 _mmplayer_set_reconfigure_state(player, FALSE);
4061                 if (!player->msg_posted) {
4062                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4063                         player->msg_posted = TRUE;
4064                 }
4065         }
4066         return;
4067 }