From: Hyunjun Date: Tue, 9 Jun 2015 08:11:42 +0000 (+0900) Subject: Fix bugs and improvements X-Git-Tag: submit/tizen/20150609.083647^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7b9889be9dd9b963dea66c0c9caf4aa18bca3b4d;p=platform%2Fcore%2Fapi%2Fscreen-mirroring.git Fix bugs and improvements Change-Id: I4b8b42f38eb44ef4e741318319a8f451e9d22331 --- diff --git a/AUTHORS b/AUTHORS old mode 100755 new mode 100644 diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/LICENSE.APLv2.0 b/LICENSE.APLv2.0 old mode 100755 new mode 100644 diff --git a/NOTICE b/NOTICE old mode 100755 new mode 100644 diff --git a/capi-media-screen-mirroring.manifest b/capi-media-screen-mirroring.manifest old mode 100755 new mode 100644 index ca37499..7376f27 --- a/capi-media-screen-mirroring.manifest +++ b/capi-media-screen-mirroring.manifest @@ -1,6 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/capi-media-screen-mirroring.pc.in b/capi-media-screen-mirroring.pc.in old mode 100755 new mode 100644 diff --git a/doc/images/capi_media_screen_mirroring_sink_state_diagram.png b/doc/images/capi_media_screen_mirroring_sink_state_diagram.png new file mode 100644 index 0000000..a5bcc18 Binary files /dev/null and b/doc/images/capi_media_screen_mirroring_sink_state_diagram.png differ diff --git a/doc/screen_mirroring_doc.h b/doc/screen_mirroring_doc.h old mode 100755 new mode 100644 index df322aa..916b047 --- a/doc/screen_mirroring_doc.h +++ b/doc/screen_mirroring_doc.h @@ -21,15 +21,199 @@ /** * @ingroup CAPI_MEDIA_FRAMEWORK * @defgroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE Screen Mirroring + * @brief The @ref CAPI_MEDIA_SCREEN_MIRRORING_MODULE API provides functions for screen mirroring as sink. + * @section CAPI_MEDIA_SCREEN_MIRRORING_MODULE_HEADER Required Header + * \#include + * \#include + * @section CAPI_MEDIA_SCREEN_MIRRORING_OVERVIEW Overview + * The @ref CAPI_MEDIA_SCREEN_MIRRORING_MODULE API allows you to implement screen mirroring application as sink. * - * @brief The @ref CAPI_MEDIA_SCREEN_MIRRORING_MODULE API provides functions for screen mirroring as source or sink. + */ + +/* + * @ingroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE + * @defgroup CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE Screen Mirroring sink + * @brief The @ref CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE API provides functions for screen mirroring as sink. * - * @section CAPI_MEDIA_SCREEN_MIRRORING_MODULE_HEADER Required Header - * \#include + * @section CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE_HEADER Required Header * \#include * - * @section CAPI_MEDIA_SCREEN_MIRRORING_OVERVIEW Overview - * The @ref CAPI_MEDIA_SCREEN_MIRRORING_MODULE API allows you to implement screen mirroring application as source or sink. + * @section CAPI_MEDIA_SCREEN_MIRRORING_SINK_OVERVIEW Overview + * The @ref CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE API allows you to implement screen mirroring application as sink. + * It gives the ability to connect to the screen mirroring source, start / disconnect / pause / resume screen mirroring sink, set resolution and display, register state change callback function. + * + * @subsection CAPI_MEDIA_SCREEN_MIRRORING_SINK_LIFE_CYCLE_STATE_DIAGRAM State Diagram + * The following diagram shows the life cycle and states of the screen mirroring sink. + * @image html capi_media_screen_mirroring_sink_state_diagram.png + * + * + * @subsection CAPI_MEDIA_SCREEN_MIRRORING_SINK_LIFE_CYCLE_STATE_TRANSITIONS State Transitions + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FUNCTIONPRE-STATEPOST-STATESYNC TYPE
scmirroring_sink_create()NONENULLSYNC
scmirroring_sink_destroy()NULLNONESYNC
scmirroring_sink_prepare()NULLPREPAREDSYNC
scmirroring_sink_unprepare()PREARED, DISCONNECTEDNULLSYNC
scmirroring_sink_connect()PREAREDCONNECTEDASYNC
scmirroring_sink_start()CONNECTEDPLAYINGASYNC
scmirroring_sink_disconnect()CONNECTED, PAUSED or PLAYING DISCONNECTED SYNC
scmirroring_sink_pause()PLAYINGPAUSEDASYNC
scmirroring_sink_resume()PAUSEDPLAYINGASYNC
+ * + * + *@subsection CAPI_MEDIA_SCREEN_MIRRORING_SINK_LIFE_CYCLE_STATE_DEPENDENT_FUNCTIONS State Dependent Function Calls + * The following table shows state-dependent function calls. + * It is forbidden to call the functions listed below in wrong state. + * Violation of this rule may result in unpredictable behavior. + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FUNCTIONVALID STATESDESCRIPTION
scmirroring_sink_create() NONE-
scmirroring_sink_destroy()NULL
scmirroring_sink_set_state_changed_cb()NULL/ PREPARED/ CONNECTED/ PLAYING/ PAUSED/ DISCONNECTEDThis function must be called after scmirroring_sink_create().
scmirroring_sink_unset_state_changed_cb()NULL/ PREPARED/ CONNECTED/ PLAYING/ PAUSED/ DISCONNECTEDThis function must be called after register callback function.
scmirroring_sink_set_display()NULLThis function must be called before scmirroring_sink_prepare().
scmirroring_sink_set_resolution()NULL
scmirroring_sink_prepare() NULLThis function must be called after scmirroring_sink_create().
scmirroring_sink_unprepare() PREPARED/ DISCONNECTED
scmirroring_sink_set_ip_and_port() NULL/ PREPAREDThis function must be called before scmirroring_sink_connect().
scmirroring_sink_connect()PREPAREDThis function must be called after scmirroring_sink_prepare().
scmirroring_sink_pause()PLAYINGThis function must be called after scmirroring_sink_start().
scmirroring_sink_resume()PAUSEDThis function must be called after scmirroring_sink_pause().
scmirroring_sink_start()CONNECTEDThis function must be called after scmirroring_sink_connect().
scmirroring_sink_disconnect() CONNECTED/ PLAYING/ PAUSED
+ * + * @subsection CAPI_MEDIA_SCREEN_MIRRORING_SINK_LIFE_CYCLE_ASYNCHRONOUS_OPERATIONS Asynchronous Operations + * All functions that change the state are synchronous except scmirroring_sink_connect(), scmirroring_sink_start(), scmirroring_sink_pause(), and scmirroring_sink_resume(). + * Thus the result is passed to the application via the callback mechanism. + * + * @subsection CAPI_MEDIA_SCREEN_MIRRORING_SINK_LIFE_CYCLE_CALLBACK_OPERATIONS Callback(Event) Operations + *
+ * + * + * + * + * + * + * + * + * + * + * + * + *
REGISTERUNREGISTERCALLBACKDESCRIPTION
scmirroring_sink_set_state_changed_cb()scmirroring_sink_unset_state_changed_cb()scmirroring_state_cb()This callback is called for state and error of screen mirroring.
*/ + #endif /* __TIZEN_SCREEN_MIRRORING_DOC_H__ */ diff --git a/include/scmirroring_private.h b/include/scmirroring_private.h index 90b2cc1..824238d 100755 --- a/include/scmirroring_private.h +++ b/include/scmirroring_private.h @@ -115,6 +115,7 @@ typedef struct GIOChannel *channel; char *sock_path; int connect_mode; + int current_state; scmirroring_state_cb_s *scmirroring_state_cb; } scmirroring_src_s; diff --git a/include/scmirroring_sink.h b/include/scmirroring_sink.h index e3aa2a9..38d7f30 100755 --- a/include/scmirroring_sink.h +++ b/include/scmirroring_sink.h @@ -29,7 +29,7 @@ extern "C" { */ /** - * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE + * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE * @{ */ diff --git a/include/scmirroring_src.h b/include/scmirroring_src.h index 1ca21e4..4e2fea6 100755 --- a/include/scmirroring_src.h +++ b/include/scmirroring_src.h @@ -29,7 +29,7 @@ extern "C" { */ /** - * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE + * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_SRC_MODULE * @{ */ @@ -377,7 +377,7 @@ int scmirroring_src_disconnect(scmirroring_src_h scmirroring_src); * @see scmirroring_src_create() * @see scmirroring_src_set_state_changed_cb() */ -int scmirroring_src_unset_state_cb(scmirroring_src_h scmirroring_src); +int scmirroring_src_unset_state_changed_cb(scmirroring_src_h scmirroring_src); /** * @brief Destroys server and screen mirroring source handle. diff --git a/miracast_server/miracast_server.c b/miracast_server/miracast_server.c index 7d68455..fa7e8a8 100755 --- a/miracast_server/miracast_server.c +++ b/miracast_server/miracast_server.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,9 +38,18 @@ #define MAX_MSG_LEN 128 #define MEDIA_IPC_PATH "/tmp/.miracast_ipc_rtspserver" +#define PROC_DBUS_OBJECT "/org/tizen/scmirroring/server" +#define PROC_DBUS_INTERFACE "org.tizen.scmirroring.server" +#define PROC_DBUS_STATUS_CHANGE_SIGNAL "miracast_wfd_source_status_changed" + +#define MIRACAST_WFD_SOURCE_ON 1 +#define MIRACAST_WFD_SOURCE_OFF 0 + GMainLoop *g_mainloop = NULL; GObject *g_server_object = NULL; +static gint g_server_status = MIRACAST_WFD_SOURCE_OFF; +static int __miracast_server_emit_status_signal(int status); static const GDBusMethodInfo scmirroring_server_method_info_method = { -1, @@ -53,7 +63,7 @@ static const GDBusMethodInfo * const scmirroring_server_method_info_pointers[] = static const GDBusInterfaceInfo scmirroring_server_interface_info = { -1, - "org.tizen.scmirroring.server", + PROC_DBUS_INTERFACE, (GDBusMethodInfo **) &scmirroring_server_method_info_pointers, (GDBusSignalInfo **) NULL, (GDBusPropertyInfo **) NULL, @@ -65,9 +75,12 @@ static GDBusNodeInfo *introspection_data = NULL; /* Introspection data for the service we are exporting */ static const gchar introspection_xml[] = "" - " " + " " " " " " + " " + " " + " " " " ""; @@ -82,11 +95,19 @@ handle_method_call (GDBusConnection *connection, GDBusMethodInvocation *invocation, gpointer user_data) { + scmirroring_debug("handle_method_call is called\n"); + + if(method_name != NULL) + scmirroring_debug("method_name is %s\n", method_name); + if (g_strcmp0 (method_name, "launch_method") == 0) { - scmirroring_debug("handle_method_call is called\n"); g_dbus_method_invocation_return_value (invocation, NULL); } + else if(g_strcmp0 (method_name, "get_miracast_wfd_source_status") == 0) + { + g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", g_server_status)); + } } @@ -107,7 +128,7 @@ on_bus_acquired (GDBusConnection *connection, scmirroring_debug ("on_bus_acquired called\n"); registration_id = g_dbus_connection_register_object (connection, - "/org/tizen/scmirroring/server", + PROC_DBUS_OBJECT, introspection_data->interfaces[0], &interface_vtable, NULL, @@ -170,6 +191,7 @@ static void miracast_server_object_init(MiracastServerObject * obj) obj->server = NULL; obj->client = NULL; obj->factory = NULL; + obj->resolution = -1; } static void miracast_server_object_class_init(MiracastServerObjectClass * klass) @@ -195,8 +217,9 @@ int __miracast_server_send_resp(MiracastServerObject *server, char *cmd) } _cmd = g_strdup(cmd); + _cmd[strlen(_cmd)] = '\0'; - if (write(client_sock, _cmd, strlen(_cmd)) != strlen(_cmd)) { + if (write(client_sock, _cmd, strlen(_cmd) + 1) != strlen(_cmd) + 1) { scmirroring_error("sendto failed [%s]", strerror(errno)); ret = SCMIRRORING_ERROR_INVALID_OPERATION; } else { @@ -213,12 +236,19 @@ static void __miracast_server_quit_program(MiracastServerObject * server) void *pool; int i; + int ret = 0; if (server->server == NULL) { scmirroring_error ("server is already NULL"); goto done; } + ret = __miracast_server_emit_status_signal(MIRACAST_WFD_SOURCE_OFF); + if(ret != SCMIRRORING_ERROR_NONE ) + { + scmirroring_error("Failed to emit miracast server off signal"); + } + pool = (void*)gst_rtsp_server_get_session_pool (server->server); gst_rtsp_session_pool_cleanup (pool); g_object_unref (pool); @@ -237,6 +267,22 @@ done: static void __miracast_server_signal_handler(int signo) { scmirroring_error("__miracast_server_signal_handler call quit_program() %d", signo); + int ret = 0; + + switch(signo) + { + case SIGINT: + case SIGQUIT: + case SIGTERM: + ret = __miracast_server_emit_status_signal(MIRACAST_WFD_SOURCE_OFF); + if(ret != SCMIRRORING_ERROR_NONE ) + { + scmirroring_error("Failed to emit miracast server off signal"); + } + break; + default: + break; + } exit(1); } @@ -307,7 +353,7 @@ static bool __miracast_server_setup() object = g_object_new (MIRACAST_SERVER_TYPE_OBJECT, NULL); g_bus_own_name (G_BUS_TYPE_SYSTEM, - "org.tizen.scmirroring.server", + PROC_DBUS_INTERFACE, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, @@ -366,6 +412,12 @@ static gboolean __miracast_server_ready_channel(int *sockfd) return FALSE; } + /*change permission of sock file*/ + if (chmod(MEDIA_IPC_PATH, 0770) < 0) + scmirroring_error ("chmod failed [%s]", strerror(errno)); + if (chown(MEDIA_IPC_PATH, 200, 5000) < 0) + scmirroring_error ("chown failed [%s]", strerror(errno)); + scmirroring_debug("Listening..."); *sockfd = sock; @@ -465,14 +517,58 @@ ERROR: #define TEST_MOUNT_POINT "/wfd1.0/streamid=0" +static void +__client_closed (GstRTSPClient * client) +{ + if (client == NULL) return; + + scmirroring_debug ("client %p: connection closed", client); + + return; +} + +static void +__new_session (GstRTSPClient * client, GstRTSPSession *session) +{ + if (client == NULL) return; + + scmirroring_debug ("New session(%p) is made for client %p", session, client); + + return; +} + +static void +__teardown_req (GstRTSPClient * client, GstRTSPContext *ctx) +{ + if (client == NULL) return; + + scmirroring_debug ("Got TEARDOWN request for client %p", client); + + return; +} + static void __miracast_server_client_connected_cb (GstRTSPServer * server, GstRTSPClient * client, gpointer user_data) { MiracastServerObject *server_obj = (MiracastServerObject *)user_data; + int ret = SCMIRRORING_ERROR_NONE; scmirroring_debug("There is a client, connected"); server_obj->client = (void *)client; + + ret = __miracast_server_emit_status_signal(MIRACAST_WFD_SOURCE_ON); + if(ret != SCMIRRORING_ERROR_NONE ) + { + scmirroring_error("Failed to emit miracast server on signal"); + } + + g_signal_connect(G_OBJECT(client), "teardown-request", G_CALLBACK(__teardown_req), NULL); + g_signal_connect(G_OBJECT(client), "closed", G_CALLBACK(__client_closed), NULL); + g_signal_connect(G_OBJECT(client), "new-session", G_CALLBACK(__new_session), NULL); + + /* Sending connected response to client */ + __miracast_server_send_resp(server_obj, "OK:CONNECTED"); } int __miracast_server_start(MiracastServerObject * server_obj) @@ -516,14 +612,37 @@ int __miracast_server_start(MiracastServerObject * server_obj) scmirroring_src_ini_get_structure()->mtu_size ); - gst_rtsp_wfd_server_set_supported_reso(server, + + if (server_obj->resolution == SCMIRRORING_RESOLUTION_1920x1080_P30) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_CEA_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_CEA_1920x1080P30); + } else if (server_obj->resolution == SCMIRRORING_RESOLUTION_1280x720_P30) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_CEA_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_CEA_1280x720P30); + } else if (server_obj->resolution == SCMIRRORING_RESOLUTION_960x540_P30) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_HH_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_HH_960x540P30); + } else if (server_obj->resolution == SCMIRRORING_RESOLUTION_864x480_P30) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_HH_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_HH_864x480P30); + } else if (server_obj->resolution == SCMIRRORING_RESOLUTION_720x480_P60) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_CEA_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_CEA_720x480P60); + } else if (server_obj->resolution == SCMIRRORING_RESOLUTION_640x480_P60) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_CEA_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_CEA_640x480P60); + } else if (server_obj->resolution == SCMIRRORING_RESOLUTION_640x360_P30) { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_HH_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, GST_WFD_HH_640x360P30); + } else { + gst_rtsp_wfd_server_set_video_native_reso(server, GST_WFD_VIDEO_CEA_RESOLUTION); + gst_rtsp_wfd_server_set_supported_reso(server, scmirroring_src_ini_get_structure()->video_reso_supported); + } gst_rtsp_media_factory_wfd_set_dump_ts (factory, scmirroring_src_ini_get_structure()->dump_ts); - gst_rtsp_media_factory_set_launch (GST_RTSP_MEDIA_FACTORY(factory), - "( " VIDEO_PIPELINE " )"); g_object_ref (factory); gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, GST_RTSP_MEDIA_FACTORY(factory)); g_object_unref (mounts); @@ -554,9 +673,9 @@ void __miracast_server_interpret(MiracastServerObject * server, char *buf) if (g_strrstr(buf, SCMIRRORING_STATE_CMD_START)) { ret = __miracast_server_start(server); if (ret == SCMIRRORING_ERROR_NONE) { - __miracast_server_send_resp(server, "OK:CONNECTED"); + __miracast_server_send_resp(server, "OK:LISTENING"); } else { - __miracast_server_send_resp(server, "FAIL:CONNECTED"); + __miracast_server_send_resp(server, "FAIL:LISTENING"); } } else if (g_strrstr(buf, "SET IP")) { gchar **addr_info; @@ -594,7 +713,7 @@ void __miracast_server_interpret(MiracastServerObject * server, char *buf) resolution_info = g_strsplit(buf, " ", 0); resolution = atoi(resolution_info[2]); - scmirroring_debug("Connection mode %d", resolution); + scmirroring_debug("Resolution %d", resolution); server->resolution = resolution; @@ -649,10 +768,27 @@ gboolean __miracast_server_client_read_cb(GIOChannel *src, if (read == 0) { scmirroring_error("Read 0 bytes"); return FALSE; + } else { + scmirroring_debug("Read %d bytes", read); + } + + int i = 0; + int idx = 0; + + /* Handling multiple commands like "CMD1\0CMD2\0CMD3\0" */ + for (i = 0; i < read; i++) { + gchar *str = NULL; + if (buf[i] == '\0') { + str = buf + idx; + idx = i + 1; + } else { + continue; + } + scmirroring_debug("Handling %s", str); + __miracast_server_interpret (server, str); + if (idx >= read) break; } - buf[read] = '\0'; - g_strstrip(buf); - __miracast_server_interpret (server, buf); + } else if (condition & G_IO_ERR) { scmirroring_error("got G_IO_ERR"); return FALSE; @@ -698,6 +834,7 @@ gboolean __miracast_server_read_cb(GIOChannel *src, /* To avoid blocking in g_io_channel_read_chars */ g_io_channel_set_encoding(channel, NULL, NULL); g_io_channel_set_buffered(channel, FALSE); + g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); server->client_channel = channel; @@ -708,6 +845,58 @@ gboolean __miracast_server_read_cb(GIOChannel *src, return TRUE; } + +static int __miracast_server_emit_status_signal(int status) +{ + GError *err = NULL; + GDBusConnection *conn = NULL; + gboolean ret; + + if (status != MIRACAST_WFD_SOURCE_ON && status != MIRACAST_WFD_SOURCE_OFF) { + scmirroring_error ("invalid arguments [%d]", status); + return -1; + } + + if (g_server_status == status) { + scmirroring_debug ("The server status is not changed, status [%d] ", status); + return 0; + } + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!conn && err) { + scmirroring_error("g_bus_get_sync() error (%s) ", err->message); + g_error_free (err); + return -1; + } + + ret = g_dbus_connection_emit_signal (conn, + NULL, PROC_DBUS_OBJECT, PROC_DBUS_INTERFACE, PROC_DBUS_STATUS_CHANGE_SIGNAL, + g_variant_new ("(i)", status), &err); + if (!ret && err) { + scmirroring_error("g_dbus_connection_emit_signal() error (%s) ", err->message); + goto error; + } + + ret = g_dbus_connection_flush_sync(conn, NULL, &err); + if (!ret && err) { + scmirroring_error("g_dbus_connection_flush_sync() error (%s) ", err->message); + goto error; + } + + g_object_unref(conn); + scmirroring_debug ("sending miracast server status [%s] success", + (status == MIRACAST_WFD_SOURCE_ON) ? "On" : "Off"); + + g_server_status = status; + + return 0; + +error: + g_error_free (err); + g_object_unref(conn); + return -1; +} + int main(int argc, char *argv[]) { int sockfd = -1; @@ -752,4 +941,3 @@ int main(int argc, char *argv[]) scmirroring_debug("MIRACAST SERVER EXIT \n"); exit(0); } - diff --git a/org.tizen.scmirroring.server.service b/org.tizen.scmirroring.server.service index 3c1c6a3..19ead85 100644 --- a/org.tizen.scmirroring.server.service +++ b/org.tizen.scmirroring.server.service @@ -1,4 +1,5 @@ [D-BUS Service] Name=org.tizen.scmirroring.server -Exec=/bin/sh -c 'export GST_DEBUG=2,*rtsp*:5;/usr/bin/miracast_server' +Exec=/bin/sh -c 'export GST_DEBUG=2,*rtsp*:5;export DISPLAY=:0;/usr/bin/miracast_server' User=system +Group=video diff --git a/packaging/capi-media-screen-mirroring.spec b/packaging/capi-media-screen-mirroring.spec index b4c3e8e..bb49f34 100755 --- a/packaging/capi-media-screen-mirroring.spec +++ b/packaging/capi-media-screen-mirroring.spec @@ -1,6 +1,6 @@ Name: capi-media-screen-mirroring Summary: A screen mirroring library in Tizen C API -Version: 0.1.23 +Version: 0.1.30 Release: 0 Group: Multimedia/API License: Apache License, Version 2.0 @@ -56,8 +56,8 @@ make %{?jobs:-j%jobs} %install rm -rf %{buildroot} %make_install -mkdir -p %{buildroot}/usr/share/dbus-1/services/ -install -m 755 org.tizen.scmirroring.server.service %{buildroot}/usr/share/dbus-1/services/ +mkdir -p %{buildroot}/usr/share/dbus-1/system-services/ +install -m 755 org.tizen.scmirroring.server.service %{buildroot}/usr/share/dbus-1/system-services/ mkdir -p %{buildroot}/%{_datadir}/license cp -rf %{_builddir}/%{name}-%{version}/LICENSE.APLv2.0 %{buildroot}%{_datadir}/license/%{name} @@ -76,7 +76,7 @@ cp -rf config/scmirroring_src.ini %{buildroot}/usr/etc/scmirroring_src.ini %files %manifest capi-media-screen-mirroring.manifest %{_libdir}/libcapi-media-screen-mirroring.so* -%{_datadir}/dbus-1/services/org.tizen.scmirroring.server.service +%{_datadir}/dbus-1/system-services/org.tizen.scmirroring.server.service #License %{_datadir}/license/%{name} %{_bindir}/miracast_server diff --git a/src/scmirroring_src.c b/src/scmirroring_src.c index 26c99b2..37eb0e1 100755 --- a/src/scmirroring_src.c +++ b/src/scmirroring_src.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -67,8 +69,9 @@ static int __scmirroring_src_send_cmd_to_server(scmirroring_src_s *scmirroring, scmirroring_retvm_if(cmd == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "cmd is NULL"); _cmd = g_strdup(cmd); + _cmd[strlen(_cmd)] = '\0'; - if (write(scmirroring->sock, _cmd, strlen(_cmd)) != (signed int) strlen(_cmd)) { + if (write(scmirroring->sock, _cmd, strlen(_cmd) + 1) != (signed int) strlen(_cmd) + 1) { scmirroring_error("sendto failed [%s]", strerror(errno)); ret = SCMIRRORING_ERROR_INVALID_OPERATION; } else { @@ -122,7 +125,7 @@ static int __miracast_server_launch(scmirroring_src_s *scmirroring) return SCMIRRORING_ERROR_INVALID_OPERATION; } - scmirroring_debug("scmirroring_proxy_initialize trying for connect"); + scmirroring_debug("Miracast server is launched successfully"); return ret; } @@ -206,7 +209,12 @@ static void __scmirroring_src_interpret(scmirroring_src_s *scmirroring, char *bu src_state = __scmirroring_src_get_status(response[1]);; g_strfreev(response); - __scmirroring_src_set_callback_info (scmirroring, error_code, src_state); + if (scmirroring->current_state != src_state) { + scmirroring->current_state = src_state; + __scmirroring_src_set_callback_info (scmirroring, error_code, src_state); + } else { + scmirroring_debug("Current state is already %d", src_state); + } return; } @@ -223,10 +231,26 @@ gboolean __scmirroring_src_read_cb(GIOChannel *src, GIOCondition condition, gpoi if (read == 0) { scmirroring_error("Read 0 bytes"); return FALSE; + } else { + scmirroring_debug("Read %d bytes", read); + } + + int i = 0; + int idx = 0; + + /* Handling multiple response like "CMD1\0CMD2\0CMD3\0" */ + for (i = 0; i < read; i++) { + gchar *str = NULL; + if (buf[i] == '\0') { + str = buf + idx; + idx = i + 1; + } else { + continue; + } + scmirroring_debug("Handling %s", str); + __scmirroring_src_interpret (_scmirroring, str); + if (idx >= read) break; } - buf[read] = '\0'; - g_strstrip(buf); - __scmirroring_src_interpret(_scmirroring, buf); } else if (condition & G_IO_ERR) { scmirroring_error("got G_IO_ERR"); return FALSE; @@ -305,9 +329,6 @@ int scmirroring_src_create(scmirroring_src_h *scmirroring) { int ret = SCMIRRORING_ERROR_NONE; scmirroring_src_s *_scmirroring = NULL; - int sock = -1; - GIOChannel *channel = NULL; - struct timeval tv_timeout = { TIMEOUT_SEC, 0 }; scmirroring_debug_fenter(); @@ -322,30 +343,11 @@ int scmirroring_src_create(scmirroring_src_h *scmirroring) _scmirroring->use_hdcp = TRUE; _scmirroring->resolution = 0; _scmirroring->connect_mode = SCMIRRORING_CONNECTION_WIFI_DIRECT; - - /*Create TCP Socket*/ - - if ((sock = socket(PF_FILE, SOCK_STREAM, 0)) < 0) { - scmirroring_error("socket failed: %s", strerror(errno)); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(tv_timeout)) == -1) { - scmirroring_error("setsockopt failed: %s", strerror(errno)); - close(sock); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - channel = g_io_channel_unix_new(sock); - if (channel == NULL) { - scmirroring_error("g_io_channel_unix_new failed: %s", strerror(errno)); - } - - g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); - - _scmirroring->sock = sock; - _scmirroring->channel = channel; - _scmirroring->sock_path = g_strdup("/tmp/.miracast_ipc_rtspserver"); + _scmirroring->scmirroring_state_cb = NULL; + _scmirroring->sock = -1; + _scmirroring->channel = NULL; + _scmirroring->sock_path = NULL; + _scmirroring->current_state = SCMIRRORING_STATE_NONE; *scmirroring = (scmirroring_src_h)_scmirroring; @@ -364,9 +366,9 @@ int scmirroring_src_set_connection_mode(scmirroring_src_h scmirroring, scmirrori scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); - if((connect_mode < SCMIRRORING_CONNECTION_WIFI_DIRECT) ||(connect_mode > SCMIRRORING_CONNECTION_MAX)) + if((connect_mode < SCMIRRORING_CONNECTION_WIFI_DIRECT) ||(connect_mode >= SCMIRRORING_CONNECTION_MAX)) { - scmirroring_error("INVALID Connection mode"); + scmirroring_error("INVALID Connection mode : %d", connect_mode); return SCMIRRORING_ERROR_INVALID_PARAMETER; } @@ -393,8 +395,15 @@ int scmirroring_src_set_state_changed_cb(scmirroring_src_h scmirroring, scmirror scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); scmirroring_retvm_if(callback == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "callback is NULL"); - _scmirroring->scmirroring_state_cb = (scmirroring_state_cb_s*)calloc(1, sizeof(scmirroring_state_cb_s)); - scmirroring_retvm_if(_scmirroring->scmirroring_state_cb == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Error Set CB"); + if(_scmirroring->scmirroring_state_cb == NULL) + { + _scmirroring->scmirroring_state_cb = (scmirroring_state_cb_s*)calloc(1, sizeof(scmirroring_state_cb_s)); + scmirroring_retvm_if(_scmirroring->scmirroring_state_cb == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Error Set CB"); + } + else + { + memset(_scmirroring->scmirroring_state_cb, 0, sizeof(scmirroring_state_cb_s)); + } _scmirroring->scmirroring_state_cb->user_data = user_data; _scmirroring->scmirroring_state_cb->state_cb = callback; @@ -404,6 +413,29 @@ int scmirroring_src_set_state_changed_cb(scmirroring_src_h scmirroring, scmirror return ret; } +int scmirroring_src_unset_state_changed_cb(scmirroring_src_h scmirroring) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_src_s *_scmirroring = (scmirroring_src_s*)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + if(_scmirroring->scmirroring_state_cb != NULL) + { + _scmirroring->scmirroring_state_cb->user_data = NULL; + _scmirroring->scmirroring_state_cb->state_cb = NULL; + } + + SCMIRRORING_SAFE_FREE(_scmirroring->scmirroring_state_cb); + + scmirroring_debug_fleave(); + + return ret; +} + int scmirroring_src_set_ip_and_port(scmirroring_src_h scmirroring, const char *ip, const char *port) { int ret = SCMIRRORING_ERROR_NONE; @@ -445,9 +477,9 @@ int scmirroring_src_set_resolution(scmirroring_src_h scmirroring, scmirroring_re scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); - if((resolution < SCMIRRORING_RESOLUTION_1920x1080_P30) ||(resolution > SCMIRRORING_RESOLUTION_MAX)) + if((resolution < SCMIRRORING_RESOLUTION_1920x1080_P30) ||(resolution >= SCMIRRORING_RESOLUTION_MAX)) { - scmirroring_error("INVALID resolution"); + scmirroring_error("INVALID resolution : %d", resolution); return SCMIRRORING_ERROR_INVALID_PARAMETER; } @@ -468,12 +500,40 @@ int scmirroring_src_connect(scmirroring_src_h scmirroring) int ret = SCMIRRORING_ERROR_NONE; int retry = 0; struct sockaddr_un serv_addr; + int sock = -1; + GIOChannel *channel = NULL; + struct timeval tv_timeout = { TIMEOUT_SEC, 0 }; scmirroring_src_s *_scmirroring = (scmirroring_src_s*)scmirroring; scmirroring_debug_fenter(); scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->connected == CONNECTED_TO_SERVER, SCMIRRORING_ERROR_INVALID_OPERATION, + "INVALID OPERATION, already connected to server."); + + /*Create TCP Socket*/ + if ((sock = socket(PF_FILE, SOCK_STREAM, 0)) < 0) { + scmirroring_error("socket failed: %s", strerror(errno)); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(tv_timeout)) == -1) { + scmirroring_error("setsockopt failed: %s", strerror(errno)); + close(sock); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + channel = g_io_channel_unix_new(sock); + if (channel == NULL) { + scmirroring_error("g_io_channel_unix_new failed: %s", strerror(errno)); + } + + g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); + + _scmirroring->sock = sock; + _scmirroring->channel = channel; + _scmirroring->sock_path = g_strdup("/tmp/.miracast_ipc_rtspserver"); /* Connecting to the miracast server */ memset(&serv_addr, 0, sizeof(struct sockaddr_un)); @@ -504,7 +564,7 @@ try: scmirroring_error("Connect error : %s", strerror(errno)); close(_scmirroring->sock); - _scmirroring->sock = 0; + _scmirroring->sock = -1; return SCMIRRORING_ERROR_INVALID_OPERATION; } } else { @@ -516,22 +576,23 @@ try: source = g_io_create_watch(_scmirroring->channel, G_IO_IN | G_IO_HUP | G_IO_ERR); int source_id = -1; - if((_scmirroring->ip != NULL) ||(_scmirroring->port != NULL)) - { - ret = __scmirroring_src_send_set_ip (_scmirroring); - ret = __scmirroring_src_send_set_cm (_scmirroring); - ret = __scmirroring_src_send_set_reso (_scmirroring); - } - /* Set callback to be called when socket is readable */ g_source_set_callback(source, (GSourceFunc)__scmirroring_src_read_cb, _scmirroring, NULL); source_id = g_source_attach(source, g_main_context_get_thread_default()); _scmirroring->source_id = source_id; _scmirroring->connected = CONNECTED_TO_SERVER; + _scmirroring->current_state = SCMIRRORING_STATE_READY; __scmirroring_src_set_callback_info (_scmirroring, SCMIRRORING_ERROR_NONE, SCMIRRORING_STATE_READY); + if((_scmirroring->ip != NULL) ||(_scmirroring->port != NULL)) + { + ret = __scmirroring_src_send_set_ip (_scmirroring); + ret = __scmirroring_src_send_set_cm (_scmirroring); + ret = __scmirroring_src_send_set_reso (_scmirroring); + } + scmirroring_debug_fleave(); return ret; @@ -547,9 +608,20 @@ int scmirroring_src_disconnect(scmirroring_src_h scmirroring) scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); - g_io_channel_shutdown (_scmirroring->channel, FALSE, NULL); - g_io_channel_unref(_scmirroring->channel); - close (_scmirroring->sock); + if(_scmirroring->channel != NULL) + { + g_io_channel_shutdown (_scmirroring->channel, FALSE, NULL); + g_io_channel_unref(_scmirroring->channel); + _scmirroring->channel = NULL; + } + + if(_scmirroring->sock != -1) + { + close (_scmirroring->sock); + _scmirroring->sock = -1; + } + + SCMIRRORING_SAFE_FREE(_scmirroring->sock_path); _scmirroring->connected = NOT_CONNECTED_TO_SERVER; scmirroring_debug_fleave(); @@ -638,9 +710,19 @@ int scmirroring_src_destroy(scmirroring_src_h scmirroring) scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); - ret = __scmirroring_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_DESTROY); - if(ret != SCMIRRORING_ERROR_NONE) - scmirroring_error("Failed to destroy [%d]", ret); + if(_scmirroring->connected == CONNECTED_TO_SERVER) + { + ret = __scmirroring_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_DESTROY); + if(ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to destroy [%d]", ret); + } + else + { + SCMIRRORING_SAFE_FREE(_scmirroring->ip); + SCMIRRORING_SAFE_FREE(_scmirroring->port); + SCMIRRORING_SAFE_FREE(_scmirroring->scmirroring_state_cb); + SCMIRRORING_SAFE_FREE(_scmirroring); + } scmirroring_debug_fleave(); diff --git a/test/scmirroring_test.c b/test/scmirroring_test.c index da75060..d674f3f 100755 --- a/test/scmirroring_test.c +++ b/test/scmirroring_test.c @@ -46,7 +46,7 @@ static void __displaymenu(void) g_print(" SCMIRRORING Testsuite (press q to quit) \n"); g_print("=====================================================================\n"); g_print("a : a ip port (ex. a 192.168.49.1 2022)\n"); - g_print("c : set resopution (ex. c 0 (0 : 1920x1080_P30, 1 : 1280x720_P30, 2 : 960x540_P30, 3: 640x360_P30)\n"); + g_print("c : set resolution (ex. c 0 (0 : 1920x1080_P30, 1 : 1280x720_P30, 2 : 960x540_P30, 3: 640x360_P30)\n"); g_print("f : set connection mode (ex. f 0 (0 : wifi_direct, 1 : Other)\n"); g_print("C : Connect\n"); g_print("I : dIsconnect\n"); diff --git a/test/scmirroring_wifi_direct_test.c b/test/scmirroring_wifi_direct_test.c index aea8588..4daeef8 100755 --- a/test/scmirroring_wifi_direct_test.c +++ b/test/scmirroring_wifi_direct_test.c @@ -63,7 +63,7 @@ static void __displaymenu(void) g_print("=====================================================================\n"); g_print("a : a ip port (ex. a 192.168.49.1 2022)\n"); g_print("b : set sink device mac address (ex. b f8:d0:bd:7f:e9:7c)\n"); - g_print("c : set resopution (ex. c 0 (0 : 1920x1080_P30, 1 : 1280x720_P30, 2 : 960x540_P30, 3: 640x360_P30)\n"); + g_print("c : set resolution (ex. c 0 (0 : 1920x1080_P30, 1 : 1280x720_P30, 2 : 960x540_P30, 3: 640x360_P30)\n"); g_print("f : set connection mode (ex. f 0 (0 : wifi_direct, 1 : Other)\n"); g_print("C : Connect\n"); g_print("I : dIsconnect\n"); @@ -83,6 +83,21 @@ gboolean __timeout_menu_display(void* data) return FALSE; } +static int __wifi_direct_device_connect() +{ + if (strlen(g_sink_mac_addr) > 17 || strlen(g_sink_mac_addr) <= 0) { + g_print("\nWrong Mac_address"); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + int err= wifi_direct_connect(g_sink_mac_addr); + if (err != WIFI_DIRECT_ERROR_NONE) { + g_print("Failed to connect [%d]\n", err); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + return SCMIRRORING_ERROR_NONE; +} + static void __interpret (char *cmd) { int ret = SCMIRRORING_ERROR_NONE; @@ -99,6 +114,7 @@ static void __interpret (char *cmd) strncpy (g_sink_mac_addr, value[1], sizeof (g_sink_mac_addr)); g_sink_mac_addr[17] = '\0'; g_print ("Sink mac address : %s\n", g_sink_mac_addr); + ret = __wifi_direct_device_connect(); } else if (strncmp(cmd, "c", 1) == 0) { @@ -268,18 +284,6 @@ void _discover_cb(int error_code, wifi_direct_discovery_state_e discovery_state, break; case WIFI_DIRECT_DISCOVERY_FINISHED: g_print("discovery_state : WIFI_DIRECT_DISCOVERY_FINISHED \n"); - - if (strlen(g_sink_mac_addr) > 17 || strlen(g_sink_mac_addr) <= 0) { - g_print("\nWrong Mac_address"); - return; - } - - int err= wifi_direct_connect(g_sink_mac_addr); - if (err != WIFI_DIRECT_ERROR_NONE) { - g_print("Failed to connect [%d]\n", err); - return; - } - break; default: g_print("discovery_state : ERROR\n"); @@ -291,7 +295,19 @@ void _discover_cb(int error_code, wifi_direct_discovery_state_e discovery_state, void _ip_assigned_cb(const char *mac_address, const char *ip_address, const char *interface_address, void *user_data) { + char *local_ip = NULL; + + wifi_direct_get_ip_address (&local_ip); + + if (!local_ip) { + g_print ("Failed to get local ip\n"); + return; + } + g_print("[_ip_assigned_cb] IP assigned [ ip addr : %s if addr : %s mac_addr:%s ]\n", ip_address, interface_address, mac_address); + + scmirroring_src_set_ip_and_port(g_scmirroring, local_ip, "2022"); + g_print ("Input server IP and port number IP[%s] Port[%s]\n", local_ip, "2022"); } void _connection_cb(int error_code, wifi_direct_connection_state_e connection_state, const char *mac_address, void *user_data) @@ -411,24 +427,23 @@ static gboolean __start_p2p_connection(gpointer data) } } - /*Enable Screen Mirroring*/ #if 0 - ret = wifi_direct_display_init(); + /*Enable Screen Mirroring*/ + ret = wifi_direct_init_display(); if(ret != WIFI_DIRECT_ERROR_NONE) { - g_print("Error : wifi_direct_display_init failed : %d\n", ret); + g_print("Error : wifi_direct_init_display failed : %d\n", ret); goto error; } - /*Enable Wifi Direct - You can set this as true if you want to see it from wifi-direct list*/ - ret = wifi_direct_display_set_wifi_direct(FALSE); + ret = wifi_direct_set_display_availability(TRUE); if(ret != WIFI_DIRECT_ERROR_NONE) { - g_print("Error : wifi_direct_display_init failed : %d\n", ret); + g_print("Error : wifi_direct_set_display_availability failed : %d\n", ret); goto error; } - ret = wifi_direct_display_set_device(WIFI_DISPLAY_TYPE_PRIMARY_SINK, 77, 0); + ret = wifi_direct_set_display(WIFI_DISPLAY_TYPE_SRC, 2022, 0); if(ret != WIFI_DIRECT_ERROR_NONE) { g_print("Error : wifi_direct_display_set_device failed : %d\n", ret);