From: Hyunjun Ko Date: Tue, 11 Aug 2015 04:11:01 +0000 (+0900) Subject: Chnage miracast-server structure to be able to inherit. X-Git-Tag: submit/tizen/20150819.094203~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5eb38d15705a73dd8977005b5dc5bbc3afe55735;p=platform%2Fcore%2Fapi%2Fscreen-mirroring.git Chnage miracast-server structure to be able to inherit. Change-Id: I71102b146e458385b8c4e8ca32fd84d70e6b9d4d Signed-off-by: Sangkyu Park --- diff --git a/miracast_server/CMakeLists.txt b/miracast_server/CMakeLists.txt index cbfa6f3..0bc3a25 100755 --- a/miracast_server/CMakeLists.txt +++ b/miracast_server/CMakeLists.txt @@ -13,11 +13,11 @@ ENDFOREACH(flag) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror -pie") aux_source_directory(. sources) -FOREACH(src ${sources}) - GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) - MESSAGE("${src_name}") - ADD_EXECUTABLE(${src_name} ${src}) - TARGET_LINK_LIBRARIES(${src_name} ${fw_name} ${${fw_test}_LDFLAGS}) -ENDFOREACH() -INSTALL(TARGETS ${src_name} DESTINATION /usr/bin) +ADD_LIBRARY(miracast_server_lib SHARED miracast_server_impl.c) +TARGET_LINK_LIBRARIES(miracast_server_lib ${fw_name} ${${fw_test}_LDFLAGS}) +INSTALL(TARGETS miracast_server_lib DESTINATION ${LIB_INSTALL_DIR}) + +ADD_EXECUTABLE(miracast_server miracast_server.c) +TARGET_LINK_LIBRARIES(miracast_server ${fw_name} ${${fw_test}_LDFLAGS} miracast_server_lib) +INSTALL(TARGETS miracast_server DESTINATION /usr/bin) diff --git a/miracast_server/miracast_server.c b/miracast_server/miracast_server.c index 8e9bc57..f135e75 100755 --- a/miracast_server/miracast_server.c +++ b/miracast_server/miracast_server.c @@ -1,5 +1,5 @@ /* - * capi-media-streaming + * miracast-server * * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. * @@ -20,939 +20,39 @@ */ #include -#include -#include -#include -#include -#include -#include - -#include -#include - +#include "miracast_server.h" #include "scmirroring_private.h" -#include "scmirroring_src_ini.h" - -#define MAX_CLIENT_CNT 1 -#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, - (char *)"launch_method", - NULL, - NULL, - NULL -}; -static const GDBusMethodInfo *const scmirroring_server_method_info_pointers[] = {&scmirroring_server_method_info_method, NULL}; - -static const GDBusInterfaceInfo scmirroring_server_interface_info = { - -1, - (char *)PROC_DBUS_INTERFACE, - (GDBusMethodInfo **) &scmirroring_server_method_info_pointers, - (GDBusSignalInfo **) NULL, - (GDBusPropertyInfo **) NULL, - NULL, -}; - -static GDBusNodeInfo *introspection_data = NULL; - -/* Introspection data for the service we are exporting */ -static const gchar introspection_xml[] = - "" - " " - " " - " " - " " - " " - " " - " " - ""; - - -static void -handle_method_call(GDBusConnection *connection, - const gchar *sender, - const gchar *object_path, - const gchar *interface_name, - const gchar *method_name, - GVariant *parameters, - 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) { - 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)); - } -} - - -/* for now */ -static const GDBusInterfaceVTable interface_vtable = { - handle_method_call, - NULL, - NULL, - {NULL} -}; - -static void -on_bus_acquired(GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - guint registration_id; - - scmirroring_debug("on_bus_acquired called\n"); - registration_id = g_dbus_connection_register_object(connection, - PROC_DBUS_OBJECT, - introspection_data->interfaces[0], - &interface_vtable, - NULL, - NULL, /* user_data_free_func */ - NULL); /* GError** */ - g_assert(registration_id > 0); -} - -static void -on_name_acquired(GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - scmirroring_debug("on_name_acquired called\n"); -} - -static void -on_name_lost(GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - scmirroring_debug("on_name_lost called\n"); -} - -typedef struct _MiracastServerObject MiracastServerObject; -typedef struct _MiracastServerObjectClass MiracastServerObjectClass; - -GType miracast_server_object_get_type(void); -struct _MiracastServerObject { - GObject parent; - - GIOChannel *client_channel; - gchar *ip; - gchar *port; - void *server; - void *client; - void *factory; - gint resolution; - gint connection_mode; -}; - -struct _MiracastServerObjectClass { - GObjectClass parent; -}; - -#define MIRACAST_SERVER_TYPE_OBJECT (miracast_server_object_get_type()) - -#define MIRACAST_SERVER_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST \ - ((object), MIRACAST_SERVER_TYPE_OBJECT, MiracastServerObject)) - -G_DEFINE_TYPE(MiracastServerObject, miracast_server_object, G_TYPE_OBJECT); - -static void miracast_server_object_init(MiracastServerObject *obj) -{ - scmirroring_debug("miracast_server_object_init\n"); - - obj->client_channel = NULL; - obj->ip = NULL; - obj->port = NULL; - obj->server = NULL; - obj->client = NULL; - obj->factory = NULL; - obj->resolution = -1; -} - -static void miracast_server_object_class_init(MiracastServerObjectClass *klass) -{ - scmirroring_debug("miracast_server_object_class_init\n"); -} - -int __miracast_server_send_resp(MiracastServerObject *server, const char *cmd) -{ - int ret = SCMIRRORING_ERROR_NONE; - char *_cmd = NULL; - int client_sock = -1; - - if (server == NULL) { - scmirroring_error("OUT_OF_MEMORY"); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - client_sock = g_io_channel_unix_get_fd(server->client_channel); - if (client_sock < 0) { - scmirroring_error("client sock fd is invalid!"); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - _cmd = g_strdup(cmd); - _cmd[strlen(_cmd)] = '\0'; - - if (write(client_sock, _cmd, strlen(_cmd) + 1) != ((int)(strlen(_cmd) + 1))) { - scmirroring_error("sendto failed [%s]", strerror(errno)); - ret = SCMIRRORING_ERROR_INVALID_OPERATION; - } else { - scmirroring_debug("Sent response [%s] successfully", _cmd); - } - - g_free(_cmd); - return ret; -} - -static void __miracast_server_quit_program(MiracastServerObject *server) -{ - scmirroring_error("Quit program is called"); - - void *pool = NULL; - 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); - if (pool) { - gst_rtsp_session_pool_cleanup(pool); - g_object_unref(pool); - } - - int serv_ref_cnt = GST_OBJECT_REFCOUNT_VALUE(server->server); - scmirroring_debug("serv ref cnt:%d", serv_ref_cnt); - - for (i = 0; i < serv_ref_cnt; i++) - g_object_unref(server->server); - -done: - __miracast_server_send_resp(server, "OK:DESTROY"); - g_main_loop_quit(g_mainloop); -} - -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); -} - -static void __miracast_server_set_signal() -{ - /*SIGABRT A Process abort signal. - SIGALRM T Alarm clock. - SIGBUS A Access to an undefined portion of a memory object. - SIGCHLD I Child process terminated, stopped, - SIGCONT C Continue executing, if stopped. - SIGFPE A Erroneous arithmetic operation. - SIGHUP T Hangup. - SIGILL A Illegal instruction. - SIGINT T Terminal interrupt signal. - SIGKILL T Kill(cannot be caught or ignored). - SIGPIPE T Write on a pipe with no one to read it. - SIGQUIT A Terminal quit signal. - SIGSEGV A Invalid memory reference. - SIGSTOP S Stop executing(cannot be caught or ignored). - SIGTERM T Termination signal. - SIGTSTP S Terminal stop signal. - SIGTTIN S Background process attempting read. - SIGTTOU S Background process attempting write. - SIGUSR1 T User-defined signal 1. - SIGUSR2 T User-defined signal 2. - SIGPOLL T Pollable event. - SIGPROF T Profiling timer expired. - SIGSYS A Bad system call. - SIGTRAP A Trace/breakpoint trap. - SIGURG I High bandwidth data is available at a socket. - SIGVTALRM T Virtual timer expired. - SIGXCPU A CPU time limit exceeded. - SIGXFSZ A File size limit exceeded. - - The default actions are as follows: - T : Abnormal termination of the process. The process is terminated with all the consequences of _exit() - A : Abnormal termination of the process. - I : Ignore the signal. - S : Stop the process - */ - struct sigaction act_new; - memset(&act_new, 0, sizeof(struct sigaction)); - - act_new.sa_handler = __miracast_server_signal_handler; - - sigaction(SIGABRT, &act_new, NULL); - sigaction(SIGBUS, &act_new, NULL); - sigaction(SIGINT, &act_new, NULL); - sigaction(SIGKILL, &act_new, NULL); - sigaction(SIGPIPE, &act_new, NULL); - sigaction(SIGQUIT, &act_new, NULL); - sigaction(SIGSEGV, &act_new, NULL); - sigaction(SIGTERM, &act_new, NULL); - sigaction(SIGSYS, &act_new, NULL); -} - -static bool __miracast_server_setup() -{ - GObject *object = NULL; - scmirroring_debug("__miracast_server_setup start\n"); - - introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); - if (introspection_data == NULL) { - scmirroring_error("Introspection data is NULL"); - return false; - } - - object = g_object_new(MIRACAST_SERVER_TYPE_OBJECT, NULL); - - g_bus_own_name(G_BUS_TYPE_SYSTEM, - PROC_DBUS_INTERFACE, - G_BUS_NAME_OWNER_FLAGS_NONE, - on_bus_acquired, - on_name_acquired, - on_name_lost, - object, - NULL); - - g_server_object = object; - - __miracast_server_set_signal(); - scmirroring_debug("__miracast_server_setup end\n"); - - return true; -} - -static gboolean __miracast_server_ready_channel(int *sockfd) -{ - int sock; - int i; - gboolean bind_success = FALSE; - struct sockaddr_un serv_addr; - - /* Create a TCP socket */ - if ((sock = socket(PF_FILE, SOCK_STREAM, 0)) < 0) { - scmirroring_error("socket failed: %s", strerror(errno)); - return FALSE; - } - - memset(&serv_addr, 0, sizeof(serv_addr)); - - serv_addr.sun_family = AF_UNIX; - unlink(MEDIA_IPC_PATH); - strncpy(serv_addr.sun_path, MEDIA_IPC_PATH, sizeof(serv_addr.sun_path)); - - /* Bind to the local address */ - for (i = 0; i < 20; i++) { - if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { - bind_success = true; - break; - } - usleep(250000); - } - - if (bind_success == false) { - scmirroring_error("bind failed : %s %d_", strerror(errno), errno); - close(sock); - return FALSE; - } - - scmirroring_debug("bind success"); - - /* Listening */ - if (listen(sock, SOMAXCONN) < 0) { - scmirroring_error("listen failed : %s", strerror(errno)); - close(sock); - 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; - - return TRUE; -} - -void __miracast_server_msg_cb(gboolean is_error, void *userdata) -{ - /*MiracastServerObject *server = (MiracastServerObject *)userdata; */ - - if (is_error) { - scmirroring_error("Error occured"); - } -} - -int __miracast_server_gst_init() -{ - gint *argc = NULL; - gchar **argv = NULL; - static const int max_argc = 50; - GError *err = NULL; - int i = 0; - - /* alloc */ - argc = calloc(1, sizeof(int)); - if (!argc) { - scmirroring_error("Cannot allocate memory for scmirroringsink\n"); - return SCMIRRORING_ERROR_OUT_OF_MEMORY; - } - - argv = calloc(max_argc, sizeof(gchar *)); - if (!argv) { - scmirroring_error("Cannot allocate memory for scmirroringsink\n"); - SCMIRRORING_SAFE_FREE(argc); - return SCMIRRORING_ERROR_OUT_OF_MEMORY; - } - - /* we would not do fork for scanning plugins */ - argv[*argc] = g_strdup("--gst-disable-registry-fork"); - (*argc)++; - - /* check disable registry scan */ - if (scmirroring_src_ini_get_structure()->skip_rescan) { - argv[*argc] = g_strdup("--gst-disable-registry-update"); - (*argc)++; - } - - /* check disable segtrap */ - if (scmirroring_src_ini_get_structure()->disable_segtrap) { - argv[*argc] = g_strdup("--gst-disable-segtrap"); - (*argc)++; - } - - scmirroring_debug("initializing gstreamer with following parameter\n"); - scmirroring_debug("argc : %d\n", *argc); - - for (i = 0; i < SCMIRRORING_SRC_INI_GST_START_PARAMS_NUM; i++) { - if (g_strcmp0(scmirroring_src_ini_get_structure()->gst_param[i], "") != 0) { - argv[*argc] = g_strdup(scmirroring_src_ini_get_structure()->gst_param[i]); - (*argc)++; - } - } - - for (i = 0; i < *argc; i++) { - scmirroring_debug("argv[%d] : %s\n", i, argv[i]); - } - - /* initializing gstreamer */ - if (!gst_init_check(argc, &argv, &err)) { - scmirroring_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); - if (err) { - g_error_free(err); - } - goto ERROR; - } - - /* release */ - for (i = 0; i < *argc; i++) { - SCMIRRORING_SAFE_FREE(argv[i]); - } - SCMIRRORING_SAFE_FREE(argc); - - return SCMIRRORING_ERROR_NONE; - -ERROR: - for (i = 0; i < *argc; i++) { - SCMIRRORING_SAFE_FREE(argv[i]); - } - SCMIRRORING_SAFE_FREE(argc); - return SCMIRRORING_ERROR_INVALID_OPERATION; -} - -#define VIDEO_PIPELINE "ximagesrc ! videorate ! videoscale ! videoconvert ! " \ - "video/x-raw, width=1280, height=720, framerate=30/1 ! " \ - "x264enc aud=false byte-stream=true bitrate=512 ! video/x-h264, profile=baseline ! mpegtsmux wfd-mode=TRUE ! " \ - "rtpmp2tpay name=pay0 pt=33" -#define AUDIO_PIPELINE "pulsesrc device=alsa_output.0.analog-stereo.monitor ! audioconvert ! " \ - "faac ! mpegtsmux wfd-mode=TRUE ! " \ - "rtpmp2tpay name=pay0 pt=33" -#define SCMIRRORING_PIPELINE "ximagesrc ! videoscale ! videoconvert ! " \ - "video/x-raw, width=1280, height=720, framerate=60/1 ! " \ - "x264enc aud=false byte-stream=true bitrate=512 ! video/x-h264, profile=baseline ! mpegtsmux name=mux " \ - "pulsesrc device=alsa_output.0.analog-stereo.monitor ! audioconvert ! " \ - "faac ! mux. mux. ! " \ - "rtpmp2tpay name=pay0 pt=33" - -#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) -{ - int ret = SCMIRRORING_ERROR_NONE; - - if (scmirroring_src_ini_load() != ERROR_NONE) { - scmirroring_error("Error occurred during parsing config file"); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - ret = __miracast_server_gst_init(); - if (ret < SCMIRRORING_ERROR_NONE) { - scmirroring_error("Gstreamer init failed"); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - guint id; - GstRTSPWFDServer *server = NULL; - GstRTSPMediaFactoryWFD *factory = NULL; - GstRTSPMountPoints *mounts = NULL; - - server = (void *)gst_rtsp_wfd_server_new(); - if (NULL == server) { - scmirroring_error("Failed to create server..."); - return SCMIRRORING_ERROR_OUT_OF_MEMORY; - } - - gst_rtsp_server_set_address(GST_RTSP_SERVER(server), server_obj->ip); - gst_rtsp_server_set_service(GST_RTSP_SERVER(server), server_obj->port); - mounts = gst_rtsp_server_get_mount_points(GST_RTSP_SERVER(server)); - if (NULL == mounts) { - scmirroring_error("Failed to get mount point..."); - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - factory = gst_rtsp_media_factory_wfd_new(); - - gst_rtsp_media_factory_wfd_set(factory, - scmirroring_src_ini_get_structure()->videosrc_element, - scmirroring_src_ini_get_structure()->name_of_audio_device, - scmirroring_src_ini_get_structure()->audio_latency_time, - scmirroring_src_ini_get_structure()->audio_buffer_time, - scmirroring_src_ini_get_structure()->audio_do_timestamp, - scmirroring_src_ini_get_structure()->mtu_size - ); - - gst_rtsp_media_factory_wfd_set_encoders (factory, - scmirroring_src_ini_get_structure()->name_of_video_encoder, - scmirroring_src_ini_get_structure()->name_of_audio_encoder_aac, - scmirroring_src_ini_get_structure()->name_of_audio_encoder_ac3); - - gst_rtsp_wfd_server_set_audio_codec (server, - scmirroring_src_ini_get_structure()->audio_codec); - - 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); - - g_object_ref(factory); - gst_rtsp_mount_points_add_factory(mounts, TEST_MOUNT_POINT, GST_RTSP_MEDIA_FACTORY(factory)); - g_object_unref(mounts); - - /* attach the server to the default maincontext */ - if ((id = gst_rtsp_server_attach(GST_RTSP_SERVER_CAST(server), NULL)) == 0) - goto failed; - - g_signal_connect(server, "client-connected", - G_CALLBACK(__miracast_server_client_connected_cb), server_obj); - - server_obj->server = (void *) server; - server_obj->factory = (void *) factory; - - return SCMIRRORING_ERROR_NONE; - -failed: - scmirroring_error("Failed to start miracast server"); - return SCMIRRORING_ERROR_INVALID_OPERATION; -} - -void __miracast_server_interpret(MiracastServerObject *server, char *buf) -{ - int ret = SCMIRRORING_ERROR_NONE; - - scmirroring_debug("Received : %s", 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:LISTENING"); - } else { - __miracast_server_send_resp(server, "FAIL:LISTENING"); - } - } else if (g_strrstr(buf, "SET IP")) { - gchar **addr_info; - gchar **IP_Port; - - addr_info = g_strsplit(buf, " ", 0); - IP_Port = g_strsplit(addr_info[2], ":", 0); - - scmirroring_debug("IP: %s, Port: %s", IP_Port[0], IP_Port[1]); - server->ip = g_strdup(IP_Port[0]); - server->port = g_strdup(IP_Port[1]); - - g_strfreev(IP_Port); - g_strfreev(addr_info); - - __miracast_server_send_resp(server, "OK:SET"); - } else if (g_strrstr(buf, "SET CM")) { - gchar **conn_mode_info; - gint connection_mode = 0; - - conn_mode_info = g_strsplit(buf, " ", 0); - - connection_mode = atoi(conn_mode_info[2]); - scmirroring_debug("Connection mode %d", connection_mode); - - server->connection_mode = connection_mode; - - g_strfreev(conn_mode_info); - - __miracast_server_send_resp(server, "OK:SET"); - } else if (g_strrstr(buf, "SET RESO")) { - gchar **resolution_info; - gint resolution = 0; - - resolution_info = g_strsplit(buf, " ", 0); - - resolution = atoi(resolution_info[2]); - scmirroring_debug("Resolution %d", resolution); - - server->resolution = resolution; - - g_strfreev(resolution_info); - - __miracast_server_send_resp(server, "OK:SET"); - } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_PAUSE)) { - gst_rtsp_wfd_server_trigger_request(GST_RTSP_SERVER(server->server), WFD_TRIGGER_PAUSE); - __miracast_server_send_resp(server, "OK:PAUSE"); - } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_RESUME)) { - gst_rtsp_wfd_server_trigger_request(GST_RTSP_SERVER(server->server), WFD_TRIGGER_PLAY); - __miracast_server_send_resp(server, "OK:RESUME"); - } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_STOP)) { - gst_rtsp_wfd_server_trigger_request(GST_RTSP_SERVER(server->server), WFD_TRIGGER_TEARDOWN); - __miracast_server_send_resp(server, "OK:STOP"); - } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_DESTROY)) { - __miracast_server_quit_program(server); - } -} - -int __miracast_server_accept(int serv_sock, int *client_sock) -{ - int sockfd = -1; - struct sockaddr_un client_addr; - socklen_t client_addr_len; - - if (client_sock == NULL) - return SCMIRRORING_ERROR_INVALID_PARAMETER; - - client_addr_len = sizeof(client_addr); - if ((sockfd = accept(serv_sock, (struct sockaddr *)&client_addr, &client_addr_len)) < 0) { - scmirroring_error("accept failed : %s", strerror(errno)); - *client_sock = -1; - return SCMIRRORING_ERROR_INVALID_OPERATION; - } - - *client_sock = sockfd; - - return SCMIRRORING_ERROR_NONE; -} - -gboolean __miracast_server_client_read_cb(GIOChannel *src, - GIOCondition condition, - gpointer data) -{ - char buf[MAX_MSG_LEN + 1]; - gsize read; - MiracastServerObject *server = (MiracastServerObject *)data; - - if (condition & G_IO_IN) { - g_io_channel_read_chars(server->client_channel, buf, MAX_MSG_LEN, &read, NULL); - if (read == 0) { - scmirroring_error("Read 0 bytes"); - return FALSE; - } else { - scmirroring_debug("Read %d bytes", read); - } - - gsize i = 0; - gsize 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; - } - - } else if (condition & G_IO_ERR) { - scmirroring_error("got G_IO_ERR"); - return FALSE; - } else if (condition & G_IO_HUP) { - scmirroring_error("got G_IO_HUP"); - return FALSE; - } - - return TRUE; -} - - -gboolean __miracast_server_read_cb(GIOChannel *src, - GIOCondition condition, - gpointer data) -{ - MiracastServerObject *server = (MiracastServerObject *)data; - - int server_sock = -1; - int client_sock = -1; - - server_sock = g_io_channel_unix_get_fd(src); - if (server_sock < 0) { - scmirroring_error("server sock fd is invalid!"); - return TRUE; - } - - __miracast_server_accept(server_sock, &client_sock); - - scmirroring_debug("New client accepted : %d", client_sock); - - GIOChannel *channel = NULL; - channel = g_io_channel_unix_new(client_sock); - if (channel == NULL) { - scmirroring_error("g_io_channel_unix_new failed: %s", strerror(errno)); - } - - /* Create new channel to watch udp socket */ - GSource *source = NULL; - source = g_io_create_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR); - /*int source_id = -1; */ - - /* 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; - - /* Set callback to be called when socket is readable */ - g_source_set_callback(source, (GSourceFunc)__miracast_server_client_read_cb, server, NULL); - g_source_attach(source, g_main_context_get_thread_default()); - - 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) { - if (err) { - scmirroring_error("g_bus_get_sync() error (%s) ", err->message); - g_error_free(err); - } else { - scmirroring_error("g_bus_get_sync() unknown error "); - } - 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); - if (conn) g_object_unref(conn); - return -1; -} int main(int argc, char *argv[]) { - int sockfd = -1; - - GSource *source = NULL; - GIOChannel *channel = NULL; - GMainContext *context = NULL; + GMainLoop *mainloop = NULL; + MiracastServer *server = NULL; #if !GLIB_CHECK_VERSION(2, 35, 0) g_type_init(); #endif - g_mainloop = g_main_loop_new(NULL, FALSE); - if (NULL == g_mainloop) { - scmirroring_error("Unable to create gmain loop! Aborting rtsp server\n"); + server = miracast_server_new(); + if (NULL == server) { + scmirroring_error("Unable to create miracast server object! Aborting rtsp server\n"); exit(-1); } - if (!__miracast_server_setup()) { - scmirroring_error("Unable to initialize test server\n"); + mainloop = g_main_loop_new(NULL, FALSE); + if (NULL == mainloop) { + scmirroring_error("Unable to create gmain loop! Aborting rtsp server\n"); exit(-1); } - if (!__miracast_server_ready_channel(&sockfd)) { - scmirroring_error("Unable to create channel"); + if (!miracast_server_setup(server, mainloop)) { + scmirroring_error("Unable to initialize test server\n"); exit(-1); } - context = g_main_loop_get_context(g_mainloop); - - /* Create new channel to watch udp socket */ - channel = g_io_channel_unix_new(sockfd); - source = g_io_create_watch(channel, G_IO_IN); - /* Set callback to be called when socket is readable */ - g_source_set_callback(source, (GSourceFunc) __miracast_server_read_cb, g_server_object, NULL); - g_source_attach(source, context); scmirroring_debug("miracast server run loop \n"); - g_main_loop_run(g_mainloop); + g_main_loop_run(mainloop); scmirroring_debug("MIRACAST SERVER EXIT \n"); exit(0); diff --git a/miracast_server/miracast_server.h b/miracast_server/miracast_server.h new file mode 100644 index 0000000..9a657d8 --- /dev/null +++ b/miracast_server/miracast_server.h @@ -0,0 +1,73 @@ +/* + * capi-media-streaming + * + * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MIRACAST_SERVER_H__ +#define __MIRACAST_SERVER_H__ + +#include +#include + +typedef struct _MiracastServer MiracastServer; +typedef struct _MiracastServerClass MiracastServerClass; + +#define MIRACAST_SERVER_TYPE_OBJECT (miracast_server_get_type()) +#define MIRACAST_SERVER(object) (G_TYPE_CHECK_INSTANCE_CAST \ + ((object), MIRACAST_SERVER_TYPE_OBJECT, MiracastServer)) +#define MIRACAST_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MIRACAST_SERVER_TYPE_OBJECT, MiracastServerClass)) +#define MIRACAST_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MIRACAST_SERVER_TYPE_OBJECT, MiracastServerClass)) +#define MIRACAST_SERVER_CAST(obj) ((MiracastServer*)(obj)) +#define MIRACAST_SERVER_CLASS_CAST(klass) ((MiracastServerClass*)(klass)) +#define IS_MIRACAST_SERVER_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIRACAST_SERVER_TYPE_OBJECT)) +#define IS_MIRACAST_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MIRACAST_SERVER_TYPE_OBJECT)) + +struct _MiracastServer { + GObject parent; + + GIOChannel *client_channel; + GMainLoop *mainloop; + gchar *ip; + gchar *port; + void *server; + void *client; + void *factory; + gint resolution; + gint connection_mode; + + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _MiracastServerClass { + GObjectClass parent; + + void (*interpret) (MiracastServer *server, gchar *buf); + int (*send_response) (MiracastServer *server, const gchar *cmd); + int (*server_start) (MiracastServer *server); + void (*quit_server) (MiracastServer *server); + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +GType miracast_server_get_type(void); +MiracastServer* miracast_server_new(void); +gboolean miracast_server_setup(MiracastServer *server, GMainLoop *mainloop); +gint miracast_server_gst_init(); + +#endif diff --git a/miracast_server/miracast_server_impl.c b/miracast_server/miracast_server_impl.c new file mode 100644 index 0000000..c750ca9 --- /dev/null +++ b/miracast_server/miracast_server_impl.c @@ -0,0 +1,934 @@ +/* + * miracast-server + * + * Copyright (c) 2011 - 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi , ByungWook Jang , + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "miracast_server.h" +#include "scmirroring_private.h" +#include "scmirroring_src_ini.h" + +#define MAX_CLIENT_CNT 1 +#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 + +#define TEST_MOUNT_POINT "/wfd1.0/streamid=0" + + +static const GDBusMethodInfo scmirroring_server_method_info_method = { + -1, + (char *)"launch_method", + NULL, + NULL, + NULL +}; +static const GDBusMethodInfo *const scmirroring_server_method_info_pointers[] = {&scmirroring_server_method_info_method, NULL}; + +static const GDBusInterfaceInfo scmirroring_server_interface_info = { + -1, + (char *)PROC_DBUS_INTERFACE, + (GDBusMethodInfo **) &scmirroring_server_method_info_pointers, + (GDBusSignalInfo **) NULL, + (GDBusPropertyInfo **) NULL, + NULL, +}; + +static gint g_server_status = MIRACAST_WFD_SOURCE_OFF; + +static GDBusNodeInfo *introspection_data = NULL; + +/* Introspection data for the service we are exporting */ +static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + ""; + + +static void +handle_method_call(GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + 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) { + 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)); + } + } +} + + +/* for now */ +static const GDBusInterfaceVTable interface_vtable = { + handle_method_call, + NULL, + NULL, + {NULL} +}; + +static void +on_bus_acquired(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + guint registration_id; + + scmirroring_debug("on_bus_acquired called\n"); + registration_id = g_dbus_connection_register_object(connection, + PROC_DBUS_OBJECT, + introspection_data->interfaces[0], + &interface_vtable, + NULL, + NULL, /* user_data_free_func */ + NULL); /* GError** */ + g_assert(registration_id > 0); +} + +static void +on_name_acquired(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + scmirroring_debug("on_name_acquired called\n"); +} + +static void +on_name_lost(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + scmirroring_debug("on_name_lost called\n"); +} + +G_DEFINE_TYPE(MiracastServer, miracast_server, G_TYPE_OBJECT); + +static int __miracast_server_emit_status_signal(int status); +static void __miracast_server_interpret(MiracastServer *server, gchar *buf); +static int __miracast_server_send_resp(MiracastServer *server, const gchar *cmd); +static void __miracast_server_quit_program(MiracastServer *server); +static int __miracast_server_start(MiracastServer *server_obj); + +static void miracast_server_init(MiracastServer *obj) +{ + scmirroring_debug("miracast_server_init\n"); + + obj->client_channel = NULL; + obj->ip = NULL; + obj->port = NULL; + obj->server = NULL; + obj->client = NULL; + obj->factory = NULL; + obj->resolution = -1; +} + +static void miracast_server_class_init(MiracastServerClass *klass) +{ + scmirroring_debug("miracast_server_class_init\n"); + //GObjectClass *gobject_class; + + //gobject_class = G_OBJECT_CLASS (klass); + //gobject_class->finalize = gst_rtsp_server_finalize; + + klass->interpret = __miracast_server_interpret; + klass->send_response = __miracast_server_send_resp; + klass->quit_server = __miracast_server_quit_program; + klass->server_start = __miracast_server_start; +} + +int __miracast_server_send_resp(MiracastServer *server, const gchar *cmd) +{ + int ret = SCMIRRORING_ERROR_NONE; + char *_cmd = NULL; + int client_sock = -1; + + if (server == NULL) { + scmirroring_error("OUT_OF_MEMORY"); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + client_sock = g_io_channel_unix_get_fd(server->client_channel); + if (client_sock < 0) { + scmirroring_error("client sock fd is invalid!"); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + _cmd = g_strdup(cmd); + _cmd[strlen(_cmd)] = '\0'; + + if (write(client_sock, _cmd, strlen(_cmd) + 1) != ((int)(strlen(_cmd) + 1))) { + scmirroring_error("sendto failed [%s]", strerror(errno)); + ret = SCMIRRORING_ERROR_INVALID_OPERATION; + } else { + scmirroring_debug("Sent response [%s] successfully", _cmd); + } + + g_free(_cmd); + return ret; +} + +void __miracast_server_quit_program(MiracastServer *server) +{ + scmirroring_error("Quit program is called"); + + MiracastServerClass *klass; + klass = MIRACAST_SERVER_GET_CLASS(server); + + void *pool = NULL; + 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); + if (pool) { + gst_rtsp_session_pool_cleanup(pool); + g_object_unref(pool); + } + + int serv_ref_cnt = GST_OBJECT_REFCOUNT_VALUE(server->server); + scmirroring_debug("serv ref cnt:%d", serv_ref_cnt); + + for (i = 0; i < serv_ref_cnt; i++) + g_object_unref(server->server); + +done: + klass->send_response(server, "OK:DESTROY"); + g_main_loop_quit(server->mainloop); +} + +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); +} + +static void __miracast_server_set_signal() +{ + /*SIGABRT A Process abort signal. + SIGALRM T Alarm clock. + SIGBUS A Access to an undefined portion of a memory object. + SIGCHLD I Child process terminated, stopped, + SIGCONT C Continue executing, if stopped. + SIGFPE A Erroneous arithmetic operation. + SIGHUP T Hangup. + SIGILL A Illegal instruction. + SIGINT T Terminal interrupt signal. + SIGKILL T Kill(cannot be caught or ignored). + SIGPIPE T Write on a pipe with no one to read it. + SIGQUIT A Terminal quit signal. + SIGSEGV A Invalid memory reference. + SIGSTOP S Stop executing(cannot be caught or ignored). + SIGTERM T Termination signal. + SIGTSTP S Terminal stop signal. + SIGTTIN S Background process attempting read. + SIGTTOU S Background process attempting write. + SIGUSR1 T User-defined signal 1. + SIGUSR2 T User-defined signal 2. + SIGPOLL T Pollable event. + SIGPROF T Profiling timer expired. + SIGSYS A Bad system call. + SIGTRAP A Trace/breakpoint trap. + SIGURG I High bandwidth data is available at a socket. + SIGVTALRM T Virtual timer expired. + SIGXCPU A CPU time limit exceeded. + SIGXFSZ A File size limit exceeded. + + The default actions are as follows: + T : Abnormal termination of the process. The process is terminated with all the consequences of _exit() + A : Abnormal termination of the process. + I : Ignore the signal. + S : Stop the process + */ + struct sigaction act_new; + memset(&act_new, 0, sizeof(struct sigaction)); + + act_new.sa_handler = __miracast_server_signal_handler; + + sigaction(SIGABRT, &act_new, NULL); + sigaction(SIGBUS, &act_new, NULL); + sigaction(SIGINT, &act_new, NULL); + sigaction(SIGKILL, &act_new, NULL); + sigaction(SIGPIPE, &act_new, NULL); + sigaction(SIGQUIT, &act_new, NULL); + sigaction(SIGSEGV, &act_new, NULL); + sigaction(SIGTERM, &act_new, NULL); + sigaction(SIGSYS, &act_new, NULL); +} + +static bool __miracast_server_setup(MiracastServer* server) +{ + scmirroring_debug("__miracast_server_setup start\n"); + + introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); + if (introspection_data == NULL) { + scmirroring_error("Introspection data is NULL"); + return false; + } + + g_bus_own_name(G_BUS_TYPE_SYSTEM, + PROC_DBUS_INTERFACE, + G_BUS_NAME_OWNER_FLAGS_NONE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + G_OBJECT(server), + NULL); + + __miracast_server_set_signal(); + scmirroring_debug("__miracast_server_setup end\n"); + + return true; +} + +static gboolean __miracast_server_ready_channel(int *sockfd) +{ + int sock; + int i; + gboolean bind_success = FALSE; + struct sockaddr_un serv_addr; + + /* Create a TCP socket */ + if ((sock = socket(PF_FILE, SOCK_STREAM, 0)) < 0) { + scmirroring_error("socket failed: %s", strerror(errno)); + return FALSE; + } + + memset(&serv_addr, 0, sizeof(serv_addr)); + + serv_addr.sun_family = AF_UNIX; + unlink(MEDIA_IPC_PATH); + strncpy(serv_addr.sun_path, MEDIA_IPC_PATH, sizeof(serv_addr.sun_path)); + + /* Bind to the local address */ + for (i = 0; i < 20; i++) { + if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) { + bind_success = true; + break; + } + usleep(250000); + } + + if (bind_success == false) { + scmirroring_error("bind failed : %s %d_", strerror(errno), errno); + close(sock); + return FALSE; + } + + scmirroring_debug("bind success"); + + /* Listening */ + if (listen(sock, SOMAXCONN) < 0) { + scmirroring_error("listen failed : %s", strerror(errno)); + close(sock); + 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; + + return TRUE; +} + +void __miracast_server_msg_cb(gboolean is_error, void *userdata) +{ + /*MiracastServer *server = (MiracastServer *)userdata; */ + + if (is_error) { + scmirroring_error("Error occured"); + } +} + +gint miracast_server_gst_init() +{ + gint *argc = NULL; + gchar **argv = NULL; + static const int max_argc = 50; + GError *err = NULL; + int i = 0; + + /* alloc */ + argc = calloc(1, sizeof(int)); + if (!argc) { + scmirroring_error("Cannot allocate memory for scmirroringsink\n"); + return SCMIRRORING_ERROR_OUT_OF_MEMORY; + } + + argv = calloc(max_argc, sizeof(gchar *)); + if (!argv) { + scmirroring_error("Cannot allocate memory for scmirroringsink\n"); + SCMIRRORING_SAFE_FREE(argc); + return SCMIRRORING_ERROR_OUT_OF_MEMORY; + } + + /* we would not do fork for scanning plugins */ + argv[*argc] = g_strdup("--gst-disable-registry-fork"); + (*argc)++; + + /* check disable registry scan */ + if (scmirroring_src_ini_get_structure()->skip_rescan) { + argv[*argc] = g_strdup("--gst-disable-registry-update"); + (*argc)++; + } + + /* check disable segtrap */ + if (scmirroring_src_ini_get_structure()->disable_segtrap) { + argv[*argc] = g_strdup("--gst-disable-segtrap"); + (*argc)++; + } + + scmirroring_debug("initializing gstreamer with following parameter\n"); + scmirroring_debug("argc : %d\n", *argc); + + for (i = 0; i < SCMIRRORING_SRC_INI_GST_START_PARAMS_NUM; i++) { + if (g_strcmp0(scmirroring_src_ini_get_structure()->gst_param[i], "") != 0) { + argv[*argc] = g_strdup(scmirroring_src_ini_get_structure()->gst_param[i]); + (*argc)++; + } + } + + for (i = 0; i < *argc; i++) { + scmirroring_debug("argv[%d] : %s\n", i, argv[i]); + } + + /* initializing gstreamer */ + if (!gst_init_check(argc, &argv, &err)) { + scmirroring_error("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred"); + if (err) { + g_error_free(err); + } + goto ERROR; + } + + /* release */ + for (i = 0; i < *argc; i++) { + SCMIRRORING_SAFE_FREE(argv[i]); + } + SCMIRRORING_SAFE_FREE(argc); + + return SCMIRRORING_ERROR_NONE; + +ERROR: + for (i = 0; i < *argc; i++) { + SCMIRRORING_SAFE_FREE(argv[i]); + } + SCMIRRORING_SAFE_FREE(argc); + return SCMIRRORING_ERROR_INVALID_OPERATION; +} + + +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) +{ + MiracastServer *server_obj = (MiracastServer *)user_data; + MiracastServerClass *klass; + klass = MIRACAST_SERVER_GET_CLASS(server_obj); + + scmirroring_debug("There is a client, connected"); + server_obj->client = (void *)client; + + 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 */ + klass->send_response(server_obj, "OK:CONNECTED"); +} + +int __miracast_server_start(MiracastServer *server_obj) +{ + int ret = SCMIRRORING_ERROR_NONE; + + if (scmirroring_src_ini_load() != ERROR_NONE) { + scmirroring_error("Error occurred during parsing config file"); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + ret = miracast_server_gst_init(); + if (ret < SCMIRRORING_ERROR_NONE) { + scmirroring_error("Gstreamer init failed"); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + guint id; + GstRTSPWFDServer *server = NULL; + GstRTSPMediaFactoryWFD *factory = NULL; + GstRTSPMountPoints *mounts = NULL; + + server = (void *)gst_rtsp_wfd_server_new(); + if (NULL == server) { + scmirroring_error("Failed to create server..."); + return SCMIRRORING_ERROR_OUT_OF_MEMORY; + } + + gst_rtsp_server_set_address(GST_RTSP_SERVER(server), server_obj->ip); + gst_rtsp_server_set_service(GST_RTSP_SERVER(server), server_obj->port); + mounts = gst_rtsp_server_get_mount_points(GST_RTSP_SERVER(server)); + if (NULL == mounts) { + scmirroring_error("Failed to get mount point..."); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + factory = gst_rtsp_media_factory_wfd_new(); + + gst_rtsp_media_factory_wfd_set(factory, + scmirroring_src_ini_get_structure()->videosrc_element, + scmirroring_src_ini_get_structure()->name_of_audio_device, + scmirroring_src_ini_get_structure()->audio_latency_time, + scmirroring_src_ini_get_structure()->audio_buffer_time, + scmirroring_src_ini_get_structure()->audio_do_timestamp, + scmirroring_src_ini_get_structure()->mtu_size + ); + + gst_rtsp_media_factory_wfd_set_encoders (factory, + scmirroring_src_ini_get_structure()->name_of_video_encoder, + scmirroring_src_ini_get_structure()->name_of_audio_encoder_aac, + scmirroring_src_ini_get_structure()->name_of_audio_encoder_ac3); + + gst_rtsp_wfd_server_set_audio_codec (server, + scmirroring_src_ini_get_structure()->audio_codec); + + 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); + + g_object_ref(factory); + gst_rtsp_mount_points_add_factory(mounts, TEST_MOUNT_POINT, GST_RTSP_MEDIA_FACTORY(factory)); + g_object_unref(mounts); + + /* attach the server to the default maincontext */ + if ((id = gst_rtsp_server_attach(GST_RTSP_SERVER_CAST(server), NULL)) == 0) + goto failed; + + g_signal_connect(server, "client-connected", + G_CALLBACK(__miracast_server_client_connected_cb), server_obj); + + server_obj->server = (void *) server; + server_obj->factory = (void *) factory; + + return SCMIRRORING_ERROR_NONE; + +failed: + scmirroring_error("Failed to start miracast server"); + return SCMIRRORING_ERROR_INVALID_OPERATION; +} + +void __miracast_server_interpret(MiracastServer *server, gchar *buf) +{ + int ret = SCMIRRORING_ERROR_NONE; + MiracastServerClass *klass; + klass = MIRACAST_SERVER_GET_CLASS(server); + + scmirroring_debug("Received : %s", buf); + + if (g_strrstr(buf, SCMIRRORING_STATE_CMD_START)) { + ret = klass->server_start(server); + if (ret == SCMIRRORING_ERROR_NONE) { + klass->send_response(server, "OK:LISTENING"); + + ret = __miracast_server_emit_status_signal(MIRACAST_WFD_SOURCE_ON); + if (ret != SCMIRRORING_ERROR_NONE) { + scmirroring_error("Failed to emit miracast server on signal"); + } + + } else { + klass->send_response(server, "FAIL:LISTENING"); + } + } else if (g_strrstr(buf, "SET IP")) { + gchar **addr_info; + gchar **IP_Port; + + addr_info = g_strsplit(buf, " ", 0); + IP_Port = g_strsplit(addr_info[2], ":", 0); + + scmirroring_debug("IP: %s, Port: %s", IP_Port[0], IP_Port[1]); + server->ip = g_strdup(IP_Port[0]); + server->port = g_strdup(IP_Port[1]); + + g_strfreev(IP_Port); + g_strfreev(addr_info); + + klass->send_response(server, "OK:SET"); + } else if (g_strrstr(buf, "SET CM")) { + gchar **conn_mode_info; + gint connection_mode = 0; + + conn_mode_info = g_strsplit(buf, " ", 0); + + connection_mode = atoi(conn_mode_info[2]); + scmirroring_debug("Connection mode %d", connection_mode); + + server->connection_mode = connection_mode; + + g_strfreev(conn_mode_info); + + klass->send_response(server, "OK:SET"); + } else if (g_strrstr(buf, "SET RESO")) { + gchar **resolution_info; + gint resolution = 0; + + resolution_info = g_strsplit(buf, " ", 0); + + resolution = atoi(resolution_info[2]); + scmirroring_debug("Resolution %d", resolution); + + server->resolution = resolution; + + g_strfreev(resolution_info); + + klass->send_response(server, "OK:SET"); + } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_PAUSE)) { + gst_rtsp_wfd_server_trigger_request(GST_RTSP_SERVER(server->server), WFD_TRIGGER_PAUSE); + klass->send_response(server, "OK:PAUSE"); + } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_RESUME)) { + gst_rtsp_wfd_server_trigger_request(GST_RTSP_SERVER(server->server), WFD_TRIGGER_PLAY); + klass->send_response(server, "OK:RESUME"); + } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_STOP)) { + gst_rtsp_wfd_server_trigger_request(GST_RTSP_SERVER(server->server), WFD_TRIGGER_TEARDOWN); + klass->send_response(server, "OK:STOP"); + } else if (g_strrstr(buf, SCMIRRORING_STATE_CMD_DESTROY)) { + klass->quit_server(server); + } +} + +int __miracast_server_accept(int serv_sock, int *client_sock) +{ + int sockfd = -1; + struct sockaddr_un client_addr; + socklen_t client_addr_len; + + if (client_sock == NULL) + return SCMIRRORING_ERROR_INVALID_PARAMETER; + + client_addr_len = sizeof(client_addr); + if ((sockfd = accept(serv_sock, (struct sockaddr *)&client_addr, &client_addr_len)) < 0) { + scmirroring_error("accept failed : %s", strerror(errno)); + *client_sock = -1; + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + *client_sock = sockfd; + + return SCMIRRORING_ERROR_NONE; +} + +gboolean __miracast_server_client_read_cb(GIOChannel *src, + GIOCondition condition, + gpointer data) +{ + char buf[MAX_MSG_LEN + 1]; + gsize read; + MiracastServer *server = (MiracastServer *)data; + MiracastServerClass *klass; + klass = MIRACAST_SERVER_GET_CLASS(server); + + if (condition & G_IO_IN) { + g_io_channel_read_chars(server->client_channel, buf, MAX_MSG_LEN, &read, NULL); + if (read == 0) { + scmirroring_error("Read 0 bytes"); + return FALSE; + } else { + scmirroring_debug("Read %d bytes", read); + } + + gsize i = 0; + gsize 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); + klass->interpret(server, str); + if (idx >= read) break; + } + + } else if (condition & G_IO_ERR) { + scmirroring_error("got G_IO_ERR"); + return FALSE; + } else if (condition & G_IO_HUP) { + scmirroring_error("got G_IO_HUP"); + return FALSE; + } + + return TRUE; +} + + +gboolean __miracast_server_read_cb(GIOChannel *src, + GIOCondition condition, + gpointer data) +{ + MiracastServer *server = (MiracastServer *)data; + + int server_sock = -1; + int client_sock = -1; + + server_sock = g_io_channel_unix_get_fd(src); + if (server_sock < 0) { + scmirroring_error("server sock fd is invalid!"); + return TRUE; + } + + __miracast_server_accept(server_sock, &client_sock); + + scmirroring_debug("New client accepted : %d", client_sock); + + GIOChannel *channel = NULL; + channel = g_io_channel_unix_new(client_sock); + if (channel == NULL) { + scmirroring_error("g_io_channel_unix_new failed: %s", strerror(errno)); + } + + /* Create new channel to watch udp socket */ + GSource *source = NULL; + source = g_io_create_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR); + /*int source_id = -1; */ + + /* 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; + + /* Set callback to be called when socket is readable */ + g_source_set_callback(source, (GSourceFunc)__miracast_server_client_read_cb, server, NULL); + g_source_attach(source, g_main_context_get_thread_default()); + + 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) { + if (err) { + scmirroring_error("g_bus_get_sync() error (%s) ", err->message); + g_error_free(err); + } else { + scmirroring_error("g_bus_get_sync() unknown error "); + } + 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); + if (conn) g_object_unref(conn); + return -1; +} + +MiracastServer* +miracast_server_new (void) +{ + return g_object_new (MIRACAST_SERVER_TYPE_OBJECT, NULL); +} + +gboolean +miracast_server_setup(MiracastServer *server, GMainLoop *mainloop) +{ + int sockfd = -1; + + GSource *source = NULL; + GIOChannel *channel = NULL; + GMainContext *context = NULL; + +#if !GLIB_CHECK_VERSION(2, 35, 0) + g_type_init(); +#endif + + if (!__miracast_server_setup(server)) { + scmirroring_error("Unable to initialize test server\n"); + return FALSE; + } + + if (!__miracast_server_ready_channel(&sockfd)) { + scmirroring_error("Unable to create channel"); + return FALSE; + } + + context = g_main_loop_get_context(mainloop); + server->mainloop = mainloop; + + /* Create new channel to watch udp socket */ + channel = g_io_channel_unix_new(sockfd); + source = g_io_create_watch(channel, G_IO_IN); + + /* Set callback to be called when socket is readable */ + g_source_set_callback(source, (GSourceFunc)__miracast_server_read_cb, server, NULL); + g_source_attach(source, context); + + return TRUE; +} diff --git a/packaging/capi-media-screen-mirroring.spec b/packaging/capi-media-screen-mirroring.spec index 58f1717..98ee2fd 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.40 +Version: 0.1.42 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -73,6 +73,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* +%{_libdir}/libmiracast_server_lib.so %{_datadir}/dbus-1/system-services/org.tizen.scmirroring.server.service #License %{_datadir}/license/%{name} @@ -87,5 +88,4 @@ cp -rf config/scmirroring_src.ini %{buildroot}/usr/etc/scmirroring_src.ini %{_includedir}/media/scmirroring_internal.h %{_libdir}/pkgconfig/*.pc %{_libdir}/libcapi-media-screen-mirroring.so - - +%{_libdir}/libmiracast_server_lib.so