[0.6.81] set the storage state as mounted in case of internal path
[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].type == STORAGE_TYPE_EXTERNAL) &&
609                  (player->storage_info[MMPLAYER_PATH_VOD].state <= STORAGE_STATE_REMOVED)) ||
610                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) &&
611                  (player->storage_info[MMPLAYER_PATH_TEXT].state <= STORAGE_STATE_REMOVED))) {
612
613                 /* The error will be handled by mused.
614                  * @ref _mmplayer_manage_external_storage_state() */
615
616                 LOGW("storage is removed, skip error post");
617                 return TRUE;
618         }
619
620         /* post error to application */
621         if (!player->msg_posted) {
622                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
623                 /* don't post more if one was sent already */
624                 player->msg_posted = TRUE;
625         } else
626                 LOGD("skip error post because it's sent already.\n");
627
628         MMPLAYER_FLEAVE();
629
630         return TRUE;
631 }
632
633 gint
634 __gst_handle_core_error(mm_player_t* player, int code)
635 {
636         gint trans_err = MM_ERROR_NONE;
637
638         MMPLAYER_FENTER();
639
640         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
641
642         switch (code) {
643         case GST_CORE_ERROR_MISSING_PLUGIN:
644                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
645         case GST_CORE_ERROR_STATE_CHANGE:
646         case GST_CORE_ERROR_SEEK:
647         case GST_CORE_ERROR_NOT_IMPLEMENTED:
648         case GST_CORE_ERROR_FAILED:
649         case GST_CORE_ERROR_TOO_LAZY:
650         case GST_CORE_ERROR_PAD:
651         case GST_CORE_ERROR_THREAD:
652         case GST_CORE_ERROR_NEGOTIATION:
653         case GST_CORE_ERROR_EVENT:
654         case GST_CORE_ERROR_CAPS:
655         case GST_CORE_ERROR_TAG:
656         case GST_CORE_ERROR_CLOCK:
657         case GST_CORE_ERROR_DISABLED:
658         default:
659                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
660                 break;
661         }
662
663         MMPLAYER_FLEAVE();
664
665         return trans_err;
666 }
667
668 gint
669 __gst_handle_library_error(mm_player_t* player, int code)
670 {
671         gint trans_err = MM_ERROR_NONE;
672
673         MMPLAYER_FENTER();
674
675         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
676
677         switch (code) {
678         case GST_LIBRARY_ERROR_FAILED:
679         case GST_LIBRARY_ERROR_TOO_LAZY:
680         case GST_LIBRARY_ERROR_INIT:
681         case GST_LIBRARY_ERROR_SHUTDOWN:
682         case GST_LIBRARY_ERROR_SETTINGS:
683         case GST_LIBRARY_ERROR_ENCODE:
684         default:
685                 trans_err =  MM_ERROR_PLAYER_INVALID_STREAM;
686                 break;
687         }
688
689         MMPLAYER_FLEAVE();
690
691         return trans_err;
692 }
693
694 gint
695 __gst_handle_resource_error(mm_player_t* player, int code, GstMessage * message)
696 {
697         gint trans_err = MM_ERROR_NONE;
698
699         MMPLAYER_FENTER();
700
701         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
702
703         switch (code) {
704         case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
705                 trans_err = MM_ERROR_PLAYER_NO_FREE_SPACE;
706                 break;
707         case GST_RESOURCE_ERROR_NOT_FOUND:
708         case GST_RESOURCE_ERROR_OPEN_READ:
709                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
710                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
711                         trans_err = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
712                         break;
713                 }
714         case GST_RESOURCE_ERROR_READ:
715                 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
716                         || MMPLAYER_IS_RTSP_STREAMING(player)) {
717                         trans_err = MM_ERROR_PLAYER_STREAMING_FAIL;
718                         break;
719                 } else if (message != NULL && message->src != NULL) {
720                         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
721                         MMPlayerPathType path_type = MMPLAYER_PATH_MAX;
722
723                         if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)
724                                 path_type = MMPLAYER_PATH_VOD;
725                         else if (message->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SUBSRC].gst)
726                                 path_type = MMPLAYER_PATH_TEXT;
727
728                         if (path_type != MMPLAYER_PATH_MAX && player->storage_info[path_type].type == STORAGE_TYPE_EXTERNAL) {
729                                 /* check storage state */
730                                 storage_get_state(player->storage_info[path_type].id, &storage_state);
731                                 player->storage_info[path_type].state = storage_state;
732                                 LOGW("path %d, storage state %d:%d", path_type, player->storage_info[path_type].id, storage_state);
733                         }
734                 } /* fall through */
735         case GST_RESOURCE_ERROR_WRITE:
736         case GST_RESOURCE_ERROR_FAILED:
737         case GST_RESOURCE_ERROR_SEEK:
738         case GST_RESOURCE_ERROR_TOO_LAZY:
739         case GST_RESOURCE_ERROR_BUSY:
740         case GST_RESOURCE_ERROR_OPEN_WRITE:
741         case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
742         case GST_RESOURCE_ERROR_CLOSE:
743         case GST_RESOURCE_ERROR_SYNC:
744         case GST_RESOURCE_ERROR_SETTINGS:
745         default:
746                 trans_err = MM_ERROR_PLAYER_INTERNAL;
747         break;
748         }
749
750         MMPLAYER_FLEAVE();
751
752         return trans_err;
753 }
754
755 gint
756 __gst_handle_stream_error(mm_player_t* player, GError* error, GstMessage * message)
757 {
758         gint trans_err = MM_ERROR_NONE;
759
760         MMPLAYER_FENTER();
761
762         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
763         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
764         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
765
766         switch (error->code) {
767         case GST_STREAM_ERROR_FAILED:
768         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
769         case GST_STREAM_ERROR_DECODE:
770         case GST_STREAM_ERROR_WRONG_TYPE:
771         case GST_STREAM_ERROR_DECRYPT:
772         case GST_STREAM_ERROR_DECRYPT_NOKEY:
773         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
774                 trans_err = __gst_transform_gsterror(player, message, error);
775                 break;
776
777         case GST_STREAM_ERROR_NOT_IMPLEMENTED:
778         case GST_STREAM_ERROR_TOO_LAZY:
779         case GST_STREAM_ERROR_ENCODE:
780         case GST_STREAM_ERROR_DEMUX:
781         case GST_STREAM_ERROR_MUX:
782         case GST_STREAM_ERROR_FORMAT:
783         default:
784                 trans_err = MM_ERROR_PLAYER_INVALID_STREAM;
785                 break;
786         }
787
788         MMPLAYER_FLEAVE();
789
790         return trans_err;
791 }
792
793 /* NOTE : decide gstreamer state whether there is some playable track or not. */
794 static gint
795 __gst_transform_gsterror(mm_player_t* player, GstMessage * message, GError* error)
796 {
797         gchar *src_element_name = NULL;
798         GstElement *src_element = NULL;
799         GstElementFactory *factory = NULL;
800         const gchar* klass = NULL;
801
802         MMPLAYER_FENTER();
803
804         MMPLAYER_RETURN_VAL_IF_FAIL(message, MM_ERROR_INVALID_ARGUMENT);
805         MMPLAYER_RETURN_VAL_IF_FAIL(message->src, MM_ERROR_INVALID_ARGUMENT);
806         MMPLAYER_RETURN_VAL_IF_FAIL(error, MM_ERROR_INVALID_ARGUMENT);
807         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
808                                                                 player->pipeline &&
809                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
810
811         src_element = GST_ELEMENT_CAST(message->src);
812         if (!src_element)
813                 goto INTERNAL_ERROR;
814
815         src_element_name = GST_ELEMENT_NAME(src_element);
816         if (!src_element_name)
817                 goto INTERNAL_ERROR;
818
819         factory = gst_element_get_factory(src_element);
820         if (!factory)
821                 goto INTERNAL_ERROR;
822
823         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
824         if (!klass)
825                 goto INTERNAL_ERROR;
826
827         LOGD("error code=%d, msg=%s, src element=%s, class=%s\n",
828                         error->code, error->message, src_element_name, klass);
829
830         /* check whether the error is posted from not-activated track or not */
831         if (player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst) {
832                 int msg_src_pos = 0;
833                 gint active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
834                 LOGD("current  active pad index  -%d", active_pad_index);
835
836                 if  (src_element_name) {
837                         int idx = 0;
838
839                         if (player->audio_decoders) {
840                                 GList *adec = player->audio_decoders;
841                                 for (; adec ; adec = g_list_next(adec)) {
842                                         gchar *name = adec->data;
843
844                                         LOGD("found audio decoder name  = %s", name);
845                                         if (g_strrstr(name, src_element_name)) {
846                                                 msg_src_pos = idx;
847                                                 break;
848                                         }
849                                         idx++;
850                                 }
851                         }
852                         LOGD("active pad = %d, error src index = %d", active_pad_index,  msg_src_pos);
853                 }
854
855                 if (active_pad_index != msg_src_pos) {
856                         LOGD("skip error because error is posted from no activated track");
857                         return MM_ERROR_NONE;
858                 }
859         }
860
861         switch (error->code) {
862         case GST_STREAM_ERROR_DECODE:
863         {
864                 /* Demuxer can't parse one track because it's corrupted.
865                  * So, the decoder for it is not linked.
866                  * But, it has one playable track.
867                  */
868                 if (g_strrstr(klass, "Demux")) {
869                         if (player->can_support_codec == FOUND_PLUGIN_VIDEO) {
870                                 return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
871                         } else if (player->can_support_codec == FOUND_PLUGIN_AUDIO) {
872                                 return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
873                         } else {
874                                 if (player->pipeline->audiobin) // PCM
875                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
876                                 else
877                                         goto CODEC_NOT_FOUND;
878                         }
879                 }
880                 return MM_ERROR_PLAYER_INVALID_STREAM;
881         }
882                 break;
883
884         case GST_STREAM_ERROR_CODEC_NOT_FOUND:
885         case GST_STREAM_ERROR_TYPE_NOT_FOUND:
886         case GST_STREAM_ERROR_WRONG_TYPE:
887         {
888                 if (src_element == player->pipeline->mainbin[MMPLAYER_M_SUBPARSE].gst) {
889                         LOGE("Not supported subtitle.");
890                         return MM_ERROR_PLAYER_NOT_SUPPORTED_SUBTITLE;
891                 }
892                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
893         }
894
895         case GST_STREAM_ERROR_FAILED:
896         {
897                 /* Decoder Custom Message */
898                 if (strstr(error->message, "ongoing")) {
899                         if (strncasecmp(klass, "audio", 5)) {
900                                 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
901                                         LOGD("Video can keep playing.\n");
902                                         return MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
903                                 } else
904                                         goto CODEC_NOT_FOUND;
905
906                         } else if (strncasecmp(klass, "video", 5)) {
907                                 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO)) {
908                                         LOGD("Audio can keep playing.\n");
909                                         return MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
910                                 } else
911                                         goto CODEC_NOT_FOUND;
912                         }
913                 }
914                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
915         }
916                 break;
917
918         case GST_STREAM_ERROR_DECRYPT:
919         case GST_STREAM_ERROR_DECRYPT_NOKEY:
920         {
921                 LOGE("decryption error, [%s] failed, reason : [%s]\n", src_element_name, error->message);
922
923                 if (strstr(error->message, "rights expired"))
924                         return MM_ERROR_PLAYER_DRM_EXPIRED;
925                 else if (strstr(error->message, "no rights"))
926                         return MM_ERROR_PLAYER_DRM_NO_LICENSE;
927                 else if (strstr(error->message, "has future rights"))
928                         return MM_ERROR_PLAYER_DRM_FUTURE_USE;
929                 else if (strstr(error->message, "opl violation"))
930                         return MM_ERROR_PLAYER_DRM_OUTPUT_PROTECTION;
931                 return MM_ERROR_PLAYER_DRM_NOT_AUTHORIZED;
932         }
933                 break;
934
935         default:
936                 break;
937         }
938
939         MMPLAYER_FLEAVE();
940
941         return MM_ERROR_PLAYER_INVALID_STREAM;
942
943 INTERNAL_ERROR:
944         return MM_ERROR_PLAYER_INTERNAL;
945
946 CODEC_NOT_FOUND:
947         LOGD("not found any available codec. Player should be destroyed.\n");
948         return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
949 }
950
951 int
952 __mmplayer_get_video_angle(mm_player_t* player, int *user_angle, int *org_angle)
953 {
954         int user_angle_type = 0;
955         gchar *org_orient = NULL;
956         MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
957
958         if (!attrs) {
959                 LOGE("cannot get content attribute");
960                 return MM_ERROR_PLAYER_INTERNAL;
961         }
962
963         /* update user roation */
964         mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
965
966         /* get angle with user type */
967         switch (user_angle_type) {
968         case MM_DISPLAY_ROTATION_NONE:
969                 *user_angle = 0;
970                 break;
971         case MM_DISPLAY_ROTATION_90: /* counter-clockwise 90 */
972                 *user_angle = 270;
973                 break;
974         case MM_DISPLAY_ROTATION_180:
975                 *user_angle = 180;
976                 break;
977         case MM_DISPLAY_ROTATION_270: /* clockwise 90 */
978                 *user_angle = 90;
979                 break;
980         }
981
982         /* get original orientation */
983         mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
984
985         if (org_orient) {
986                 if (!strcmp(org_orient, "rotate-90"))
987                         *org_angle = 90;
988                 else if (!strcmp(org_orient, "rotate-180"))
989                         *org_angle = 180;
990                 else if (!strcmp(org_orient, "rotate-270"))
991                         *org_angle = 270;
992                 else
993                         LOGD("original rotation is %s", org_orient);
994         } else
995                 LOGD("content_video_orientation get fail");
996
997         LOGD("check user angle: %d, orientation: %d", *user_angle, *org_angle);
998
999         return MM_ERROR_NONE;
1000 }
1001