<manifest>
+ <define>
+ <domain name="miracast-server" policy="restricted" />
+ <request>
+ <smack request="system::use_internet" type="rwxat"/>
+ <smack request="device::app_logging" type="w"/>
+ <smack request="device::sys_logging" type="w"/>
+ <smack request="security-server::api-privilege-by-pid" type="w"/>
+ <smack request="dbus" type="rwxat"/>
+ <smack request="xorg" type="rwx"/>
+ <smack request="system::share" type="rwxat"/>
+ <smack request="pulseaudio" type="rwxat"/>
+ <smack request="pulseaudio::record" type="rwxat"/>
+ <smack request="device::hwcodec" type="rw"/>
+ <smack request="drmfw" type="rw"/>
+ <smack request="wifi-direct" type="rwx"/>
+ <smack request="wifi-direct::admin" type="rwx"/>
+ <smack request="wifi-direct::discover" type="rwx"/>
+ <smack request="wifi-direct::info" type="rwx"/>
+ <smack request="wifi-direct::native" type="rwx"/>
+ </request>
+ <permit>
+ <smack permit="dbus" type="rwxat"/>
+ <smack permit="system::use_internet" type="rwxat"/>
+ </permit>
+ </define>
<request>
<domain name="_" />
</request>
+ <assign>
+ <filesystem path="/usr/bin/miracast_server" label="miracast-server" exec_label="miracast-server" />
+ </assign>
</manifest>
-
/**
* @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 <scmirroring_type.h>
+ * \#include <scmirroring_sink.h>
+ * @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 <scmirroring_src.h>
+ * @section CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE_HEADER Required Header
* \#include <scmirroring_sink.h>
*
- * @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
+ * <div><table class="doxtable" >
+ * <tr>
+ * <th><b>FUNCTION</b></th>
+ * <th><b>PRE-STATE</b></th>
+ * <th><b>POST-STATE</b></th>
+ * <th><b>SYNC TYPE</b></th>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_create()</td>
+ * <td>NONE</td>
+ * <td>NULL</td>
+ * <td>SYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_destroy()</td>
+ * <td>NULL</td>
+ * <td>NONE</td>
+ * <td>SYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_prepare()</td>
+ * <td>NULL</td>
+ * <td>PREPARED</td>
+ * <td>SYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_unprepare()</td>
+ * <td>PREARED, DISCONNECTED</td>
+ * <td>NULL</td>
+ * <td>SYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_connect()</td>
+ * <td>PREARED</td>
+ * <td>CONNECTED</td>
+ * <td>ASYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_start()</td>
+ * <td>CONNECTED</td>
+ * <td>PLAYING</td>
+ * <td>ASYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_disconnect()</td>
+ * <td>CONNECTED, PAUSED or PLAYING </td>
+ * <td>DISCONNECTED </td>
+ * <td>SYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_pause()</td>
+ * <td>PLAYING</td>
+ * <td>PAUSED</td>
+ * <td>ASYNC</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_resume()</td>
+ * <td>PAUSED</td>
+ * <td>PLAYING</td>
+ * <td>ASYNC</td>
+ * </tr>
+ * </table></div>
+ *
+ *
+ *@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.
+ * <div><table class="doxtable" >
+ * <tr>
+ * <th><b>FUNCTION</b></th>
+ * <th><b>VALID STATES</b></th>
+ * <th><b>DESCRIPTION</b></th>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_create() </td>
+ * <td>NONE</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_destroy()</td>
+ * <td>NULL</td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_set_state_changed_cb()</td>
+ * <td>NULL/ PREPARED/ CONNECTED/ PLAYING/ PAUSED/ DISCONNECTED</td>
+ * <td>This function must be called after scmirroring_sink_create().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_unset_state_changed_cb()</td>
+ * <td>NULL/ PREPARED/ CONNECTED/ PLAYING/ PAUSED/ DISCONNECTED</td>
+ * <td>This function must be called after register callback function.</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_set_display()</td>
+ * <td>NULL</td>
+ * <td>This function must be called before scmirroring_sink_prepare().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_set_resolution()</td>
+ * <td>NULL</td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_prepare() </td>
+ * <td>NULL</td>
+ * <td>This function must be called after scmirroring_sink_create().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_unprepare() </td>
+ * <td>PREPARED/ DISCONNECTED </td>
+ * <td></td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_set_ip_and_port() </td>
+ * <td>NULL/ PREPARED</td>
+ * <td>This function must be called before scmirroring_sink_connect().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_connect()</td>
+ * <td>PREPARED</td>
+ * <td>This function must be called after scmirroring_sink_prepare().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_pause()</td>
+ * <td>PLAYING</td>
+ * <td>This function must be called after scmirroring_sink_start().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_resume()</td>
+ * <td>PAUSED</td>
+ * <td>This function must be called after scmirroring_sink_pause().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_start()</td>
+ * <td>CONNECTED</td>
+ * <td>This function must be called after scmirroring_sink_connect().</td>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_disconnect() </td>
+ * <td>CONNECTED/ PLAYING/ PAUSED</td>
+ * <td></td>
+ * </tr>
+ * </table></div>
+ *
+ * @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
+ * <div><table class="doxtable" >
+ * <tr>
+ * <th><b>REGISTER</b></th>
+ * <th><b>UNREGISTER</b></th>
+ * <th><b>CALLBACK</b></th>
+ * <th><b>DESCRIPTION</b></th>
+ * </tr>
+ * <tr>
+ * <td>scmirroring_sink_set_state_changed_cb()</td>
+ * <td>scmirroring_sink_unset_state_changed_cb()</td>
+ * <td>scmirroring_state_cb()</td>
+ * <td>This callback is called for state and error of screen mirroring.</td>
+ * </tr>
+ *</table></div>
*/
+
#endif /* __TIZEN_SCREEN_MIRRORING_DOC_H__ */
GIOChannel *channel;
char *sock_path;
int connect_mode;
+ int current_state;
scmirroring_state_cb_s *scmirroring_state_cb;
} scmirroring_src_s;
*/
/**
- * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE
+ * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_SINK_MODULE
* @{
*/
*/
/**
- * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE
+ * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_SRC_MODULE
* @{
*/
* @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.
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <gio/gio.h>
#include <gst/rtsp-server/rtsp-server-wfd.h>
#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,
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,
/* Introspection data for the service we are exporting */
static const gchar introspection_xml[] =
"<node>"
- " <interface name='org.tizen.scmirroring.server'>"
+ " <interface name='"PROC_DBUS_INTERFACE"'>"
" <method name='launch_method'>"
" </method>"
+ " <method name='get_miracast_wfd_source_status'>"
+ " <arg type='i' name='status' direction='out'/>"
+ " </method>"
" </interface>"
"</node>";
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));
+ }
}
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,
obj->server = NULL;
obj->client = NULL;
obj->factory = NULL;
+ obj->resolution = -1;
}
static void miracast_server_object_class_init(MiracastServerObjectClass * klass)
}
_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 {
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);
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);
}
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,
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;
#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)
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);
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;
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;
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;
/* 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;
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;
scmirroring_debug("MIRACAST SERVER EXIT \n");
exit(0);
}
-
[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
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
%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}
%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
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
+#include <linux/socket.h>
+#include <netinet/tcp.h>
#include <scmirroring_src.h>
#include <scmirroring_private.h>
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 {
return SCMIRRORING_ERROR_INVALID_OPERATION;
}
- scmirroring_debug("scmirroring_proxy_initialize trying for connect");
+ scmirroring_debug("Miracast server is launched successfully");
return ret;
}
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;
}
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;
{
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();
_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;
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;
}
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;
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;
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;
}
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));
scmirroring_error("Connect error : %s", strerror(errno));
close(_scmirroring->sock);
- _scmirroring->sock = 0;
+ _scmirroring->sock = -1;
return SCMIRRORING_ERROR_INVALID_OPERATION;
}
} else {
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;
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();
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();
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");
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");
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;
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)
{
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");
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)
}
}
- /*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);