From 11016d9e03d5263f65cc5c2512bb11b1f1579653 Mon Sep 17 00:00:00 2001 From: Derek Dai Date: Wed, 15 Feb 2017 18:37:33 +0800 Subject: [PATCH] remove unused files --- src/CMakeLists.txt | 1 - src/ctl/CMakeLists.txt | 1 - src/ctl/srcctl.c | 873 ------------------------------------ src/ctl/wfd-src.c | 851 ----------------------------------- src/ctl/wfd-src.h | 106 ----- src/stream/CMakeLists.txt | 42 -- src/stream/sender-iface.xml | 20 - src/stream/sender.c | 746 ------------------------------ src/stream/sender.h | 25 -- 9 files changed, 2665 deletions(-) delete mode 100644 src/ctl/srcctl.c delete mode 100644 src/ctl/wfd-src.c delete mode 100644 src/ctl/wfd-src.h delete mode 100644 src/stream/CMakeLists.txt delete mode 100644 src/stream/sender-iface.xml delete mode 100644 src/stream/sender.c delete mode 100644 src/stream/sender.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 294207c..96fe570 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,6 @@ add_subdirectory(wifi) add_subdirectory(dhcp) add_subdirectory(ctl) add_subdirectory(uibc) -add_subdirectory(stream) set(miracled_SRCS miracled.h miracled.c) add_executable(miracled ${miracled_SRCS}) diff --git a/src/ctl/CMakeLists.txt b/src/ctl/CMakeLists.txt index e9d3af5..8b0e469 100644 --- a/src/ctl/CMakeLists.txt +++ b/src/ctl/CMakeLists.txt @@ -48,7 +48,6 @@ include_directories(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_D ########### next target ############### set(miracle-wfdctl_SRCS ctl-cli.c ctl-wifi.c - wfd-src.c wfd-sink.c wfd-dbus.c wfd-session.c diff --git a/src/ctl/srcctl.c b/src/ctl/srcctl.c deleted file mode 100644 index b9d4893..0000000 --- a/src/ctl/srcctl.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * MiracleCast - Wifi-Display/Miracast Implementation - * - * Copyright (c) 2013-2014 David Herrmann - * - * MiracleCast is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * MiracleCast is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MiracleCast; If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctl.h" -#include "ctl-src.h" -#include "wfd.h" -#include "shl_macro.h" -#include "shl_util.h" -#include "config.h" -#include "sender-iface.h" - -void launch_sender(struct ctl_src *s); - -static sd_bus *bus; -static struct ctl_wifi *wifi; -static struct ctl_src *src; -static sd_event_source *scan_timeout; -static sd_event_source *src_timeout; -static unsigned int src_timeout_time; -static bool src_connected; - -//static char *selected_ link; -static struct ctl_link *running_link; -static struct ctl_peer *running_peer; -static struct ctl_peer *pending_peer; - -// -//char *gst_scale_res; -static int gst_audio_en = 1; -static const int DEFAULT_RTSP_PORT = 1991; -//bool uibc; -static int rtsp_port; -//int uibc_port; -// -//unsigned int wfd_supported_res_cea = 0x0000001f; /* up to 720x576 */ -//unsigned int wfd_supported_res_vesa = 0x00000003; /* up to 800x600 */ -//unsigned int wfd_supported_res_hh = 0x00000000; /* not supported */ - -static Sender *sender; - -/* - * cmd: select - */ - -static int cmd_select(char **args, unsigned int n) -{ - struct ctl_link *l; - - if (!n) { - if (running_link) { - cli_printf("link %s deselected\n", - running_link->label); - running_link = NULL; - } - - return 0; - } - - l = ctl_wifi_search_link(wifi, args[0]); - if (!l) { - cli_error("unknown link %s", args[0]); - return 0; - } - - running_link = l; - cli_printf("link %s selected\n", running_link->label); - - return 0; -} - -/* - * cmd list - */ - -static int cmd_list(char **args, unsigned int n) -{ - size_t link_cnt = 0, peer_cnt = 0; - struct shl_dlist *i, *j; - struct ctl_link *l; - struct ctl_peer *p; - - /* list links */ - - cli_printf("%6s %-24s %-30s\n", - "LINK", "INTERFACE", "FRIENDLY-NAME"); - - shl_dlist_for_each(i, &wifi->links) { - l = link_from_dlist(i); - ++link_cnt; - - cli_printf("%6s %-24s %-30s\n", - l->label, - shl_isempty(l->ifname) ? - "" : l->ifname, - shl_isempty(l->friendly_name) ? - "" : l->friendly_name); - } - - cli_printf("\n"); - - /* list peers */ - - cli_printf("%6s %-24s %-30s %-10s\n", - "LINK", "PEER-ID", "FRIENDLY-NAME", "CONNECTED"); - - shl_dlist_for_each(i, &wifi->links) { - l = link_from_dlist(i); - - shl_dlist_for_each(j, &l->peers) { - p = peer_from_dlist(j); - ++peer_cnt; - - cli_printf("%6s %-24s %-30s %-10s\n", - p->l->label, - p->label, - shl_isempty(p->friendly_name) ? - "" : p->friendly_name, - p->connected ? "yes" : "no"); - } - } - - cli_printf("\n %u peers and %u links listed.\n", peer_cnt, link_cnt); - - return 0; -} - -/* - * cmd: show - */ - -static int cmd_show(char **args, unsigned int n) -{ - struct ctl_link *l = NULL; - struct ctl_peer *p = NULL; - - if (n > 0) { - if (!(l = ctl_wifi_find_link(wifi, args[0])) && - !(p = ctl_wifi_find_peer(wifi, args[0])) && - !(l = ctl_wifi_search_link(wifi, args[0])) && - !(p = ctl_wifi_search_peer(wifi, args[0]))) { - cli_error("unknown link or peer %s", args[0]); - return 0; - } - } - - if (l) { - cli_printf("Link=%s\n", l->label); - if (l->ifindex > 0) - cli_printf("InterfaceIndex=%u\n", l->ifindex); - if (l->ifname && *l->ifname) - cli_printf("InterfaceName=%s\n", l->ifname); - if (l->friendly_name && *l->friendly_name) - cli_printf("FriendlyName=%s\n", l->friendly_name); - cli_printf("P2PScanning=%d\n", l->p2p_scanning); - if (l->wfd_subelements && *l->wfd_subelements) - cli_printf("WfdSubelements=%s\n", l->wfd_subelements); - } else if (p) { - cli_printf("Peer=%s\n", p->label); - if (p->p2p_mac && *p->p2p_mac) - cli_printf("P2PMac=%s\n", p->p2p_mac); - if (p->friendly_name && *p->friendly_name) - cli_printf("FriendlyName=%s\n", p->friendly_name); - cli_printf("Connected=%d\n", p->connected); - if (p->interface && *p->interface) - cli_printf("Interface=%s\n", p->interface); - if (p->local_address && *p->local_address) - cli_printf("LocalAddress=%s\n", p->local_address); - if (p->remote_address && *p->remote_address) - cli_printf("RemoteAddress=%s\n", p->remote_address); - if (p->wfd_subelements && *p->wfd_subelements) - cli_printf("WfdSubelements=%s\n", p->wfd_subelements); - } else { - cli_printf("Show what?\n"); - return 0; - } - - return 0; -} - -/* - * cmd: set-friendly-name - */ - -static int cmd_set_friendly_name(char **args, unsigned int n) -{ - struct ctl_link *l = NULL; - const char *name; - - if (n < 1) { - cli_printf("To what?\n"); - return 0; - } - - if (n > 1) { - l = ctl_wifi_search_link(wifi, args[0]); - if (!l) { - cli_error("unknown link %s", args[0]); - return 0; - } - - name = args[1]; - } else { - name = args[0]; - } - - l = l ? : running_link; - if (!l) { - cli_error("no link selected"); - return 0; - } - - return ctl_link_set_friendly_name(l, name); -} - -/* - * cmd: p2p-scan - */ - -static int cmd_p2p_scan(char **args, unsigned int n) -{ - struct ctl_link *l = NULL; - unsigned int i; - bool stop = false; - int r; - - for (i = 0; i < n; ++i) { - if (!strcmp(args[i], "stop")) { - stop = true; - } else { - l = ctl_wifi_search_link(wifi, args[i]); - if (!l) { - cli_error("unknown link %s", args[i]); - return 0; - } - } - } - - l = l ? : running_link; - if (!l) { - cli_error("no link selected"); - return 0; - } - - ctl_link_set_wfd_subelements(l, "000600101c4400c8"); - r = ctl_link_set_p2p_scanning(l, !stop); - if(!r && !running_link) { - running_link = l; - } - - return r; -} - -/* - * cmd: connect - */ - -static bool is_valid_prov(const char *prov) -{ - return prov && (!strcmp(prov, "auto") || - !strcmp(prov, "pbc") || - !strcmp(prov, "display") || - !strcmp(prov, "pin")); -} - -static int cmd_connect(char **args, unsigned int n) -{ - struct ctl_peer *p; - const char *prov, *pin; - - if (n < 1) { - cli_printf("To whom?\n"); - return 0; - } - - p = ctl_wifi_search_peer(wifi, args[0]); - if (!p) { - cli_error("unknown peer %s", args[0]); - return 0; - } - - if (n > 2) { - prov = args[1]; - pin = args[2]; - } else if (n > 1) { - if (is_valid_prov(args[1])) { - prov = args[1]; - pin = ""; - } else { - prov = "auto"; - pin = args[1]; - } - } else { - prov = "auto"; - pin = ""; - } - - return ctl_peer_connect(p, prov, pin); -} - -/* - * cmd: disconnect - */ - -static int cmd_disconnect(char **args, unsigned int n) -{ - struct ctl_peer *p; - - if (n < 1) { - cli_printf("From whom?\n"); - return 0; - } - - p = ctl_wifi_search_peer(wifi, args[0]); - if (!p) { - cli_error("unknown peer %s", args[0]); - return 0; - } - - return ctl_peer_disconnect(p); -} - -/* - * cmd: quit/exit - */ - -static int cmd_quit(char **args, unsigned int n) -{ - cli_exit(); - return 0; -} - -/* - * main - */ - -static void schedule_timeout(sd_event_source **out, - uint64_t rel_usec, - sd_event_time_handler_t timeout_fn, - void *data) -{ - int r; - - rel_usec += shl_now(CLOCK_MONOTONIC); - - if (*out) { - r = sd_event_source_set_time(*out, rel_usec); - if (r < 0) - cli_vERR(r); - } else { - r = sd_event_add_time(cli_event, - out, - CLOCK_MONOTONIC, - rel_usec, - 0, - timeout_fn, - data); - if (r < 0) - cli_vERR(r); - } -} - -static void stop_timeout(sd_event_source **out) -{ - if (*out) { - sd_event_source_set_enabled(*out, SD_EVENT_OFF); - sd_event_source_unref(*out); - *out = NULL; - } -} - -static int scan_timeout_fn(sd_event_source *s, uint64_t usec, void *data) -{ - stop_timeout(&scan_timeout); - - if (pending_peer) { - if (cli_running()) { - cli_printf("[" CLI_RED "TIMEOUT" CLI_DEFAULT "] waiting for %s\n", - pending_peer->friendly_name); - } - pending_peer = NULL; - } - - if (running_link) - ctl_link_set_p2p_scanning(running_link, true); - - return 0; -} - -static int src_timeout_fn(sd_event_source *s, uint64_t usec, void *data) -{ - int r; - - stop_timeout(&src_timeout); - - if (running_peer && - running_peer->connected && - ctl_src_is_closed(src)) { - r = ctl_src_listen(src, running_peer->local_address); - if (r < 0) { - if (src_timeout_time++ >= 3) - cli_vERR(r); - else - schedule_timeout(&src_timeout, - src_timeout_time * 1000ULL * 1000ULL, - src_timeout_fn, - NULL); - } - - log_info("listening on %s", running_peer->local_address); - } - - return 0; -} - -static const struct cli_cmd cli_cmds[] = { - { "list", NULL, CLI_M, CLI_LESS, 0, cmd_list, "List all objects" }, - { "select", "[link]", CLI_Y, CLI_LESS, 1, cmd_select, "Select default link" }, - { "show", "", CLI_M, CLI_LESS, 1, cmd_show, "Show detailed object information" }, - { "set-friendly-name", "[link] ", CLI_M, CLI_LESS, 2, cmd_set_friendly_name, "Set friendly name of an object" }, - { "p2p-scan", "[link] [stop]", CLI_Y, CLI_LESS, 2, cmd_p2p_scan, "Control neighborhood P2P scanning" }, - { "connect", " [provision] [pin]", CLI_M, CLI_LESS, 3, cmd_connect, "Connect to peer" }, - { "disconnect", "", CLI_M, CLI_EQUAL, 1, cmd_disconnect, "Disconnect from peer" }, - { "quit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, "Quit program" }, - { "exit", NULL, CLI_Y, CLI_MORE, 0, cmd_quit, NULL }, - { "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" }, - { }, -}; - -static void stop_sender(void) -{ - GError *error = NULL; - - if (!sender) - return; - - sender_call_stop_sync(sender, NULL, &error); - if(error) { - cli_error("SOURCE failed to stop sender: %s", error->message); - g_error_free(error); - } - - g_object_unref(sender); - sender = NULL; -} - -void ctl_fn_wfd_connected(struct ctl_src *s) -{ - cli_notice("SOURCE connected"); - src_connected = true; -} - -void ctl_fn_wfd_disconnected(struct ctl_src *s) -{ - if (!src_connected) { - /* treat HUP as timeout */ - src_timeout_fn(src_timeout, 0, NULL); - } else { - cli_notice("SRC disconnected"); - src_connected = false; - - if(sender) { - GError *error = NULL; - if(sender_call_stop_sync(sender, NULL, &error)) { - cli_error("SRC failed to stop sender: %s", error->message); - g_error_free(error); - } - - g_object_unref(sender); - sender = NULL; - } - } -} - -void ctl_fn_wfd_setup(struct ctl_src *s) -{ - GError *error = NULL; - - cli_printf("SRC got setup request\n"); - - if(!sender) { - sender = sender_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - "org.freedesktop.miracle", - "/org/freedesktop/miracle/Sender/0", - NULL, - &error); - if(!sender) { - cli_error("SRC failed to connect to sender: %s", error->message); - g_error_free(error); - return; - } - } - - sender_call_prepare_sync(sender, - inet_ntoa(((struct sockaddr_in *) &s->addr)->sin_addr), - s->sink.rtp_ports.port0, - ":0", - 1920, - 1080, - 25, - FALSE, - NULL, - &error); - if(error) { - cli_error("SRC failed to setup: %s", error->message); - g_error_free(error); - return; - } - - g_info("SRC sender prepared"); -} - -void ctl_fn_wfd_playing(struct ctl_src *s) -{ - GError *error = NULL; - - cli_printf("SRC got play request\n"); - - if(!sender) { - cli_error("SRC not setup yet"); - return; - } - - if(!sender_call_play_sync(sender, NULL, &error)) { - cli_error("SRC failed to play: %s", error->message); - g_error_free(error); - return; - } - - cli_printf("SRC sender playing\n"); -} - -void ctl_fn_peer_new(struct ctl_peer *p) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (cli_running()) - cli_printf("[" CLI_GREEN "ADD" CLI_DEFAULT "] Peer: %s\n", - p->label); -} - -void ctl_fn_peer_free(struct ctl_peer *p) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (p == pending_peer) { - cli_printf("no longer waiting for peer %s (%s)\n", - p->friendly_name, p->label); - pending_peer = NULL; - stop_timeout(&scan_timeout); - ctl_link_set_p2p_scanning(p->l, true); - } - - if (p == running_peer) { - cli_printf("no longer running on peer %s\n", - running_peer->label); - stop_timeout(&src_timeout); - stop_sender(); - ctl_src_close(src); - running_peer = NULL; - stop_timeout(&scan_timeout); - ctl_link_set_p2p_scanning(p->l, true); - } - - if (cli_running()) - cli_printf("[" CLI_RED "REMOVE" CLI_DEFAULT "] Peer: %s\n", - p->label); -} -// -void ctl_fn_peer_provision_discovery(struct ctl_peer *p, - const char *prov, - const char *pin) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (cli_running()) - cli_printf("[" CLI_YELLOW "PROV" CLI_DEFAULT "] Peer: %s Type: %s PIN: %s\n", - p->label, prov, pin); -} - -void ctl_fn_peer_go_neg_request(struct ctl_peer *p, - const char *prov, - const char *pin) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (cli_running()) - cli_printf("[" CLI_YELLOW "GO NEG" CLI_DEFAULT "] Peer: %s Type: %s PIN: %s\n", - p->label, prov, pin); - - if (!running_peer) { - /* auto accept any incoming connection attempt */ - ctl_peer_connect(p, "auto", ""); - pending_peer = p; - - /* 60s timeout in case the connect fails. Yes, stupid wpas does - * not catch this and notify us.. and as it turns out, DHCP - * negotiation with some proprietary devices can take up to 30s - * so lets be safe. */ - schedule_timeout(&scan_timeout, - 60 * 1000ULL * 1000ULL, - scan_timeout_fn, - NULL); - } -} - -void ctl_fn_peer_formation_failure(struct ctl_peer *p, const char *reason) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (cli_running()) - cli_printf("[" CLI_YELLOW "FAIL" CLI_DEFAULT "] Peer: %s Reason: %s\n", - p->label, reason); - - if (!running_peer) { - stop_timeout(&scan_timeout); - ctl_link_set_p2p_scanning(p->l, true); - } -} - -void ctl_fn_peer_connected(struct ctl_peer *p) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (cli_running()) - cli_printf("[" CLI_GREEN "CONNECT" CLI_DEFAULT "] Peer: %s\n", - p->label); - - pending_peer = NULL; - - if (!running_peer) { - running_peer = p; - cli_printf("now running on peer %s\n", running_peer->label); - stop_timeout(&scan_timeout); - - src_connected = false; - src_timeout_time = 1; - schedule_timeout(&src_timeout, - src_timeout_time * 1000ULL * 1000ULL, - src_timeout_fn, - NULL); - } -} -// -void ctl_fn_peer_disconnected(struct ctl_peer *p) -{ - if (p->l != running_link || shl_isempty(p->wfd_subelements)) - return; - - if (p == running_peer) { - cli_printf("no longer running on peer %s\n", - running_peer->label); - stop_timeout(&src_timeout); - stop_sender(); - ctl_src_close(src); - running_peer = NULL; - stop_timeout(&scan_timeout); - ctl_link_set_p2p_scanning(p->l, true); - } - - if (cli_running()) - cli_printf("[" CLI_YELLOW "DISCONNECT" CLI_DEFAULT "] Peer: %s\n", - p->label); -} -// -void ctl_fn_link_new(struct ctl_link *l) -{ - if (cli_running()) - cli_printf("[" CLI_GREEN "ADD" CLI_DEFAULT "] Link: %s\n", - l->label); -} - -void ctl_fn_link_free(struct ctl_link *l) -{ - if (l == running_link) { - cli_printf("no longer running on link %s\n", - running_link->label); - running_link = NULL; - stop_timeout(&scan_timeout); - } - - if (cli_running()) - cli_printf("[" CLI_RED "REMOVE" CLI_DEFAULT "] Link: %s\n", - l->label); -} - -void cli_fn_help() -{ - /* - * 80-char barrier: - * 01234567890123456789012345678901234567890123456789012345678901234567890123456789 - */ - printf("%s [OPTIONS...] ...\n\n" - "Control a dedicated local sink via MiracleCast.\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --log-level Maximum level for log messages\n" - " --log-journal-level Maximum level for journal log messages\n" - " --audio <0/1> Enable audio support (default %d)\n" - "\n" - , program_invocation_short_name, gst_audio_en - ); - /* - * 80-char barrier: - * 01234567890123456789012345678901234567890123456789012345678901234567890123456789 - */ -} - -static int ctl_interactive(char **argv, int argc) -{ - int r; - - r = cli_init(bus, cli_cmds); - if (r < 0) - return r; - - r = ctl_src_new(&src, cli_event); - if (r < 0) - goto error; - - r = ctl_wifi_fetch(wifi); - if (r < 0) - goto error; - - if (argc > 0) { - r = cli_do(cli_cmds, argv, argc); - if (r == -EAGAIN) - cli_error("unknown operation %s", argv[0]); - } - - r = cli_run(); - -error: - stop_sender(); - ctl_src_free(src); - src = NULL; - cli_destroy(); - return r; -} - -static int ctl_main(int argc, char *argv[]) -{ - struct shl_dlist *i; - struct ctl_link *l; - int r, left; - - r = ctl_wifi_new(&wifi, bus); - if (r < 0) - return r; - - left = argc - optind; - r = ctl_interactive(argv + optind, left <= 0 ? 0 : left); - - /* stop all scans */ - shl_dlist_for_each(i, &wifi->links) { - l = link_from_dlist(i); - if (l->have_p2p_scan) - ctl_link_set_p2p_scanning(l, false); - } - - ctl_wifi_free(wifi); - return r; -} - -static int parse_argv(int argc, char *argv[]) -{ - enum { - ARG_VERSION = 0x100, - ARG_LOG_LEVEL, - ARG_JOURNAL_LEVEL, - ARG_AUDIO, - }; - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "log-level", required_argument, NULL, ARG_LOG_LEVEL }, - { "log-journal-level", required_argument, NULL, ARG_JOURNAL_LEVEL }, - { "audio", required_argument, NULL, ARG_AUDIO }, - {} - }; - int c; - - rtsp_port = DEFAULT_RTSP_PORT; - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - switch (c) { - case 'h': - return cli_help(cli_cmds); - case ARG_VERSION: - puts(PACKAGE_STRING); - return 0; - case ARG_LOG_LEVEL: - cli_max_sev = log_parse_arg(optarg); - break; - case ARG_JOURNAL_LEVEL: - log_max_sev = log_parse_arg(optarg); - break; - case ARG_AUDIO: - gst_audio_en = atoi(optarg); - break; - case '?': - return -EINVAL; - } - } - - return 1; -} - -int main(int argc, char **argv) -{ - int r; - setlocale(LC_ALL, ""); - - r = parse_argv(argc, argv); - if (r < 0) - return EXIT_FAILURE; - if (!r) - return EXIT_SUCCESS; - - r = sd_bus_default_system(&bus); - if (r < 0) { - cli_error("cannot connect to system bus: %s", strerror(-r)); - return EXIT_FAILURE; - } - - r = ctl_main(argc, argv); - sd_bus_unref(bus); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} - diff --git a/src/ctl/wfd-src.c b/src/ctl/wfd-src.c deleted file mode 100644 index efb7c66..0000000 --- a/src/ctl/wfd-src.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * MiracleCast - Wifi-Display/Miracast Implementation - * - * Copyright (c) 2013-2014 David Herrmann - * - * MiracleCast is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * MiracleCast is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MiracleCast; If not, see . - */ - -#include "wfd-src.h" -#include "util.h" - -#define DEFAULT_RTSP_PORT (7236) - -/* - * RTSP Session - */ - -static void src_handle_options(struct wfd_src *s, - struct rtsp_message *m) -{ - _rtsp_message_unref_ struct rtsp_message *rep = NULL; - int r; - - cli_debug("INCOMING (M2): %s\n", rtsp_message_get_raw(m)); - - r = rtsp_message_new_reply_for(m, &rep, RTSP_CODE_OK, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(rep, "", - "Public", - "org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER, " - "SETUP, PLAY, PAUSE, TEARDOWN"); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(rep); - cli_debug("OUTGOING (M2): %s\n", rtsp_message_get_raw(rep)); - - r = rtsp_send(s->rtsp, rep); - if (r < 0) { - cli_vERR(r); - goto error; - } - - return; - -error: - wfd_src_close(s); - wfd_fn_src_disconnected(s); -} - -static int src_trigger_play_rep_fn(struct rtsp *bus, - struct rtsp_message *m, - void *data) -{ - cli_debug("INCOMING (M5): %s\n", rtsp_message_get_raw(m)); - - return 0; -} - -static void src_handle_setup(struct wfd_src *s, - struct rtsp_message *m) -{ - _rtsp_message_unref_ struct rtsp_message *rep = NULL; - _rtsp_message_unref_ struct rtsp_message *req = NULL; - int r; - - cli_debug("INCOMING (M6): %s\n", rtsp_message_get_raw(m)); - - r = rtsp_message_new_reply_for(m, &rep, RTSP_CODE_OK, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(rep, "", - "Session", "0;timeout=30"); - if (r < 0) { - cli_vERR(r); - goto error; - } - - char buf[256]; - snprintf(buf, sizeof(buf), "RTP/AVP/UDP;unicast;client_port=%d", s->sink.rtp_ports.port0); - r = rtsp_message_append(rep, "", - "Transport", buf); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(rep); - cli_debug("OUTGOING (M6): %s\n", rtsp_message_get_raw(rep)); - - r = rtsp_send(s->rtsp, rep); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_new_request(s->rtsp, - &req, - "SET_PARAMETER", - s->url); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(req, "{&}", "wfd_trigger_method: PLAY"); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(req); - cli_debug("OUTGOING (M5): %s\n", rtsp_message_get_raw(req)); - - r = rtsp_call_async(s->rtsp, req, src_trigger_play_rep_fn, s, 0, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - wfd_fn_src_setup(s); - - return; - -error: - wfd_src_close(s); - wfd_fn_src_disconnected(s); -} - -static void src_handle_play(struct wfd_src *s, - struct rtsp_message *m) -{ - _rtsp_message_unref_ struct rtsp_message *rep = NULL; - _rtsp_message_unref_ struct rtsp_message *req = NULL; - int r; - - cli_debug("INCOMING (M7): %s\n", rtsp_message_get_raw(m)); - - r = rtsp_message_new_reply_for(m, &rep, RTSP_CODE_OK, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(rep, "", - "Session", "0;timeout=30"); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(rep, "", - "Range", "ntp=now-"); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(rep); - cli_debug("OUTGOING (M7): %s\n", rtsp_message_get_raw(rep)); - - r = rtsp_send(s->rtsp, rep); - if (r < 0) { - cli_vERR(r); - goto error; - } - - wfd_fn_src_playing(s); - - return; - -error: - wfd_src_close(s); - wfd_fn_src_disconnected(s); -} - -static void src_handle_pause(struct wfd_src *s, - struct rtsp_message *m) -{ - cli_debug("INCOMING (M9): %s\n", rtsp_message_get_raw(m)); -} - -static void src_handle_teardown(struct wfd_src *s, - struct rtsp_message *m) -{ - cli_debug("INCOMING (M8): %s\n", rtsp_message_get_raw(m)); -} - -static bool parse_video_formats(struct rtsp_message *m, - struct video_formats *formats) -{ - const char *param; - int r; - - r = rtsp_message_read(m, "{<&>}", "wfd_video_formats", ¶m); - if(r < 0) { - goto error; - } - else if(!strncmp("none", param, 4) || strlen(param) < 55) { - return false; - } - - r = sscanf(param, "%hhx %hhx %hhx %hhx %x %x %x %hhx %hx %hx %hhx", - &formats->native_disp_mode, - &formats->pref_disp_mode, - &formats->codec_profile, - &formats->codec_level, - &formats->resolutions_cea, - &formats->resolutions_vesa, - &formats->resolutions_hh, - &formats->latency, - &formats->min_slice_size, - &formats->slice_enc_params, - &formats->frame_rate_control); - if(r < 11) { - goto error; - } - - formats->hres = -1; - formats->vres = -1; - sscanf(param + 55, "%x %x", &formats->hres, &formats->vres); - - return true; - -error: - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] Invalid video formats\n"); - return false; -} - -static bool parse_audio_codecs(struct rtsp_message *m, - struct audio_codecs *codecs) -{ - const char *param; - int r; - - r = rtsp_message_read(m, "{<&>}", "wfd_audio_codecs", ¶m); - if(r < 0) { - goto error; - } - else if(!strncmp("none", param, 4) || strlen(param) < 4) { - return false; - } - - cli_printf("audio codecs: %s\n", param); - - if(!strncmp("LPCM", param, 4)) { - codecs->format = AUDIO_FORMAT_LPCM; - } - else if(!strncmp("AAC", param, 3)) { - codecs->format = AUDIO_FORMAT_AAC; - } - else if(!strncmp("AC3", param, 3)) { - codecs->format = AUDIO_FORMAT_AC3; - } - else { - goto error; - } - - r = sscanf(param, "%x %hhx", - &codecs->modes, - &codecs->latency); - if(r < 2) { - goto error; - } - - return true; - -error: - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] Invalid audio codecs\n"); - return false; -} - -static bool parse_client_rtp_ports(struct rtsp_message *m, - struct client_rtp_ports *ports) -{ - const char *param; - int r; - char mode[10] = ""; - - r = rtsp_message_read(m, "{<&>}", "wfd_client_rtp_ports", ¶m); - if(r < 0) { - goto error; - } - - r = sscanf(param, "%ms %hu %hu %9s", - &ports->profile, - &ports->port0, - &ports->port1, - mode); - if(r < 4 || strcmp("mode=play", mode)) { - goto error; - } - - return true; - -error: - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] Invalid client RTP ports\n"); - return false; -} - -static int src_trigger_setup_rep_fn(struct rtsp *bus, - struct rtsp_message *m, - void *data) -{ - struct wfd_src *s = data; - _rtsp_message_unref_ struct rtsp_message *req = NULL; - - cli_debug("INCOMING (M5): %s\n", rtsp_message_get_raw(m)); - - if(rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) { - return 0; - } - - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] Sink failed to SETUP\n"); - - wfd_src_close(s); - wfd_fn_src_disconnected(s); - - return 0; -} - -static int src_set_parameter_rep_fn(struct rtsp *bus, - struct rtsp_message *m, - void *data) -{ - struct wfd_src *s = data; - _rtsp_message_unref_ struct rtsp_message *req = NULL; - int r; - - cli_debug("INCOMING (M4): %s\n", rtsp_message_get_raw(m)); - - if(!rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) { - r = -1; - goto error; - } - - r = rtsp_message_new_request(s->rtsp, - &req, - "SET_PARAMETER", - s->url); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(req, "{&}", "wfd_trigger_method: SETUP"); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(req); - cli_debug("OUTGOING (M5): %s\n", rtsp_message_get_raw(req)); - - r = rtsp_call_async(s->rtsp, req, src_trigger_setup_rep_fn, s, 0, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - return 0; - -error: - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] SETUP failed\n"); - return r; -} - -char buf[1024]; - -static int src_send_set_parameter(struct wfd_src *s) -{ - _rtsp_message_unref_ struct rtsp_message *req; - int r; - const static char tmp[] = - "wfd_video_formats: 38 00 02 10 00000080 00000000 00000000 00 0000 0000 11 none none\n" - //"wfd_audio_codecs: AAC 00000001 00\n" - //"wfd_uibc_capability: input_category_list=GENERIC\n;generic_cap_list=SingleTouch;hidc_cap_list=none;port=5100\n" - //"wfd_uibc_setting: disable\n" - "wfd_presentation_URL: %s/streamid=0 none\n" - "wfd_client_rtp_ports: %s %d %d mode=play"; - - r = rtsp_message_new_request(s->rtsp, - &req, - "SET_PARAMETER", - s->url); - if (r < 0) { - cli_vERR(r); - goto error; - } - - snprintf(buf, sizeof(buf), tmp, s->url, s->sink.rtp_ports.profile, - s->sink.rtp_ports.port0, s->sink.rtp_ports.port1); - - r = rtsp_message_append(req, "{&}", buf); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(req); - cli_debug("OUTGOING (M4): %s\n", rtsp_message_get_raw(req)); - - r = rtsp_call_async(s->rtsp, req, src_set_parameter_rep_fn, s, 0, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - return 0; - -error: - wfd_src_close(s); - wfd_fn_src_disconnected(s); - - return r; -} - -static int src_get_parameter_rep_fn(struct rtsp *bus, - struct rtsp_message *m, - void *data) -{ - struct wfd_src *s = data; - - cli_debug("INCOMING (M3): %s\n", rtsp_message_get_raw(m)); - - if (!rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) { - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] GET_PARAMETER failed\n"); - - wfd_src_close(s); - wfd_fn_src_disconnected(s); - - return -EINVAL; - } - - free(s->sink.rtp_ports.profile); - s->sink.rtp_ports.profile = NULL; - - s->sink.has_video_formats = parse_video_formats(m, &s->sink.video_formats); - //s->sink.has_audio_codecs = parse_audio_codecs(m, &s->sink.audio_codecs); - s->sink.has_rtp_ports = parse_client_rtp_ports(m, &s->sink.rtp_ports); - - return src_send_set_parameter(s); -} - -static int src_options_rep_fn(struct rtsp *bus, - struct rtsp_message *m, - void *data) -{ - struct wfd_src *s = data; - _rtsp_message_unref_ struct rtsp_message *req = NULL; - int r; - - cli_debug("INCOMING (M1): %s\n", rtsp_message_get_raw(m)); - - if(!rtsp_message_is_reply(m, RTSP_CODE_OK, NULL)) { - cli_printf("[" CLI_RED "ERROR" CLI_DEFAULT "] Failed to get OPTIONS from sink\n"); - goto error; - } - - r = rtsp_message_new_request(s->rtsp, - &req, - "GET_PARAMETER", - s->url); - if (r < 0) { - cli_vERR(r); - goto error; - } - - r = rtsp_message_append(req, "{&}", - "wfd_video_formats\n" - //"wfd_audio_codecs\n" - "wfd_client_rtp_ports\n" - //"wfd_uibc_capability" - ); - if (r < 0) { - cli_vERR(r); - goto error; - } - - rtsp_message_seal(req); - cli_debug("OUTGOING (M3): %s\n", rtsp_message_get_raw(req)); - - r = rtsp_call_async(s->rtsp, req, src_get_parameter_rep_fn, s, 0, NULL); - if (r < 0) { - cli_vERR(r); - goto error; - } - - return 0; - -error: - wfd_src_close(s); - wfd_fn_src_disconnected(s); - - return r; -} - -static void src_handle(struct wfd_src *s, - struct rtsp_message *m) -{ - const char *method; - - if(!m) { - wfd_src_close(s); - wfd_fn_src_disconnected(s); - return; - } - - method = rtsp_message_get_method(m); - if(!method) { - cli_debug("INCOMING: Unexpected message (%d): %s\n", - rtsp_message_get_type(m), - rtsp_message_get_raw(m)); - } - else if (!strcmp(method, "OPTIONS")) { - src_handle_options(s, m); - } else if (!strcmp(method, "SETUP")) { - src_handle_setup(s, m); - } else if (!strcmp(method, "PLAY")) { - src_handle_play(s, m); - } else if (!strcmp(method, "PAUSE")) { - src_handle_pause(s, m); - } else if (!strcmp(method, "TEARDOWN")) { - src_handle_teardown(s, m); - } -} - -static int src_rtsp_fn(struct rtsp *bus, - struct rtsp_message *m, - void *data) -{ - struct wfd_src *s = data; - - if (!m) - s->hup = true; - else - src_handle(s, m); - - if (s->hup) { - wfd_src_close(s); - wfd_fn_src_disconnected(s); - } - - return 0; -} - -static void src_send_options(struct wfd_src *s) -{ - _rtsp_message_unref_ struct rtsp_message *req = NULL; - int r; - - r = rtsp_message_new_request(s->rtsp, - &req, - "OPTIONS", - "*"); - if (r < 0) - return cli_vERR(r); - - r = rtsp_message_append(req, "", - "Require", - "org.wfa.wfd1.0"); - if (r < 0) - return cli_vERR(r); - - rtsp_message_seal(req); - - r = rtsp_call_async(s->rtsp, req, src_options_rep_fn, s, 0, NULL); - if (r < 0) - return cli_vERR(r); - - cli_debug("OUTGOING (M1): %s\n", rtsp_message_get_raw(req)); -} - -/* - * Source I/O - */ - -static void src_connected(struct wfd_src *s) -{ - int r, val; - struct sockaddr_storage addr; - socklen_t len; - - cli_printf("got incomming connection request\n"); - - if (s->connected || s->hup) - return; - - sd_event_source_set_enabled(s->fd_source, SD_EVENT_OFF); - - len = sizeof(addr); - int fd = accept4(s->fd, (struct sockaddr *) &addr, &len, SOCK_CLOEXEC); - - r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len); - if (r < 0) { - s->hup = true; - cli_vERRNO(); - return; - } else if (val) { - s->hup = true; - errno = val; - cli_error("cannot connect to remote host (%d): %m", errno); - return; - } - - cli_debug("connection established"); - - close(s->fd); - s->fd = fd; - s->addr = addr; - s->addr_size = len; - - r = rtsp_open(&s->rtsp, s->fd); - if (r < 0) - goto error; - - r = rtsp_attach_event(s->rtsp, s->event, 0); - if (r < 0) - goto error; - - r = rtsp_add_match(s->rtsp, src_rtsp_fn, s); - if (r < 0) - goto error; - - s->connected = true; - wfd_fn_src_connected(s); - - src_send_options(s); - - return; - -error: - s->hup = true; - cli_vERR(r); -} - -static void src_io(struct wfd_src *s, uint32_t mask) -{ - cli_notice("src_io: %u", mask); - - if (mask & EPOLLIN) { - src_connected(s); - } - - if (mask & EPOLLERR) { - cli_notice("ERR on socket"); - s->hup = true; - } - - if (s->hup) { - wfd_src_close(s); - wfd_fn_src_disconnected(s); - } -} - -static int src_io_fn(sd_event_source *source, - int fd, - uint32_t mask, - void *data) -{ - src_io(data, mask); - return 0; -} - -static int src_listen(struct wfd_src *s) -{ - int fd, r, enable = 1; - - if (!s) - return cli_EINVAL(); - if (s->fd >= 0) - return 0; - if (!s->addr.ss_family || !s->addr_size) - return cli_EINVAL(); - - fd = socket(s->addr.ss_family, - SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - 0); - if (fd < 0) - return cli_ERRNO(); - - r = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); - if(r < 0) { - r = -errno; - cli_vERR(r); - goto err_close; - } - - r = bind(fd, (struct sockaddr*)&s->addr, s->addr_size); - if (r < 0) { - r = -errno; - cli_vERR(r); - goto err_close; - } - - r = listen(fd, 1); - if (r < 0) { - r = -errno; - if (r != -EINPROGRESS) { - cli_vERR(r); - goto err_close; - } - } - - cli_printf("Wait for RTSP connection request from sink...\n"); - - r = sd_event_add_io(s->event, - &s->fd_source, - fd, - EPOLLERR | EPOLLIN | EPOLLET, - src_io_fn, - s); - if (r < 0) { - cli_vERR(r); - goto err_close; - } - - s->fd = fd; - return 0; - -err_close: - close(fd); - return r; -} - -static void src_close(struct wfd_src *s) -{ - if (!s || s->fd < 0) - return; - - free(s->sink.rtp_ports.profile); - s->sink.rtp_ports.profile = NULL; - rtsp_remove_match(s->rtsp, src_rtsp_fn, s); - rtsp_detach_event(s->rtsp); - rtsp_unref(s->rtsp); - s->rtsp = NULL; - sd_event_source_unref(s->fd_source); - s->fd_source = NULL; - close(s->fd); - s->fd = -1; - s->connected = false; - s->hup = false; -} - -/* - * Source Management - */ - -int wfd_src_new(struct wfd_src **out, - sd_event *event) -{ - struct wfd_src *s; - - if (!out || !event) - return cli_EINVAL(); - - s = calloc(1, sizeof(*s)); - if (!s) - return cli_ENOMEM(); - - s->event = sd_event_ref(event); - s->fd = -1; - - *out = s; - return 0; -} - -void wfd_src_free(struct wfd_src *s) -{ - if (!s) - return; - - wfd_src_close(s); - free(s->local); - free(s->session); - sd_event_unref(s->event); - free(s); -} - -int wfd_src_listen(struct wfd_src *s, const char *local) -{ - struct sockaddr_in addr = { }; - char *l; - int r; - - if (!s || !local || s->fd >= 0) - return cli_EINVAL(); - - addr.sin_family = AF_INET; - addr.sin_port = htons(DEFAULT_RTSP_PORT); - r = inet_pton(AF_INET, local, &addr.sin_addr); - if (r != 1) - return cli_EINVAL(); - - l = strdup(local); - if (!l) - return cli_ENOMEM(); - - free(s->local); - s->local = l; - - memcpy(&s->addr, &addr, sizeof(addr)); - s->addr_size = sizeof(addr); - - snprintf(s->url, sizeof(s->url), "rtsp://%s/wfd1.0", local); - - return src_listen(s); -} - -void wfd_src_close(struct wfd_src *s) -{ - if (!s) - return; - - src_close(s); -} - -bool wfd_src_is_connecting(struct wfd_src *s) -{ - return s && s->fd >= 0 && !s->connected; -} - -bool wfd_src_is_connected(struct wfd_src *s) -{ - return s && s->connected; -} - -bool wfd_src_is_closed(struct wfd_src *s) -{ - return !s || s->fd < 0; -} diff --git a/src/ctl/wfd-src.h b/src/ctl/wfd-src.h deleted file mode 100644 index 48e775f..0000000 --- a/src/ctl/wfd-src.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * MiracleCast - Wifi-Display/Miracast Implementation - * - * MiracleCast is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * MiracleCast is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MiracleCast; If not, see . - */ - -#ifndef CTL_SRC_H -#define CTL_SRC_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctl.h" - -#include "rtsp.h" -#include "shl_macro.h" -#include "shl_util.h" -#include "wfd.h" - -enum audio_format { - AUDIO_FORMAT_UNKNOWN, - AUDIO_FORMAT_LPCM, - AUDIO_FORMAT_AAC, - AUDIO_FORMAT_AC3, -}; - -struct video_formats { - uint8_t native_disp_mode; - uint8_t pref_disp_mode; - uint8_t codec_profile; - uint8_t codec_level; - unsigned int resolutions_cea; - unsigned int resolutions_vesa; - unsigned int resolutions_hh; - uint8_t latency; - unsigned short min_slice_size; - unsigned short slice_enc_params; - uint8_t frame_rate_control; - int hres; - int vres; -}; - -struct audio_codecs { - enum audio_format format; - unsigned int modes; - uint8_t latency; -}; - -struct client_rtp_ports { - char *profile; - unsigned short port0; - unsigned short port1; -}; - -struct wfd_src { - sd_event *event; - - char *local; - char *session; - char url[256]; - struct sockaddr_storage addr; - size_t addr_size; - int fd; - sd_event_source *fd_source; - - sd_event_source *req_source; - - struct rtsp *rtsp; - - struct { - struct video_formats video_formats; - struct audio_codecs audio_codecs; - struct client_rtp_ports rtp_ports; - - bool has_video_formats : 1; - bool has_audio_codecs : 1; - bool has_rtp_ports : 1; - } sink; - - bool connected : 1; - bool hup : 1; -}; - -#endif /* CTL_SRC_H */ diff --git a/src/stream/CMakeLists.txt b/src/stream/CMakeLists.txt deleted file mode 100644 index 5296219..0000000 --- a/src/stream/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -pkg_check_modules(GDK REQUIRED gdk-3.0>=3.20) -pkg_check_modules(GIO REQUIRED gio-2.0>=2.30) -pkg_check_modules(GST REQUIRED gstreamer-1.0) -pkg_check_modules(GST_PBUTILS REQUIRED gstreamer-pbutils-1.0) -find_program(GDBUS_CODEGEN_EXEC NAMES gdbus-codegen) - -if(NOT GDBUS_CODEGEN_EXEC) - message(ERROR gdbus-codegen not found) -endif() - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${GDK_INCLUDE_DIRS} - ${GST_INCLUDE_DIRS} - ${GST_PBUTILS_INCLUDE_DIRS} - ${GIO_INCLUDE_DIRS} -) - -add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sender-iface.c - ${CMAKE_CURRENT_BINARY_DIR}/sender-iface.h - COMMAND ${GDBUS_CODEGEN_EXEC} - ARGS --generate-c-code sender-iface - --annotate org.freedesktop.miracle.Sender org.gtk.GDBus.C.Name Sender - --interface-prefix org.freedesktop.miracle.Sender - ${CMAKE_CURRENT_SOURCE_DIR}/sender-iface.xml - DEPENDS sender-iface.xml - COMMENT "generating sender interface" -) - -add_definitions(-DG_LOG_USE_STRUCTURED) - -add_library(sender-iface STATIC ${CMAKE_CURRENT_BINARY_DIR}/sender-iface.c) - -add_executable(miracle-sender sender) - -target_link_libraries(miracle-sender sender-iface - ${GDK_LIBRARIES} - ${GIO_LIBRARIES} - ${GST_LIBRARIES} - ${GST_PBUTILS_LIBRARIES}) - -install(TARGETS miracle-sender DESTINATION bin) diff --git a/src/stream/sender-iface.xml b/src/stream/sender-iface.xml deleted file mode 100644 index c4e14ec..0000000 --- a/src/stream/sender-iface.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/stream/sender.c b/src/stream/sender.c deleted file mode 100644 index ef1ca23..0000000 --- a/src/stream/sender.c +++ /dev/null @@ -1,746 +0,0 @@ -/* - * MiracleCast - Wifi-Display/Miracast Implementation - * - * MiracleCast is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * MiracleCast is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MiracleCast; If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sender-iface.h" -#include "sender.h" - -struct SenderImpl -{ - Sender *skeleton; - - GMainLoop *loop; - - GstElement *pipeline; - - struct CmdChannel *channel; - - guint bus_owner_id; - - guint bus_obj_id; - - GDBusMethodInvocation *method_invoke; - - guint timer_handle; -}; - -static gchar *arg_host = NULL; - -static guint arg_port = 1991; - -static guint arg_width = 0; - -static guint arg_height = 0; - -static gint arg_screen = -1; - -static gchar *arg_acodec = NULL; - -static gboolean arg_audio_only = FALSE; - -static guint arg_refresh_rate = 25; - -static const char *vpipeline_desc = - "ximagesrc name=vsrc use-damage=false show-pointer=false starty=%d startx=%d endy=%d endx=%d " - "capsfilter name=caps_framerate caps=\"video/x-raw, framerate=%u/1\" " - //"videoscale name=vscale " - //"capsfilter name=caps_scale caps=\"video/x-raw, width=%d, height=%d\" " - "autovideoconvert name=vconv " - "capsfilter name=caps_format caps=\"video/x-raw, format=I420\" " - //"encodebin name=vencoder " - //"vaapih264enc name=vencoder max-bframes=0 " - "x264enc name=vencoder tune=zerolatency " - "capsfilter name=caps_vencoder caps=\"video/x-h264, profile=baseline\" " - //"queue name=vqueue max-size-buffers=0 max-size-bytes=0 " - "mpegtsmux name=muxer " - "rtpmp2tpay name=rtppay " - "udpsink name=sink host=\"%s\" port=%d "; - //"filesink name=sink location=vaapi.mp2t "; - -static const char *apipeline_desc = - "pulsesrc name=asrc device=\"%s\" " - "audioconvert name=aconv " - "audioresample name=aresample " - "encodebin name=aencoder " - "queue name=aqueue "; - -static gboolean sender_impl_prepare(struct SenderImpl *self, - GDBusMethodInvocation *invocation, - const gchar *host, - guint16 port, - const gchar *display, - guint16 width, - guint16 height, - guint16 refresh_rate, - gboolean interleave); - -static gboolean sender_impl_play(struct SenderImpl *sender, GDBusMethodInvocation *invocation); - -static gboolean sender_impl_pause(struct SenderImpl *sender, GDBusMethodInvocation *invocation); - -static gboolean sender_impl_stop(struct SenderImpl *sender, GDBusMethodInvocation *invocation); - -#define SENDER_IMPL_ERROR_DOMAIN_NAME "miracle-sender-impl" - -static const GDBusErrorEntry sender_dbus_error_entries[] = { - { MIRACLE_SENDER_ERROR_UNKNOWN, "org.freedesktop.miracle.Sender.Error.Unknown" }, - { MIRACLE_SENDER_ERROR_NOT_PREPARED, "org.freedesktop.miracle.Sender.Error.NoPrepared" }, -}; - -static GQuark sender_impl_error_quark() -{ - static gsize registered = 0; - g_dbus_error_register_error_domain("miracle-sender", - ®istered, - sender_dbus_error_entries, - G_N_ELEMENTS(sender_dbus_error_entries)); - - return g_quark_from_static_string("miracle-sender-impl"); -} - -static struct SenderImpl * sender_impl_new() -{ - struct SenderImpl *self = g_slice_new0(struct SenderImpl); - - return self; -} - -static void sender_impl_free(struct SenderImpl *self) -{ - if(self->pipeline) { - gst_element_set_state(self->pipeline, GST_STATE_NULL); - g_object_unref(G_OBJECT(self->pipeline)); - } - - if(self->loop) { - g_main_loop_unref(self->loop); - } - - if(self->bus_owner_id) { - g_bus_unown_name(self->bus_owner_id); - } - - g_slice_free(struct SenderImpl, self); -} - -static void get_screen_dimension(gint *top, - gint *left, - gint *bottom, - gint *right) -{ - GdkRectangle rect; - -#if GDK_VERSION_MIN_REQUIRED > GDK_VERSION_3_20 - GdkDisplay *display = gdk_display_get_default(); - GdkMonitor *monitor; - - if(arg_screen < 0 || arg_screen >= gdk_display_get_n_monitors(display)) { - monitor = gdk_display_get_primary_monitor(display); - } - else { - monitor = gdk_display_get_monitor(display, arg_screen); - } - gdk_monitor_get_geometry(monitor, &rect); -#else - GdkScreen *screen = gdk_screen_get_default(); - gint monitor; - if(arg_screen < 0 || arg_screen >= gdk_screen_get_n_monitors(screen)) { - monitor = gdk_screen_get_primary_monitor(screen); - } - else { - monitor = arg_screen; - } - gdk_screen_get_monitor_geometry(screen, monitor, &rect); -#endif - - *top = rect.y; - *left = rect.x; - *bottom = rect.y + rect.height - 1; - *right = rect.x + rect.width - 1; -} - -static int link_elements(GstBin *bin, const char *name, ...) -{ - va_list argv; - const char *name1, *name2; - - va_start(argv, name); - name1 = name; - while((name2 = va_arg(argv, const char *))) { - GstElement *e1 = gst_bin_get_by_name(bin, name1); - if(!e1) { - g_warning("no such element: %s", name1); - return -1; - } - GstElement *e2 = gst_bin_get_by_name(bin, name2); - if(!e2) { - g_warning("no such element: %s", name2); - return -1; - } - gboolean linked = gst_element_link(e1, e2); - g_object_unref(G_OBJECT(e2)); - g_object_unref(G_OBJECT(e1)); - - if(!linked) { - g_warning("failed to link %s to %s", name1, name2); - errno = EINVAL; - return -1; - } - - name1 = name2; - } - va_end(argv); - - return 0; -} - -void on_gst_message_state_changed(struct SenderImpl *self, - GstMessage *message) -{ - GstState old, curr, pending; - gst_message_parse_state_changed(message, &old, &curr, &pending); - const char *src = GST_MESSAGE_SRC_NAME(message); - if(strncmp("pipeline", src, 8) || !self->skeleton) { - return; - } - - g_info("%s(%s) state changed: %s => %s", - GST_MESSAGE_SRC_NAME(message), - g_type_name(G_OBJECT_TYPE(GST_MESSAGE_SRC(message))), - gst_element_state_get_name(old), - gst_element_state_get_name(curr)); - - switch(curr) { - case GST_STATE_PLAYING: - g_object_set(self->skeleton, "state", "playing", NULL); - if(self->method_invoke) { - sender_complete_play(SENDER(self->skeleton), - self->method_invoke); - self->method_invoke = NULL; - } - g_info("sender playing"); - GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(self->pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, - "miracle-sender-playing"); - break; - case GST_STATE_READY: - g_object_set(self->skeleton, "state", "paused", NULL); - if(self->method_invoke) { - sender_complete_prepare(SENDER(self->skeleton), - self->method_invoke); - self->method_invoke = NULL; - } - g_info("sender ready"); - - GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(self->pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, - "miracle-sender-ready"); - break; - case GST_STATE_PAUSED: - g_object_set(self->skeleton, "state", "paused", NULL); - if(self->method_invoke) { - sender_complete_pause(SENDER(self->skeleton), - self->method_invoke); - self->method_invoke = NULL; - } - g_info("sender paused"); - break; - default: - break; - } -} - -void on_gst_message_error(struct SenderImpl *self, - GstMessage *message) -{ - GError *error = NULL; - char *dbg = NULL; - gst_message_parse_error(message, &error, &dbg); - if(self->method_invoke) { - g_dbus_method_invocation_return_gerror(self->method_invoke, error); - self->method_invoke = NULL; - } - g_warning("%s", dbg); - g_error_free(error); - g_free(dbg); -} - -void on_gst_message(struct SenderImpl *self, - GstMessage *message, - GstBus *bus) -{ - g_debug("pipeline message: %s", GST_MESSAGE_TYPE_NAME(message)); - switch(GST_MESSAGE_TYPE(message)) { - case GST_MESSAGE_ERROR: - on_gst_message_error(self, message); - break; - case GST_MESSAGE_STATE_CHANGED: - on_gst_message_state_changed(self, message); - break; - case GST_MESSAGE_LATENCY: { - GstClockTime latency = gst_pipeline_get_latency(GST_PIPELINE(self->pipeline)); - g_info("New latency is: %lu", latency); - } - break; - default: - break; - } -} - -static int prepare_pipeline(struct SenderImpl *self) -{ - GError *error = NULL; - gint result; - gint screen_top, screen_left, screen_bottom, screen_right; - GString * desc; - - desc = g_string_new(NULL); - if(!desc) { - result = -1; - goto end; - } - - get_screen_dimension(&screen_top, &screen_left, &screen_bottom, &screen_right); - g_string_append_printf(desc, - vpipeline_desc, - screen_top, - screen_left, - screen_bottom, - screen_right, - arg_refresh_rate, - //arg_width ? arg_width : screen_right - screen_left + 1, - //arg_height ? arg_height : screen_bottom - screen_top + 1, - arg_host, - arg_port); - - if(arg_acodec) { - g_string_append_printf(desc, - apipeline_desc, - "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor"); - } - - g_debug("finale pipeline: %s", desc->str); - - self->pipeline = gst_parse_launch(desc->str, &error); - if(error) { - g_error("%s", error->message); - goto free_desc; - } - - gst_element_set_name(GST_ELEMENT(self->pipeline), "pipeline"); - - /*GstEncodingVideoProfile *vencode_profile = gst_encoding_video_profile_new(*/ - /*gst_caps_from_string("video/x-h264, profile=high"),*/ - /*NULL,*/ - /*gst_caps_new_any(),*/ - /*0);*/ - GstElement *vencoder = gst_bin_get_by_name(GST_BIN(self->pipeline), "vencoder"); - g_object_set(G_OBJECT(vencoder), - //"profile", vencode_profile, - "max-bframes", 0, - NULL); - g_object_unref(G_OBJECT(vencoder)); - //g_object_unref(G_OBJECT(vencode_profile)); - - if(arg_acodec) { - const char *format; - if(!strncmp("ac3", arg_acodec, 3)) { - format = "audio/x-ac3, framed=true"; - } - else if(!strncmp("pcm", arg_acodec, 3)) { - format = "audio/x-lpcm"; - } - else { - format = "audio/mpeg, framed=true, mpegversion=4, stream-format=adts"; - } - GstEncodingAudioProfile *aencode_profile = gst_encoding_audio_profile_new( - gst_caps_from_string(format), - NULL, - gst_caps_new_any(), - 0); - GstElement *aencoder = gst_bin_get_by_name(GST_BIN(self->pipeline), "aencoder"); - g_object_set(G_OBJECT(aencoder), "profile", aencode_profile, NULL); - g_object_unref(G_OBJECT(aencoder)); - } - - result = link_elements(GST_BIN(self->pipeline), - "vsrc", - "caps_framerate", - //"vscale", - //"caps_scale", - "vconv", - "caps_format", - "vencoder", - "caps_vencoder", - //"vqueue", - "muxer", - "rtppay", - "sink", - NULL); - if(result < 0) { - goto error; - } - - if(arg_acodec) { - link_elements(GST_BIN(self->pipeline), - "asrc", - "aconv", - "aresample", - "aencoder", - "aqueue", - "muxer", - NULL); - } - - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(self->pipeline)); - g_signal_connect_swapped(bus, "message", G_CALLBACK(on_gst_message), self); - gst_bus_add_signal_watch(bus); - - gst_element_set_state(self->pipeline, GST_STATE_READY); - - goto free_desc; - -error: - if(self->pipeline) { - g_object_unref(self->pipeline); - self->pipeline = NULL; - } -free_desc: - g_string_free(desc, TRUE); -end: - return result; -} - -static void sender_on_name_acquired(GDBusConnection *conn, - const char *name, - gpointer user_data) -{ - struct SenderImpl *self = user_data; - GError *error = NULL; - gboolean result; - - g_info("dbus name org.freedesktop.miracle acquired"); - - self->skeleton = sender_skeleton_new(); - g_signal_connect_swapped(self->skeleton, - "handle-prepare", - G_CALLBACK(sender_impl_prepare), - self); - g_signal_connect_swapped(self->skeleton, - "handle-play", - G_CALLBACK(sender_impl_play), - self); - g_signal_connect_swapped(self->skeleton, - "handle-pause", - G_CALLBACK(sender_impl_pause), - self); - g_signal_connect_swapped(self->skeleton, - "handle-stop", - G_CALLBACK(sender_impl_stop), - self); - g_object_set(self->skeleton, "state", "stop", NULL); - - result = g_dbus_interface_skeleton_export( - G_DBUS_INTERFACE_SKELETON(self->skeleton), - conn, - "/org/freedesktop/miracle/Sender/0", - &error); - if(!result) { - g_error("failed to expose object"); - } -} - -static void sender_on_name_lost(GDBusConnection *conn, - const char *name, - gpointer user_data) -{ - struct SenderImpl *self = user_data; - if(self->skeleton) { - g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(self->skeleton)); - g_signal_handlers_disconnect_by_data(self->skeleton, self); - g_object_unref(self->skeleton); - self->skeleton = NULL; - } -} - -static gint sender_impl_init(struct SenderImpl *self) -{ - gint result; - self->loop = g_main_loop_new(NULL, FALSE); - if(!self->loop) { - result = -1; - goto end; - } - - g_info("trying to acquire dbus name org.freedesktop.miracle..."); - - self->bus_owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, - "org.freedesktop.miracle", - G_BUS_NAME_OWNER_FLAGS_NONE, - NULL, - sender_on_name_acquired, - NULL, - self, - NULL); - -end: - return result; -} - -static gboolean sender_impl_prepare(struct SenderImpl *self, - GDBusMethodInvocation *invocation, - const gchar *host, - guint16 port, - const gchar *display, - guint16 width, - guint16 height, - guint16 refresh_rate, - gboolean interleave) -{ - if(self->timer_handle) { - g_source_remove(self->timer_handle); - self->timer_handle = 0; - } - - if(self->pipeline) { - sender_complete_prepare(SENDER(self->skeleton), invocation); - return TRUE; - } - - if(self->method_invoke) { - g_dbus_method_invocation_return_error(invocation, - MIRACLE_SENDER_ERROR, - MIRACLE_SENDER_ERROR_AGAIN, - "request handling in progress"); - return TRUE; - } - - self->method_invoke = invocation; - - if(arg_host) { - g_free(arg_host); - } - arg_host = g_strdup(host); - arg_port = port; - g_setenv("DISPLAY", display ? display : ":0", TRUE); - arg_width = width; - arg_height = height; - - prepare_pipeline(self); - - return TRUE; -} - -static gboolean start_play(gpointer user_data) -{ - gst_element_set_state(((struct SenderImpl *) user_data)->pipeline, GST_STATE_PLAYING); - - return FALSE; -} - -static gboolean sender_impl_play(struct SenderImpl *self, - GDBusMethodInvocation *invocation) -{ - if(!self->pipeline) { - g_dbus_method_invocation_return_error(invocation, - MIRACLE_SENDER_ERROR, - MIRACLE_SENDER_ERROR_NOT_PREPARED, - "sender not prepared"); - return TRUE; - } - - if(self->method_invoke) { - g_dbus_method_invocation_return_error(invocation, - MIRACLE_SENDER_ERROR, - MIRACLE_SENDER_ERROR_AGAIN, - "request handling in progress"); - return TRUE; - } - - self->method_invoke = invocation; - - g_timeout_add_seconds(1, start_play, self); - - return TRUE; -} - -static gboolean sender_impl_pause(struct SenderImpl *self, - GDBusMethodInvocation *invocation) -{ - if(!self->pipeline) { - g_dbus_method_invocation_return_error(invocation, - MIRACLE_SENDER_ERROR, - MIRACLE_SENDER_ERROR_NOT_PREPARED, - "sender not prepared"); - return TRUE; - } - - if(self->method_invoke) { - g_dbus_method_invocation_return_error(invocation, - MIRACLE_SENDER_ERROR, - MIRACLE_SENDER_ERROR_AGAIN, - "request handling in progress"); - return TRUE; - } - - self->method_invoke = invocation; - - gst_element_set_state(self->pipeline, GST_STATE_PAUSED); - - return TRUE; -} - -static gboolean on_timeout_quit(gpointer user_data) -{ - struct SenderImpl *self = user_data; - - g_main_loop_quit(self->loop); - - return FALSE; -} - -static gboolean sender_impl_stop(struct SenderImpl *self, - GDBusMethodInvocation *invocation) -{ - if(!self->pipeline) { - goto end; - } - - if(self->method_invoke) { - g_dbus_method_invocation_return_error(invocation, - MIRACLE_SENDER_ERROR, - MIRACLE_SENDER_ERROR_AGAIN, - "request handling in progress"); - return TRUE; - } - - g_object_set(self->skeleton, "state", "stop", NULL); - - gst_element_set_state(self->pipeline, GST_STATE_NULL); - g_object_unref(self->pipeline); - self->pipeline = NULL; - - self->timer_handle = g_timeout_add_seconds(3, on_timeout_quit, self); - -end: - sender_complete_stop(SENDER(self->skeleton), invocation); - - return TRUE; -} - -static void sender_impl_run(struct SenderImpl *self) -{ - g_main_loop_run(self->loop); -} - -static GOptionEntry entries[] = { - { "host", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &arg_host, "the hostname of sink", "" }, - { "port", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_port, "the port which sink is waiting for RTP string", "" }, - { "width", 'w', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_width, "", "" }, - { "height", 'h', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_height, "", "" }, - { "screen-num", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_screen, "screen number to cast to", "" }, - { "acodec", 'a', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &arg_acodec, "codec to encode audio", "" }, - { "audio-only", 'o', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &arg_audio_only, "no video, audio stream only", "" }, - { 0 } -}; - -static void arg_parse(int *argc, char ***args) -{ - GOptionContext *opt_context; - GError *error = NULL; - - opt_context = g_option_context_new(""); - if(!opt_context) { - g_error("%s", strerror(errno)); - } - - g_option_context_add_main_entries(opt_context, entries, NULL); - if(!g_option_context_parse(opt_context, argc, args, &error)) { - g_fprintf(stderr, "%s\n", error->message); - exit(1); - } - - if(0 >= arg_port || arg_port > 65535) { - g_fprintf(stderr, "Invalid port number: %i\n", arg_port); - exit(1); - } - - g_option_context_free(opt_context); -} - -static void gst_raise_rank(const char *name, ...) -{ - va_list names; - GstRegistry *reg = gst_registry_get(); - - va_start(names, name); - while(name) { - GstPluginFeature *plugin = gst_registry_lookup_feature(reg, name); - if(!plugin) { - goto next; - } - - g_info("raising rank of plugin %s from %u to %u", - name, - gst_plugin_feature_get_rank(plugin), - GST_RANK_PRIMARY + 1); - gst_plugin_feature_set_rank(plugin, GST_RANK_PRIMARY + 1); - gst_object_unref(plugin); - -next: - name = va_arg(names, const char *); - } - - va_end(names); -} - -int main(int argc, char *args[]) -{ - struct SenderImpl *sender; - - arg_parse(&argc, &args); - - gdk_init(&argc, &args); - gst_init(&argc, &args); - gst_pb_utils_init(); - gst_raise_rank("vaapih264enc", "vaapienc_h264", "glcolorconvert", NULL); - - sender = sender_impl_new(); - if(!sender) { - g_error("%s", strerror(errno)); - } - - if(!sender_impl_init(sender)) { - g_error("%s", strerror(errno)); - } - - sender_impl_run(sender); - - sender_impl_free(sender); - - return 0; -} diff --git a/src/stream/sender.h b/src/stream/sender.h deleted file mode 100644 index 4269ef3..0000000 --- a/src/stream/sender.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: sender.h - * - * Description: - * - * Version: 1.0 - * Created: 2016年11月25日 10時42分20秒 - * Revision: none - * Compiler: gcc - * - * Author: YOUR NAME (), - * Organization: - * - * ===================================================================================== - */ - -#define MIRACLE_SENDER_ERROR sender_impl_error_quark() - -enum { - MIRACLE_SENDER_ERROR_UNKNOWN, - MIRACLE_SENDER_ERROR_NOT_PREPARED, - MIRACLE_SENDER_ERROR_AGAIN, -};