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:
parent
91e62a740b
commit
0a7517d8e9
2 changed files with 182 additions and 44 deletions
|
@ -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
|
||||||
|
|
224
demo/wfdctl.vala
224
demo/wfdctl.vala
|
@ -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) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue