mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
add a demostration for wifid + dispd
This commit is contained in:
parent
7c3f32111d
commit
29a89849ff
8 changed files with 670 additions and 1 deletions
|
@ -12,6 +12,7 @@ SET(BUILD_BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
|
||||||
OPTION(BUILD_ENABLE_DEBUG "Enable Debug" ON )
|
OPTION(BUILD_ENABLE_DEBUG "Enable Debug" ON )
|
||||||
OPTION(RELY_UDEV "Rely in udev tag to select device" OFF )
|
OPTION(RELY_UDEV "Rely in udev tag to select device" OFF )
|
||||||
OPTION(BUILD_TESTS "Enable TEST" ON )
|
OPTION(BUILD_TESTS "Enable TEST" ON )
|
||||||
|
OPTION(BUILD_DEMO "Enable DEMO" OFF )
|
||||||
|
|
||||||
if(BUILD_ENABLE_DEBUG)
|
if(BUILD_ENABLE_DEBUG)
|
||||||
add_definitions(-DBUILD_ENABLE_DEBUG)
|
add_definitions(-DBUILD_ENABLE_DEBUG)
|
||||||
|
@ -26,10 +27,10 @@ pkg_check_modules (GSTREAMER_BASE REQUIRED gstreamer-base-1.0)
|
||||||
|
|
||||||
include(CheckCCompilerFlag)
|
include(CheckCCompilerFlag)
|
||||||
check_c_compiler_flag(-fstack-protector-strong HAS_STACK_PROTCTOR_STRONG)
|
check_c_compiler_flag(-fstack-protector-strong HAS_STACK_PROTCTOR_STRONG)
|
||||||
|
check_c_compiler_flag(-fsanitize=undefined HAS_SANITIZE_UNDEFINED)
|
||||||
if(HAS_STACK_PROTCTOR_STRONG)
|
if(HAS_STACK_PROTCTOR_STRONG)
|
||||||
set(CMAKE_C_FLAGS "-fstack-protector-strong ${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "-fstack-protector-strong ${CMAKE_C_FLAGS}")
|
||||||
endif()
|
endif()
|
||||||
check_c_compiler_flag(-fsanitize=undefined HAS_SANITIZE_UNDEFINED)
|
|
||||||
if(HAS_SANITIZE_UNDEFINED)
|
if(HAS_SANITIZE_UNDEFINED)
|
||||||
set(CMAKE_C_FLAGS "-fsanitize=undefined ${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "-fsanitize=undefined ${CMAKE_C_FLAGS}")
|
||||||
endif()
|
endif()
|
||||||
|
@ -50,3 +51,7 @@ add_subdirectory(src)
|
||||||
add_subdirectory(res)
|
add_subdirectory(res)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
||||||
|
if(BUILD_DEMO)
|
||||||
|
add_subdirectory(demo)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
70
demo/CMakeLists.txt
Normal file
70
demo/CMakeLists.txt
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
find_program(VALAC valac)
|
||||||
|
if(NOT VALAC)
|
||||||
|
message(FATAL_ERROR "valac not found")
|
||||||
|
endif()
|
||||||
|
find_program(VALA_DBUS_BINDING_TOOL vala-dbus-binding-tool)
|
||||||
|
if(NOT VALA_DBUS_BINDING_TOOL)
|
||||||
|
message(FATAL_ERROR "vala-dbus-binding-tool not found")
|
||||||
|
endif()
|
||||||
|
find_library(READLINE REQUIRED)
|
||||||
|
|
||||||
|
pkg_check_modules(GIO2 REQUIRED gio-2.0)
|
||||||
|
|
||||||
|
set(RES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/res)
|
||||||
|
set(DBUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dbus)
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT org-freedesktop-networkmanager.vala
|
||||||
|
org-freedesktop-miracle-wifi.vala
|
||||||
|
org-freedesktop-miracle-wfd.vala
|
||||||
|
COMMAND ${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=${DBUS_DIR}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT wfdctl.c
|
||||||
|
wfdctl.h
|
||||||
|
org-freedesktop-networkmanager.c
|
||||||
|
org-freedesktop-miracle-wifi.c
|
||||||
|
org-freedesktop-miracle-wfd.c
|
||||||
|
COMMAND ${VALAC} --target-glib=2.50 -H wfdctl.h --use-header -C
|
||||||
|
--pkg=gio-2.0
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/wfdctl.vala
|
||||||
|
org-freedesktop-networkmanager.vala
|
||||||
|
org-freedesktop-miracle-wifi.vala
|
||||||
|
org-freedesktop-miracle-wfd.vala
|
||||||
|
DEPENDS wfdctl.vala
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/org-freedesktop-networkmanager.vala
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/org-freedesktop-miracle-wifi.vala
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/org-freedesktop-miracle-wfd.vala
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT wfdctl-res.c
|
||||||
|
COMMAND ${GLIB_COMPILE_RESOURCES}
|
||||||
|
--target=${CMAKE_CURRENT_BINARY_DIR}/wfdctl-res.c
|
||||||
|
--generate-source ${RES_DIR}/wfdctl-res.xml
|
||||||
|
DEPENDS ${RES_DIR}/wfdctl.ui
|
||||||
|
${RES_DIR}/wfdctl-res.xml
|
||||||
|
WORKING_DIRECTORY ${RES_DIR})
|
||||||
|
|
||||||
|
include_directories(${GIO2_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# silent C compiler warning about valac generated code, bad practice
|
||||||
|
set(CMAKE_C_FLAGS "-Wno-unused-label ${CMAKE_C_FLAGS}")
|
||||||
|
set(CMAKE_C_FLAGS "-Wno-incompatible-pointer-types ${CMAKE_C_FLAGS}")
|
||||||
|
set(CMAKE_C_FLAGS "-Wno-deprecated-declarations ${CMAKE_C_FLAGS}")
|
||||||
|
set(CMAKE_C_FLAGS "-Wno-unused-but-set-variable ${CMAKE_C_FLAGS}")
|
||||||
|
|
||||||
|
add_executable(miracle-wfdctl wfdctl
|
||||||
|
wfdctl-res.c
|
||||||
|
org-freedesktop-networkmanager.c
|
||||||
|
org-freedesktop-miracle-wifi.c
|
||||||
|
org-freedesktop-miracle-wfd.c)
|
||||||
|
|
||||||
|
target_link_libraries(miracle-wfdctl ${GIO2_LIBRARIES})
|
||||||
|
|
50
demo/dbus/org.freedesktop.NetworkManager.Devices.xml
Normal file
50
demo/dbus/org.freedesktop.NetworkManager.Devices.xml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
<!-- GDBus 2.50.3 -->
|
||||||
|
<node>
|
||||||
|
<interface name="org.freedesktop.NetworkManager.Device">
|
||||||
|
<method name="Reapply">
|
||||||
|
<arg type="a{sa{sv}}" name="connection" direction="in"/>
|
||||||
|
<arg type="t" name="version_id" direction="in"/>
|
||||||
|
<arg type="u" name="flags" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="GetAppliedConnection">
|
||||||
|
<arg type="u" name="flags" direction="in"/>
|
||||||
|
<arg type="a{sa{sv}}" name="connection" direction="out"/>
|
||||||
|
<arg type="t" name="version_id" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<method name="Disconnect"/>
|
||||||
|
<method name="Delete"/>
|
||||||
|
<signal name="StateChanged">
|
||||||
|
<arg type="u" name="new_state"/>
|
||||||
|
<arg type="u" name="old_state"/>
|
||||||
|
<arg type="u" name="reason"/>
|
||||||
|
</signal>
|
||||||
|
<property type="s" name="Udi" access="readonly"/>
|
||||||
|
<property type="s" name="Interface" access="readonly"/>
|
||||||
|
<property type="s" name="IpInterface" access="readonly"/>
|
||||||
|
<property type="s" name="Driver" access="readonly"/>
|
||||||
|
<property type="s" name="DriverVersion" access="readonly"/>
|
||||||
|
<property type="s" name="FirmwareVersion" access="readonly"/>
|
||||||
|
<property type="u" name="Capabilities" access="readonly"/>
|
||||||
|
<property type="u" name="Ip4Address" access="readonly"/>
|
||||||
|
<property type="u" name="State" access="readonly"/>
|
||||||
|
<property type="(uu)" name="StateReason" access="readonly"/>
|
||||||
|
<property type="o" name="ActiveConnection" access="readonly"/>
|
||||||
|
<property type="o" name="Ip4Config" access="readonly"/>
|
||||||
|
<property type="o" name="Dhcp4Config" access="readonly"/>
|
||||||
|
<property type="o" name="Ip6Config" access="readonly"/>
|
||||||
|
<property type="o" name="Dhcp6Config" access="readonly"/>
|
||||||
|
<property type="b" name="Managed" access="readwrite"/>
|
||||||
|
<property type="b" name="Autoconnect" access="readwrite"/>
|
||||||
|
<property type="b" name="FirmwareMissing" access="readonly"/>
|
||||||
|
<property type="b" name="NmPluginMissing" access="readonly"/>
|
||||||
|
<property type="u" name="DeviceType" access="readonly"/>
|
||||||
|
<property type="ao" name="AvailableConnections" access="readonly"/>
|
||||||
|
<property type="s" name="PhysicalPortId" access="readonly"/>
|
||||||
|
<property type="u" name="Mtu" access="readonly"/>
|
||||||
|
<property type="u" name="Metered" access="readonly"/>
|
||||||
|
<property type="aa{sv}" name="LldpNeighbors" access="readonly"/>
|
||||||
|
<property type="b" name="Real" access="readonly"/>
|
||||||
|
</interface>
|
||||||
|
</node>
|
36
demo/dbus/org.freedesktop.miracle.wfd.xml
Normal file
36
demo/dbus/org.freedesktop.miracle.wfd.xml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
<node>
|
||||||
|
<interface name="org.freedesktop.miracle.wfd.Session">
|
||||||
|
<method name="Resume">
|
||||||
|
</method>
|
||||||
|
<method name="Pause">
|
||||||
|
</method>
|
||||||
|
<method name="Teardown">
|
||||||
|
</method>
|
||||||
|
<property name="Sink" type="o" access="readonly">
|
||||||
|
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||||
|
</property>
|
||||||
|
<property name="Url" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="State" type="i" access="readonly">
|
||||||
|
</property>
|
||||||
|
</interface>
|
||||||
|
<interface name="org.freedesktop.miracle.wfd.Sink">
|
||||||
|
<method name="StartSession">
|
||||||
|
<arg type="s" direction="in"/>
|
||||||
|
<arg type="s" direction="in"/>
|
||||||
|
<arg type="u" direction="in"/>
|
||||||
|
<arg type="u" direction="in"/>
|
||||||
|
<arg type="u" direction="in"/>
|
||||||
|
<arg type="u" direction="in"/>
|
||||||
|
<arg type="s" direction="in"/>
|
||||||
|
<arg type="o" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<property name="Session" type="o" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="Peer" type="o" access="readonly">
|
||||||
|
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||||
|
</property>
|
||||||
|
</interface>
|
||||||
|
</node>
|
60
demo/dbus/org.freedesktop.miracle.wifi.xml
Normal file
60
demo/dbus/org.freedesktop.miracle.wifi.xml
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
<node>
|
||||||
|
<interface name="org.freedesktop.miracle.wifi.Peer">
|
||||||
|
<method name="Connect">
|
||||||
|
<arg type="s" direction="in"/>
|
||||||
|
<arg type="s" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="Disconnect">
|
||||||
|
</method>
|
||||||
|
<property name="Link" type="o" access="readonly">
|
||||||
|
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||||
|
</property>
|
||||||
|
<property name="P2PMac" type="s" access="readonly">
|
||||||
|
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||||
|
</property>
|
||||||
|
<property name="FriendlyName" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="Connected" type="b" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="Interface" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="LocalAddress" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="RemoteAddress" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="WfdSubelements" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<signal name="ProvisionDiscovery">
|
||||||
|
<arg type="s"/>
|
||||||
|
<arg type="s"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="GoNegRequest">
|
||||||
|
<arg type="s"/>
|
||||||
|
<arg type="s"/>
|
||||||
|
</signal>
|
||||||
|
</interface>
|
||||||
|
<interface name="org.freedesktop.miracle.wifi.Link">
|
||||||
|
<method name="Manage">
|
||||||
|
</method>
|
||||||
|
<method name="Unmanage">
|
||||||
|
</method>
|
||||||
|
<property name="InterfaceIndex" type="u" access="readonly">
|
||||||
|
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||||
|
</property>
|
||||||
|
<property name="MACAddress" type="s" access="readonly">
|
||||||
|
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||||||
|
</property>
|
||||||
|
<property name="InterfaceName" type="s" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="FriendlyName" type="s" access="readwrite">
|
||||||
|
</property>
|
||||||
|
<property name="Managed" type="b" access="readonly">
|
||||||
|
</property>
|
||||||
|
<property name="P2PScanning" type="b" access="readwrite">
|
||||||
|
</property>
|
||||||
|
<property name="WfdSubelements" type="s" access="readwrite">
|
||||||
|
</property>
|
||||||
|
</interface>
|
||||||
|
</node>
|
6
demo/res/wfdctl-res.xml
Normal file
6
demo/res/wfdctl-res.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/org/freedesktop/miracle">
|
||||||
|
<file compressed="true" preprocess="xml-stripblanks">wfdctl.ui</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
11
demo/res/wfdctl.ui
Normal file
11
demo/res/wfdctl.ui
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.18.3 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.12"/>
|
||||||
|
<object class="GtkWindow" id="main_win">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
431
demo/wfdctl.vala
Normal file
431
demo/wfdctl.vala
Normal file
|
@ -0,0 +1,431 @@
|
||||||
|
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";
|
||||||
|
|
||||||
|
errordomain WfdCtlError
|
||||||
|
{
|
||||||
|
NO_SUCH_NIC,
|
||||||
|
}
|
||||||
|
|
||||||
|
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_id;
|
||||||
|
int retry_count = 0;
|
||||||
|
|
||||||
|
string opt_iface;
|
||||||
|
string opt_wfd_subelems;
|
||||||
|
string opt_peer_mac;
|
||||||
|
|
||||||
|
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: 000600111c4400c8", "device info subelems" },
|
||||||
|
{ "peer-mac", 'p', 0, OptionArg.STRING, ref opt_peer_mac, "MAC address of target peer", "peer MAC" },
|
||||||
|
{ null },
|
||||||
|
};
|
||||||
|
|
||||||
|
void print(string format, ...)
|
||||||
|
{
|
||||||
|
var argv = va_list();
|
||||||
|
stderr.printf("%s: ", Environment.get_prgname());
|
||||||
|
stderr.vprintf(format, argv);
|
||||||
|
stderr.printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
unowned Sink? find_sink_by_label(string id)
|
||||||
|
{
|
||||||
|
return sinks.lookup(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_wnic(string nic_name)
|
||||||
|
{
|
||||||
|
return find_link_by_name(nic_name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// to deal with sd_bus_path_encode/decode()ed path
|
||||||
|
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 async void wait_prop_changed(DBusProxy o, string name)
|
||||||
|
{
|
||||||
|
ulong id = o.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
yield;
|
||||||
|
|
||||||
|
o.disconnect(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async void add_object(DBusObject o) throws Error
|
||||||
|
{
|
||||||
|
unowned string path = o.get_object_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:
|
||||||
|
Device dev = yield Bus.get_proxy(BusType.SYSTEM,
|
||||||
|
BUS_NAME_NETWORK_MANAGER,
|
||||||
|
path);
|
||||||
|
if(!is_wnic(dev.interface)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
devices.insert(dev.interface, dev);
|
||||||
|
break;
|
||||||
|
case OBJ_PATH_LINK:
|
||||||
|
Link link = yield Bus.get_proxy(BusType.SYSTEM,
|
||||||
|
BUS_NAME_WIFID,
|
||||||
|
path);
|
||||||
|
links.insert(key, link);
|
||||||
|
info("found wnic: %s\n", link.interface_name);
|
||||||
|
break;
|
||||||
|
case OBJ_PATH_PEER:
|
||||||
|
key = decode_path(key);
|
||||||
|
if(!peers.contains(key)) {
|
||||||
|
Peer peer = yield Bus.get_proxy(BusType.SYSTEM,
|
||||||
|
BUS_NAME_WIFID,
|
||||||
|
path);
|
||||||
|
peers.insert(key, peer);
|
||||||
|
info("found peer: %s\n", key);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OBJ_PATH_SINK:
|
||||||
|
key = decode_path(key);
|
||||||
|
Sink sink = yield Bus.get_proxy(BusType.SYSTEM,
|
||||||
|
BUS_NAME_DISPD,
|
||||||
|
path);
|
||||||
|
sinks.insert(key, sink);
|
||||||
|
info("found sink: %s", key);
|
||||||
|
form_p2p_group.begin(key, sink);
|
||||||
|
break;
|
||||||
|
case OBJ_PATH_SESSION:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_object_added(DBusObjectManager m, DBusObject o)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
add_object.begin(o);
|
||||||
|
}
|
||||||
|
catch(Error e) {
|
||||||
|
warning("error occured while adding newly created DBus object: %s",
|
||||||
|
e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_object_removed(DBusObjectManager m, DBusObject o)
|
||||||
|
{
|
||||||
|
//try {
|
||||||
|
//remove_object.begin(o);
|
||||||
|
//}
|
||||||
|
//catch(Error e) {
|
||||||
|
//warning("error occured while removing newly created DBus object: %s",
|
||||||
|
//e.message);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
async void fetch_info_from_dbus() throws Error
|
||||||
|
{
|
||||||
|
wifi = yield DBusObjectManagerClient.new_for_bus(
|
||||||
|
BusType.SYSTEM,
|
||||||
|
DBusObjectManagerClientFlags.NONE,
|
||||||
|
BUS_NAME_WIFID,
|
||||||
|
"/org/freedesktop/miracle/wifi",
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
foreach(var o in wifi.get_objects()) {
|
||||||
|
yield add_object(o);
|
||||||
|
}
|
||||||
|
wifi.object_added.connect(on_object_added);
|
||||||
|
wifi.object_removed.connect(on_object_removed);
|
||||||
|
|
||||||
|
nm = yield DBusObjectManagerClient.new_for_bus(
|
||||||
|
BusType.SYSTEM,
|
||||||
|
DBusObjectManagerClientFlags.NONE,
|
||||||
|
BUS_NAME_NETWORK_MANAGER,
|
||||||
|
"/org/freedesktop",
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
foreach(var o in nm.get_objects()) {
|
||||||
|
yield add_object(o);
|
||||||
|
}
|
||||||
|
nm.object_added.connect(on_object_added);
|
||||||
|
nm.object_removed.connect(on_object_removed);
|
||||||
|
|
||||||
|
wfd = yield DBusObjectManagerClient.new_for_bus(
|
||||||
|
BusType.SYSTEM,
|
||||||
|
DBusObjectManagerClientFlags.NONE,
|
||||||
|
BUS_NAME_DISPD,
|
||||||
|
"/org/freedesktop/miracle/wfd",
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
foreach(var o in wfd.get_objects()) {
|
||||||
|
yield add_object(o);
|
||||||
|
}
|
||||||
|
wfd.object_added.connect(on_object_added);
|
||||||
|
wfd.object_removed.connect(on_object_removed);
|
||||||
|
}
|
||||||
|
|
||||||
|
async void initiate_session() throws Error
|
||||||
|
{
|
||||||
|
unowned Sink sink = find_sink_by_label(curr_sink_id);
|
||||||
|
|
||||||
|
unowned string xauth = Environment.get_variable("XAUTHORITY");
|
||||||
|
if(null == xauth) {
|
||||||
|
error("no environment variable XAUTHORITY specified");
|
||||||
|
}
|
||||||
|
unowned string display = Environment.get_variable("DISPLAY");
|
||||||
|
if(null == display) {
|
||||||
|
error("no environment variable DISPLAY specified");
|
||||||
|
}
|
||||||
|
info(@"establishing display session...");
|
||||||
|
sink.start_session(xauth,
|
||||||
|
@"x://$(display).0",
|
||||||
|
0, 0, 1920, 1080,
|
||||||
|
"alsa_output.pci-0000_00_1b.0.analog-stereo.monitor");
|
||||||
|
}
|
||||||
|
|
||||||
|
async void form_p2p_group(string id, Sink sink) throws Error
|
||||||
|
{
|
||||||
|
if(null != curr_sink_id) {
|
||||||
|
print("already hang out with sink: %s", curr_sink_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!id.has_prefix(opt_peer_mac)) {
|
||||||
|
print("not the sink we are waiting for: %s", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr_sink_id = id;
|
||||||
|
|
||||||
|
Peer p = peers.lookup(id);
|
||||||
|
if(null == p) {
|
||||||
|
p = yield Bus.get_proxy(BusType.SYSTEM,
|
||||||
|
BUS_NAME_WIFID,
|
||||||
|
sink.peer);
|
||||||
|
peers.insert(id, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
info("forming P2P group with %s (%s)...", p.p2_p_mac, p.friendly_name);
|
||||||
|
|
||||||
|
uint timeout_id = Timeout.add_seconds(20, () => {
|
||||||
|
p.disconnect();
|
||||||
|
form_p2p_group.callback();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
ulong prop_changed_id = (p as DBusProxy).g_properties_changed.connect((props) => {
|
||||||
|
foreach(var prop in props) {
|
||||||
|
string k;
|
||||||
|
Variant v;
|
||||||
|
prop.get("{sv}", out k, out v);
|
||||||
|
if("Connected" == k) {
|
||||||
|
form_p2p_group.callback();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
p.connect("auto", "");
|
||||||
|
yield;
|
||||||
|
|
||||||
|
Source.remove(timeout_id);
|
||||||
|
(p as DBusProxy).disconnect(prop_changed_id);
|
||||||
|
|
||||||
|
if(!p.connected) {
|
||||||
|
++ retry_count;
|
||||||
|
if(3 == retry_count) {
|
||||||
|
print("tried our best to form P2P group but with failure, bye");
|
||||||
|
}
|
||||||
|
|
||||||
|
print("failed to form P2P group with %s, try again", p.p2_p_mac);
|
||||||
|
|
||||||
|
curr_sink_id = null;
|
||||||
|
|
||||||
|
form_p2p_group.begin(id, sink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield initiate_session();
|
||||||
|
}
|
||||||
|
|
||||||
|
async void start_p2p_scan() throws Error
|
||||||
|
{
|
||||||
|
Device d = find_device_by_name(opt_iface);
|
||||||
|
if(null == d) {
|
||||||
|
throw new WfdCtlError.NO_SUCH_NIC("no such wireless adapter: %s",
|
||||||
|
opt_iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d.managed) {
|
||||||
|
info("tell NetworkManager do not touch %s anymore", opt_iface);
|
||||||
|
|
||||||
|
d.managed = false;
|
||||||
|
yield wait_prop_changed(d as DBusProxy, "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("let wifid manage %s", opt_iface);
|
||||||
|
|
||||||
|
l.manage();
|
||||||
|
yield wait_prop_changed(l as DBusProxy, "Managed");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 as DBusProxy, "WfdSubelements");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!l.p2_p_scanning) {
|
||||||
|
info("start P2P scanning...");
|
||||||
|
l.p2_p_scanning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
info("wait for peer '%s'...", opt_peer_mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
async void start_wireless_display() throws Error
|
||||||
|
{
|
||||||
|
yield fetch_info_from_dbus();
|
||||||
|
yield start_p2p_scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_activate(Application app)
|
||||||
|
{
|
||||||
|
if(null == opt_iface) {
|
||||||
|
opt_iface = "wlan0";
|
||||||
|
print("no wireless adapter specified by -i, use '%s' instead",
|
||||||
|
opt_iface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(null == opt_wfd_subelems) {
|
||||||
|
opt_wfd_subelems = "000600111c4400c8";
|
||||||
|
print("no wfd_subelems specified by -w, use '%s' instead",
|
||||||
|
opt_wfd_subelems);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(null == opt_peer_mac) {
|
||||||
|
print("no peer MAC specified by -p, bye");
|
||||||
|
app.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_wireless_display.begin((o, r) => {
|
||||||
|
try {
|
||||||
|
start_wireless_display.end(r);
|
||||||
|
}
|
||||||
|
catch(Error e) {
|
||||||
|
print("failed to fetch device information from DBus");
|
||||||
|
app.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_startup(Application app)
|
||||||
|
{
|
||||||
|
app.hold();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(string[]? argv)
|
||||||
|
{
|
||||||
|
Intl.setlocale();
|
||||||
|
Environment.set_prgname(Path.get_basename(argv[0]));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
var options = new OptionContext("- WfdCtl");
|
||||||
|
options.set_help_enabled(true);
|
||||||
|
options.add_main_entries(option_entries, null);
|
||||||
|
|
||||||
|
Application app = new Application("org.freedesktop.miracle.WfdCtl",
|
||||||
|
ApplicationFlags.FLAGS_NONE);
|
||||||
|
app.set_default();
|
||||||
|
app.startup.connect(app_startup);
|
||||||
|
app.activate.connect(app_activate);
|
||||||
|
|
||||||
|
try {
|
||||||
|
options.parse(ref argv);
|
||||||
|
app.register();
|
||||||
|
}
|
||||||
|
catch(Error e) {
|
||||||
|
print("failed to startup: %s", e.message);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.run(argv);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue