-
Notifications
You must be signed in to change notification settings - Fork 3
/
webrtc_client.py
executable file
·109 lines (89 loc) · 4.86 KB
/
webrtc_client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/python3
import sys,gi,json,argparse,os
gi.require_version('GLib', '2.0')
gi.require_version('Gst', '1.0')
gi.require_version('Soup', '2.4')
gi.require_version('GstWebRTC', '1.0')
gi.require_version('GstSdp', '1.0')
from gi.repository import GLib, Gst, Soup, GstWebRTC, GstSdp
from gst_helpers import *
from webrtc_peer import WebRTCDecoder
from client import BaseClient
args = None
flags = []
# Websocket connection was closed by remote
def ws_close_handler(connection, wrb):
logging.info("WebSocket closed by remote.")
sys.exit(1)
# outgoing Websocket connection
def ws_conn_handler(session, result):
connection = session.websocket_connect_finish(result)
wrb = WebRTCDecoder(connection,"client",args.stun,True,flags,surf_pipe=args.sp) # e.g. "udpsink host=224.1.1.1 port=3000 auto-multicast=true"
client = BaseClient("client",wrb)
connection.connect("closed",ws_close_handler,wrb)
# element message was posted on bus
def message_cb(bus, message):
name = message.src.name
struct = message.get_structure()
# use window-handle message to set title
if "fps-display" in name and "have-window-handle" in struct.get_name():
toplevel = message.src.parent.parent.name
logging.debug("Setting window name for "+toplevel+"...")
res, val = struct.get_uint64("window-handle")
# FIXME: this is obviously a hack...
os.system("xprop -id "+str(val)+" -format _NET_WM_NAME 8u -set _NET_WM_NAME "+toplevel)
# debug output for automated tests
if "zbar" in name:
logging.debug(message.get_structure().to_string())
def on_element_added(thebin, element):
name = element.get_name()
if not name.startswith("output_"):
return
name = name.split("_")[-1]
if name == "front" or name == "surface":
logging.info("Starting video output for "+name)
videopipe = "videoconvert ! fpsdisplaysink sync=false name={name} text-overlay={debug!s}" if name == "front" or args.out == "" else args.out
add_and_link([ element, Gst.parse_bin_from_description( videopipe.format(name=name,debug=bool(args.debug)), True ) ])
elif name == "audio":
logging.info("Starting audio output")
add_and_link([ element, new_element("audioconvert"), new_element("autoaudiosink") ])
# "main"
print("\nSurfaceCast frontend client v0.2.2 - https://github.com/floe/surfacecast\n")
parser = argparse.ArgumentParser()
parser.add_argument( "--fake", help="use fake sources (desc. from -f/-s)",action="store_true")
parser.add_argument("-m","--main", help="flag this client as main (lowest z)",action="store_true")
parser.add_argument("-o","--own", help="include own surfacestream in output",action="store_true")
parser.add_argument("-d","--debug", help="more debug output (-dd=max)",action="count",default=0 )
parser.add_argument("-t","--target", help="server to connect to (%(default)s)", default="127.0.0.1")
parser.add_argument("-a","--audio", help="audio source (device name or pipeline)", default="" )
parser.add_argument("-f","--front", help="front image source (device or pipeline)",default="" )
parser.add_argument("-s","--surface",help="surface image source (device or pipeline)",default="" )
parser.add_argument("-u","--stun", help="STUN server", default="stun://stun.l.google.com:19302" )
parser.add_argument("-p","--port", help="server HTTPS listening port", default=8080 )
parser.add_argument("-n","--nick", help="client nickname", default="" )
parser.add_argument( "--persp", help="perspective transform", default="" )
parser.add_argument( "--size", help="surface stream output size", default="1280x720" )
parser.add_argument( "--out", help="video output pipeline", default="" )
parser.add_argument( "--sp", help="surface processing pipeline", default="" )
parser.add_argument( "--fps", help="frames per second", default=15 )
args = parser.parse_args()
args.size = [ int(n) for n in args.size.split("x") ]
print("Option",args,"\n")
if args.main:
flags.append({"main":True})
if args.own:
flags.append({"own":True})
if args.nick != "":
flags.append({"nick":args.nick})
if args.persp != "":
flags.append({"perspective":args.persp})
init_pipeline(on_element_added,args.debug)
connect_bus("message::element",message_cb)
if not args.fake and (args.front == "" or args.surface == ""):
logging.warning("Need to either specify --fake for test sources, or -f/-s for source devices/pipelines.")
add_test_sources(args.front,args.surface,args.audio,args.fake,sw=args.size[0],sh=args.size[1],fps=args.fps)
session = Soup.Session()
session.set_property("ssl-strict", False)
msg = Soup.Message.new("GET", "wss://"+args.target+":"+str(args.port)+"/ws")
session.websocket_connect_async(msg, None, None, None, ws_conn_handler)
run_mainloop()