1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-03-09 23:38:56 +00:00

demo/miracle-wfdctl: better handling session tearing down

This commit is contained in:
Derek Dai 2017-03-25 15:36:13 +08:00
parent 91e62a740b
commit 0a7517d8e9
No known key found for this signature in database
GPG key ID: E109CC97553EF009
2 changed files with 182 additions and 44 deletions

View file

@ -56,6 +56,8 @@ add_custom_command(OUTPUT wfdctl.c
COMMAND ${VALAC} --target-glib=2.50 -H wfdctl.h --use-header -C COMMAND ${VALAC} --target-glib=2.50 -H wfdctl.h --use-header -C
--pkg=gio-2.0 --pkg=gio-2.0
--pkg=gdk-3.0 --pkg=gdk-3.0
--pkg=posix
--pkg=linux
${CMAKE_CURRENT_SOURCE_DIR}/wfdctl.vala ${CMAKE_CURRENT_SOURCE_DIR}/wfdctl.vala
org-freedesktop-networkmanager.vala org-freedesktop-networkmanager.vala
org-freedesktop-miracle-wifi.vala org-freedesktop-miracle-wifi.vala

View file

@ -81,6 +81,8 @@ private class WfdCtl : GLib.Application
string curr_sink_mac; string curr_sink_mac;
Gdk.Display display; Gdk.Display display;
Session curr_session;
IOChannel sig_channel;
const GLib.OptionEntry[] option_entries = { const GLib.OptionEntry[] option_entries = {
{ "interface", 'i', 0, OptionArg.STRING, ref opt_iface, "name of wireless network interface", "WNIC name" }, { "interface", 'i', 0, OptionArg.STRING, ref opt_iface, "name of wireless network interface", "WNIC name" },
@ -107,7 +109,7 @@ private class WfdCtl : GLib.Application
add_main_option_entries(option_entries); add_main_option_entries(option_entries);
} }
private void add_object(string path) throws Error private DBusProxy? add_object(string path) throws Error
{ {
int sep = path.last_index_of_char('/'); int sep = path.last_index_of_char('/');
string prefix = path.substring(0, sep); string prefix = path.substring(0, sep);
@ -117,71 +119,108 @@ private class WfdCtl : GLib.Application
Device d = Bus.get_proxy_sync(BusType.SYSTEM, Device d = Bus.get_proxy_sync(BusType.SYSTEM,
BUS_NAME_NETWORK_MANAGER, BUS_NAME_NETWORK_MANAGER,
path); path);
if(is_wnic(d.interface)) { if(is_wnic(d.interface) && !devices.contains(d.interface)) {
devices.insert(d.interface, d); devices.insert(d.interface, d);
return d as DBusProxy;
} }
break; break;
case OBJ_PATH_LINK: case OBJ_PATH_LINK:
Link l = Bus.get_proxy_sync(BusType.SYSTEM,
BUS_NAME_WIFID,
path);
key = decode_path(key); key = decode_path(key);
links.insert(key, l); Link l = links.lookup(key);
info("found wireless interface: %s\n", l.interface_name); if(null == l) {
link_added(key, l); l = Bus.get_proxy_sync(BusType.SYSTEM,
break; BUS_NAME_WIFID,
path);
links.insert(key, l);
info("found wireless interface: %s\n", l.interface_name);
link_added(key, l);
}
return l as DBusProxy;
case OBJ_PATH_PEER: case OBJ_PATH_PEER:
key = decode_path(key); key = decode_path(key);
if(peers.contains(key)) { Peer p = peers.lookup(key);
break; if(null == p) {
p = Bus.get_proxy_sync(BusType.SYSTEM,
BUS_NAME_WIFID,
path);
peers.insert(key, p);
info("peer added: %s\n", key);
peer_added(key, p);
} }
Peer p = Bus.get_proxy_sync(BusType.SYSTEM, return p as DBusProxy;
BUS_NAME_WIFID,
path);
peers.insert(key, p);
info("peer added: %s\n", key);
peer_added(key, p);
break;
case OBJ_PATH_SINK: case OBJ_PATH_SINK:
Sink s = Bus.get_proxy_sync(BusType.SYSTEM,
BUS_NAME_DISPD,
path);
key = decode_path(key); key = decode_path(key);
sinks.insert(key, s); Sink s = sinks.lookup(key);
info("sink added: %s", key); if(null == s) {
sink_added(key, s); s = Bus.get_proxy_sync(BusType.SYSTEM,
break; 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: case OBJ_PATH_SESSION:
Session s = Bus.get_proxy_sync(BusType.SYSTEM,
BUS_NAME_DISPD,
path);
key = decode_path(key); key = decode_path(key);
sessions.insert(key, s); Session s = sessions.lookup(key);
info("session added: %s", key); if(null == s) {
session_added(key, s); s = Bus.get_proxy_sync(BusType.SYSTEM,
break; 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) private void remove_object(string path)
{ {
debug("object removed: %s", path);
int sep = path.last_index_of_char('/'); int sep = path.last_index_of_char('/');
string prefix = path.substring(0, sep); string prefix = path.substring(0, sep);
string key = path.substring(sep + 1); string key = path.substring(sep + 1);
switch(prefix) { switch(prefix) {
case OBJ_PATH_DEVICE: case OBJ_PATH_DEVICE:
devices.remove(key);
break; break;
case OBJ_PATH_LINK: 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; break;
case OBJ_PATH_PEER: case OBJ_PATH_PEER:
key = decode_path(key);
Peer p = peers.lookup(key);
if(null == p) {
break;
}
peers.remove(key);
peer_removed(key, p);
break; break;
case OBJ_PATH_SINK: case OBJ_PATH_SINK:
key = decode_path(key); key = decode_path(key);
Sink s = sinks.lookup(key);
if(null == s) {
break;
}
sinks.remove(key);
sink_removed(key, s);
break; break;
case OBJ_PATH_SESSION: case OBJ_PATH_SESSION:
key = decode_path(key); key = decode_path(key);
Session s = sessions.lookup(key);
if(null == s) {
break;
}
sessions.remove(key);
session_removed(key, s);
break; break;
} }
} }
@ -247,16 +286,11 @@ private class WfdCtl : GLib.Application
} }
} }
private async void start_p2p_scan() throws Error private async void acquire_wnic_ownership() throws Error
{ {
Device d = find_device_by_name(opt_iface); Device d = find_device_by_name(opt_iface);
if(null == d) { if(null != d && d.managed) {
throw new WfdCtlError.NO_SUCH_NIC("no such wireless adapter: %s", info("NetworkManager is releasing ownership of %s...", opt_iface);
opt_iface);
}
if(d.managed) {
info("tell NetworkManager do not touch %s anymore", opt_iface);
d.managed = false; d.managed = false;
yield wait_prop_changed(d as DBusProxy, "Managed"); yield wait_prop_changed(d as DBusProxy, "Managed");
@ -269,12 +303,16 @@ private class WfdCtl : GLib.Application
} }
if(!l.managed) { if(!l.managed) {
info("let wifid manage %s", opt_iface); info("wifid is acquiring ownership of %s...", opt_iface);
l.manage(); l.manage();
yield wait_prop_changed(l as DBusProxy, "Managed"); yield wait_prop_changed(l as DBusProxy, "Managed");
} }
}
private async void start_p2p_scan() throws Error
{
Link l = find_link_by_name(opt_iface);
if(l.wfd_subelements != opt_wfd_subelems) { if(l.wfd_subelements != opt_wfd_subelems) {
info("update wfd_subelems to broadcast what kind of device we are"); info("update wfd_subelems to broadcast what kind of device we are");
@ -363,6 +401,28 @@ private class WfdCtl : GLib.Application
} }
#endif #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";
}
return "unknown";
}
private async void establish_session() throws Error private async void establish_session() throws Error
{ {
Gdk.Rectangle g; Gdk.Rectangle g;
@ -371,22 +431,77 @@ private class WfdCtl : GLib.Application
info("establishing display session..."); info("establishing display session...");
Sink sink = find_sink_by_mac(opt_peer_mac); Sink sink = find_sink_by_mac(opt_peer_mac);
sink.start_session(opt_authority, string path = sink.start_session(opt_authority,
@"x://$(opt_display)", @"x://$(opt_display)",
g.x, g.x,
g.y, g.y,
g.width, g.width,
g.height, g.height,
null == opt_audio_device ? "" : opt_audio_device); 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()));
}
});
info("session status: %s", session_state_to_str(curr_session.state));
}
private async void wait_for_session_ending()
{
info("wait for session ending");
session_removed.connect((id, s) => {
info("session ended");
curr_session = null;
wait_for_session_ending.callback();
});
yield;
}
private async void release_wnic_ownership() throws Error
{
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 as DBusProxy, "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 as DBusProxy, "Managed");
}
} }
private async void start_wireless_display() throws Error private async void start_wireless_display() throws Error
{ {
fetch_info_from_dbus(); fetch_info_from_dbus();
yield acquire_wnic_ownership();
yield start_p2p_scan(); yield start_p2p_scan();
yield wait_for_target_sink(); yield wait_for_target_sink();
yield form_p2p_group(); yield form_p2p_group();
yield establish_session(); yield establish_session();
yield wait_for_session_ending();
yield release_wnic_ownership();
release();
print("Bye");
} }
private bool check_options() private bool check_options()
@ -460,6 +575,27 @@ private class WfdCtl : GLib.Application
return; return;
} }
/* vala has bug in generatde C code looks like
* sigset_t _tmp2_ = {0};
* sigset_t _tmp3_ = {0};
* sigset_t _tmp4_ = {0};
* sigset_t _tmp5_ = {0};
* sigset_t _tmp6_ = {0};
* sigset_t _tmp7_ = {0};
* sigemptyset (&_tmp3_);
* sigaddset (&_tmp4_, SIGINT);
* sigprocmask (SIG_BLOCK, &_tmp5_, &_tmp6_); */
//Posix.sigset_t mask = {}, oldmask = {};
//Posix.sigemptyset(mask);
//Posix.sigaddset(mask, Posix.SIGINT);
//Posix.sigprocmask(Posix.SIG_BLOCK, mask, oldmask);
//sig_channel = new IOChannel.unix_new(Linux.signalfd(-1, mask));
//sig_channel.add_watch(IOCondition.IN, (s, e) => {
//info("Bye");
//release();
//return false;
//});
hold(); hold();
start_wireless_display.begin((o, r) => { start_wireless_display.begin((o, r) => {