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