mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
move miracle-wfdctl from demo/ to res/
Change-Id: I37df75135e4713a73d3c63353c9a17dc248e2d7e
This commit is contained in:
parent
1129625c66
commit
6d1591de00
16 changed files with 115 additions and 147 deletions
|
@ -1,69 +1,3 @@
|
|||
|
||||
########### install files ###############
|
||||
|
||||
execute_process(
|
||||
COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=system_bus_services_dir dbus-1
|
||||
OUTPUT_VARIABLE DBUS_SYSTEM_SERVICES_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=systemdsystemunitdir systemd
|
||||
OUTPUT_VARIABLE SYSTEMD_SYSTEM_UNIT_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
configure_file(
|
||||
miracle-wifid.service.cmake
|
||||
miracle-wifid.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/miracle-wifid.service
|
||||
DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR}/
|
||||
)
|
||||
install(
|
||||
CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink miracle-wifid.service \$ENV{DESTDIR}/${SYSTEMD_SYSTEM_UNIT_DIR}/dbus-org.freedesktop.miracle.wifi.service)"
|
||||
)
|
||||
|
||||
configure_file(
|
||||
miracle-dispd.service.cmake
|
||||
miracle-dispd.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/miracle-dispd.service
|
||||
DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR}/
|
||||
)
|
||||
install(
|
||||
CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink miracle-dispd.service \$ENV{DESTDIR}/${SYSTEMD_SYSTEM_UNIT_DIR}/dbus-org.freedesktop.miracle.wfd.service)"
|
||||
)
|
||||
|
||||
configure_file(
|
||||
org.freedesktop.miracle.wifi.service.cmake
|
||||
org.freedesktop.miracle.wifi.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.miracle.wifi.service
|
||||
DESTINATION ${DBUS_SYSTEM_SERVICES_DIR}/
|
||||
)
|
||||
|
||||
configure_file(
|
||||
org.freedesktop.miracle.wfd.service.cmake
|
||||
org.freedesktop.miracle.wfd.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.miracle.wfd.service
|
||||
DESTINATION ${DBUS_SYSTEM_SERVICES_DIR}/
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS miracle-gst gstplayer uibc-viewer
|
||||
DESTINATION bin
|
||||
)
|
||||
|
||||
install(
|
||||
FILES org.freedesktop.miracle.conf
|
||||
DESTINATION /etc/dbus-1/system.d
|
||||
)
|
||||
|
||||
include(ValaPrecompile)
|
||||
pkg_check_modules(GIO2 REQUIRED gio-2.0)
|
||||
pkg_check_modules(GDK3 REQUIRED gdk-3.0)
|
||||
|
@ -73,11 +7,15 @@ include_directories(
|
|||
${GST1_INCLUDE_DIRS}
|
||||
${GDK3_INCLUDE_DIRS}
|
||||
${GIO_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
set(CMAKE_C_FLAGS "-Wno-deprecated-declarations ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "-Wno-unused-but-set-variable ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "-Wno-missing-braces ${CMAKE_C_FLAGS}")
|
||||
if(VALA_VERSION VERSION_GREATER 0.34.0 AND NOT GDK_VERSION_NEWER_THEN_3_22)
|
||||
list(APPEND VALA_EXTRA_OPTIONS -D GDK3_HAS_MONITOR_CLASS)
|
||||
endif()
|
||||
|
||||
vala_precompile(
|
||||
GSTENCODER_SRC gstencoder
|
||||
|
@ -89,7 +27,6 @@ vala_precompile(
|
|||
gio-2.0
|
||||
posix
|
||||
)
|
||||
|
||||
add_executable(gstencoder ${GSTENCODER_SRC})
|
||||
target_link_libraries(
|
||||
gstencoder
|
||||
|
@ -98,4 +35,92 @@ target_link_libraries(
|
|||
${GIO2_LIBRARIES}
|
||||
)
|
||||
|
||||
vala_precompile(
|
||||
WFDCTL_SRC wfdctl
|
||||
wfdctl.vala
|
||||
networkmanager.vala
|
||||
miracle-wifi.vala
|
||||
miracle-wfd.vala
|
||||
GENERATE_HEADER
|
||||
wfdctl.h
|
||||
CUSTOM_VAPIS
|
||||
sigint.vapi
|
||||
OPTIONS
|
||||
--target-glib=2.50
|
||||
${VALA_EXTRA_OPTIONS}
|
||||
PACKAGES
|
||||
gio-2.0
|
||||
gdk-3.0
|
||||
)
|
||||
add_executable(miracle-wfdctl ${WFDCTL_SRC} sigint.c)
|
||||
target_link_libraries(miracle-wfdctl ${GIO2_LIBRARIES} ${GDK3_LIBRARIES})
|
||||
|
||||
########### install files ###############
|
||||
|
||||
install(TARGETS gstencoder DESTINATION bin)
|
||||
|
||||
install(TARGETS miracle-wfdctl DESTINATION bin)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=system_bus_services_dir dbus-1
|
||||
OUTPUT_VARIABLE DBUS_SYSTEM_SERVICES_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=systemdsystemunitdir systemd
|
||||
OUTPUT_VARIABLE SYSTEMD_SYSTEM_UNIT_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
configure_file(
|
||||
miracle-wifid.service.cmake
|
||||
miracle-wifid.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/miracle-wifid.service
|
||||
DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR}/
|
||||
)
|
||||
install(
|
||||
CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink miracle-wifid.service \$ENV{DESTDIR}${SYSTEMD_SYSTEM_UNIT_DIR}/dbus-org.freedesktop.miracle.wifi.service)"
|
||||
)
|
||||
|
||||
configure_file(
|
||||
miracle-dispd.service.cmake
|
||||
miracle-dispd.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/miracle-dispd.service
|
||||
DESTINATION ${SYSTEMD_SYSTEM_UNIT_DIR}/
|
||||
)
|
||||
install(
|
||||
CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink miracle-dispd.service \$ENV{DESTDIR}${SYSTEMD_SYSTEM_UNIT_DIR}/dbus-org.freedesktop.miracle.wfd.service)"
|
||||
)
|
||||
|
||||
configure_file(
|
||||
org.freedesktop.miracle.wifi.service.cmake
|
||||
org.freedesktop.miracle.wifi.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.miracle.wifi.service
|
||||
DESTINATION $ENV{DESTDIR}${DBUS_SYSTEM_SERVICES_DIR}/
|
||||
)
|
||||
|
||||
configure_file(
|
||||
org.freedesktop.miracle.wfd.service.cmake
|
||||
org.freedesktop.miracle.wfd.service
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/org.freedesktop.miracle.wfd.service
|
||||
DESTINATION $ENV{DESTDIR}${DBUS_SYSTEM_SERVICES_DIR}/
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS miracle-gst gstplayer uibc-viewer
|
||||
DESTINATION bin
|
||||
)
|
||||
|
||||
install(
|
||||
FILES org.freedesktop.miracle.conf
|
||||
DESTINATION $ENV{DESTDIR}/etc/dbus-1/system.d
|
||||
)
|
||||
|
||||
|
|
|
@ -43,11 +43,32 @@ install_data('miracle-gst', 'gstplayer', 'uibc-viewer',
|
|||
install_dir: get_option('bindir'),
|
||||
install_mode: 'rwxr-xr-x')
|
||||
|
||||
add_languages('vala')
|
||||
gio2 = dependency('gio-2.0')
|
||||
gdk3 = dependency('gdk-3.0')
|
||||
gst1 = dependency('gstreamer-1.0')
|
||||
gst1_base = dependency('gstreamer-base-1.0')
|
||||
|
||||
add_languages('vala')
|
||||
valac = meson.get_compiler('vala')
|
||||
valac_extra_args = []
|
||||
if valac.version().version_compare('>=0.34') and gdk3.version().version_compare('>=3.22')
|
||||
valac_extra_args += ['-D', 'GDK3_HAS_MONITOR_CLASS']
|
||||
endif
|
||||
|
||||
executable('gstencoder', 'gstencoder.vala',
|
||||
dependencies: [gst1, gst1_base, gio2],
|
||||
install: true,
|
||||
vala_args: ['--pkg=posix'])
|
||||
|
||||
miracle_wfdctl_src = ['wfdctl.vala',
|
||||
'sigint.vapi',
|
||||
'sigint.c',
|
||||
'networkmanager.vala',
|
||||
'miracle-wifi.vala',
|
||||
'miracle-wfd.vala'
|
||||
]
|
||||
executable('miracle-wfdctl', miracle_wfdctl_src,
|
||||
dependencies: [gio2, gdk3],
|
||||
vala_args: valac_extra_args,
|
||||
install: true
|
||||
)
|
||||
|
|
50
res/miracle-wfd.vala
Normal file
50
res/miracle-wfd.vala
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* Generated by vala-dbus-binding-tool 0.4.0. Do not modify! */
|
||||
/* Generated with: /usr/bin/vala-dbus-binding-tool --gdbus --no-synced --rename-namespace=org:Org --rename-namespace=freedesktop:Freedesktop --rename-namespace=miracle:Miracle --rename-namespace=wifi:Wifi --rename-namespace=wfd:Wfd --api-path=/home/derekdai/Projects/miraclecast/demo/dbus */
|
||||
using GLib;
|
||||
|
||||
namespace Org {
|
||||
|
||||
namespace Freedesktop {
|
||||
|
||||
namespace Miracle {
|
||||
|
||||
namespace Wfd {
|
||||
|
||||
[DBus (name = "org.freedesktop.miracle.wfd.Sink")]
|
||||
public interface Sink : GLib.Object {
|
||||
|
||||
[DBus (name = "StartSession", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath start_session(string param0, string param1, uint param2, uint param3, uint param4, uint param5, string param6) throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Session", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath session { owned get; }
|
||||
|
||||
[DBus (name = "Peer", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath peer { owned get; }
|
||||
}
|
||||
|
||||
[DBus (name = "org.freedesktop.miracle.wfd.Session")]
|
||||
public interface Session : GLib.Object {
|
||||
|
||||
[DBus (name = "Resume", timeout = 120000)]
|
||||
public abstract void resume() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Pause", timeout = 120000)]
|
||||
public abstract void pause() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Teardown", timeout = 120000)]
|
||||
public abstract void teardown() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Sink", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath sink { owned get; }
|
||||
|
||||
[DBus (name = "Url", timeout = 120000)]
|
||||
public abstract string url { owned get; }
|
||||
|
||||
[DBus (name = "State", timeout = 120000)]
|
||||
public abstract int state { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
92
res/miracle-wifi.vala
Normal file
92
res/miracle-wifi.vala
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* Generated by vala-dbus-binding-tool 0.4.0. Do not modify! */
|
||||
/* Generated with: /usr/bin/vala-dbus-binding-tool --gdbus --no-synced --rename-namespace=org:Org --rename-namespace=freedesktop:Freedesktop --rename-namespace=miracle:Miracle --rename-namespace=wifi:Wifi --rename-namespace=wfd:Wfd --api-path=/home/derekdai/Projects/miraclecast/demo/dbus */
|
||||
using GLib;
|
||||
|
||||
namespace Org {
|
||||
|
||||
namespace Freedesktop {
|
||||
|
||||
namespace Miracle {
|
||||
|
||||
namespace Wifi {
|
||||
|
||||
[DBus (name = "org.freedesktop.miracle.wifi.Peer")]
|
||||
public interface Peer : GLib.Object {
|
||||
|
||||
[DBus (name = "Connect", timeout = 120000)]
|
||||
public abstract void connect(string param0, string param1) throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Disconnect", timeout = 120000)]
|
||||
public abstract void disconnect() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Link", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath link { owned get; }
|
||||
|
||||
[DBus (name = "P2PMac", timeout = 120000)]
|
||||
public abstract string p2p_mac { owned get; }
|
||||
|
||||
[DBus (name = "FriendlyName", timeout = 120000)]
|
||||
public abstract string friendly_name { owned get; }
|
||||
|
||||
[DBus (name = "Connected", timeout = 120000)]
|
||||
public abstract bool connected { get; }
|
||||
|
||||
[DBus (name = "Interface", timeout = 120000)]
|
||||
public abstract string interface { owned get; }
|
||||
|
||||
[DBus (name = "LocalAddress", timeout = 120000)]
|
||||
public abstract string local_address { owned get; }
|
||||
|
||||
[DBus (name = "RemoteAddress", timeout = 120000)]
|
||||
public abstract string remote_address { owned get; }
|
||||
|
||||
[DBus (name = "WfdSubelements", timeout = 120000)]
|
||||
public abstract string wfd_subelements { owned get; }
|
||||
|
||||
[DBus (name = "ProvisionDiscovery")]
|
||||
public signal void provision_discovery(string param0, string param1);
|
||||
|
||||
[DBus (name = "GoNegRequest")]
|
||||
public signal void go_neg_request(string param0, string param1);
|
||||
|
||||
[DBus (name = "FormationFailure")]
|
||||
public signal void formation_failure(string param0);
|
||||
}
|
||||
|
||||
[DBus (name = "org.freedesktop.miracle.wifi.Link")]
|
||||
public interface Link : GLib.Object {
|
||||
|
||||
[DBus (name = "Manage", timeout = 120000)]
|
||||
public abstract void manage() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Unmanage", timeout = 120000)]
|
||||
public abstract void unmanage() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "InterfaceIndex", timeout = 120000)]
|
||||
public abstract uint interface_index { get; }
|
||||
|
||||
[DBus (name = "MACAddress", timeout = 120000)]
|
||||
public abstract string m_a_c_address { owned get; }
|
||||
|
||||
[DBus (name = "InterfaceName", timeout = 120000)]
|
||||
public abstract string interface_name { owned get; }
|
||||
|
||||
[DBus (name = "FriendlyName", timeout = 120000)]
|
||||
public abstract string friendly_name { owned get; set; }
|
||||
|
||||
[DBus (name = "Managed", timeout = 120000)]
|
||||
public abstract bool managed { get; }
|
||||
|
||||
[DBus (name = "P2PState", timeout = 120000)]
|
||||
public abstract int p2p_state { get; }
|
||||
|
||||
[DBus (name = "P2PScanning", timeout = 120000)]
|
||||
public abstract bool p2p_scanning { get; set; }
|
||||
|
||||
[DBus (name = "WfdSubelements", timeout = 120000)]
|
||||
public abstract string wfd_subelements { owned get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
res/networkmanager.vala
Normal file
114
res/networkmanager.vala
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* Generated by vala-dbus-binding-tool 0.4.0. Do not modify! */
|
||||
/* Generated with: /usr/bin/vala-dbus-binding-tool --gdbus --no-synced --rename-namespace=org:Org --rename-namespace=freedesktop:Freedesktop --rename-namespace=miracle:Miracle --rename-namespace=wifi:Wifi --rename-namespace=wfd:Wfd --api-path=/home/derekdai/Projects/miraclecast/demo/dbus */
|
||||
using GLib;
|
||||
|
||||
namespace Org {
|
||||
|
||||
namespace Freedesktop {
|
||||
|
||||
namespace NetworkManager {
|
||||
|
||||
[DBus (name = "org.freedesktop.NetworkManager.Device")]
|
||||
public interface Device : GLib.Object {
|
||||
|
||||
[DBus (name = "Reapply", timeout = 120000)]
|
||||
public abstract void reapply(GLib.HashTable<string, GLib.HashTable<string, GLib.Variant>> connection, uint64 version_id, uint flags) throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "GetAppliedConnection", timeout = 120000)]
|
||||
public abstract void get_applied_connection(uint flags, out GLib.HashTable<string, GLib.HashTable<string, GLib.Variant>> connection, out uint64 version_id) throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Disconnect", timeout = 120000)]
|
||||
public abstract void disconnect() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "Delete", timeout = 120000)]
|
||||
public abstract void delete() throws DBusError, IOError;
|
||||
|
||||
[DBus (name = "StateChanged", timeout = 120000)]
|
||||
public signal void state_changed(uint new_state, uint old_state, uint reason);
|
||||
|
||||
[DBus (name = "Udi", timeout = 120000)]
|
||||
public abstract string udi { owned get; }
|
||||
|
||||
[DBus (name = "Interface", timeout = 120000)]
|
||||
public abstract string interface { owned get; }
|
||||
|
||||
[DBus (name = "IpInterface", timeout = 120000)]
|
||||
public abstract string ip_interface { owned get; }
|
||||
|
||||
[DBus (name = "Driver", timeout = 120000)]
|
||||
public abstract string driver { owned get; }
|
||||
|
||||
[DBus (name = "DriverVersion", timeout = 120000)]
|
||||
public abstract string driver_version { owned get; }
|
||||
|
||||
[DBus (name = "FirmwareVersion", timeout = 120000)]
|
||||
public abstract string firmware_version { owned get; }
|
||||
|
||||
[DBus (name = "Capabilities", timeout = 120000)]
|
||||
public abstract uint capabilities { get; }
|
||||
|
||||
[DBus (name = "Ip4Address", timeout = 120000)]
|
||||
public abstract uint ip4_address { get; }
|
||||
|
||||
[DBus (name = "State", timeout = 120000)]
|
||||
public abstract uint state { get; }
|
||||
|
||||
[DBus (name = "StateReason", timeout = 120000)]
|
||||
public abstract DeviceStateReasonStruct state_reason { owned get; }
|
||||
|
||||
[DBus (name = "ActiveConnection", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath active_connection { owned get; }
|
||||
|
||||
[DBus (name = "Ip4Config", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath ip4_config { owned get; }
|
||||
|
||||
[DBus (name = "Dhcp4Config", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath dhcp4_config { owned get; }
|
||||
|
||||
[DBus (name = "Ip6Config", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath ip6_config { owned get; }
|
||||
|
||||
[DBus (name = "Dhcp6Config", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath dhcp6_config { owned get; }
|
||||
|
||||
[DBus (name = "Managed", timeout = 120000)]
|
||||
public abstract bool managed { get; set; }
|
||||
|
||||
[DBus (name = "Autoconnect", timeout = 120000)]
|
||||
public abstract bool autoconnect { get; set; }
|
||||
|
||||
[DBus (name = "FirmwareMissing", timeout = 120000)]
|
||||
public abstract bool firmware_missing { get; }
|
||||
|
||||
[DBus (name = "NmPluginMissing", timeout = 120000)]
|
||||
public abstract bool nm_plugin_missing { get; }
|
||||
|
||||
[DBus (name = "DeviceType", timeout = 120000)]
|
||||
public abstract uint device_type { get; }
|
||||
|
||||
[DBus (name = "AvailableConnections", timeout = 120000)]
|
||||
public abstract GLib.ObjectPath[] available_connections { owned get; }
|
||||
|
||||
[DBus (name = "PhysicalPortId", timeout = 120000)]
|
||||
public abstract string physical_port_id { owned get; }
|
||||
|
||||
[DBus (name = "Mtu", timeout = 120000)]
|
||||
public abstract uint mtu { get; }
|
||||
|
||||
[DBus (name = "Metered", timeout = 120000)]
|
||||
public abstract uint metered { get; }
|
||||
|
||||
[DBus (name = "LldpNeighbors", timeout = 120000)]
|
||||
public abstract GLib.HashTable<string, GLib.Variant>[] lldp_neighbors { owned get; }
|
||||
|
||||
[DBus (name = "Real", timeout = 120000)]
|
||||
public abstract bool real { get; }
|
||||
|
||||
public struct DeviceStateReasonStruct {
|
||||
public uint attr1;
|
||||
public uint attr2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
res/sigint.c
Normal file
64
res/sigint.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <sys/signalfd.h>
|
||||
#include "sigint.h"
|
||||
|
||||
typedef struct _SigintDelegate SigintDelegate;
|
||||
|
||||
struct _SigintDelegate
|
||||
{
|
||||
SigintHandler handler;
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
static gboolean sigint_on_signal(GIOChannel *c, GIOCondition e, gpointer d)
|
||||
{
|
||||
struct signalfd_siginfo siginfo;
|
||||
g_io_channel_read_chars(c, (gchar *) &siginfo, sizeof(siginfo), NULL, NULL);
|
||||
|
||||
SigintDelegate *delegate = d;
|
||||
(*delegate->handler)(delegate->user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void sigint_add_watch(SigintHandler handler, gpointer user_data)
|
||||
{
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
|
||||
SigintDelegate *d = g_malloc(sizeof(SigintDelegate));
|
||||
*d = (SigintDelegate) {
|
||||
handler = handler,
|
||||
user_data = user_data
|
||||
};
|
||||
|
||||
int fd = signalfd(-1, &mask, SFD_CLOEXEC);
|
||||
GIOChannel *c = g_io_channel_unix_new(fd);
|
||||
g_io_add_watch_full(c,
|
||||
G_PRIORITY_DEFAULT,
|
||||
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||||
sigint_on_signal,
|
||||
d,
|
||||
g_free);
|
||||
g_io_channel_set_encoding(c, NULL, NULL);
|
||||
/*g_io_channel_unref(c);*/
|
||||
}
|
29
res/sigint.h
Normal file
29
res/sigint.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifndef DISP_SIGFD_H
|
||||
#define DISP_SIGFD_H
|
||||
|
||||
typedef void (*SigintHandler)(gpointer user_data);
|
||||
|
||||
void sigint_add_watch(SigintHandler handler, gpointer user_data);
|
||||
|
||||
#endif /* DISP_SIGFD_H */
|
8
res/sigint.vapi
Normal file
8
res/sigint.vapi
Normal file
|
@ -0,0 +1,8 @@
|
|||
[CCode(cheader_filename="sigint.h")]
|
||||
class Sigint
|
||||
{
|
||||
public delegate void Handler();
|
||||
|
||||
public static void add_watch(Handler handler);
|
||||
public static void remove_watch();
|
||||
}
|
798
res/wfdctl.vala
Normal file
798
res/wfdctl.vala
Normal file
|
@ -0,0 +1,798 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Org.Freedesktop.NetworkManager;
|
||||
using Org.Freedesktop.Miracle.Wifi;
|
||||
using Org.Freedesktop.Miracle.Wfd;
|
||||
|
||||
const string BUS_NAME_NETWORK_MANAGER = "org.freedesktop.NetworkManager";
|
||||
const string BUS_NAME_WIFID = "org.freedesktop.miracle.wifi";
|
||||
const string BUS_NAME_DISPD = "org.freedesktop.miracle.wfd";
|
||||
const string OBJ_PATH_DEVICE = "/org/freedesktop/NetworkManager/Devices";
|
||||
const string OBJ_PATH_LINK = "/org/freedesktop/miracle/wifi/link";
|
||||
const string OBJ_PATH_PEER = "/org/freedesktop/miracle/wifi/peer";
|
||||
const string OBJ_PATH_SINK = "/org/freedesktop/miracle/wfd/sink";
|
||||
const string OBJ_PATH_SESSION = "/org/freedesktop/miracle/wfd/session";
|
||||
const string IFACE_DEVICE = "org.freedesktop.NetworkManager.Device";
|
||||
const string IFACE_LINK = "org.freedesktop.miracle.wifi.Link";
|
||||
const string IFACE_PEER = "org.freedesktop.miracle.wifi.Peer";
|
||||
const string IFACE_SINK = "org.freedesktop.miracle.wfd.Sink";
|
||||
const string IFACE_SESSION = "org.freedesktop.miracle.wfd.Session";
|
||||
|
||||
errordomain WfdCtlError
|
||||
{
|
||||
NO_SUCH_NIC,
|
||||
TIMEOUT,
|
||||
MONITOR_GONE,
|
||||
FORMATION_ERROR,
|
||||
NO_P2P_SUPPORT,
|
||||
}
|
||||
|
||||
private void print(string format, ...)
|
||||
{
|
||||
stderr.printf("%s: ", Environment.get_prgname());
|
||||
stderr.vprintf(format, va_list());
|
||||
stderr.printf("\n");
|
||||
}
|
||||
|
||||
// to deal with sd_bus_path_encode/decode()ed path
|
||||
private string decode_path(string s)
|
||||
{
|
||||
char c;
|
||||
StringBuilder d = new StringBuilder();
|
||||
for(var i = 0; i < s.length; i ++) {
|
||||
if(s.data[i] == (uint8) '_') {
|
||||
c = (char) s.substring(i + 1, 2).to_long(null, 16);
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
c = (char) s.data[i];
|
||||
}
|
||||
d.append_c(c);
|
||||
}
|
||||
|
||||
return d.str;
|
||||
}
|
||||
|
||||
private class WfdCtl : GLib.Application
|
||||
{
|
||||
static string opt_iface;
|
||||
static string opt_wfd_subelems;
|
||||
static string opt_peer_mac;
|
||||
static string opt_display;
|
||||
static string opt_authority;
|
||||
static int opt_monitor_num;
|
||||
static string opt_audio_device;
|
||||
static bool opt_dont_borrow_wnic = false;
|
||||
static bool opt_dont_return_wnic = false;
|
||||
|
||||
protected signal void link_added(string index, Link link);
|
||||
protected signal void link_removed(string index, Link link);
|
||||
protected signal void peer_added(string label, Peer peer);
|
||||
protected signal void peer_removed(string label, Peer peer);
|
||||
protected signal void sink_added(string label, Sink sink);
|
||||
protected signal void sink_removed(string label, Sink sink);
|
||||
protected signal void session_added(string id, Session session);
|
||||
protected signal void session_removed(string id, Session session);
|
||||
|
||||
DBusObjectManagerClient nm;
|
||||
DBusObjectManagerClient wifi;
|
||||
DBusObjectManagerClient wfd;
|
||||
|
||||
HashTable<string, Device> devices;
|
||||
HashTable<string, Link> links;
|
||||
HashTable<string, Peer> peers;
|
||||
HashTable<string, Sink> sinks;
|
||||
HashTable<string, Session> sessions;
|
||||
|
||||
string curr_sink_mac;
|
||||
Gdk.Display display;
|
||||
Peer curr_peer;
|
||||
Sink curr_sink;
|
||||
Session curr_session;
|
||||
|
||||
const GLib.OptionEntry[] option_entries = {
|
||||
{ "interface", 'i', 0, OptionArg.STRING, ref opt_iface, "name of wireless network interface", "WNIC name" },
|
||||
{ "wfd-subelems", 'w', 0, OptionArg.STRING, ref opt_wfd_subelems, "device infomation. default: 000600001c4400c8", "device info subelems" },
|
||||
{ "peer-mac", 'p', 0, OptionArg.STRING, ref opt_peer_mac, "MAC address of target peer", "peer MAC" },
|
||||
{ "authority", 'x', 0, OptionArg.STRING, ref opt_authority, "authority to capture from display. default: XAUTHORITY environment variable", "display authority" },
|
||||
{ "display", 'd', 0, OptionArg.STRING, ref opt_display, "display name. default: DISPLAY environment variable", "display name" },
|
||||
{ "monitor-num", 'm', 0, OptionArg.INT, ref opt_monitor_num, "monitor number. default: -1, primary monitor", "monitor number" },
|
||||
{ "audio-device", 'a', 0, OptionArg.STRING, ref opt_audio_device, "pulseaudio device name", "audio device name" },
|
||||
{ "dont-borrow", 'b', 0, OptionArg.NONE, ref opt_dont_borrow_wnic, "do not acquire the ownership of WNIC before using it", "don't borrow WNIC" },
|
||||
{ "dont-return", 'r', 0, OptionArg.NONE, ref opt_dont_return_wnic, "do not release the ownership of WNIC after using it", "don't release WNIC" },
|
||||
{ null },
|
||||
};
|
||||
|
||||
public WfdCtl()
|
||||
{
|
||||
Object(application_id: "org.freedesktop.miracle.WfdCtl",
|
||||
flags: ApplicationFlags.FLAGS_NONE);
|
||||
|
||||
devices = new HashTable<string, Device>(str_hash, str_equal);
|
||||
links = new HashTable<string, Link>(str_hash, str_equal);
|
||||
peers = new HashTable<string, Peer>(str_hash, str_equal);
|
||||
sinks = new HashTable<string, Sink>(str_hash, str_equal);
|
||||
sessions = new HashTable<string, Session>(str_hash, str_equal);
|
||||
|
||||
add_main_option_entries(option_entries);
|
||||
}
|
||||
|
||||
private DBusProxy? add_object(string path) throws Error
|
||||
{
|
||||
int sep = path.last_index_of_char('/');
|
||||
string prefix = path.substring(0, sep);
|
||||
string key = path.substring(sep + 1);
|
||||
switch(prefix) {
|
||||
case OBJ_PATH_DEVICE:
|
||||
Device d = Bus.get_proxy_sync(BusType.SYSTEM,
|
||||
BUS_NAME_NETWORK_MANAGER,
|
||||
path);
|
||||
if(is_wnic(d.interface) && !devices.contains(d.interface)) {
|
||||
devices.insert(d.interface, d);
|
||||
return d as DBusProxy;
|
||||
}
|
||||
break;
|
||||
case OBJ_PATH_LINK:
|
||||
key = decode_path(key);
|
||||
Link l = links.lookup(key);
|
||||
if(null == l) {
|
||||
l = Bus.get_proxy_sync(BusType.SYSTEM,
|
||||
BUS_NAME_WIFID,
|
||||
path);
|
||||
links.insert(key, l);
|
||||
info("found wireless interface: %s", l.interface_name);
|
||||
link_added(key, l);
|
||||
}
|
||||
return l as DBusProxy;
|
||||
case OBJ_PATH_PEER:
|
||||
key = decode_path(key);
|
||||
Peer p = peers.lookup(key);
|
||||
if(null == p) {
|
||||
p = Bus.get_proxy_sync(BusType.SYSTEM,
|
||||
BUS_NAME_WIFID,
|
||||
path);
|
||||
peers.insert(key, p);
|
||||
info("peer added: %s (%s)", key, p.friendly_name);
|
||||
peer_added(key, p);
|
||||
}
|
||||
return p as DBusProxy;
|
||||
case OBJ_PATH_SINK:
|
||||
key = decode_path(key);
|
||||
Sink s = sinks.lookup(key);
|
||||
if(null == s) {
|
||||
s = Bus.get_proxy_sync(BusType.SYSTEM,
|
||||
BUS_NAME_DISPD,
|
||||
path);
|
||||
sinks.insert(key, s);
|
||||
info("sink added: %s", key);
|
||||
sink_added(key, s);
|
||||
}
|
||||
return s as DBusProxy;
|
||||
case OBJ_PATH_SESSION:
|
||||
key = decode_path(key);
|
||||
Session s = sessions.lookup(key);
|
||||
if(null == s) {
|
||||
s = Bus.get_proxy_sync(BusType.SYSTEM,
|
||||
BUS_NAME_DISPD,
|
||||
path);
|
||||
sessions.insert(key, s);
|
||||
info("session added: %s", key);
|
||||
session_added(key, s);
|
||||
}
|
||||
return s as DBusProxy;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void remove_object(string path)
|
||||
{
|
||||
int sep = path.last_index_of_char('/');
|
||||
string prefix = path.substring(0, sep);
|
||||
string key = path.substring(sep + 1);
|
||||
switch(prefix) {
|
||||
case OBJ_PATH_DEVICE:
|
||||
devices.remove(key);
|
||||
break;
|
||||
case OBJ_PATH_LINK:
|
||||
key = decode_path(key);
|
||||
Link l = links.lookup(key);
|
||||
if(null == l) {
|
||||
break;
|
||||
}
|
||||
links.remove(key);
|
||||
link_removed(key, l);
|
||||
break;
|
||||
case OBJ_PATH_PEER:
|
||||
key = decode_path(key);
|
||||
Peer p = peers.lookup(key);
|
||||
if(null == p) {
|
||||
info("removing stray peer: %s", key);
|
||||
break;
|
||||
}
|
||||
if(p == curr_peer) {
|
||||
curr_peer = null;
|
||||
}
|
||||
peers.remove(key);
|
||||
peer_removed(key, p);
|
||||
break;
|
||||
case OBJ_PATH_SINK:
|
||||
key = decode_path(key);
|
||||
Sink s = sinks.lookup(key);
|
||||
if(null == s) {
|
||||
info("removing stray sink: %s", key);
|
||||
break;
|
||||
}
|
||||
if(s == curr_sink) {
|
||||
curr_sink = null;
|
||||
}
|
||||
sinks.remove(key);
|
||||
sink_removed(key, s);
|
||||
break;
|
||||
case OBJ_PATH_SESSION:
|
||||
key = decode_path(key);
|
||||
Session s = sessions.lookup(key);
|
||||
if(null == s) {
|
||||
info("removing stray session: %s", key);
|
||||
break;
|
||||
}
|
||||
if(s == curr_session) {
|
||||
curr_session = null;
|
||||
}
|
||||
sessions.remove(key);
|
||||
session_removed(key, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void on_object_added(DBusObjectManager m, DBusObject o)
|
||||
{
|
||||
try {
|
||||
add_object(o.get_object_path());
|
||||
}
|
||||
catch(Error e) {
|
||||
print("failed to fetch information from DBus for object: %s",
|
||||
o.get_object_path());
|
||||
}
|
||||
}
|
||||
|
||||
private void on_object_removed(DBusObjectManager m, DBusObject o)
|
||||
{
|
||||
remove_object(o.get_object_path());
|
||||
}
|
||||
|
||||
private void fetch_info_from_dbus() throws Error
|
||||
{
|
||||
info("connecting to wifid...");
|
||||
wifi = new DBusObjectManagerClient.for_bus_sync(
|
||||
BusType.SYSTEM,
|
||||
DBusObjectManagerClientFlags.NONE,
|
||||
BUS_NAME_WIFID,
|
||||
"/org/freedesktop/miracle/wifi",
|
||||
null,
|
||||
null);
|
||||
wifi.object_added.connect(on_object_added);
|
||||
wifi.object_removed.connect(on_object_removed);
|
||||
|
||||
info("connecting to nm...");
|
||||
nm = new DBusObjectManagerClient.for_bus_sync(
|
||||
BusType.SYSTEM,
|
||||
DBusObjectManagerClientFlags.NONE,
|
||||
BUS_NAME_NETWORK_MANAGER,
|
||||
"/org/freedesktop",
|
||||
null,
|
||||
null);
|
||||
nm.object_added.connect(on_object_added);
|
||||
nm.object_removed.connect(on_object_removed);
|
||||
|
||||
info("connecting to dispd...");
|
||||
wfd = new DBusObjectManagerClient.for_bus_sync(
|
||||
BusType.SYSTEM,
|
||||
DBusObjectManagerClientFlags.NONE,
|
||||
BUS_NAME_DISPD,
|
||||
"/org/freedesktop/miracle/wfd",
|
||||
null,
|
||||
null);
|
||||
wfd.object_added.connect(on_object_added);
|
||||
wfd.object_removed.connect(on_object_removed);
|
||||
|
||||
info("fetching from wifid...");
|
||||
foreach(var o in wifi.get_objects()) {
|
||||
add_object(o.get_object_path());
|
||||
}
|
||||
|
||||
info("fetching from nm...");
|
||||
foreach(var o in nm.get_objects()) {
|
||||
add_object(o.get_object_path());
|
||||
}
|
||||
|
||||
info("fetching from wfd...");
|
||||
foreach(var o in wfd.get_objects()) {
|
||||
add_object(o.get_object_path());
|
||||
}
|
||||
}
|
||||
|
||||
private async void acquire_wnic_ownership() throws Error
|
||||
{
|
||||
Device d = find_device_by_name(opt_iface);
|
||||
if(null != d && d.managed) {
|
||||
info("NetworkManager is releasing ownership of %s...", opt_iface);
|
||||
|
||||
d.managed = false;
|
||||
yield wait_prop_changed(d, "Managed");
|
||||
}
|
||||
|
||||
Link l = find_link_by_name(opt_iface);
|
||||
if(null == l) {
|
||||
throw new WfdCtlError.NO_SUCH_NIC("no such wireless adapter: %s",
|
||||
opt_iface);
|
||||
}
|
||||
|
||||
if(l.managed) {
|
||||
info("wifid is releasing ownership of %s...", opt_iface);
|
||||
l.unmanage();
|
||||
yield wait_prop_changed(l, "Managed");
|
||||
}
|
||||
|
||||
info("wifid is acquiring ownership of %s...", opt_iface);
|
||||
l.manage();
|
||||
yield wait_prop_changed(l, "Managed");
|
||||
}
|
||||
|
||||
private async void start_p2p_scan() throws Error
|
||||
{
|
||||
Link? l = find_link_by_name(opt_iface);
|
||||
if(l.wfd_subelements != opt_wfd_subelems) {
|
||||
info("update wfd_subelems to broadcast what kind of device we are");
|
||||
|
||||
l.wfd_subelements = opt_wfd_subelems;
|
||||
yield wait_prop_changed(l, "WfdSubelements");
|
||||
}
|
||||
|
||||
if(-1 == l.p2p_state) {
|
||||
throw new WfdCtlError.NO_P2P_SUPPORT("link %s has no P2P supporting", l.interface_name);
|
||||
}
|
||||
else if(0 == l.p2p_state) {
|
||||
info("wait for P2P supporting status...");
|
||||
yield wait_prop_changed(l, "P2PState", 3);
|
||||
}
|
||||
|
||||
if(!l.p2p_scanning) {
|
||||
info("start P2P scanning...");
|
||||
l.p2p_scanning = true;
|
||||
yield wait_prop_changed(l, "P2PScanning");
|
||||
}
|
||||
|
||||
print("wait for peer '%s'...", opt_peer_mac);
|
||||
}
|
||||
|
||||
private async void wait_for_target_sink()
|
||||
{
|
||||
if(null != find_sink_by_mac(opt_peer_mac)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ulong id = sink_added.connect((l, s) => {
|
||||
if(null != find_sink_by_mac(opt_peer_mac)) {
|
||||
wait_for_target_sink.callback();
|
||||
}
|
||||
});
|
||||
|
||||
yield;
|
||||
|
||||
disconnect(id);
|
||||
}
|
||||
|
||||
private async void form_p2p_group() throws Error
|
||||
{
|
||||
if(null != curr_sink_mac) {
|
||||
print("already hang out with sink: %s", curr_sink_mac);
|
||||
return;
|
||||
}
|
||||
|
||||
Sink s = find_sink_by_mac(opt_peer_mac);
|
||||
curr_sink_mac = opt_peer_mac;
|
||||
|
||||
string l = s.peer;
|
||||
l = decode_path(l.substring(l.last_index_of_char('/') + 1));
|
||||
Peer p = peers.lookup(l);
|
||||
|
||||
info("forming P2P group with %s (%s)...", p.p2p_mac, p.friendly_name);
|
||||
|
||||
ulong id = p.formation_failure.connect((r) => {
|
||||
info("failed to form P2P group: %s", r);
|
||||
});
|
||||
p.connect("auto", "");
|
||||
yield wait_prop_changed(p, "Connected", 20);
|
||||
|
||||
(p as Object).disconnect(id);
|
||||
|
||||
curr_peer = p;
|
||||
|
||||
info("P2P group formed");
|
||||
}
|
||||
|
||||
#if GDK3_HAS_MONITOR_CLASS
|
||||
private void get_monitor_geometry(out Gdk.Rectangle g) throws Error
|
||||
{
|
||||
Gdk.Monitor m;
|
||||
if(-1 == opt_monitor_num) {
|
||||
m = display.get_primary_monitor();
|
||||
}
|
||||
else {
|
||||
m = display.get_monitor(opt_monitor_num);
|
||||
}
|
||||
|
||||
if(null == m) {
|
||||
throw new WfdCtlError.MONITOR_GONE("specified monitor disappeared");
|
||||
}
|
||||
|
||||
g = m.geometry;
|
||||
}
|
||||
#else
|
||||
private void get_monitor_geometry(out Gdk.Rectangle g) throws Error
|
||||
{
|
||||
var s = display.get_default_screen();
|
||||
int m = (-1 == opt_monitor_num)
|
||||
? s.get_primary_monitor()
|
||||
: opt_monitor_num;
|
||||
|
||||
if(s.get_n_monitors() <= m) {
|
||||
throw new WfdCtlError.MONITOR_GONE("specified monitor disappeared");
|
||||
}
|
||||
|
||||
s.get_monitor_geometry(m, out g);
|
||||
}
|
||||
#endif
|
||||
|
||||
private unowned string session_state_to_str(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case 1:
|
||||
return "connecting";
|
||||
case 2:
|
||||
return "capabilities exchanging";
|
||||
case 3:
|
||||
return "established";
|
||||
case 4:
|
||||
return "seting up session parameters";
|
||||
case 5:
|
||||
return "paused";
|
||||
case 6:
|
||||
return "playing";
|
||||
case 7:
|
||||
return "tearing down";
|
||||
case 8:
|
||||
return "destroyed";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
private async void establish_session() throws Error
|
||||
{
|
||||
Gdk.Rectangle g;
|
||||
get_monitor_geometry(out g);
|
||||
|
||||
info("establishing display session...");
|
||||
|
||||
Sink sink = find_sink_by_mac(opt_peer_mac);
|
||||
string path = sink.start_session(opt_authority,
|
||||
@"x://$(opt_display)",
|
||||
g.x,
|
||||
g.y,
|
||||
g.width,
|
||||
g.height,
|
||||
null == opt_audio_device ? "" : opt_audio_device);
|
||||
curr_session = add_object(path) as Session;
|
||||
(curr_session as DBusProxy).g_properties_changed.connect((props) => {
|
||||
string k;
|
||||
Variant v;
|
||||
foreach(var prop in props) {
|
||||
prop.get("{sv}", out k, out v);
|
||||
if(k != "State") {
|
||||
continue;
|
||||
}
|
||||
|
||||
info("session status: %s", session_state_to_str(v.get_int32()));
|
||||
|
||||
if(6 == v.get_int32()) {
|
||||
Idle.add(establish_session.callback);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
Error error = null;
|
||||
var timeout_src = new TimeoutSource(10);
|
||||
timeout_src.set_callback(() => {
|
||||
error = new WfdCtlError.TIMEOUT("failed to establish session");
|
||||
Idle.add(establish_session.callback);
|
||||
return false;
|
||||
});
|
||||
|
||||
yield;
|
||||
|
||||
timeout_src.destroy();
|
||||
if(null != error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
curr_sink = sink;
|
||||
}
|
||||
|
||||
private async void wait_for_session_ending()
|
||||
{
|
||||
info("wait for session ending");
|
||||
ulong id = session_removed.connect((id, s) => {
|
||||
wait_for_session_ending.callback();
|
||||
});
|
||||
|
||||
yield;
|
||||
|
||||
disconnect(id);
|
||||
|
||||
info("session ended");
|
||||
curr_session = null;
|
||||
}
|
||||
|
||||
private async void release_wnic_ownership() throws Error
|
||||
{
|
||||
if(opt_dont_return_wnic) {
|
||||
return;
|
||||
}
|
||||
|
||||
Link l = find_link_by_name(opt_iface);
|
||||
if(null == l) {
|
||||
throw new WfdCtlError.NO_SUCH_NIC("no such wireless adapter: %s",
|
||||
opt_iface);
|
||||
}
|
||||
|
||||
if(l.managed) {
|
||||
info("wifid is releasing ownership of %s...", opt_iface);
|
||||
l.unmanage();
|
||||
yield wait_prop_changed(l, "Managed");
|
||||
}
|
||||
|
||||
Device d = find_device_by_name(opt_iface);
|
||||
if(null != d && !d.managed) {
|
||||
info("NetworkManager is acquiring ownership of %s...", opt_iface);
|
||||
d.managed = true;
|
||||
yield wait_prop_changed(d, "Managed");
|
||||
}
|
||||
}
|
||||
|
||||
private async void start_wireless_display() throws Error
|
||||
{
|
||||
fetch_info_from_dbus();
|
||||
if(!opt_dont_borrow_wnic) {
|
||||
yield acquire_wnic_ownership();
|
||||
}
|
||||
yield start_p2p_scan();
|
||||
yield wait_for_target_sink();
|
||||
yield form_p2p_group();
|
||||
yield establish_session();
|
||||
yield wait_for_session_ending();
|
||||
}
|
||||
|
||||
public void stop_wireless_display()
|
||||
{
|
||||
if(null != curr_session) {
|
||||
info("tearing down wireless display...");
|
||||
|
||||
try {
|
||||
curr_session.teardown();
|
||||
}
|
||||
catch(Error e) {
|
||||
warning("failed to tearing down normally: %s", e.message);
|
||||
}
|
||||
|
||||
wait_prop_changed.begin(curr_sink, "Session", 3, () => {
|
||||
release_wnic_ownership.begin(quit);
|
||||
});
|
||||
}
|
||||
else {
|
||||
release_wnic_ownership.begin(quit);
|
||||
}
|
||||
}
|
||||
|
||||
private bool check_options()
|
||||
{
|
||||
if(null == opt_peer_mac) {
|
||||
print("please specify a peer MAC with -p option");
|
||||
return false;
|
||||
}
|
||||
print("peer-mac=%s", opt_peer_mac);
|
||||
|
||||
if(null == opt_display) {
|
||||
opt_display = Environment.get_variable("DISPLAY");
|
||||
}
|
||||
print("display=%s", opt_display);
|
||||
|
||||
if(null == opt_authority) {
|
||||
opt_authority = Environment.get_variable("XAUTHORITY");
|
||||
}
|
||||
print("authority=%s", opt_authority);
|
||||
|
||||
if(null == opt_iface) {
|
||||
opt_iface = "wlan0";
|
||||
}
|
||||
print("interface=%s", opt_iface);
|
||||
|
||||
if(null == opt_wfd_subelems) {
|
||||
opt_wfd_subelems = "000600001c4400c8";
|
||||
}
|
||||
print("wfd_subelemens=%s", opt_wfd_subelems);
|
||||
|
||||
display = Gdk.Display.open(opt_display);
|
||||
if(null == display) {
|
||||
print("invalid display option: %s", opt_display);
|
||||
return false;
|
||||
}
|
||||
|
||||
int n_monitors;
|
||||
#if GDK3_HAS_MONITOR_CLASS
|
||||
n_monitors = display.get_n_monitors();
|
||||
#else
|
||||
n_monitors = display.get_default_screen().get_n_monitors();
|
||||
#endif
|
||||
if(-1 > opt_monitor_num || opt_monitor_num >= n_monitors) {
|
||||
print("invalid screen number option: %d", opt_monitor_num);
|
||||
return false;
|
||||
}
|
||||
print("monitor-num=%d", opt_monitor_num);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void activate()
|
||||
{
|
||||
if(!check_options()) {
|
||||
return;
|
||||
}
|
||||
|
||||
start_wireless_display.begin((o, r) => {
|
||||
try {
|
||||
start_wireless_display.end(r);
|
||||
}
|
||||
catch(Error e) {
|
||||
print("failed to cast to wireless display: %s", e.message);
|
||||
release();
|
||||
}
|
||||
|
||||
release_wnic_ownership.begin((o, r) => {
|
||||
try {
|
||||
release_wnic_ownership.end(r);
|
||||
}
|
||||
catch(Error e) {
|
||||
}
|
||||
|
||||
quit();
|
||||
});
|
||||
});
|
||||
|
||||
hold();
|
||||
}
|
||||
|
||||
private unowned Device? find_device_by_name(string nic_name)
|
||||
{
|
||||
foreach(var d in devices.get_values()) {
|
||||
if(nic_name == d.interface) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private unowned Link? find_link_by_name(string nic_name)
|
||||
{
|
||||
foreach(var l in links.get_values()) {
|
||||
if(nic_name == l.interface_name) {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private unowned Sink? find_sink_by_mac(string m)
|
||||
{
|
||||
foreach(var l in sinks.get_keys()) {
|
||||
if(l.has_prefix(m)) {
|
||||
return sinks.lookup(l);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool is_wnic(string nic_name)
|
||||
{
|
||||
return find_link_by_name(nic_name) != null;
|
||||
}
|
||||
|
||||
private async void wait_prop_changed<T>(T o,
|
||||
string name,
|
||||
uint timeout = 1) throws WfdCtlError
|
||||
{
|
||||
ulong prop_changed_id = (o as DBusProxy).g_properties_changed.connect((props) => {
|
||||
string k;
|
||||
Variant v;
|
||||
foreach(var prop in props) {
|
||||
prop.get("{sv}", out k, out v);
|
||||
if(k == name) {
|
||||
wait_prop_changed.callback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bool timed_out = false;
|
||||
uint timeout_id = 0;
|
||||
if(0 < timeout) {
|
||||
timeout_id = Timeout.add_seconds(timeout,
|
||||
() => {
|
||||
timed_out = true;
|
||||
wait_prop_changed.callback();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
yield;
|
||||
|
||||
if(0 < timeout) {
|
||||
Source.remove(timeout_id);
|
||||
}
|
||||
(o as DBusProxy).disconnect(prop_changed_id);
|
||||
|
||||
if(timed_out) {
|
||||
throw new WfdCtlError.TIMEOUT("timeout to wait for property %s change",
|
||||
name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(string[]? argv)
|
||||
{
|
||||
Gdk.init(ref argv);
|
||||
Intl.setlocale();
|
||||
Environment.set_prgname(Path.get_basename(argv[0]));
|
||||
|
||||
|
||||
Application app = new WfdCtl();
|
||||
app.set_default();
|
||||
|
||||
Sigint.add_watch((app as WfdCtl).stop_wireless_display);
|
||||
|
||||
try {
|
||||
app.register();
|
||||
}
|
||||
catch(Error e) {
|
||||
print("failed to startup: %s", e.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int r = app.run(argv);
|
||||
|
||||
print("Bye");
|
||||
|
||||
return r;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue