942ac89a38d688a0c8f2212a44cfb864b314ef55
[platform/core/multimedia/libmm-player.git] / src / mm_player_common_priv.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 <mm_attrs_private.h>
31
32 #include "mm_player_priv.h"
33 #include "mm_player_attrs.h"
34 #include "mm_player_utils.h"
35
36 /*===========================================================================================
37 |                                                                                                                                                                                       |
38 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
39 |                                                                                                                                                                                       |
40 ========================================================================================== */
41
42 /*---------------------------------------------------------------------------
43 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
44 ---------------------------------------------------------------------------*/
45
46 /*---------------------------------------------------------------------------
47 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
48 ---------------------------------------------------------------------------*/
49
50 /*---------------------------------------------------------------------------
51 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
52 ---------------------------------------------------------------------------*/
53
54 /*---------------------------------------------------------------------------
55 |    LOCAL #defines:                                                                                                            |
56 ---------------------------------------------------------------------------*/
57
58 /*---------------------------------------------------------------------------
59 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
60 ---------------------------------------------------------------------------*/
61
62 /*---------------------------------------------------------------------------
63 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
64 ---------------------------------------------------------------------------*/
65
66 /*---------------------------------------------------------------------------
67 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
68 ---------------------------------------------------------------------------*/
69
70 /*---------------------------------------------------------------------------
71 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
72 ---------------------------------------------------------------------------*/
73
74 /*---------------------------------------------------------------------------
75 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
76 ---------------------------------------------------------------------------*/
77 static gint __gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error);
78
79 /*===========================================================================================
80 |                                                                                                                                                                                       |
81 |  FUNCTION DEFINITIONS                                                                                                                                         |
82 |                                                                                                                                                                                       |
83 ========================================================================================== */
84 int
85 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
86 {
87         MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
88         MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
89
90         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
91
92         //LOGD("incomming command : %d \n", command);
93
94         current_state = MMPLAYER_CURRENT_STATE(player);
95         pending_state = MMPLAYER_PENDING_STATE(player);
96
97         MMPLAYER_PRINT_STATE(player);
98
99         switch (command) {
100         case MMPLAYER_COMMAND_CREATE:
101         {
102                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
103
104                 if (current_state == MM_PLAYER_STATE_NULL ||
105                         current_state == MM_PLAYER_STATE_READY ||
106                         current_state == MM_PLAYER_STATE_PAUSED ||
107                         current_state == MM_PLAYER_STATE_PLAYING)
108                         goto NO_OP;
109         }
110         break;
111
112         case MMPLAYER_COMMAND_DESTROY:
113         {
114                 /* destroy can called anytime */
115
116                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
117         }
118         break;
119
120         case MMPLAYER_COMMAND_REALIZE:
121         {
122                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
123
124                 if (pending_state != MM_PLAYER_STATE_NONE) {
125                         goto INVALID_STATE;
126                 } else {
127                         /* need ready state to realize */
128                         if (current_state == MM_PLAYER_STATE_READY)
129                                 goto NO_OP;
130
131                         if (current_state != MM_PLAYER_STATE_NULL)
132                                 goto INVALID_STATE;
133                 }
134         }
135         break;
136
137         case MMPLAYER_COMMAND_UNREALIZE:
138         {
139                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
140
141                 if (current_state == MM_PLAYER_STATE_NULL)
142                         goto NO_OP;
143         }
144         break;
145
146         case MMPLAYER_COMMAND_START:
147         {
148                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
149
150                 if (pending_state == MM_PLAYER_STATE_NONE) {
151                         if (current_state == MM_PLAYER_STATE_PLAYING)
152                                 goto NO_OP;
153                         else if (current_state  != MM_PLAYER_STATE_READY &&
154                                 current_state != MM_PLAYER_STATE_PAUSED)
155                                 goto INVALID_STATE;
156                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
157                         goto ALREADY_GOING;
158                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
159                         LOGD("player is going to paused state, just change the pending state as playing");
160                 } else
161                         goto INVALID_STATE;
162         }
163         break;
164
165         case MMPLAYER_COMMAND_STOP:
166         {
167                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
168
169                 if (current_state == MM_PLAYER_STATE_READY)
170                         goto NO_OP;
171
172                 /* need playing/paused state to stop */
173                 if (current_state != MM_PLAYER_STATE_PLAYING &&
174                          current_state != MM_PLAYER_STATE_PAUSED)
175                         goto INVALID_STATE;
176         }
177         break;
178
179         case MMPLAYER_COMMAND_PAUSE:
180         {
181                 if (MMPLAYER_IS_LIVE_STREAMING(player))
182                         goto NO_OP;
183
184                 if (player->doing_seek)
185                         goto NOT_COMPLETED_SEEK;
186
187                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
188
189                 if (pending_state == MM_PLAYER_STATE_NONE) {
190                         if (current_state == MM_PLAYER_STATE_PAUSED)
191                                 goto NO_OP;
192                         else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
193                                 goto INVALID_STATE;
194                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
195                         goto ALREADY_GOING;
196                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
197                         if (current_state == MM_PLAYER_STATE_PAUSED)
198                                 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
199                         else
200                                 goto INVALID_STATE;
201                 }
202         }
203         break;
204
205         case MMPLAYER_COMMAND_RESUME:
206         {
207
208                 if (player->doing_seek)
209                         goto NOT_COMPLETED_SEEK;
210
211                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
212
213                 if (pending_state == MM_PLAYER_STATE_NONE) {
214                         if (current_state == MM_PLAYER_STATE_PLAYING)
215                                 goto NO_OP;
216                         else if (current_state != MM_PLAYER_STATE_PAUSED)
217                                 goto INVALID_STATE;
218                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
219                         goto ALREADY_GOING;
220                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
221                         LOGD("player is going to paused state, just change the pending state as playing");
222                 } else
223                         goto INVALID_STATE;
224         }
225                 break;
226
227         default:
228                 break;
229         }
230         player->cmd = command;
231
232         return MM_ERROR_NONE;
233
234 INVALID_STATE:
235         LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
236                 MMPLAYER_STATE_GET_NAME(current_state), command);
237         return MM_ERROR_PLAYER_INVALID_STATE;
238
239 NOT_COMPLETED_SEEK:
240         LOGW("not completed seek");
241         return MM_ERROR_PLAYER_DOING_SEEK;
242
243 NO_OP:
244         LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
245         return MM_ERROR_PLAYER_NO_OP;
246
247 ALREADY_GOING:
248         LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
249         return MM_ERROR_PLAYER_NO_OP;
250 }
251
252 int
253 __mmplayer_gst_set_state(mm_player_t* player, GstElement * element,  GstState state, gboolean async, gint timeout)
254 {
255         GstState element_state = GST_STATE_VOID_PENDING;
256         GstState element_pending_state = GST_STATE_VOID_PENDING;
257         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
258
259         MMPLAYER_FENTER();
260
261         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
262         MMPLAYER_RETURN_VAL_IF_FAIL(element, MM_ERROR_INVALID_ARGUMENT);
263
264         LOGD("setting [%s] element state to : %s\n", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
265
266         /* set state */
267         ret = gst_element_set_state(element, state);
268
269         if (ret == GST_STATE_CHANGE_FAILURE) {
270                 LOGE("failed to set [%s] state\n", GST_ELEMENT_NAME(element));
271
272                 /* dump state of all element */
273                 __mmplayer_dump_pipeline_state(player);
274
275                 return MM_ERROR_PLAYER_INTERNAL;
276         }
277
278         /* return here so state transition to be done in async mode */
279         if (async) {
280                 LOGD("async state transition. not waiting for state complete.\n");
281                 return MM_ERROR_NONE;
282         }
283
284         /* wait for state transition */
285         ret = gst_element_get_state(element, &element_state, &element_pending_state, timeout * GST_SECOND);
286
287         if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) {
288                 LOGE("failed to change [%s] element state to [%s] within %d sec\n",
289                         GST_ELEMENT_NAME(element),
290                         gst_element_state_get_name(state), timeout);
291
292                 LOGE(" [%s] state : %s   pending : %s \n",
293                         GST_ELEMENT_NAME(element),
294                         gst_element_state_get_name(element_state),
295                         gst_element_state_get_name(element_pending_state));
296
297                 /* dump state of all element */
298                 __mmplayer_dump_pipeline_state(player);
299
300                 return MM_ERROR_PLAYER_INTERNAL;
301         }
302
303         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
304
305         MMPLAYER_FLEAVE();
306
307         return MM_ERROR_NONE;
308 }
309
310 void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
311 {
312         GSource *source = NULL;
313
314         MMPLAYER_FENTER();
315
316         source = g_main_context_find_source_by_id(context, source_id);
317
318         if (source != NULL) {
319                 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
320                 g_source_destroy(source);
321         }
322
323         MMPLAYER_FLEAVE();
324 }
325
326 gboolean
327 __mmplayer_dump_pipeline_state(mm_player_t* player)
328 {
329         GstIterator*iter = NULL;
330         gboolean done = FALSE;
331
332         GValue item = {0, };
333         GstElement *element = NULL;
334         GstElementFactory *factory = NULL;
335
336         GstState state = GST_STATE_VOID_PENDING;
337         GstState pending = GST_STATE_VOID_PENDING;
338         GstClockTime time = 200*GST_MSECOND;
339
340         MMPLAYER_FENTER();
341
342         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
343                 player->pipeline &&
344                 player->pipeline->mainbin,
345                 FALSE);
346
347         iter = gst_bin_iterate_recurse(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
348
349         if (iter != NULL) {
350                 while (!done) {
351                         switch (gst_iterator_next(iter, &item)) {
352                         case GST_ITERATOR_OK:
353                                 element = g_value_get_object(&item);
354                                 gst_element_get_state(element, &state, &pending, time);
355
356                                 factory = gst_element_get_factory(element) ;
357                                 if (factory)
358                                         LOGE("%s:%s : From:%s To:%s   refcount : %d\n", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(element) ,
359                                                 gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(element));
360                                 g_value_reset(&item);
361                                 break;
362                         case GST_ITERATOR_RESYNC:
363                                 gst_iterator_resync(iter);
364                                 break;
365                         case GST_ITERATOR_ERROR:
366                                 done = TRUE;
367                                 break;
368                         case GST_ITERATOR_DONE:
369                                 done = TRUE;
370                                 break;
371                         }
372                 }
373         }
374
375         element = GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
376
377         gst_element_get_state(element, &state, &pending, time);
378
379         factory = gst_element_get_factory(element) ;
380
381         if (factory) {
382                 LOGE("%s:%s : From:%s To:%s  refcount : %d\n",
383                         GST_OBJECT_NAME(factory),
384                         GST_ELEMENT_NAME(element),
385                         gst_element_state_get_name(state),
386                         gst_element_state_get_name(pending),
387                         GST_OBJECT_REFCOUNT_VALUE(element));
388         }
389
390         g_value_unset(&item);
391
392         if (iter)
393                 gst_iterator_free(iter);
394
395         MMPLAYER_FLEAVE();
396
397         return FALSE;
398 }
399
400 const gchar *
401 __get_state_name(int state)
402 {
403         switch (state) {
404         case MM_PLAYER_STATE_NULL:
405                 return "NULL";
406         case MM_PLAYER_STATE_READY:
407                 return "READY";
408         case MM_PLAYER_STATE_PAUSED:
409                 return "PAUSED";
410         case MM_PLAYER_STATE_PLAYING:
411                 return "PLAYING";
412         case MM_PLAYER_STATE_NONE:
413                 return "NONE";
414         default:
415                 return "INVAID";
416         }
417 }
418
419 gboolean
420 __is_rtsp_streaming(mm_player_t* player)
421 {
422         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
423
424         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_RTSP) ? TRUE : FALSE;
425 }
426
427 gboolean
428 __is_http_streaming(mm_player_t* player)
429 {
430         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
431
432         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_HTTP) ? TRUE : FALSE;
433 }
434
435 gboolean
436 __is_streaming(mm_player_t* player)
437 {
438         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
439
440         return (__is_http_progressive_down(player) || __is_rtsp_streaming(player) || __is_http_streaming(player)
441                 || __is_http_live_streaming(player) || __is_dash_streaming(player) || __is_smooth_streaming(player)) ? TRUE : FALSE;
442 }
443
444 gboolean
445 __is_live_streaming(mm_player_t* player)
446 {
447         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
448
449         return (__is_rtsp_streaming(player) && player->streaming_type == STREAMING_SERVICE_LIVE) ? TRUE : FALSE;
450 }
451
452 gboolean
453 __is_http_live_streaming(mm_player_t* player)
454 {
455         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
456
457         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_HLS) ? TRUE : FALSE;
458 }
459
460 gboolean
461 __is_dash_streaming(mm_player_t* player)
462 {
463         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
464
465         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_DASH) ? TRUE : FALSE;
466 }
467
468 gboolean
469 __is_smooth_streaming(mm_player_t* player)
470 {
471         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
472
473         return (player->profile.uri_type == MM_PLAYER_URI_TYPE_SS) ? TRUE : FALSE;
474 }
475
476
477 gboolean
478 __is_http_progressive_down(mm_player_t* player)
479 {
480         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
481
482         return ((player->pd_mode) ? TRUE : FALSE);
483 }
484
485 /* if retval is FALSE, it will be dropped for perfomance. */
486 gboolean
487 __mmplayer_check_useful_message(mm_player_t *player, GstMessage * message)
488 {
489         gboolean retval = FALSE;
490
491         if (!(player->pipeline && player->pipeline->mainbin)) {
492                 LOGE("player pipeline handle is null");
493                 return TRUE;
494         }
495
496         switch (GST_MESSAGE_TYPE(message)) {
497         case GST_MESSAGE_TAG:
498         case GST_MESSAGE_EOS:
499         case GST_MESSAGE_ERROR:
500         case GST_MESSAGE_WARNING:
501         case GST_MESSAGE_CLOCK_LOST:
502         case GST_MESSAGE_NEW_CLOCK:
503         case GST_MESSAGE_ELEMENT:
504         case GST_MESSAGE_DURATION_CHANGED:
505         case GST_MESSAGE_ASYNC_START:
506                 retval = TRUE;
507                 break;
508         case GST_MESSAGE_ASYNC_DONE:
509         case GST_MESSAGE_STATE_CHANGED:
510                 /* we only handle messages from pipeline */
511                 if ((message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst) && (!player->gapless.reconfigure))
512                         retval = TRUE;
513                 else
514                         retval = FALSE;
515                 break;
516         case GST_MESSAGE_BUFFERING:
517         {
518                 gint buffer_percent = 0;
519
520                 retval = TRUE;
521                 gst_message_parse_buffering(message, &buffer_percent);
522                 if (buffer_percent != MAX_BUFFER_PERCENT) {
523                         LOGD("[%s] buffering msg %d%%!!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), buffer_percent);
524                         break;
525                 }
526
527                 if (!MMPLAYER_CMD_TRYLOCK(player)) {
528                         LOGW("can't get cmd lock, send msg to bus");
529                         break;
530                 }
531
532                 if ((player->streamer) && (player->streamer->is_buffering == TRUE)) {
533                         LOGD("[%s] Buffering DONE is detected !!\n", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
534                         player->streamer->is_buffering_done = TRUE;
535                 }
536
537                 MMPLAYER_CMD_UNLOCK(player);
538
539                 break;
540         }
541         default:
542                 retval = FALSE;
543                 break;
544         }
545
546         return retval;
547 }
548
549 gboolean
550 __mmplayer_post_message(mm_player_t* player, enum MMMessageType msgtype, MMMessageParamType* param)
551 {
552         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
553
554         if (!player->msg_cb)
555                 return FALSE;
556
557         //LOGD("Message (type : %d)  will be posted using msg-cb(%p). \n", msgtype, player->msg_cb);
558
559         player->msg_cb(msgtype, param, player->msg_cb_param);
560
561         return TRUE;
562 }
563
564 gboolean
565 __mmplayer_handle_gst_error(mm_player_t* player, GstMessage * message, GError* error)
566 {
567         MMMessageParamType msg_param;
568         gchar *msg_src_element;
569
570         MMPLAYER_FENTER();
571
572         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
573         MMPLAYER_RETURN_VAL_IF_FAIL(error, FALSE);
574
575         /* NOTE : do somthing necessary inside of __gst_handle_XXX_error. not here */
576
577         memset(&msg_param, 0, sizeof(MMMessageParamType));
578
579         if (error->domain == GST_CORE_ERROR) {
580                 msg_param.code = __gst_handle_core_error(player, error->code);
581         } else if (error->domain == GST_LIBRARY_ERROR) {
582                 msg_param.code = __gst_handle_library_error(player, error->code);
583         } else if (error->domain == GST_RESOURCE_ERROR) {
584                 msg_param.code = __gst_handle_resource_error(player, error->code, message);
585         } else if (error->domain == GST_STREAM_ERROR) {
586                 msg_param.code = __gst_handle_stream_error(player, error, message);
587         } else {
588                 LOGW("This error domain is not defined.\n");
589
590                 /* we treat system error as an internal error */
591                 msg_param.code = MM_ERROR_PLAYER_INVALID_STREAM;
592         }
593
594         if (message->src) {
595                 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
596
597                 msg_param.data = (void *) error->message;
598
599                 LOGE("-Msg src : [%s]   Domain : [%s]   Error : [%s]  Code : [%d] is tranlated to error code : [0x%x]\n",
600                         msg_src_element, g_quark_to_string(error->domain), error->message, error->code, msg_param.code);
601         }
602
603         /* no error */
604         if (msg_param.code == MM_ERROR_NONE)
605                 return TRUE;
606
607         /* skip error to avoid duplicated posting */
608         if ((player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED) ||
609                 (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED)) {
610
611                 /* The error will be handled by mused.
612                  * @ref _mmplayer_manage_external_storage_state() */
613
614                 LOGW("storage is removed, skip error post");
615                 return TRUE;
616         }
617
618         /* post error to application */
619         if (!player->msg_posted) {
620                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
621                 /* don't post more if one was sent already */
622                 player->msg_posted = TRUE;
623         } else
624                 LOGD("skip error post because it's sent already.\n");
625
626         MMPLAYER_FLEAVE();
627
628         return TRUE;
629 }
630
631 gint
632 __gst_handle_core_error(mm_player_t* player, int code)
633 {
634         gint trans_err = MM_ERROR_NONE;
635
636         MMPLAYER_FENTER();
637
638         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
639
640         switch (code) {
641         case GST_CORE_ERROR_MISSING_PLUGIN:
642                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
643         case GST_CORE_ERROR_STATE_CHANGE:
644         case GST_CORE_ERROR_SEEK:
645         case GST_CORE_ERROR_NOT_IMPLEMENTED:
646         case GST_CORE_ERROR_FAILED:
647         case GST_CORE_ERROR_TOO_LAZY:
648         case GST_CORE_ERROR_PAD:
649         case GST_CORE_ERROR_THREAD:
650         case GST_CORE_ERROR_NEGOTIATION:
651         case GST_CORE_ERROR_EVENT:
652         case GST_CORE_ERROR_CAPS:
653         case GST_CORE_ERROR_TAG:
654         case GST_CORE_ERROR_CLOCK:
655         case GST_CORE_ERROR_DISABLED:
656         default:
657                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
658                 break;
659         }
660
661         MMPLAYER_FLEAVE();
662
663         return trans_err;
664 }
665
666 gint
667 __gst_handle_library_error(mm_player_t* player, int code)
668 {
669         gint trans_err = MM_ERROR_NONE;
670
671         MMPLAYER_FENTER();
672
673         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
674
675         switch (code) {
676         case GST_LIBRARY_ERROR_FAILED:
677         case GST_LIBRARY_ERROR_TOO_LAZY:
678         case GST_LIBRARY_ERROR_INIT:
679         case GST_LIBRARY_ERROR_SHUTDOWN:
680         case GST_LIBRARY_ERROR_SETTINGS:
681         case GST_LIBRARY_ERROR_ENCODE:
682         default:
683                 trans_err =  MM_ERROR_PLAYER_INVALID_STREAM;
684                 break;
685         }
686
687         MMPLAYER_FLEAVE();
688
689         return trans_err;
690 }
691
692 gint
693 __gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
694 {
695         gint trans_err = MM_ERROR_NONE;
696
697         MMPLAYER_FENTER();
698
699         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
700
701         switch (code) {
702         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
703                 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
704                 break;
705         case GST_RESOURCE_ERROR_NOT_FOUND:
706         case GST_RESOURCE_ERROR_OPEN_READ:
707                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
708                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
709                         trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
710                         break;
711                 }
712         case GST_RESOURCE_ERROR_READ:
713                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
714                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
715                         trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
716                         break;
717                 } else if (message != NULL && message->src != NULL) {
718                         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
719                         MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
720
721                         if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
722                                 path_type = MMPLAYER_PATH_VOD;
723                         else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
724                                 path_type = MMPLAYER_PATH_TEXT;
725
726                         if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
727                                 /* check storage state */
728                                 storage_get_state(player->storage_info[path_type].id, &storage_state);
729                                 player->storage_info[path_type].state = storage_state;
730                                 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
731                         }
732                 } /* fall through */
733         case GST_RESOURCE_ERROR_WRITE:
734         case GST_RESOURCE_ERROR_FAILED:
735         case GST_RESOURCE_ERROR_SEEK:
736         case GST_RESOURCE_ERROR_TOO_LAZY:
737         case GST_RESOURCE_ERROR_BUSY:
738         case GST_RESOURCE_ERROR_OPEN_WRITE:
739         case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
740         case GST_RESOURCE_ERROR_CLOSE:
741         case GST_RESOURCE_ERROR_SYNC:
742         case GST_RESOURCE_ERROR_SETTINGS:
743         default:
744                 trans_err = MM_ERROR_PLAYER_INTERNAL;
745         break;
746         }
747
748         MMPLAYER_FLEAVE();
749
750         return trans_err;
751 }
752
753 gint
754 __gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
755 {
756         gint trans_err = MM_ERROR_NONE;
757
758         MMPLAYER_FENTER();
759
760         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
761         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
762         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
763
764         switch (error->code) {
765         case GST_STREAM_ERROR_FAILED:
766         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
767         case GST_STREAM_ERROR_DECODE:
768         case GST_STREAM_ERROR_WRONG_TYPE:
769         case GST_STREAM_ERROR_DECRYPT:
770         case GST_STREAM_ERROR_DECRYPT_NOKEY:
771         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
772                 trans_err = __gst_transform_gsterror(player, message, error);
773                 break;
774
775         case GST_STREAM_ERROR_NOT_IMPLEMENTED:
776         case GST_STREAM_ERROR_TOO_LAZY:
777         case GST_STREAM_ERROR_ENCODE:
778         case GST_STREAM_ERROR_DEMUX:
779         case GST_STREAM_ERROR_MUX:
780         case GST_STREAM_ERROR_FORMAT:
781         default:
782                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
783                 break;
784         }
785
786         MMPLAYER_FLEAVE();
787
788         return trans_err;
789 }
790
791 /* NOTE : decide gstreamer state whether there is some playable track or not. */
792 static gint
793 __gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
794 {
795         gchar *src_element_name = NULL;
796         GstElement *src_element = NULL;
797         GstElementFactory *factory = NULL;
798         const gchar* klass = NULL;
799
800         MMPLAYER_FENTER();
801
802         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
803         MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
804         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
805         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
806                                                                 player->pipeline &&
807                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
808
809         src_element = GST_ELEMENT_CAST(message->src);
810         if (!src_element)
811                 goto INTERNAL_ERROR;
812
813         src_element_name = GST_ELEMENT_NAME(src_element);
814         if (!src_element_name)
815                 goto INTERNAL_ERROR;
816
817         factory = gst_element_get_factory(src_element);
818         if (!factory)
819                 goto INTERNAL_ERROR;
820
821         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
822         if (!klass)
823                 goto INTERNAL_ERROR;
824
825         LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
826                         error->code, error->message, src_element_name, klass);
827
828         /* check whether the error is posted from not-activated track or not */
829         if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
830                 int msg_src_pos = 0;
831                 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
832                 LOGD("current  active pad index  -%d", active_pad_index);
833
834                 if  (src_element_name) {
835                         int idx = 0;
836
837                         if (player->audio_decoders) {
838                                 GList *adec = player->audio_decoders;
839                                 for (; adec ; adec = g_list_next(adec)) {
840                                         gchar *name = adec->data;
841
842                                         LOGD("found audio decoder name  = %s", name);
843                                         if (g_strrstr(name, src_element_name)) {
844                                                 msg_src_pos = idx;
845                                                 break;
846                                         }
847                                         idx++;
848                                 }
849                         }
850                         LOGD("active pad = %d, error src index = %d", active_pad_index,  msg_src_pos);
851                 }
852
853                 if (active_pad_index != msg_src_pos) {
854                         LOGD("skip error because error is posted from no activated track");
855                         return MM_ERROR_NONE;
856                 }
857         }
858
859         switch (error->code) {
860         case GST_STREAM_ERROR_DECODE:
861         {
862                 /* Demuxer can't parse one track because it's corrupted.
863                  * So, the decoder for it is not linked.
864                  * But, it has one playable track.
865                  */
866                 if (g_strrstr(klass, "Demux")) {
867                         if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
868                                 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
869                         } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
870                                 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
871                         } else {
872                                 if (player->pipeline->audiobin) // PCM
873                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
874                                 else
875                                         goto CODEC_NOT_FOUND;
876                         }
877                 }
878                 return MM_ERROR_PLAYER_INVALID_STREAM;
879         }
880                 break;
881
882         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
883         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
884         case GST_STREAM_ERROR_WRONG_TYPE:
885         {
886                 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
887                         LOGE("Not supported subtitle.");
888                         return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
889                 }
890                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
891         }
892
893         case GST_STREAM_ERROR_FAILED:
894         {
895                 /* Decoder Custom Message */
896                 if (strstr(error->message, "ongoing")) {
897                         if (strncasecmp(klass, "audio", 5)) {
898                                 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
899                                         LOGD("Video can keep playing.\n");
900                                         return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
901                                 } else
902                                         goto CODEC_NOT_FOUND;
903
904                         } else if (strncasecmp(klass, "video", 5)) {
905                                 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
906                                         LOGD("Audio can keep playing.\n");
907                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
908                                 } else
909                                         goto CODEC_NOT_FOUND;
910                         }
911                 }
912                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
913         }
914                 break;
915
916         case GST_STREAM_ERROR_DECRYPT:
917         case GST_STREAM_ERROR_DECRYPT_NOKEY:
918         {
919                 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
920
921                 if (strstr(error->message, "rights expired"))
922                         return MM_ERROR_PLAYER_DRM_EXPIRED;
923                 else if (strstr(error->message, "no rights"))
924                         return MM_ERROR_PLAYER_DRM_NO_LICENSE;
925                 else if (strstr(error->message, "has future rights"))
926                         return MM_ERROR_PLAYER_DRM_FUTURE_USE;
927                 else if (strstr(error->message, "opl violation"))
928                         return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
929                 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
930         }
931                 break;
932
933         default:
934                 break;
935         }
936
937         MMPLAYER_FLEAVE();
938
939         return MM_ERROR_PLAYER_INVALID_STREAM;
940
941 INTERNAL_ERROR:
942         return MM_ERROR_PLAYER_INTERNAL;
943
944 CODEC_NOT_FOUND:
945         LOGD("not found any available codec. Player should be destroyed.\n");
946         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
947 }
948
949 int
950 __mmplayer_get_video_angle(mm_player_t* player, int *user_angle, int *org_angle)
951 {
952         int user_angle_type = 0;
953         gchar *org_orient = NULL;
954         MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
955
956         if (!attrs) {
957                 LOGE("cannot get content attribute");
958                 return MM_ERROR_PLAYER_INTERNAL;
959         }
960
961         /* update user roation */
962         mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
963
964         /* get angle with user type */
965         switch (user_angle_type) {
966         case MM_DISPLAY_ROTATION_NONE:
967                 *user_angle = 0;
968                 break;
969         case MM_DISPLAY_ROTATION_90: /* counter-clockwise 90 */
970                 *user_angle = 270;
971                 break;
972         case MM_DISPLAY_ROTATION_180:
973                 *user_angle = 180;
974                 break;
975         case MM_DISPLAY_ROTATION_270: /* clockwise 90 */
976                 *user_angle = 90;
977                 break;
978         }
979
980         /* get original orientation */
981         mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
982
983         if (org_orient) {
984                 if (!strcmp(org_orient, "rotate-90"))
985                         *org_angle = 90;
986                 else if (!strcmp(org_orient, "rotate-180"))
987                         *org_angle = 180;
988                 else if (!strcmp(org_orient, "rotate-270"))
989                         *org_angle = 270;
990                 else
991                         LOGD("original rotation is %s", org_orient);
992         } else
993                 LOGD("content_video_orientation get fail");
994
995         LOGD("check user angle: %d, orientation: %d", *user_angle, *org_angle);
996
997         return MM_ERROR_NONE;
998 }
999