4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, ByungWook Jang <bw.jang@samsung.com>,
7 * Manoj Kumar K <manojkumar.k@samsung.com>, Hyunil Park <hyunil46.park@samsung.com>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "mm_wfd_priv.h"
27 static const gchar * __get_state_name ( int state );
28 static int __mmwfd_check_state(mm_wfd_t* wfd, enum PlayerCommandState command);
29 static gboolean __mmwfd_set_state(mm_wfd_t* wfd, int state);
30 static gboolean __mmwfd_gstreamer_init(void);
32 void __mmwfd_server_cb(gboolean is_error, void *userdata)
34 MMMessageParamType msg = {0, };
35 mm_wfd_t* wfd = (mm_wfd_t*)userdata;
39 /* check wfd handle */
40 return_if_fail ( wfd);
41 debug_error("posting message to app...");
43 // msg.state.previous = prev_state;
44 // msg.state.current = new_state;
46 MMWFD_POST_MSG( wfd, MM_MESSAGE_ERROR, &msg );
49 int _mmwfd_create (MMHandleType hwfd) // @
51 mm_wfd_t* wfd = (mm_wfd_t*)hwfd;
54 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
56 MMTA_ACUM_ITEM_BEGIN("[KPI] media wifi-display service create->playing", FALSE);
58 /* initialize wfd state */
59 MMWFD_CURRENT_STATE(wfd) = MM_WFD_STATE_NONE;
60 MMWFD_PREV_STATE(wfd) = MM_WFD_STATE_NONE;
61 MMWFD_PENDING_STATE(wfd) = MM_WFD_STATE_NONE;
62 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_NONE;
64 debug_log ("\n\n\ncur : %d, prev : %d, pend : %d, target : %d\n\n\n\n",
65 MMWFD_CURRENT_STATE(wfd),
66 MMWFD_PREV_STATE(wfd),
67 MMWFD_PENDING_STATE(wfd),
68 MMWFD_TARGET_STATE(wfd));
70 MMWFD_PRINT_STATE(wfd);
72 /* check current state */
73 MMWFD_CHECK_STATE_RETURN_IF_FAIL ( wfd, MMWFD_COMMAND_CREATE );
75 /* construct attributes */
76 // TODO: need to decide on attributes
78 wfd->attrs = _mmwfd_construct_attribute(wfd);
79 if ( NULL == wfd->attrs)
81 debug_critical("Failed to construct attributes\n");
85 /* initialize gstreamer with configured parameter */
86 if ( ! __mmwfd_gstreamer_init() )
88 debug_critical("Initializing gstreamer failed\n");
92 /* creates the server object */
93 wfd->server = gst_rtsp_server_new(__mmwfd_server_cb, wfd);
94 if (NULL == wfd->server)
96 debug_error("Failed to create server...");
100 /* Gets the media mapping object for the server */
101 wfd->mapping = gst_rtsp_server_get_media_mapping (wfd->server);
102 if (wfd->mapping == NULL)
104 debug_error ("No media mapping...");
108 wfd->factory = gst_rtsp_media_factory_new ();
109 if (wfd->factory == NULL)
111 debug_error ("Failed to create factory...");
115 /* attach the test factory to the /test url */
116 // TODO: Check why test url name is required.... ???
117 gst_rtsp_media_mapping_add_factory (wfd->mapping, "/wfd1.0", wfd->factory);
119 /* set wfd state to ready */
120 MMWFD_SET_STATE(wfd, MM_WFD_STATE_NULL);
124 return MM_ERROR_NONE;
128 /* release attributes */
129 _mmwfd_deconstruct_attribute((mm_wfd_t *)wfd);
131 return MM_ERROR_WFD_INTERNAL;
135 int _mmwfd_destroy (MMHandleType hwfd) // @
137 mm_wfd_t* wfd = (mm_wfd_t*)hwfd;
141 /* check wfd handle */
142 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
144 /* destroy can called at anytime */
145 MMWFD_CHECK_STATE_RETURN_IF_FAIL ( wfd, MMWFD_COMMAND_DESTROY );
147 g_object_unref (wfd->client);
148 g_object_unref (wfd->server);
149 g_object_unref (wfd->mapping);
150 g_object_unref (wfd->factory);
152 /* release attributes */
153 _mmwfd_deconstruct_attribute( wfd );
157 return MM_ERROR_NONE;
160 int _mmwfd_realize (MMHandleType hwfd) // @
162 mm_wfd_t* wfd = (mm_wfd_t*)hwfd;
163 char *server_ip =NULL;
166 MMHandleType attrs = 0;
167 int ret = MM_ERROR_NONE;
171 /* check wfd handle */
172 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED )
174 /* check current state */
175 MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMWFD_COMMAND_REALIZE );
177 attrs = MMWFD_GET_ATTRS(wfd);
180 debug_error("fail to get attributes.\n");
181 return MM_ERROR_WFD_INTERNAL;
184 /* set the server_ip address on WFD-server */
185 mm_attrs_get_string_by_name ( attrs, "server_ip", &server_ip);
186 gst_rtsp_server_set_address(wfd->server, server_ip);
188 debug_log ("server_ip : %s", server_ip);
190 /* set service address on WFD-server */
191 mm_attrs_get_string_by_name(attrs, "server_port", &port);
192 gst_rtsp_server_set_service (wfd->server, port);
194 debug_log ("server_port : %s", port);
196 /* set max clients allowed on WFD-server */
197 mm_attrs_get_int_by_name(attrs, "max_client_count", &backlog_cnt);
198 gst_rtsp_server_set_backlog (wfd->server, backlog_cnt);
200 debug_log ("max_client_count : %d", backlog_cnt);
202 /* attach the server to the default maincontext */
203 if (gst_rtsp_server_attach (wfd->server, NULL) == 0)
205 debug_error ("Failed to attach server to context");
206 return MM_ERROR_WFD_INTERNAL;
209 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_READY );
216 int _mmwfd_unrealize (MMHandleType hwfd)
218 mm_wfd_t* wfd = (mm_wfd_t*)hwfd;
221 int ret = MM_ERROR_NONE;
225 pool = gst_rtsp_server_get_session_pool (wfd->server);
226 gst_rtsp_session_pool_cleanup (pool);
227 g_object_unref (pool);
234 int _mmwfd_connect (MMHandleType hwfd)
236 mm_wfd_t* wfd = (mm_wfd_t*)hwfd;
238 int ret = MM_ERROR_NONE;
242 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
244 /* check current state */
245 MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMFWD_COMMAND_CONNECT);
247 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_CONNECTION_WAIT );
249 /* start accepting the client.. this call is a blocking call & keep on waiting on accept () sys API */
250 wfd->client = gst_rtsp_server_accept_client (wfd->server);
251 if (wfd->client == NULL)
253 debug_error ("Error in client accept");
254 return MM_ERROR_WFD_INTERNAL;
257 if (!gst_rtsp_server_negotiate_client (wfd->server, wfd->client))
259 debug_error ("Error in starting client");
260 return MM_ERROR_WFD_INTERNAL;
263 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_CONNECTED );
270 int _mmwfd_start (MMHandleType hwfd) // @
272 mm_wfd_t* wfd = (mm_wfd_t*) hwfd;
273 gint ret = MM_ERROR_NONE;
277 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
279 /* check current state */
280 MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMWFD_COMMAND_START );
282 /* set client params */
283 gst_rtsp_server_set_client_params (wfd->server, wfd->client, WFD_INI()->videosrc_element, WFD_INI()->session_mode, WFD_INI()->videobitrate, WFD_INI()->mtu_size,
286 if (!gst_rtsp_server_start_client (wfd->server, wfd->client))
288 debug_error ("Error in starting client");
289 return MM_ERROR_WFD_INTERNAL;
292 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_PLAYING );
299 int _mmwfd_pause (MMHandleType hwfd) // @
301 mm_wfd_t* wfd = (mm_wfd_t*) hwfd;
302 gint ret = MM_ERROR_NONE;
306 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
308 /* check current state */
309 //MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMWFD_COMMAND_PLAY );
311 if (!gst_rtsp_server_pause_client (wfd->server, wfd->client))
313 debug_error ("Error in starting client");
314 return MM_ERROR_WFD_INTERNAL;
317 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_PAUSED);
324 int _mmwfd_resume (MMHandleType hwfd) // @
326 mm_wfd_t* wfd = (mm_wfd_t*) hwfd;
327 gint ret = MM_ERROR_NONE;
331 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
333 /* check current state */
334 //MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMWFD_COMMAND_PAUSE );
336 if (!gst_rtsp_server_resume_client (wfd->server, wfd->client))
338 debug_error ("Error in starting client");
339 return MM_ERROR_WFD_INTERNAL;
342 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_PLAYING );
349 int _mmwfd_standby (MMHandleType hwfd) // @
351 mm_wfd_t* wfd = (mm_wfd_t*) hwfd;
352 gint ret = MM_ERROR_NONE;
355 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
357 /* check current state */
358 //MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMWFD_COMMAND_PLAY );
360 if (!gst_rtsp_server_standby_client (wfd->server, wfd->client))
362 debug_error ("Error in client standby");
363 return MM_ERROR_WFD_INTERNAL;
366 MMWFD_SET_STATE ( wfd, MM_WFD_STATE_PAUSED);
373 int _mmwfd_stop (MMHandleType hwfd) // @
375 mm_wfd_t* wfd = (mm_wfd_t*) hwfd;
376 gint ret = MM_ERROR_NONE;
380 return_val_if_fail ( wfd, MM_ERROR_WFD_NOT_INITIALIZED );
382 /* check current state */
383 //MMWFD_CHECK_STATE_RETURN_IF_FAIL( wfd, MMWFD_COMMAND_STOP );
384 if (!gst_rtsp_server_stop_client (wfd->server, wfd->client))
386 debug_error ("Error in starting client");
387 return MM_ERROR_WFD_INTERNAL;
394 int _mmwfd_get_state(MMHandleType hwfd, int *state) // @
396 mm_wfd_t *wfd = (mm_wfd_t*)hwfd;
398 return_val_if_fail(state, MM_ERROR_INVALID_ARGUMENT);
400 *state = MMWFD_CURRENT_STATE(wfd);
402 return MM_ERROR_NONE;
406 __get_state_name ( int state )
410 case MM_WFD_STATE_NULL:
412 case MM_WFD_STATE_READY:
414 case MM_WFD_STATE_PAUSED:
416 case MM_WFD_STATE_CONNECTION_WAIT:
417 return "WAIT_FOR_CONNECTION";
418 case MM_WFD_STATE_CONNECTED:
420 case MM_WFD_STATE_PLAYING:
422 case MM_WFD_STATE_NONE:
425 debug_log ("\n\n\nstate value : %d\n\n\n", state);
431 __mmwfd_check_state(mm_wfd_t* wfd, enum PlayerCommandState command)
433 MMWfdStateType current_state = MM_WFD_STATE_NUM;
434 MMWfdStateType pending_state = MM_WFD_STATE_NUM;
435 MMWfdStateType target_state = MM_WFD_STATE_NUM;
436 MMWfdStateType prev_state = MM_WFD_STATE_NUM;
440 return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED);
442 current_state = MMWFD_CURRENT_STATE(wfd);
443 pending_state = MMWFD_PENDING_STATE(wfd);
444 target_state = MMWFD_TARGET_STATE(wfd);
445 prev_state = MMWFD_PREV_STATE(wfd);
447 MMWFD_PRINT_STATE(wfd);
449 debug_log("incomming command : %d \n", command );
453 case MMWFD_COMMAND_CREATE:
455 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_NULL;
457 if ( current_state == MM_WFD_STATE_NULL ||
458 current_state == MM_WFD_STATE_READY ||
459 current_state == MM_WFD_STATE_PAUSED ||
460 current_state == MM_WFD_STATE_CONNECTION_WAIT ||
461 current_state == MM_WFD_STATE_CONNECTED ||
462 current_state == MM_WFD_STATE_PLAYING )
467 case MMWFD_COMMAND_DESTROY:
469 /* destroy can called anytime */
471 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_NONE;
475 case MMWFD_COMMAND_REALIZE:
477 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_READY;
479 if ( pending_state != MM_WFD_STATE_NONE )
485 /* need ready state to realize */
486 if ( current_state == MM_WFD_STATE_READY )
489 if ( current_state != MM_WFD_STATE_NULL )
495 case MMWFD_COMMAND_UNREALIZE:
497 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_NULL;
499 if ( current_state == MM_WFD_STATE_NULL )
504 case MMFWD_COMMAND_CONNECT:
506 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_CONNECTED;
508 // TODO: check any extra error handing is needed
510 MMWFD_PRINT_STATE(wfd);
512 debug_log ("target state is CONNECTED...");
516 case MMWFD_COMMAND_START:
518 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_PLAYING;
520 if ( pending_state == MM_WFD_STATE_NONE )
522 if ( current_state == MM_WFD_STATE_PLAYING )
524 else if ( current_state != MM_WFD_STATE_READY &&
525 current_state != MM_WFD_STATE_PAUSED && current_state != MM_WFD_STATE_CONNECTED)
528 else if ( pending_state == MM_WFD_STATE_PLAYING )
532 else if ( pending_state == MM_WFD_STATE_PAUSED )
534 debug_log("wfd is going to paused state, just change the pending state as playing.\n");
543 case MMWFD_COMMAND_STOP:
546 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_READY;
548 if ( current_state == MM_WFD_STATE_READY )
552 /* need playing/paused state to stop */
553 if ( current_state != MM_WFD_STATE_PLAYING &&
554 current_state != MM_WFD_STATE_PAUSED )
559 case MMWFD_COMMAND_PAUSE:
562 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_PAUSED;
564 if ( pending_state == MM_WFD_STATE_NONE )
566 if ( current_state == MM_WFD_STATE_PAUSED )
568 else if ( current_state != MM_WFD_STATE_PLAYING && current_state != MM_WFD_STATE_READY ) // support loading state of broswer
571 else if ( pending_state == MM_WFD_STATE_PAUSED )
575 else if ( pending_state == MM_WFD_STATE_PLAYING )
577 if ( current_state == MM_WFD_STATE_PAUSED ) {
578 debug_log("wfd is PAUSED going to PLAYING, just change the pending state as PAUSED.\n");
586 case MMWFD_COMMAND_RESUME:
588 MMWFD_TARGET_STATE(wfd) = MM_WFD_STATE_PLAYING;
590 if ( pending_state == MM_WFD_STATE_NONE )
592 if ( current_state == MM_WFD_STATE_PLAYING )
594 else if ( current_state != MM_WFD_STATE_PAUSED )
597 else if ( pending_state == MM_WFD_STATE_PLAYING )
601 else if ( pending_state == MM_WFD_STATE_PAUSED )
603 debug_log("wfd is going to paused state, just change the pending state as playing.\n");
616 debug_log("status OK\n");
622 return MM_ERROR_NONE;
626 debug_warning("since wfd is in wrong state(%s). it's not able to apply the command(%d)\n",
627 MMWFD_STATE_GET_NAME(current_state), command);
628 return MM_ERROR_WFD_INVALID_STATE;
631 debug_warning("wfd is in the desired state(%s). doing nothing\n", MMWFD_STATE_GET_NAME(current_state));
632 return MM_ERROR_WFD_NO_OP;
635 debug_warning("wfd is already going to %s, doing nothing.\n", MMWFD_STATE_GET_NAME(pending_state));
636 return MM_ERROR_WFD_NO_OP;
640 __mmwfd_gstreamer_init(void) // @
642 static gboolean initialized = FALSE;
643 static const int max_argc = 50;
653 debug_log("gstreamer already initialized.\n");
658 argc = malloc( sizeof(int) );
659 argv = malloc( sizeof(gchar*) * max_argc );
661 if ( !argc || !argv )
664 memset( argv, 0, sizeof(gchar*) * max_argc );
668 argv[0] = g_strdup( "mmwfd" );
671 for ( i = 0; i < 5; i++ ) /* FIXIT : num of param is now fixed to 5. make it dynamic */
673 if ( strlen( WFD_INI()->gst_param[i] ) > 0 )
675 argv[*argc] = g_strdup( WFD_INI()->gst_param[i] );
680 /* we would not do fork for scanning plugins */
681 argv[*argc] = g_strdup("--gst-disable-registry-fork");
684 /* check disable registry scan */
685 if ( WFD_INI()->skip_rescan )
687 argv[*argc] = g_strdup("--gst-disable-registry-update");
691 /* check disable segtrap */
692 if ( WFD_INI()->disable_segtrap )
694 argv[*argc] = g_strdup("--gst-disable-segtrap");
698 debug_log("initializing gstreamer with following parameter\n");
699 debug_log("argc : %d\n", *argc);
701 for ( i = 0; i < *argc; i++ )
703 debug_log("argv[%d] : %s\n", i, argv[i]);
707 /* initializing gstreamer */
708 __ta__("gst_init time",
710 if ( ! gst_init_check (argc, &argv, &err))
712 debug_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
723 for ( i = 0; i < *argc; i++ )
725 MMWFD_FREEIF( argv[i] );
728 MMWFD_FREEIF( argv );
729 MMWFD_FREEIF( argc );
740 MMWFD_FREEIF( argv );
741 MMWFD_FREEIF( argc );
748 __mmwfd_set_state(mm_wfd_t* wfd, int state) // @
750 MMWfdStateType current_state = MM_WFD_STATE_NONE;
751 MMWfdStateType prev_state = MM_WFD_STATE_NONE;
752 MMWfdStateType target_state = MM_WFD_STATE_NONE;
753 MMWfdStateType pending_state = MM_WFD_STATE_NONE;
754 MMMessageParamType msg = {0, };
755 int asm_result = MM_ERROR_NONE;
756 int new_state = state;
760 return_val_if_fail ( wfd, FALSE );
762 prev_state = MMWFD_PREV_STATE(wfd);
763 current_state = MMWFD_CURRENT_STATE(wfd);
764 pending_state = MMWFD_PENDING_STATE(wfd);
765 target_state = MMWFD_TARGET_STATE(wfd);
768 MMWFD_PRINT_STATE(wfd);
770 MMWFD_PREV_STATE(wfd) = current_state;
771 MMWFD_CURRENT_STATE(wfd) = new_state;
773 if ( pending_state == new_state )
774 MMWFD_PENDING_STATE(wfd) = MM_WFD_STATE_NONE;
776 if ( current_state == new_state )
778 debug_warning("already same state(%s)\n", MMWFD_STATE_GET_NAME(state));
782 MMWFD_PRINT_STATE(wfd);
784 if (target_state == new_state)
786 msg.state.previous = prev_state;
787 msg.state.current = new_state;
789 MMWFD_POST_MSG( wfd, MM_MESSAGE_STATE_CHANGED, &msg );
791 debug_log ("wfd reach the target state, then do something in each state(%s).\n", MMWFD_STATE_GET_NAME(target_state));
795 debug_log ("intermediate state, do nothing.\n");
799 switch ( target_state )
801 case MM_WFD_STATE_NULL:
802 case MM_WFD_STATE_READY:
803 case MM_WFD_STATE_CONNECTION_WAIT:
804 case MM_WFD_STATE_CONNECTED:
807 case MM_WFD_STATE_PAUSED:
809 /* special care for local playback. normaly we can get some content attribute
810 * when the demuxer is changed to PAUSED. so we are trying it. it will be tried again
811 * when PLAYING state has signalled if failed.
812 * note that this is only happening pause command has come before the state of pipeline
813 * reach to the PLAYING.
815 //_mmwfd_update_content_attrs( wfd );
820 case MM_WFD_STATE_PLAYING:
822 /* update attributes which are only available on playing status */
823 //_mmwfd_update_content_attrs ( wfd );
825 if ( wfd->cmd == MMWFD_COMMAND_START )
832 case MM_WFD_STATE_NONE:
834 debug_warning("invalid target state, there is nothing to do.\n");
844 __gst_set_message_callback(mm_wfd_t* wfd, MMMessageCallback callback, gpointer user_param) // @
850 debug_warning("set_message_callback is called with invalid wfd handle\n");
851 return MM_ERROR_WFD_NOT_INITIALIZED;
854 wfd->msg_cb = callback;
855 wfd->msg_cb_param = user_param;
857 debug_log("msg_cb : 0x%x msg_cb_param : 0x%x\n", (guint)callback, (guint)user_param);
861 return MM_ERROR_NONE;
865 _mmwfd_set_message_callback(MMHandleType hwfd, MMMessageCallback callback, gpointer user_param) // @
867 mm_wfd_t* wfd = (mm_wfd_t*)hwfd;
869 return_val_if_fail(wfd, MM_ERROR_WFD_NOT_INITIALIZED);
871 return __gst_set_message_callback(wfd, callback, user_param);
875 __mmwfd_post_message(mm_wfd_t* wfd, enum MMMessageType msgtype, MMMessageParamType* param) // @
877 return_val_if_fail( wfd, FALSE );
881 debug_warning("no msg callback. can't post\n");
885 //debug_log("Message (type : %d) will be posted using msg-cb(%p). \n", msgtype, wfd->msg_cb);
887 wfd->msg_cb(msgtype, param, wfd->msg_cb_param);