From c5da5327324b6a503dcbe4d3196c52f72d3370fa Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sat, 27 Oct 2018 17:30:30 +0100 Subject: [PATCH 01/35] tmp --- Cargo.lock | 744 ++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + backends/gstreamer/Cargo.toml | 15 + backends/gstreamer/src/lib.rs | 17 + examples/Cargo.toml | 10 + servo-media/Cargo.toml | 3 + servo-media/src/lib.rs | 8 + webrtc/Cargo.toml | 6 + webrtc/src/lib.rs | 17 + 9 files changed, 822 insertions(+) create mode 100644 webrtc/Cargo.toml create mode 100644 webrtc/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f1a13e1b..8097861c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,6 +77,44 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "backtrace" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "binary-space-partition" version = "0.1.2" @@ -91,6 +129,11 @@ dependencies = [ "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bitflags" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "1.0.3" @@ -121,6 +164,15 @@ name = "byteorder" version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bzip2" version = "0.3.3" @@ -202,6 +254,15 @@ dependencies = [ "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core-foundation" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core-foundation" version = "0.6.1" @@ -211,6 +272,14 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core-foundation-sys" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core-foundation-sys" version = "0.6.1" @@ -278,6 +347,15 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-epoch" version = "0.3.1" @@ -384,14 +462,39 @@ dependencies = [ "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media 0.1.0", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "webrender 0.57.2 (git+https://github.com/servo/webrender/)", + "websocket 0.20.3 (registry+https://github.com/rust-lang/crates.io-index)", "winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fixedbitset" version = "0.1.9" @@ -447,6 +550,20 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-cpupool" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -693,6 +810,33 @@ dependencies = [ "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gstreamer-sdp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sdp-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gstreamer-sdp-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gstreamer-sys" version = "0.6.1" @@ -734,6 +878,66 @@ dependencies = [ "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gstreamer-webrtc" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sdp 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-webrtc-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gstreamer-webrtc-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sdp-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "h2" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "httparse" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "humantime" version = "1.1.1" @@ -742,6 +946,50 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hyper" +version = "0.10.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.1.5" @@ -752,6 +1000,11 @@ dependencies = [ "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "iovec" version = "0.1.2" @@ -778,6 +1031,11 @@ dependencies = [ "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "jni" version = "0.5.3" @@ -809,6 +1067,16 @@ name = "khronos_api" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.0.2" @@ -901,6 +1169,14 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miniz_oxide" version = "0.1.3" @@ -939,6 +1215,16 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miow" version = "0.2.1" @@ -964,6 +1250,20 @@ name = "muldiv" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "native-tls" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "net2" version = "0.2.33" @@ -1029,6 +1329,29 @@ dependencies = [ "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "openssl" +version = "0.9.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys" +version = "0.9.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ordered-float" version = "1.0.1" @@ -1134,6 +1457,16 @@ dependencies = [ "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.4.2" @@ -1223,6 +1556,11 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-demangle" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rusttype" version = "0.7.3" @@ -1234,6 +1572,16 @@ dependencies = [ "stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ryu" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "safemem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "same-file" version = "1.0.4" @@ -1242,11 +1590,45 @@ dependencies = [ "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "schannel" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scoped-tls" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "security-framework" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "security-framework-sys" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde" version = "1.0.66" @@ -1273,6 +1655,16 @@ dependencies = [ "syn 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_json" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "servo-freetype-sys" version = "4.0.3" @@ -1289,6 +1681,7 @@ dependencies = [ "servo-media-audio 0.1.0", "servo-media-gstreamer 0.1.0", "servo-media-player 0.1.0", + "servo-media-webrtc 0.1.0", ] [[package]] @@ -1312,6 +1705,7 @@ name = "servo-media-gstreamer" version = "0.1.0" dependencies = [ "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1321,12 +1715,16 @@ dependencies = [ "gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-audio 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sdp 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-webrtc 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media-audio 0.1.0", "servo-media-player 0.1.0", + "servo-media-webrtc 0.1.0", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1340,6 +1738,10 @@ dependencies = [ "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "servo-media-webrtc" +version = "0.1.0" + [[package]] name = "servo_media_android" version = "0.1.0" @@ -1357,6 +1759,11 @@ dependencies = [ "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha1" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "shared_library" version = "0.1.9" @@ -1409,6 +1816,11 @@ dependencies = [ "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "string" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.14.7" @@ -1429,6 +1841,26 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "synstructure" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempfile" version = "3.0.3" @@ -1483,11 +1915,216 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tls" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-uds" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -1538,6 +2175,16 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vcpkg" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "void" version = "1.0.2" @@ -1553,6 +2200,16 @@ dependencies = [ "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "want" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wayland-client" version = "0.21.4" @@ -1653,6 +2310,27 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "websocket" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -1772,14 +2450,20 @@ dependencies = [ "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" +"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" +"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff" "checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7" +"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbec60c560f322d8e3cd403f91d8908cfd965fff53ba97154bd1b9d90149d98e" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28346c117b50270785fbc123bd6e4ecad20d0c6d5f43d081dc80a3abcc62be64" "checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" +"checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62" "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" "checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b" "checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" @@ -1790,7 +2474,9 @@ dependencies = [ "checksum cmake 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "b56821938fa1a3aaf4f0c4f49504928c5a7fcc56cbc9855be8fc2e98567e750c" "checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b" "checksum combine 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c" +"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc3532ec724375c7cb7ff0a097b714fde180bb1f6ed2ab27cfcd99ffca873cd2" +"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9" "checksum core-graphics 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92801c908ea6301ae619ed842a72e01098085fc321b9c2f3f833dad555bba055" "checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" @@ -1798,6 +2484,7 @@ dependencies = [ "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6c0a94250b0278d7fc5a894c3d276b11ea164edc8bf8feb10ca1ea517b44a649" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" @@ -1809,6 +2496,8 @@ dependencies = [ "checksum env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d7e69c283751083d53d01eac767407343b8b69c4bd70058e08adc2637cb257" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2ebdf55fb9d6329046e026329a55ef8fbaae5ea833f56e170beb3125a8a5f" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -1817,6 +2506,8 @@ dependencies = [ "checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604" @@ -1836,17 +2527,30 @@ dependencies = [ "checksum gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb57a7d013604ab7af2b843b62b13b8fb30f22d066919f7e198f528c3296cd0" "checksum gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1144c6c5c3af25dd1f89b4f9d2762f1c2d8789e65cdc79e2451dd24350d84dd2" "checksum gstreamer-player-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e642cb58d3733e2724def7186101bb00144fc97d45b2c379eba6d0c0662dec" +"checksum gstreamer-sdp 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ade1226bb5a0622125e49f1a801ac6b673986d96513862ff0b1f21b0b3595ae" +"checksum gstreamer-sdp-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "816628556bc2c9a627efd6e7d9b67ab4abb246b143bff2b3ad7fff6923f11cb1" "checksum gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3aec69f30ab98a7b0cf4a29179eeffa8a1e7d6062f5ee55e9792917cb0980bda" "checksum gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1f04816d7e183714830da26274f97e7aeff09ae6641058538d21443b4ec07d" "checksum gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e2efb301a0b94fa4af503122faa04247085936dd888fd59fa4e21eab3cbd37" +"checksum gstreamer-webrtc 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f7fc9422d65781cfe8d2f9994b1010476ce0839b8fce7db97eb87bdf75b614e" +"checksum gstreamer-webrtc-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "38a27025af94512f0d798ff9dd0b269951ce305879873c4ab6266885c7bd207f" +"checksum h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd33bafe2e6370e6c8eb0cf1b8c5f93390b90acde7e9b03723f166b28b648ed" +"checksum http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "24f58e8c2d8e886055c3ead7b28793e1455270b5fb39650984c224bc538ba581" +"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" +"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c" +"checksum hyper 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "95ffee0d1d30de4313fdaaa485891ce924991d45bbc18adfc8ac5b1639e62fbb" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd75debad4ffd295c00c6e3634d254df30050b0837a85e5cd039ac424365f24a" +"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum jni 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cffc930ce6a38a4013e30567b559bdc79f601013ba4a81e65dbda9207263efd4" "checksum jni-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de0aaaba8809ab8d83a53fe2b313b996b79e8632b855eae9f70ad4323dca91b8" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62237e6d326bd5871cd21469323bf096de81f1618cd82cbaf5d87825335aeb49" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" @@ -1860,12 +2564,15 @@ dependencies = [ "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum miniz_oxide 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9ba430291c9d6cedae28bcd2d49d1c32fc57d60cd49086646c5dd5673a870eb5" "checksum miniz_oxide_c_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5a5b8234d6103ebfba71e29786da4608540f862de5ce980a1c94f86a40ca0d51" "checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "451a9a05d2a32c566c897835e0ea95cf79ed2fdfe957924045a1721a36c9980f" +"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" @@ -1874,6 +2581,8 @@ dependencies = [ "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9833ab0efe5361b1e2122a0544a5d3359576911a42cb098c2e59be8650807367" +"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" +"checksum openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)" = "278c1ad40a89aa1e741a1eed089a2f60b18fab8089c3139b542140fc7d674106" "checksum ordered-float 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0015e9e8e28ee20c581cfbfe47c650cedeb9ed0721090e0b7ebb10b9cdbcc2" "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" @@ -1888,6 +2597,7 @@ dependencies = [ "checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3372dc35766b36a99ce2352bd1b6ea0137c38d215cc0c8780bf6de6df7842ba9" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" @@ -1898,28 +2608,58 @@ dependencies = [ "checksum regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbbea44c5490a1e84357ff28b7d518b4619a159fed5d25f6c1de2d19cc42814" "checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rusttype 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "436c67ae0d0d24f14e1177c3ed96780ee16db82b405f0fba1bb80b46c9a30625" +"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" +"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" +"checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" +"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" +"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" "checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" "checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3" "checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" +"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" "checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b" +"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" "checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" "checksum smithay-client-toolkit 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef227bd9251cf8f8e54f8dd9a4b164307e515f5312cd632ebc87b56f723893a2" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48fa7d3136d8645909de1f7c7eb5416cc43057a75ace08fc39ae736bc9da8af1" +"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" "checksum syn 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e13df71f29f9440b50261a5882c86eac334f1badb3134ec26f0de2f1418e44" "checksum syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3391038ebc3e4ab24eb028cb0ef2f2dc4ba0cbf72ee895ed6a6fad730640b5bc" +"checksum synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec37f4fab4bafaf6b5621c1d54e6aa5d4d059a8f84929e87abfdd7f9f04c6db2" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5920e77802b177479ab5795767fa48e68f61b2f516c2ac0041e2978dd8efe483" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6e93c78d23cc61aa245a8acd2c4a79c4d7fa7fb5c3ca90d5737029f043a84895" +"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" +"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" +"checksum tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f90fcd90952f0a496d438a976afba8e5c205fb12123f813d8ab3aa1c8436638c" +"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" +"checksum tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "60ae25f6b17d25116d2cba342083abe5255d3c2c79cb21ea11aa049c53bf7c75" +"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" +"checksum tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4b26fd37f1125738b2170c80b551f69ff6fecb277e6e5ca885e53eec2b005018" +"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" +"checksum tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3929aee321c9220ed838ed6c3928be7f9b69986b0e3c22c972a66dbf8a298c68" +"checksum tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3a52f00c97fedb6d535d27f65cccb7181c8dd4c6edc3eda9ea93f6d45d05168e" +"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" +"checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" +"checksum tokio-uds 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df195376b43508f01570bacc73e13a1de0854dc59e79d1ec09913e8db6dd2a70" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" @@ -1927,8 +2667,11 @@ dependencies = [ "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" +"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum wayland-client 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ff03d0651389f99aba804e89685c6211fc1d66fb3c234ed52d028904675adbcb" "checksum wayland-commons 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6f06d6b155a2be033ee1684fd084c1c1821e0d61d4c303f11fc9400a911fa24a" "checksum wayland-protocols 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f6cebb98963f028d397e9bad2acf9d3b2f6b76fae65aea191edd9e7c0df88c" @@ -1936,6 +2679,7 @@ dependencies = [ "checksum wayland-sys 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ca41ed78a12256f81df6f53fcbe4503213ba442e02cdad3c9c888a64a668eaf4" "checksum webrender 0.57.2 (git+https://github.com/servo/webrender/)" = "" "checksum webrender_api 0.57.2 (git+https://github.com/servo/webrender/)" = "" +"checksum websocket 0.20.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9234b4e667c19995475227172446884f516ec0963380afa960d962ab9f4c0bfa" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index cded2571..8bb4a8c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,6 @@ members = [ "player", "servo-media", "servo-media-derive", + "webrtc" ] +license = "MPL-2.0" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 7bbfe285..522c6121 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -13,6 +13,9 @@ version = "0.2" [dependencies.glib] version = "0.6" +[dependencies.failure] +version = "*" + [dependencies.glib-sys] version = "0.7" @@ -40,12 +43,21 @@ version = "0.12" [dependencies.gstreamer-sys] version = "0.6.1" +[dependencies.gstreamer-sdp] +version = "0.12" + +[dependencies.gstreamer-webrtc] +version = "0.12" + [dependencies.gstreamer-video] version = "0.12" [dependencies.ipc-channel] version = "0.11" +[dependencies.lazy_static] +version = "*" + [dependencies.servo-media-audio] path = "../../audio" @@ -54,3 +66,6 @@ path = "../../player" [dependencies.url] version = "1.7.2" + +[dependencies.servo-media-webrtc] +path = "../../webrtc" diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 7085d774..722b71bd 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -1,5 +1,7 @@ extern crate byte_slice_cast; +#[macro_use] +extern crate failure; #[macro_use] extern crate glib; extern crate glib_sys as glib_ffi; @@ -12,20 +14,28 @@ extern crate gstreamer_app as gst_app; extern crate gstreamer_audio as gst_audio; extern crate gstreamer_player as gst_player; extern crate gstreamer_sys as gst_ffi; +extern crate gstreamer_sdp as gst_sdp; extern crate gstreamer_video as gst_video; +extern crate gstreamer_webrtc as gst_webrtc; extern crate ipc_channel; +#[macro_use] +extern crate lazy_static; + extern crate servo_media_audio; extern crate servo_media_player; +extern crate servo_media_webrtc; extern crate url; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; use servo_media_player::PlayerBackend; +use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller}; pub mod audio_decoder; pub mod audio_sink; pub mod player; mod source; +pub mod webrtc; pub struct GStreamerBackend; @@ -47,6 +57,13 @@ impl PlayerBackend for GStreamerBackend { } } +impl WebRtcBackend for GStreamerBackend { + type Controller = webrtc::GStreamerWebRtcController; + fn start_webrtc_controller(signaller: Box) -> Self::Controller { + webrtc::start(signaller) + } +} + impl GStreamerBackend { pub fn init() { gst::init().unwrap(); diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 6238c3f7..43b894b6 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -7,10 +7,16 @@ license = "MPL-2.0" env_logger = "0.5" euclid = "0.19.0" gleam = "0.6.8" +hyper = "0.12" rand = "0.5.0" time = "0.1.40" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" servo-media = { path = "../servo-media" } webrender = { git = "https://github.com/servo/webrender/" } +websocket = "*" +#ws = "*" ipc-channel = "0.11" [target.'cfg(not(target_os = "android"))'.dependencies] @@ -80,3 +86,7 @@ path = "oscillator.rs" [[bin]] name = "constant_source" path = "constant_source.rs" + +[[bin]] +name = "simple_webrtc" +path = "simple_webrtc.rs" diff --git a/servo-media/Cargo.toml b/servo-media/Cargo.toml index d03f6151..ec3c18be 100644 --- a/servo-media/Cargo.toml +++ b/servo-media/Cargo.toml @@ -12,5 +12,8 @@ path = "../audio" [dependencies.servo-media-player] path = "../player" +[dependencies.servo-media-webrtc] +path = "../webrtc" + [target.'cfg(any(all(target_os = "android", target_arch = "arm"), target_arch = "x86_64"))'.dependencies.servo-media-gstreamer] path = "../backends/gstreamer" diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 13938c1c..29def77a 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -5,6 +5,7 @@ pub extern crate servo_media_audio as audio; ))] extern crate servo_media_gstreamer; pub extern crate servo_media_player as player; +pub extern crate servo_media_webrtc as webrtc; use std::sync::{self, Arc, Mutex, Once}; use audio::context::{AudioContext, AudioContextOptions}; @@ -12,6 +13,7 @@ use audio::decoder::DummyAudioDecoder; use audio::sink::{AudioSinkError, DummyAudioSink}; use audio::AudioBackend; use player::{DummyPlayer, Player, PlayerBackend}; +use webrtc::{WebRtcBackend, WebRtcSignaller}; pub struct ServoMedia; @@ -54,6 +56,8 @@ pub type Backend = servo_media_gstreamer::GStreamerBackend; )))] pub type Backend = DummyBackend; +pub type WebRtcController = servo_media_gstreamer::webrtc::GStreamerWebRtcController; + impl ServoMedia { pub fn new() -> Self { Backend::init(); @@ -79,4 +83,8 @@ impl ServoMedia { pub fn create_player(&self) -> Box { Box::new(Backend::make_player()) } + + pub fn create_webrtc(&self, signaller: Box) -> Box { + Box::new(Backend::start_webrtc_controller(signaller)) + } } diff --git a/webrtc/Cargo.toml b/webrtc/Cargo.toml new file mode 100644 index 00000000..b32d71bb --- /dev/null +++ b/webrtc/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "servo-media-webrtc" +version = "0.1.0" +authors = ["Josh Matthews "] + +[dependencies] diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs new file mode 100644 index 00000000..fc45a8e3 --- /dev/null +++ b/webrtc/src/lib.rs @@ -0,0 +1,17 @@ +pub trait WebRtcController: Send { + fn notify_signal_server_error(&self); + fn notify_sdp(&self, type_: String, sdp: String); + fn notify_ice(&self, sdp_mline_index: u32, candidate: String); + fn trigger_negotiation(&self); +} + +pub trait WebRtcSignaller: Send { + fn send_sdp_offer(&self, offer: String); + fn send_ice_candidate(&self, mlineindex: u32, candidate: String); +} + +pub trait WebRtcBackend { + type Controller: WebRtcController; + + fn start_webrtc_controller(signaller: Box) -> Self::Controller; +} From a157fe773c4df8e2c24084731880b11d81529a49 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sat, 27 Oct 2018 18:10:50 +0100 Subject: [PATCH 02/35] checkpoint --- examples/simple_webrtc.rs | 343 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 examples/simple_webrtc.rs diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs new file mode 100644 index 00000000..d4df545a --- /dev/null +++ b/examples/simple_webrtc.rs @@ -0,0 +1,343 @@ +extern crate env_logger; +extern crate rand; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; +extern crate servo_media; +extern crate websocket; +//extern crate ws; + +use rand::Rng; +use servo_media::ServoMedia; +use servo_media::webrtc::{WebRtcController, WebRtcSignaller}; +use std::env; +use std::net; +use std::sync::{Arc, mpsc}; +use std::thread; +use websocket::OwnedMessage; +//use websocket::server::sync::Server; + +/*fn start_server(port: u32) { + thread::spawn(move || { + let s = Server::bind(format!("localhost:{}", port)).unwrap(); + let conns = s.filter_map(Result::ok).take(2); + let conn1 = conns.next().unwrap(); + let mut client = conn1.accept().unwrap(); + thread::spawn(move || { + let msg = client.recv_message().unwrap(); + let uid = match msg { + OwnedMessage::Text(m) => { + let mut parts = m.split(' '); + assert_eq!(parts.next().unwrap(), "HELLO"); + parts.next().unwrap().parse::().unwrap() + } + _ => panic!("invalid greeting"), + }; + client.send_message(&OwnedMessage::Text("HELLO".to_owned())).unwrap(); + + let msg = client.recv_message().unwrap(); + let peer_id = match msg { + OwnedMessage::Text(m) => { + let mut parts = m.split(' '); + assert_eq!(parts.next().unwrap(), "SESSION"); + parts.next().unwrap().to_owned() + } + _ => panic!("invalid session"), + }; + client.send_message(&OwnedMessage::Text("SESSION_OK".to_owned())).unwrap(); + }); + + let conn2 = conns.next().unwrap(); + + + loop { + + } + }); +}*/ + +#[derive(PartialEq, PartialOrd, Eq, Debug, Copy, Clone, Ord)] +enum AppState { + Error = 1, + ServerConnected, + ServerRegistering = 2000, + ServerRegisteringError, + ServerRegistered, + PeerConnecting = 3000, + PeerConnectionError, + PeerConnected, + PeerCallNegotiating = 4000, + PeerCallStarted, + PeerCallError, +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +enum JsonMsg { + Ice { + candidate: String, + #[serde(rename = "sdpMLineIndex")] + sdp_mline_index: u32, + }, + Sdp { + #[serde(rename = "type")] + type_: String, + sdp: String, + }, +} + +fn send_loop( + mut sender: websocket::sender::Writer, + send_msg_rx: mpsc::Receiver, +) -> thread::JoinHandle<()> { + thread::spawn(move || loop { + let msg = match send_msg_rx.recv() { + Ok(msg) => msg, + Err(err) => { + println!("Send loop error {:?}", err); + return; + } + }; + + if let OwnedMessage::Close(_) = msg { + let _ = sender.send_message(&msg); + return; + } + + if let Err(err) = sender.send_message(&msg) { + println!("Error sending {:?}", err); + } + }) +} + +struct State { + app_state: AppState, + send_msg_tx: mpsc::Sender, + uid: u32, + peer_id: String, + media: Arc, + webrtc: Option>, +} + +impl State { + fn handle_error(&self) { + let _error = match self.app_state { + AppState::ServerRegistering => AppState::ServerRegisteringError, + AppState::PeerConnecting => AppState::PeerConnectionError, + AppState::PeerConnected => AppState::PeerCallError, + AppState::PeerCallNegotiating => AppState::PeerCallError, + AppState::ServerRegisteringError => AppState::ServerRegisteringError, + AppState::PeerConnectionError => AppState::PeerConnectionError, + AppState::PeerCallError => AppState::PeerCallError, + AppState::Error => AppState::Error, + AppState::ServerConnected => AppState::Error, + AppState::ServerRegistered => AppState::Error, + AppState::PeerCallStarted => AppState::Error, + }; + } + + fn handle_hello(&mut self) { + assert_eq!(self.app_state, AppState::ServerRegistering); + self.app_state = AppState::ServerRegistered; + self.send_msg_tx.send(OwnedMessage::Text(format!("SESSION {}", self.peer_id))).unwrap(); + self.app_state = AppState::PeerConnecting; + } + + fn handle_session_ok(&mut self) { + println!("session is ok; creating webrtc objects"); + assert_eq!(self.app_state, AppState::PeerConnecting); + self.app_state = AppState::PeerConnected; + let signaller = Signaller(self.send_msg_tx.clone()); + self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + //self.webrtc.as_ref().unwrap().trigger_negotiation(); +} + + /*fn handle_registered(&mut self) { + println!("session is ok; creating webrtc objects"); + let signaller = Signaller(self.send_msg_tx.clone(), self.uid); + self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + }*/ +} + +struct Signaller(mpsc::Sender); + +impl WebRtcSignaller for Signaller { + fn send_sdp_offer(&self, offer: String) { + let message = serde_json::to_string(&JsonMsg::Sdp { + type_: "offer".to_string(), + sdp: offer, + }).unwrap(); + //self.0.send((SignalMsg::ToPeer(message), self.1)).unwrap(); + self.0.send(OwnedMessage::Text(message)); + } + + fn send_ice_candidate(&self, mline_index: u32, candidate: String) { + let message = serde_json::to_string(&JsonMsg::Ice { + candidate, + sdp_mline_index: mline_index, + }).unwrap(); + self.0.send(OwnedMessage::Text(message)); + //self.0.send((SignalMsg::ToPeer(message), self.1)).unwrap(); + } +} + +fn receive_loop( + mut receiver: websocket::receiver::Reader, + send_msg_tx: mpsc::Sender, + mut state: State, +) -> thread::JoinHandle<()> { + thread::spawn(move || { + for message in receiver.incoming_messages() { + let message = match message { + Ok(m) => m, + Err(e) => { + println!("Receive Loop error: {:?}", e); + if let Some(ref mut controller) = state.webrtc { + controller.notify_signal_server_error(); + } + /*let mbuilder = + gst::Message::new_application(gst::Structure::new("ws-error", &[])); + let _ = bus.post(&mbuilder.build());*/ + let _ = send_msg_tx.send(OwnedMessage::Close(None)); + return; + } + }; + + match message { + OwnedMessage::Close(_) => { + let _ = send_msg_tx.send(OwnedMessage::Close(None)); + return; + } + + OwnedMessage::Ping(data) => { + if let Err(e) = send_msg_tx.send(OwnedMessage::Pong(data)) { + println!("Receive Loop error: {:?}", e); + return; + } + } + + OwnedMessage::Text(msg) => { + match &*msg { + "HELLO" => state.handle_hello(), + + "SESSION_OK" => state.handle_session_ok(), + + x if x.starts_with("ERROR") => { + println!("Got error message! {}", msg); + state.handle_error() + } + + _ => { + let json_msg: JsonMsg = serde_json::from_str(&msg).unwrap(); + + match json_msg { + JsonMsg::Sdp { type_, sdp } => + state.webrtc.as_ref().unwrap().notify_sdp(type_, sdp), + JsonMsg::Ice { + sdp_mline_index, + candidate, + } => state.webrtc.as_ref().unwrap().notify_ice(sdp_mline_index, candidate), + }; + } + } + /*let mbuilder = gst::Message::new_application(gst::Structure::new( + "ws-message", + &[("body", &msg)], + )); + let _ = bus.post(&mbuilder.build());*/ + } + + _ => { + println!("Unmatched message type: {:?}", message); + } + } + } + }) +} + +fn start_client(peer_id: String) { +} + +fn run_example(servo_media: Arc) { + env_logger::init(); + let mut args = env::args(); + let _ = args.next(); + let server_port = args.next().unwrap().parse::().unwrap(); + let server = format!("ws://localhost:{}", server_port); + let peer_id = args.next().unwrap(); + + /*let sender = start_server2(); + start_client(sender.clone(), false); + start_client(sender.clone(), true);*/ + //start_server(server_port); + + println!("Connecting to server {}", server); + let client = match websocket::client::ClientBuilder::new(&server) + .unwrap() + .connect_insecure() + { + Ok(client) => client, + Err(err) => { + println!("Failed to connect to {} with error: {:?}", server, err); + panic!("uh oh"); + } + }; + let (receiver, sender) = client.split().unwrap(); + //start_client(peer_id, sender, receiver); + + + //thread::spawn(move || { + let (send_msg_tx, send_msg_rx) = mpsc::channel::(); + let send_loop = send_loop(sender, send_msg_rx); + let send_msg_tx_clone = send_msg_tx.clone(); + + //let (send_msg_tx, send_msg_rx) = mpsc::channel(); + + let our_id = rand::thread_rng().gen_range(10, 10_000); + println!("Registering id {} with server", our_id); + //server_sender.send((SignalMsg::Session(send_msg_tx), our_id)); + send_msg_tx.send(OwnedMessage::Text(format!("HELLO {}", our_id))).expect("error sending"); + + let state = State { + app_state: AppState::ServerRegistering, + send_msg_tx: send_msg_tx.clone(), + uid: our_id, + peer_id: peer_id.to_owned(), + media: ServoMedia::get().unwrap(), + webrtc: None, + }; + + //let bus_clone = bus.clone(); + //let webrtc = servo_media.create_webrtc(); + + let receive_loop = receive_loop(receiver, send_msg_tx, state); + let _ = send_loop.join(); + let _ = receive_loop.join(); + + /*while let Ok(msg) = send_msg_rx.recv() { + match msg { + SignalNotification::Registered => { + println!("{} registered", our_id); + state.handle_registered(); + if initial_offer { + state.webrtc.as_ref().unwrap().trigger_negotiation(); + } + } + + } + }*/ + + //}); + + //let client = ws::connect(&server, |out| + +} + +fn main() { + if let Ok(servo_media) = ServoMedia::get() { + run_example(servo_media); + } else { + unreachable!(); + } +} From 9646cf21bfe071f808ada5c1d38d464faed53d18 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 28 Oct 2018 11:00:22 +0000 Subject: [PATCH 03/35] cleanup --- examples/simple_webrtc.rs | 74 ++++++++------------------------------- webrtc/src/lib.rs | 1 + 2 files changed, 15 insertions(+), 60 deletions(-) diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index d4df545a..6be6ea10 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -16,48 +16,9 @@ use std::net; use std::sync::{Arc, mpsc}; use std::thread; use websocket::OwnedMessage; -//use websocket::server::sync::Server; - -/*fn start_server(port: u32) { - thread::spawn(move || { - let s = Server::bind(format!("localhost:{}", port)).unwrap(); - let conns = s.filter_map(Result::ok).take(2); - let conn1 = conns.next().unwrap(); - let mut client = conn1.accept().unwrap(); - thread::spawn(move || { - let msg = client.recv_message().unwrap(); - let uid = match msg { - OwnedMessage::Text(m) => { - let mut parts = m.split(' '); - assert_eq!(parts.next().unwrap(), "HELLO"); - parts.next().unwrap().parse::().unwrap() - } - _ => panic!("invalid greeting"), - }; - client.send_message(&OwnedMessage::Text("HELLO".to_owned())).unwrap(); - - let msg = client.recv_message().unwrap(); - let peer_id = match msg { - OwnedMessage::Text(m) => { - let mut parts = m.split(' '); - assert_eq!(parts.next().unwrap(), "SESSION"); - parts.next().unwrap().to_owned() - } - _ => panic!("invalid session"), - }; - client.send_message(&OwnedMessage::Text("SESSION_OK".to_owned())).unwrap(); - }); - - let conn2 = conns.next().unwrap(); - - - loop { - - } - }); -}*/ #[derive(PartialEq, PartialOrd, Eq, Debug, Copy, Clone, Ord)] +#[allow(unused)] enum AppState { Error = 1, ServerConnected, @@ -114,7 +75,7 @@ fn send_loop( struct State { app_state: AppState, send_msg_tx: mpsc::Sender, - uid: u32, + _uid: u32, peer_id: String, media: Arc, webrtc: Option>, @@ -151,25 +112,25 @@ impl State { let signaller = Signaller(self.send_msg_tx.clone()); self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); //self.webrtc.as_ref().unwrap().trigger_negotiation(); -} - - /*fn handle_registered(&mut self) { - println!("session is ok; creating webrtc objects"); - let signaller = Signaller(self.send_msg_tx.clone(), self.uid); - self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); - }*/ + } } struct Signaller(mpsc::Sender); impl WebRtcSignaller for Signaller { + fn close(&self, reason: String) { + let _ = self.0.send(OwnedMessage::Close(Some(websocket::message::CloseData { + status_code: 1011, //Internal Error + reason: reason, + }))); + } + fn send_sdp_offer(&self, offer: String) { let message = serde_json::to_string(&JsonMsg::Sdp { type_: "offer".to_string(), sdp: offer, }).unwrap(); - //self.0.send((SignalMsg::ToPeer(message), self.1)).unwrap(); - self.0.send(OwnedMessage::Text(message)); + self.0.send(OwnedMessage::Text(message)).unwrap(); } fn send_ice_candidate(&self, mline_index: u32, candidate: String) { @@ -177,8 +138,7 @@ impl WebRtcSignaller for Signaller { candidate, sdp_mline_index: mline_index, }).unwrap(); - self.0.send(OwnedMessage::Text(message)); - //self.0.send((SignalMsg::ToPeer(message), self.1)).unwrap(); + self.0.send(OwnedMessage::Text(message)).unwrap(); } } @@ -256,9 +216,6 @@ fn receive_loop( }) } -fn start_client(peer_id: String) { -} - fn run_example(servo_media: Arc) { env_logger::init(); let mut args = env::args(); @@ -290,9 +247,6 @@ fn run_example(servo_media: Arc) { //thread::spawn(move || { let (send_msg_tx, send_msg_rx) = mpsc::channel::(); let send_loop = send_loop(sender, send_msg_rx); - let send_msg_tx_clone = send_msg_tx.clone(); - - //let (send_msg_tx, send_msg_rx) = mpsc::channel(); let our_id = rand::thread_rng().gen_range(10, 10_000); println!("Registering id {} with server", our_id); @@ -302,9 +256,9 @@ fn run_example(servo_media: Arc) { let state = State { app_state: AppState::ServerRegistering, send_msg_tx: send_msg_tx.clone(), - uid: our_id, + _uid: our_id, peer_id: peer_id.to_owned(), - media: ServoMedia::get().unwrap(), + media: servo_media, webrtc: None, }; diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index fc45a8e3..c4d0bb8b 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -8,6 +8,7 @@ pub trait WebRtcController: Send { pub trait WebRtcSignaller: Send { fn send_sdp_offer(&self, offer: String); fn send_ice_candidate(&self, mlineindex: u32, candidate: String); + fn close(&self, reason: String); } pub trait WebRtcBackend { From a4d4d3984a739ed3b200d243aacc28c7b06b015f Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Sun, 28 Oct 2018 13:35:33 +0000 Subject: [PATCH 04/35] support running example twice with simple signalling server. --- examples/simple_webrtc.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 6be6ea10..8cad46f4 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -76,7 +76,7 @@ struct State { app_state: AppState, send_msg_tx: mpsc::Sender, _uid: u32, - peer_id: String, + peer_id: Option, media: Arc, webrtc: Option>, } @@ -101,16 +101,24 @@ impl State { fn handle_hello(&mut self) { assert_eq!(self.app_state, AppState::ServerRegistering); self.app_state = AppState::ServerRegistered; - self.send_msg_tx.send(OwnedMessage::Text(format!("SESSION {}", self.peer_id))).unwrap(); - self.app_state = AppState::PeerConnecting; + if let Some(ref peer_id) = self.peer_id { + self.send_msg_tx.send(OwnedMessage::Text(format!("SESSION {}", peer_id))).unwrap(); + self.app_state = AppState::PeerConnecting; + } + if self.peer_id.is_none() { + let signaller = Signaller(self.send_msg_tx.clone()); + self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + } } fn handle_session_ok(&mut self) { println!("session is ok; creating webrtc objects"); assert_eq!(self.app_state, AppState::PeerConnecting); self.app_state = AppState::PeerConnected; - let signaller = Signaller(self.send_msg_tx.clone()); - self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + if self.peer_id.is_some() { + let signaller = Signaller(self.send_msg_tx.clone()); + self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + } //self.webrtc.as_ref().unwrap().trigger_negotiation(); } } @@ -222,7 +230,7 @@ fn run_example(servo_media: Arc) { let _ = args.next(); let server_port = args.next().unwrap().parse::().unwrap(); let server = format!("ws://localhost:{}", server_port); - let peer_id = args.next().unwrap(); + let peer_id = args.next(); /*let sender = start_server2(); start_client(sender.clone(), false); @@ -257,7 +265,7 @@ fn run_example(servo_media: Arc) { app_state: AppState::ServerRegistering, send_msg_tx: send_msg_tx.clone(), _uid: our_id, - peer_id: peer_id.to_owned(), + peer_id: peer_id, media: servo_media, webrtc: None, }; From 12b80b62de4a2a41517cbff82dbe2ba5edda4ddc Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 29 Oct 2018 07:25:47 -0400 Subject: [PATCH 05/35] add gstreamer backend --- backends/gstreamer/src/webrtc.rs | 556 +++++++++++++++++++++++++++++++ 1 file changed, 556 insertions(+) create mode 100644 backends/gstreamer/src/webrtc.rs diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs new file mode 100644 index 00000000..85ae3a2e --- /dev/null +++ b/backends/gstreamer/src/webrtc.rs @@ -0,0 +1,556 @@ +use failure::Error; +use glib::{self, ObjectExt}; +use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; +use gst_sdp; +use gst_webrtc; +use servo_media_webrtc::{WebRtcController, WebRtcSignaller}; +use std::sync::{Arc, Mutex}; + +// TODO: +// - configurable STUN server? +// - remove use of failure? +// - figure out purpose of glib loop + +const STUN_SERVER: &str = "stun://stun.l.google.com:19302"; +lazy_static! { + static ref RTP_CAPS_OPUS: gst::Caps = { + gst::Caps::new_simple( + "application/x-rtp", + &[ + ("media", &"audio"), + ("encoding-name", &"OPUS"), + ("payload", &(97i32)), + ], + ) + }; + static ref RTP_CAPS_VP8: gst::Caps = { + gst::Caps::new_simple( + "application/x-rtp", + &[ + ("media", &"video"), + ("encoding-name", &"VP8"), + ("payload", &(96i32)), + ], + ) + }; +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum MediaType { + Audio, + Video, +} + +#[derive(PartialEq, PartialOrd, Eq, Debug, Copy, Clone, Ord)] +#[allow(unused)] +enum AppState { + Error = 1, + ServerConnected, + ServerRegistering = 2000, + ServerRegisteringError, + ServerRegistered, + PeerConnecting = 3000, + PeerConnectionError, + PeerConnected, + PeerCallNegotiating = 4000, + PeerCallStarted, + PeerCallError, +} + +#[derive(Clone)] +pub struct GStreamerWebRtcController(Arc>); + +impl WebRtcController for GStreamerWebRtcController { + fn trigger_negotiation(&self) { + let app_control = self.0.lock().unwrap(); + app_control + .webrtc + .as_ref() + .unwrap() + .emit("on-negotiation-needed", &[]) + .unwrap(); + } + + fn notify_signal_server_error(&self) { + //TODO + } + + fn notify_ice(&self, sdp_mline_index: u32, candidate: String) { + let app_control = self.0.lock().unwrap(); + app_control + .webrtc + .as_ref() + .unwrap() + .emit("add-ice-candidate", &[&sdp_mline_index, &candidate]) + .unwrap(); + } + + fn notify_sdp(&self, type_: String, sdp: String) { + if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { + return; + } + + if type_ == "offer" { + let mut app_control = self.0.lock().unwrap(); + + print!("Received offer:\n{}\n", sdp); + + let ret = gst_sdp::SDPMessage::parse_buffer(sdp.as_bytes()).unwrap(); + let answer = + gst_webrtc::WebRTCSessionDescription::new(gst_webrtc::WebRTCSDPType::Offer, ret); + let promise = gst::Promise::new(); + app_control + .webrtc + .as_ref() + .unwrap() + .emit("set-remote-description", &[&answer, &promise]) + .unwrap(); + return; + } + + if type_ != "answer" { + self.send_bus_error("Sdp type is not \"answer\""); + return; + } + + let mut app_control = self.0.lock().unwrap(); + + print!("Received answer:\n{}\n", sdp); + + let ret = gst_sdp::SDPMessage::parse_buffer(sdp.as_bytes()).unwrap(); + let answer = + gst_webrtc::WebRTCSessionDescription::new(gst_webrtc::WebRTCSDPType::Answer, ret); + let promise = gst::Promise::new(); + app_control + .webrtc + .as_ref() + .unwrap() + .emit("set-remote-description", &[&answer, &promise]) + .unwrap(); + + app_control.app_state = AppState::PeerCallStarted; + } +} + +impl GStreamerWebRtcController { + fn start_pipeline(&self) -> Result<(), Error> { + self.0.lock().unwrap().start_pipeline(self.clone()) + } + + fn assert_app_state_is(&self, state: AppState, error_msg: &'static str) -> bool { + if self.0.lock().unwrap().app_state != state { + self.send_bus_error(error_msg); + + false + } else { + true + } + } + + fn assert_app_state_is_at_least(&self, state: AppState, error_msg: &'static str) -> bool { + if self.0.lock().unwrap().app_state < state { + self.send_bus_error(error_msg); + + false + } else { + true + } + } + + //#[allow(unused)] + fn send_bus_error(&self, body: &str) { + eprintln!("Bus error: {}", body); + /*let mbuilder = + gst::Message::new_application(gst::Structure::new("error", &[("body", &body)])); + let _ = self.0.lock().unwrap().bus.post(&mbuilder.build());*/ + //XXXjdm + } + + #[allow(unused)] + fn update_state(&self, state: AppState) { + self.0.lock().unwrap().update_state(state); + } + + #[allow(unused)] + fn close_and_quit(&self, err: &Error) { + println!("{}\nquitting", err); + + // Must not hold mutex while shutting down the pipeline + // as something might call into here and take the mutex too + let pipeline = { + let app_control = self.0.lock().unwrap(); + app_control.signaller.close(err.to_string()); + app_control.pipeline.clone() + }; + + pipeline.set_state(gst::State::Null).into_result().unwrap(); + + //main_loop.quit(); + } +} + +struct WebRtcControllerState { + webrtc: Option, + app_state: AppState, + pipeline: gst::Pipeline, + signaller: Box, + //send_msg_tx: mpsc::Sender, + //peer_id: String, + main_loop: glib::MainLoop, + //bus: gst::Bus, +} + +impl WebRtcControllerState { + fn construct_pipeline(&self) -> Result { + let pipeline = self.pipeline.clone(); + + let webrtcbin = gst::ElementFactory::make("webrtcbin", "sendrecv").unwrap(); + pipeline.add(&webrtcbin)?; + + webrtcbin.set_property_from_str("stun-server", STUN_SERVER); + webrtcbin.set_property_from_str("bundle-policy", "max-bundle"); + + add_video_source(&pipeline, &webrtcbin)?; + add_audio_source(&pipeline, &webrtcbin)?; + + Ok(pipeline) + } + + fn start_pipeline(&mut self, target: GStreamerWebRtcController) -> Result<(), Error> { + let pipe = self.construct_pipeline()?; + let webrtc = pipe.get_by_name("sendrecv").unwrap(); + + let app_control_clone = target.clone(); + webrtc.connect("on-negotiation-needed", false, move |values| { + on_negotiation_needed(&app_control_clone, values).unwrap(); + None + })?; + + let app_control_clone = target.clone(); + webrtc.connect("on-ice-candidate", false, move |values| { + send_ice_candidate_message(&app_control_clone, values); + None + })?; + + let pipe_clone = pipe.clone(); + let app_control_clone = target.clone(); + webrtc.connect("pad-added", false, move |values| { + on_incoming_stream(&app_control_clone, values, &pipe_clone) + })?; + + pipe.set_state(gst::State::Playing).into_result()?; + + self.webrtc = Some(webrtc); + + Ok(()) + } + + fn update_state(&mut self, state: AppState) { + self.app_state = state; + } +} + +pub fn start(signaller: Box) -> GStreamerWebRtcController { + let main_loop = glib::MainLoop::new(None, false); + let pipeline = gst::Pipeline::new("main"); + //let bus = pipeline.get_bus().unwrap(); + + let controller = WebRtcControllerState { + webrtc: None, + pipeline, + signaller, + app_state: AppState::ServerConnected, + main_loop, + }; + let controller = GStreamerWebRtcController(Arc::new(Mutex::new(controller))); + controller.start_pipeline().unwrap(); + + let controller_clone = controller.clone(); + + /*bus.add_watch(move |_, msg| { + use gst::message::MessageView; + + match msg.view() { + MessageView::Error(err) => controller.close_and_quit(&Error::from(err.get_error())), + MessageView::Warning(warning) => { + println!("Warning: \"{}\"", warning.get_debug().unwrap()); + } + MessageView::Application(a) => { + let struc = a.get_structure().unwrap(); + if let Err(err) = handle_application_msg(&controller, struc) { + controller.close_and_quit(&err) + } + } + _ => {} + }; + + glib::Continue(true) + });*/ + + controller_clone +} + +/*fn handle_application_msg( + app_control: &GStreamerWebRtcController, + struc: &gst::StructureRef, +) -> Result<(), Error> { + match struc.get_name() { + "ws-message" => { + let msg = struc.get_value("body").unwrap(); + app_control.on_message(msg.get().unwrap()) + } + "ws-error" => Err(WsError(app_control.0.lock().unwrap().app_state))?, + "error" => { + let msg: String = struc.get_value("body").unwrap().get().unwrap(); + Err(BusError(msg))? + } + u => { + println!("Got unknown application message {:?}", u); + + Ok(()) + } + } +}*/ + +fn add_video_source(pipeline: &gst::Pipeline, webrtcbin: &gst::Element) -> Result<(), Error> { + let videotestsrc = gst::ElementFactory::make("videotestsrc", None).unwrap(); + let videoconvert = gst::ElementFactory::make("videoconvert", None).unwrap(); + let queue = gst::ElementFactory::make("queue", None).unwrap(); + let vp8enc = gst::ElementFactory::make("vp8enc", None).unwrap(); + + videotestsrc.set_property_from_str("pattern", "ball"); + videotestsrc.set_property("is-live", &true).unwrap(); + vp8enc.set_property("deadline", &1i64).unwrap(); + + let rtpvp8pay = gst::ElementFactory::make("rtpvp8pay", None).unwrap(); + let queue2 = gst::ElementFactory::make("queue", None).unwrap(); + + pipeline.add_many(&[ + &videotestsrc, + &videoconvert, + &queue, + &vp8enc, + &rtpvp8pay, + &queue2, + ])?; + + gst::Element::link_many(&[ + &videotestsrc, + &videoconvert, + &queue, + &vp8enc, + &rtpvp8pay, + &queue2, + ])?; + + queue2.link_filtered(webrtcbin, &*RTP_CAPS_VP8)?; + + Ok(()) +} + +fn add_audio_source(pipeline: &gst::Pipeline, webrtcbin: &gst::Element) -> Result<(), Error> { + let audiotestsrc = gst::ElementFactory::make("audiotestsrc", None).unwrap(); + let queue = gst::ElementFactory::make("queue", None).unwrap(); + let audioconvert = gst::ElementFactory::make("audioconvert", None).unwrap(); + let audioresample = gst::ElementFactory::make("audioresample", None).unwrap(); + let queue2 = gst::ElementFactory::make("queue", None).unwrap(); + let opusenc = gst::ElementFactory::make("opusenc", None).unwrap(); + let rtpopuspay = gst::ElementFactory::make("rtpopuspay", None).unwrap(); + let queue3 = gst::ElementFactory::make("queue", None).unwrap(); + + audiotestsrc.set_property_from_str("wave", "red-noise"); + audiotestsrc.set_property("is-live", &true).unwrap(); + + pipeline.add_many(&[ + &audiotestsrc, + &queue, + &audioconvert, + &audioresample, + &queue2, + &opusenc, + &rtpopuspay, + &queue3, + ])?; + + gst::Element::link_many(&[ + &audiotestsrc, + &queue, + &audioconvert, + &audioresample, + &queue2, + &opusenc, + &rtpopuspay, + &queue3, + ])?; + + queue3.link_filtered(webrtcbin, &*RTP_CAPS_OPUS)?; + + Ok(()) +} + +fn send_sdp_offer(app_control: &GStreamerWebRtcController, offer: &gst_webrtc::WebRTCSessionDescription) { + if !app_control.assert_app_state_is_at_least( + AppState::PeerCallNegotiating, + "Can't send offer, not in call", + ) { + return; + } + + app_control.0.lock().unwrap().signaller.send_sdp_offer( + offer.get_sdp().as_text().unwrap() + ); +} + +fn on_offer_created( + app_control: &GStreamerWebRtcController, + webrtc: &gst::Element, + promise: &gst::Promise, +) -> Result<(), Error> { + if !app_control.assert_app_state_is( + AppState::PeerCallNegotiating, + "Not negotiating call when creating offer", + ) { + return Ok(()); + } + + let reply = promise.get_reply().unwrap(); + + let offer = reply + .get_value("offer") + .unwrap() + .get::() + .expect("Invalid argument"); + webrtc.emit("set-local-description", &[&offer, &None::])?; + + send_sdp_offer(&app_control, &offer); + + Ok(()) +} + +fn on_negotiation_needed(app_control: &GStreamerWebRtcController, values: &[glib::Value]) -> Result<(), Error> { + app_control.0.lock().unwrap().app_state = AppState::PeerCallNegotiating; + + let webrtc = values[0].get::().unwrap(); + let webrtc_clone = webrtc.clone(); + let app_control_clone = app_control.clone(); + let promise = gst::Promise::new_with_change_func(move |promise| { + on_offer_created(&app_control_clone, &webrtc, promise).unwrap(); + }); + + webrtc_clone.emit("create-offer", &[&None::, &promise])?; + + Ok(()) +} + +fn handle_media_stream( + pad: &gst::Pad, + pipe: &gst::Pipeline, + media_type: MediaType, +) -> Result<(), Error> { + println!("Trying to handle stream {:?}", media_type); + + let (q, conv, sink) = match media_type { + MediaType::Audio => { + let q = gst::ElementFactory::make("queue", None).unwrap(); + let conv = gst::ElementFactory::make("audioconvert", None).unwrap(); + let sink = gst::ElementFactory::make("autoaudiosink", None).unwrap(); + let resample = gst::ElementFactory::make("audioresample", None).unwrap(); + + pipe.add_many(&[&q, &conv, &resample, &sink])?; + gst::Element::link_many(&[&q, &conv, &resample, &sink])?; + + resample.sync_state_with_parent()?; + + (q, conv, sink) + } + MediaType::Video => { + let q = gst::ElementFactory::make("queue", None).unwrap(); + let conv = gst::ElementFactory::make("videoconvert", None).unwrap(); + let sink = gst::ElementFactory::make("autovideosink", None).unwrap(); + + pipe.add_many(&[&q, &conv, &sink])?; + gst::Element::link_many(&[&q, &conv, &sink])?; + + (q, conv, sink) + } + }; + q.sync_state_with_parent()?; + conv.sync_state_with_parent()?; + sink.sync_state_with_parent()?; + + let qpad = q.get_static_pad("sink").unwrap(); + pad.link(&qpad).into_result()?; + + Ok(()) +} + +fn on_incoming_decodebin_stream( + app_control: &GStreamerWebRtcController, + values: &[glib::Value], + pipe: &gst::Pipeline, +) -> Option { + let pad = values[1].get::().expect("Invalid argument"); + if !pad.has_current_caps() { + println!("Pad {:?} has no caps, can't do anything, ignoring", pad); + return None; + } + + let caps = pad.get_current_caps().unwrap(); + let name = caps.get_structure(0).unwrap().get_name(); + + let handled = if name.starts_with("video") { + handle_media_stream(&pad, &pipe, MediaType::Video) + } else if name.starts_with("audio") { + handle_media_stream(&pad, &pipe, MediaType::Audio) + } else { + println!("Unknown pad {:?}, ignoring", pad); + Ok(()) + }; + + if let Err(err) = handled { + app_control.send_bus_error(&format!("Error adding pad with caps {} {:?}", name, err)); + } + + None +} + +fn on_incoming_stream( + app_control: &GStreamerWebRtcController, + values: &[glib::Value], + pipe: &gst::Pipeline, +) -> Option { + let webrtc = values[0].get::().expect("Invalid argument"); + + let decodebin = gst::ElementFactory::make("decodebin", None).unwrap(); + let pipe_clone = pipe.clone(); + let app_control_clone = app_control.clone(); + decodebin + .connect("pad-added", false, move |values| { + on_incoming_decodebin_stream(&app_control_clone, values, &pipe_clone) + }) + .unwrap(); + + pipe.add(&decodebin).unwrap(); + + decodebin.sync_state_with_parent().unwrap(); + webrtc.link(&decodebin).unwrap(); + + None +} + +fn send_ice_candidate_message(app_control: &GStreamerWebRtcController, values: &[glib::Value]) { + if !app_control + .assert_app_state_is_at_least(AppState::PeerCallNegotiating, "Can't send ICE, not in call") + { + return; + } + + let _webrtc = values[0].get::().expect("Invalid argument"); + let mlineindex = values[1].get::().expect("Invalid argument"); + let candidate = values[2].get::().expect("Invalid argument"); + + app_control.0.lock().unwrap().signaller.send_ice_candidate( + mlineindex, + candidate, + ); +} From f6a58b05954f78c5ba58d4fc60ece45d24dafb19 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Wed, 16 Jan 2019 12:35:46 -0500 Subject: [PATCH 06/35] tmp --- examples/Cargo.toml | 3 +- examples/simple_webrtc.rs | 80 ++++++++++++--------------------------- servo-media/src/lib.rs | 5 +++ 3 files changed, 30 insertions(+), 58 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 43b894b6..38be14fd 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -15,8 +15,7 @@ serde_derive = "1.0" serde_json = "1.0" servo-media = { path = "../servo-media" } webrender = { git = "https://github.com/servo/webrender/" } -websocket = "*" -#ws = "*" +websocket = "0.20" ipc-channel = "0.11" [target.'cfg(not(target_os = "android"))'.dependencies] diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 8cad46f4..3fbbd39d 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -1,3 +1,11 @@ +//! To run this, clone https://github.com/centricular/gstwebrtc-demos, then: +//! $ cd signalling +//! $ ./simple-server.py +//! $ cd ../js +//! $ python -m SimpleHTTPServer +//! Then load http://localhost:8000 in a web browser, note the client id. +//! Then run this example with arguments `8443 {id}`. + extern crate env_logger; extern crate rand; extern crate serde; @@ -6,7 +14,6 @@ extern crate serde_derive; extern crate serde_json; extern crate servo_media; extern crate websocket; -//extern crate ws; use rand::Rng; use servo_media::ServoMedia; @@ -119,7 +126,6 @@ impl State { let signaller = Signaller(self.send_msg_tx.clone()); self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); } - //self.webrtc.as_ref().unwrap().trigger_negotiation(); } } @@ -164,9 +170,6 @@ fn receive_loop( if let Some(ref mut controller) = state.webrtc { controller.notify_signal_server_error(); } - /*let mbuilder = - gst::Message::new_application(gst::Structure::new("ws-error", &[])); - let _ = bus.post(&mbuilder.build());*/ let _ = send_msg_tx.send(OwnedMessage::Close(None)); return; } @@ -209,11 +212,6 @@ fn receive_loop( }; } } - /*let mbuilder = gst::Message::new_application(gst::Structure::new( - "ws-message", - &[("body", &msg)], - )); - let _ = bus.post(&mbuilder.build());*/ } _ => { @@ -232,11 +230,6 @@ fn run_example(servo_media: Arc) { let server = format!("ws://localhost:{}", server_port); let peer_id = args.next(); - /*let sender = start_server2(); - start_client(sender.clone(), false); - start_client(sender.clone(), true);*/ - //start_server(server_port); - println!("Connecting to server {}", server); let client = match websocket::client::ClientBuilder::new(&server) .unwrap() @@ -249,51 +242,26 @@ fn run_example(servo_media: Arc) { } }; let (receiver, sender) = client.split().unwrap(); - //start_client(peer_id, sender, receiver); - - - //thread::spawn(move || { - let (send_msg_tx, send_msg_rx) = mpsc::channel::(); - let send_loop = send_loop(sender, send_msg_rx); - - let our_id = rand::thread_rng().gen_range(10, 10_000); - println!("Registering id {} with server", our_id); - //server_sender.send((SignalMsg::Session(send_msg_tx), our_id)); - send_msg_tx.send(OwnedMessage::Text(format!("HELLO {}", our_id))).expect("error sending"); - - let state = State { - app_state: AppState::ServerRegistering, - send_msg_tx: send_msg_tx.clone(), - _uid: our_id, - peer_id: peer_id, - media: servo_media, - webrtc: None, - }; - //let bus_clone = bus.clone(); - //let webrtc = servo_media.create_webrtc(); + let (send_msg_tx, send_msg_rx) = mpsc::channel::(); + let send_loop = send_loop(sender, send_msg_rx); - let receive_loop = receive_loop(receiver, send_msg_tx, state); - let _ = send_loop.join(); - let _ = receive_loop.join(); + let our_id = rand::thread_rng().gen_range(10, 10_000); + println!("Registering id {} with server", our_id); + send_msg_tx.send(OwnedMessage::Text(format!("HELLO {}", our_id))).expect("error sending"); - /*while let Ok(msg) = send_msg_rx.recv() { - match msg { - SignalNotification::Registered => { - println!("{} registered", our_id); - state.handle_registered(); - if initial_offer { - state.webrtc.as_ref().unwrap().trigger_negotiation(); - } - } - - } - }*/ - - //}); - - //let client = ws::connect(&server, |out| + let state = State { + app_state: AppState::ServerRegistering, + send_msg_tx: send_msg_tx.clone(), + _uid: our_id, + peer_id: peer_id, + media: servo_media, + webrtc: None, + }; + let receive_loop = receive_loop(receiver, send_msg_tx, state); + let _ = send_loop.join(); + let _ = receive_loop.join(); } fn main() { diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 29def77a..8df47529 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -58,6 +58,8 @@ pub type Backend = DummyBackend; pub type WebRtcController = servo_media_gstreamer::webrtc::GStreamerWebRtcController; +pub type MediaStream = servo_media_gstreamer::media_stream::GStreamerMediaStream; + impl ServoMedia { pub fn new() -> Self { Backend::init(); @@ -87,4 +89,7 @@ impl ServoMedia { pub fn create_webrtc(&self, signaller: Box) -> Box { Box::new(Backend::start_webrtc_controller(signaller)) } + + pub fn create_mediastream(&self) -> Box { + } } From 36f2601ee06386558912e0d0ff0c15b25da0627f Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 17 Jan 2019 11:54:43 -0500 Subject: [PATCH 07/35] dummy media stream --- backends/gstreamer/src/lib.rs | 5 +++++ backends/gstreamer/src/webrtc.rs | 6 +++--- servo-media/src/lib.rs | 5 +++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 722b71bd..72bddd73 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -33,6 +33,7 @@ use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller}; pub mod audio_decoder; pub mod audio_sink; +pub mod media_stream; pub mod player; mod source; pub mod webrtc; @@ -68,4 +69,8 @@ impl GStreamerBackend { pub fn init() { gst::init().unwrap(); } + + pub fn create_mediastream() -> media_stream::GStreamerMediaStream { + media_stream::GStreamerMediaStream + } } diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 85ae3a2e..213552c2 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -91,7 +91,7 @@ impl WebRtcController for GStreamerWebRtcController { } if type_ == "offer" { - let mut app_control = self.0.lock().unwrap(); + let app_control = self.0.lock().unwrap(); print!("Received offer:\n{}\n", sdp); @@ -196,7 +196,7 @@ struct WebRtcControllerState { signaller: Box, //send_msg_tx: mpsc::Sender, //peer_id: String, - main_loop: glib::MainLoop, + _main_loop: glib::MainLoop, //bus: gst::Bus, } @@ -260,7 +260,7 @@ pub fn start(signaller: Box) -> GStreamerWebRtcController { pipeline, signaller, app_state: AppState::ServerConnected, - main_loop, + _main_loop: main_loop, }; let controller = GStreamerWebRtcController(Arc::new(Mutex::new(controller))); controller.start_pipeline().unwrap(); diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 8df47529..0f1301ea 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -20,6 +20,7 @@ pub struct ServoMedia; static INITIALIZER: Once = sync::ONCE_INIT; static mut INSTANCE: *mut Mutex>> = 0 as *mut _; +pub struct DummyMediaStream; pub struct DummyBackend {} impl AudioBackend for DummyBackend { @@ -43,6 +44,9 @@ impl PlayerBackend for DummyBackend { impl DummyBackend { pub fn init() {} + pub fn create_mediastream() -> DummyMediaStream { + DummyMediaStream + } } #[cfg(any( @@ -91,5 +95,6 @@ impl ServoMedia { } pub fn create_mediastream(&self) -> Box { + Box::new(Backend::create_mediastream()) } } From f124bd4217d00c358374b9c53382e8aebfd367f4 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 17 Jan 2019 13:17:08 -0500 Subject: [PATCH 08/35] add missing media stream --- backends/gstreamer/src/media_stream.rs | 1 + 1 file changed, 1 insertion(+) create mode 100644 backends/gstreamer/src/media_stream.rs diff --git a/backends/gstreamer/src/media_stream.rs b/backends/gstreamer/src/media_stream.rs new file mode 100644 index 00000000..043c2f8e --- /dev/null +++ b/backends/gstreamer/src/media_stream.rs @@ -0,0 +1 @@ +pub struct GStreamerMediaStream; From e537d45a9ad34bde2996668e1ccb88446c724e62 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 13:22:19 -0500 Subject: [PATCH 09/35] Correct path for js --- examples/simple_webrtc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 3fbbd39d..017858c9 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -1,7 +1,7 @@ //! To run this, clone https://github.com/centricular/gstwebrtc-demos, then: //! $ cd signalling //! $ ./simple-server.py -//! $ cd ../js +//! $ cd ../sendrcv/js //! $ python -m SimpleHTTPServer //! Then load http://localhost:8000 in a web browser, note the client id. //! Then run this example with arguments `8443 {id}`. From 8a894d8bc8689e946045d941c9de866354344465 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 13:25:40 -0500 Subject: [PATCH 10/35] Refactor remote description setting --- backends/gstreamer/src/webrtc.rs | 41 +++++++++----------------------- examples/simple_webrtc.rs | 11 ++++++--- webrtc/src/lib.rs | 40 ++++++++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 213552c2..94973380 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -3,7 +3,7 @@ use glib::{self, ObjectExt}; use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; use gst_sdp; use gst_webrtc; -use servo_media_webrtc::{WebRtcController, WebRtcSignaller}; +use servo_media_webrtc::{RTCSdpType, RTCSessionDescription, WebRtcController, WebRtcSignaller}; use std::sync::{Arc, Mutex}; // TODO: @@ -85,41 +85,23 @@ impl WebRtcController for GStreamerWebRtcController { .unwrap(); } - fn notify_sdp(&self, type_: String, sdp: String) { + fn set_remote_description(&self, desc: RTCSessionDescription) { + use gst_webrtc::WebRTCSDPType; if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { return; } - if type_ == "offer" { - let app_control = self.0.lock().unwrap(); - - print!("Received offer:\n{}\n", sdp); - - let ret = gst_sdp::SDPMessage::parse_buffer(sdp.as_bytes()).unwrap(); - let answer = - gst_webrtc::WebRTCSessionDescription::new(gst_webrtc::WebRTCSDPType::Offer, ret); - let promise = gst::Promise::new(); - app_control - .webrtc - .as_ref() - .unwrap() - .emit("set-remote-description", &[&answer, &promise]) - .unwrap(); - return; - } - - if type_ != "answer" { - self.send_bus_error("Sdp type is not \"answer\""); - return; - } + let ty = match desc.type_ { + RTCSdpType::Answer => WebRTCSDPType::Answer, + RTCSdpType::Offer => WebRTCSDPType::Offer, + RTCSdpType::Pranswer => WebRTCSDPType::Pranswer, + RTCSdpType::Rollback => WebRTCSDPType::Rollback, + }; let mut app_control = self.0.lock().unwrap(); - - print!("Received answer:\n{}\n", sdp); - - let ret = gst_sdp::SDPMessage::parse_buffer(sdp.as_bytes()).unwrap(); + let ret = gst_sdp::SDPMessage::parse_buffer(desc.sdp.as_bytes()).unwrap(); let answer = - gst_webrtc::WebRTCSessionDescription::new(gst_webrtc::WebRTCSDPType::Answer, ret); + gst_webrtc::WebRTCSessionDescription::new(ty, ret); let promise = gst::Promise::new(); app_control .webrtc @@ -127,7 +109,6 @@ impl WebRtcController for GStreamerWebRtcController { .unwrap() .emit("set-remote-description", &[&answer, &promise]) .unwrap(); - app_control.app_state = AppState::PeerCallStarted; } } diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 017858c9..1c818fb3 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -17,7 +17,7 @@ extern crate websocket; use rand::Rng; use servo_media::ServoMedia; -use servo_media::webrtc::{WebRtcController, WebRtcSignaller}; +use servo_media::webrtc::{RTCSessionDescription, WebRtcController, WebRtcSignaller}; use std::env; use std::net; use std::sync::{Arc, mpsc}; @@ -203,8 +203,13 @@ fn receive_loop( let json_msg: JsonMsg = serde_json::from_str(&msg).unwrap(); match json_msg { - JsonMsg::Sdp { type_, sdp } => - state.webrtc.as_ref().unwrap().notify_sdp(type_, sdp), + JsonMsg::Sdp { type_, sdp } => { + let desc = RTCSessionDescription { + type_: type_.parse().unwrap(), + sdp: sdp.into() + }; + state.webrtc.as_ref().unwrap().set_remote_description(desc); + } JsonMsg::Ice { sdp_mline_index, candidate, diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index c4d0bb8b..853bc423 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -1,6 +1,8 @@ +use std::str::FromStr; + pub trait WebRtcController: Send { fn notify_signal_server_error(&self); - fn notify_sdp(&self, type_: String, sdp: String); + fn set_remote_description(&self, RTCSessionDescription); fn notify_ice(&self, sdp_mline_index: u32, candidate: String); fn trigger_negotiation(&self); } @@ -16,3 +18,39 @@ pub trait WebRtcBackend { fn start_webrtc_controller(signaller: Box) -> Self::Controller; } + +pub enum RTCSdpType { + Answer, + Offer, + Pranswer, + Rollback, +} + +impl RTCSdpType { + pub fn as_str(self) -> &'static str { + match self { + RTCSdpType::Answer => "answer", + RTCSdpType::Offer => "offer", + RTCSdpType::Pranswer => "pranswer", + RTCSdpType::Rollback => "rollback", + } + } +} + +impl FromStr for RTCSdpType { + type Err = (); + fn from_str(s: &str) -> Result { + Ok(match s { + "answer" => RTCSdpType::Answer, + "offer" => RTCSdpType::Offer, + "pranswer" => RTCSdpType::Pranswer, + "rollback" => RTCSdpType::Rollback, + _ => return Err(()) + }) + } +} + +pub struct RTCSessionDescription { + pub type_: RTCSdpType, + pub sdp: String, +} From 6c522a8341f29f073ec015af445cd2fe42ffecb7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 13:38:33 -0500 Subject: [PATCH 11/35] remove RTC from names --- backends/gstreamer/src/webrtc.rs | 12 ++++++------ examples/simple_webrtc.rs | 4 ++-- webrtc/src/lib.rs | 32 ++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 94973380..b9220b0e 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -3,7 +3,7 @@ use glib::{self, ObjectExt}; use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; use gst_sdp; use gst_webrtc; -use servo_media_webrtc::{RTCSdpType, RTCSessionDescription, WebRtcController, WebRtcSignaller}; +use servo_media_webrtc::{SdpType, SessionDescription, WebRtcController, WebRtcSignaller}; use std::sync::{Arc, Mutex}; // TODO: @@ -85,17 +85,17 @@ impl WebRtcController for GStreamerWebRtcController { .unwrap(); } - fn set_remote_description(&self, desc: RTCSessionDescription) { + fn set_remote_description(&self, desc: SessionDescription) { use gst_webrtc::WebRTCSDPType; if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { return; } let ty = match desc.type_ { - RTCSdpType::Answer => WebRTCSDPType::Answer, - RTCSdpType::Offer => WebRTCSDPType::Offer, - RTCSdpType::Pranswer => WebRTCSDPType::Pranswer, - RTCSdpType::Rollback => WebRTCSDPType::Rollback, + SdpType::Answer => WebRTCSDPType::Answer, + SdpType::Offer => WebRTCSDPType::Offer, + SdpType::Pranswer => WebRTCSDPType::Pranswer, + SdpType::Rollback => WebRTCSDPType::Rollback, }; let mut app_control = self.0.lock().unwrap(); diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 1c818fb3..e938c900 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -17,7 +17,7 @@ extern crate websocket; use rand::Rng; use servo_media::ServoMedia; -use servo_media::webrtc::{RTCSessionDescription, WebRtcController, WebRtcSignaller}; +use servo_media::webrtc::{SessionDescription, WebRtcController, WebRtcSignaller}; use std::env; use std::net; use std::sync::{Arc, mpsc}; @@ -204,7 +204,7 @@ fn receive_loop( match json_msg { JsonMsg::Sdp { type_, sdp } => { - let desc = RTCSessionDescription { + let desc = SessionDescription { type_: type_.parse().unwrap(), sdp: sdp.into() }; diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index 853bc423..bc8e2c7d 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -2,7 +2,7 @@ use std::str::FromStr; pub trait WebRtcController: Send { fn notify_signal_server_error(&self); - fn set_remote_description(&self, RTCSessionDescription); + fn set_remote_description(&self, SessionDescription); fn notify_ice(&self, sdp_mline_index: u32, candidate: String); fn trigger_negotiation(&self); } @@ -19,38 +19,42 @@ pub trait WebRtcBackend { fn start_webrtc_controller(signaller: Box) -> Self::Controller; } -pub enum RTCSdpType { +/// https://www.w3.org/TR/webrtc/#rtcsdptype +pub enum SdpType { Answer, Offer, Pranswer, Rollback, } -impl RTCSdpType { +impl SdpType { pub fn as_str(self) -> &'static str { match self { - RTCSdpType::Answer => "answer", - RTCSdpType::Offer => "offer", - RTCSdpType::Pranswer => "pranswer", - RTCSdpType::Rollback => "rollback", + SdpType::Answer => "answer", + SdpType::Offer => "offer", + SdpType::Pranswer => "pranswer", + SdpType::Rollback => "rollback", } } } -impl FromStr for RTCSdpType { +impl FromStr for SdpType { type Err = (); fn from_str(s: &str) -> Result { Ok(match s { - "answer" => RTCSdpType::Answer, - "offer" => RTCSdpType::Offer, - "pranswer" => RTCSdpType::Pranswer, - "rollback" => RTCSdpType::Rollback, + "answer" => SdpType::Answer, + "offer" => SdpType::Offer, + "pranswer" => SdpType::Pranswer, + "rollback" => SdpType::Rollback, _ => return Err(()) }) } } -pub struct RTCSessionDescription { - pub type_: RTCSdpType, +/// https://www.w3.org/TR/webrtc/#rtcsessiondescription-class +/// +/// https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription +pub struct SessionDescription { + pub type_: SdpType, pub sdp: String, } From 7606b3c40d1aee08cddf7d90b4fc6c7aa2e16cb3 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 13:43:35 -0500 Subject: [PATCH 12/35] add IceCandidate type, notify_ice -> add_ice_candidate --- backends/gstreamer/src/webrtc.rs | 6 +++--- examples/simple_webrtc.rs | 9 +++++++-- webrtc/src/lib.rs | 11 ++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index b9220b0e..5844dbde 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -3,7 +3,7 @@ use glib::{self, ObjectExt}; use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; use gst_sdp; use gst_webrtc; -use servo_media_webrtc::{SdpType, SessionDescription, WebRtcController, WebRtcSignaller}; +use servo_media_webrtc::*; use std::sync::{Arc, Mutex}; // TODO: @@ -75,13 +75,13 @@ impl WebRtcController for GStreamerWebRtcController { //TODO } - fn notify_ice(&self, sdp_mline_index: u32, candidate: String) { + fn add_ice_candidate(&self, candidate: IceCandidate) { let app_control = self.0.lock().unwrap(); app_control .webrtc .as_ref() .unwrap() - .emit("add-ice-candidate", &[&sdp_mline_index, &candidate]) + .emit("add-ice-candidate", &[&candidate.sdp_mline_index, &candidate.candidate]) .unwrap(); } diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index e938c900..54f15bc1 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -17,7 +17,7 @@ extern crate websocket; use rand::Rng; use servo_media::ServoMedia; -use servo_media::webrtc::{SessionDescription, WebRtcController, WebRtcSignaller}; +use servo_media::webrtc::*; use std::env; use std::net; use std::sync::{Arc, mpsc}; @@ -213,7 +213,12 @@ fn receive_loop( JsonMsg::Ice { sdp_mline_index, candidate, - } => state.webrtc.as_ref().unwrap().notify_ice(sdp_mline_index, candidate), + } => { + let candidate = IceCandidate { + sdp_mline_index, candidate + }; + state.webrtc.as_ref().unwrap().add_ice_candidate(candidate) + } }; } } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index bc8e2c7d..966d13bf 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -3,7 +3,7 @@ use std::str::FromStr; pub trait WebRtcController: Send { fn notify_signal_server_error(&self); fn set_remote_description(&self, SessionDescription); - fn notify_ice(&self, sdp_mline_index: u32, candidate: String); + fn add_ice_candidate(&self, candidate: IceCandidate); fn trigger_negotiation(&self); } @@ -58,3 +58,12 @@ pub struct SessionDescription { pub type_: SdpType, pub sdp: String, } + +/// https://www.w3.org/TR/webrtc/#rtcicecandidate-interface +/// +/// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate +pub struct IceCandidate { + pub sdp_mline_index: u32, + pub candidate: String, + // XXXManishearth this is missing a bunch +} From 6b4902f145e17169272b8e380b8c3b1b9e9842ff Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 14:04:34 -0500 Subject: [PATCH 13/35] Add set_local_description --- backends/gstreamer/src/webrtc.rs | 35 ++++++++++++++++++++++++-------- webrtc/src/lib.rs | 1 + 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 5844dbde..c5f67d85 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -86,11 +86,33 @@ impl WebRtcController for GStreamerWebRtcController { } fn set_remote_description(&self, desc: SessionDescription) { - use gst_webrtc::WebRTCSDPType; if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { return; } + self.set_description(desc, false); + + let mut app_control = self.0.lock().unwrap(); + app_control.app_state = AppState::PeerCallStarted; + } + + fn set_local_description(&self, desc: SessionDescription) { + if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { + return; + } + + self.set_description(desc, true); + } +} + +impl GStreamerWebRtcController { + fn start_pipeline(&self) -> Result<(), Error> { + self.0.lock().unwrap().start_pipeline(self.clone()) + } + + fn set_description(&self, desc: SessionDescription, local: bool) { + use gst_webrtc::WebRTCSDPType; + let ty = match desc.type_ { SdpType::Answer => WebRTCSDPType::Answer, SdpType::Offer => WebRTCSDPType::Offer, @@ -98,6 +120,8 @@ impl WebRtcController for GStreamerWebRtcController { SdpType::Rollback => WebRTCSDPType::Rollback, }; + let kind = if local { "set-local-description" } else { "set-remote-description" }; + let mut app_control = self.0.lock().unwrap(); let ret = gst_sdp::SDPMessage::parse_buffer(desc.sdp.as_bytes()).unwrap(); let answer = @@ -107,15 +131,8 @@ impl WebRtcController for GStreamerWebRtcController { .webrtc .as_ref() .unwrap() - .emit("set-remote-description", &[&answer, &promise]) + .emit(kind, &[&answer, &promise]) .unwrap(); - app_control.app_state = AppState::PeerCallStarted; - } -} - -impl GStreamerWebRtcController { - fn start_pipeline(&self) -> Result<(), Error> { - self.0.lock().unwrap().start_pipeline(self.clone()) } fn assert_app_state_is(&self, state: AppState, error_msg: &'static str) -> bool { diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index 966d13bf..9ec24111 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -3,6 +3,7 @@ use std::str::FromStr; pub trait WebRtcController: Send { fn notify_signal_server_error(&self); fn set_remote_description(&self, SessionDescription); + fn set_local_description(&self, SessionDescription); fn add_ice_candidate(&self, candidate: IceCandidate); fn trigger_negotiation(&self); } From 954d9d81081d2b95a12f1f7593fc72da019788c5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 14:39:38 -0500 Subject: [PATCH 14/35] send_ice_candidate -> on_ice_candidate --- backends/gstreamer/src/webrtc.rs | 9 +++++---- examples/simple_webrtc.rs | 6 +++--- webrtc/src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index c5f67d85..396f023f 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -544,11 +544,12 @@ fn send_ice_candidate_message(app_control: &GStreamerWebRtcController, values: & } let _webrtc = values[0].get::().expect("Invalid argument"); - let mlineindex = values[1].get::().expect("Invalid argument"); + let sdp_mline_index = values[1].get::().expect("Invalid argument"); let candidate = values[2].get::().expect("Invalid argument"); - app_control.0.lock().unwrap().signaller.send_ice_candidate( - mlineindex, + let candidate = IceCandidate { + sdp_mline_index, candidate, - ); + }; + app_control.0.lock().unwrap().signaller.on_ice_candidate(candidate); } diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 54f15bc1..d55ab1a7 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -147,10 +147,10 @@ impl WebRtcSignaller for Signaller { self.0.send(OwnedMessage::Text(message)).unwrap(); } - fn send_ice_candidate(&self, mline_index: u32, candidate: String) { + fn on_ice_candidate(&self, candidate: IceCandidate) { let message = serde_json::to_string(&JsonMsg::Ice { - candidate, - sdp_mline_index: mline_index, + candidate: candidate.candidate, + sdp_mline_index: candidate.sdp_mline_index, }).unwrap(); self.0.send(OwnedMessage::Text(message)).unwrap(); } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index 9ec24111..a3a666fa 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -10,7 +10,7 @@ pub trait WebRtcController: Send { pub trait WebRtcSignaller: Send { fn send_sdp_offer(&self, offer: String); - fn send_ice_candidate(&self, mlineindex: u32, candidate: String); + fn on_ice_candidate(&self, candidate: IceCandidate); fn close(&self, reason: String); } From fac72fa882e680ae11b98a47e4cdae93c865f73b Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 17 Jan 2019 13:15:38 -0500 Subject: [PATCH 15/35] Extract media stream creation from webrtc pipeline creation. --- backends/gstreamer/src/lib.rs | 19 +++- backends/gstreamer/src/media_stream.rs | 112 +++++++++++++++++- backends/gstreamer/src/webrtc.rs | 152 ++++++------------------- servo-media/src/lib.rs | 29 +++-- webrtc/src/lib.rs | 11 +- 5 files changed, 192 insertions(+), 131 deletions(-) diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 72bddd73..a77a2e7b 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -29,7 +29,7 @@ extern crate url; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; use servo_media_player::PlayerBackend; -use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller}; +use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller, MediaStream}; pub mod audio_decoder; pub mod audio_sink; @@ -60,8 +60,13 @@ impl PlayerBackend for GStreamerBackend { impl WebRtcBackend for GStreamerBackend { type Controller = webrtc::GStreamerWebRtcController; - fn start_webrtc_controller(signaller: Box) -> Self::Controller { - webrtc::start(signaller) + + fn start_webrtc_controller( + signaller: Box, + audio: &MediaStream, + video: &MediaStream, + ) -> Self::Controller { + webrtc::start(signaller, audio, video) } } @@ -70,7 +75,11 @@ impl GStreamerBackend { gst::init().unwrap(); } - pub fn create_mediastream() -> media_stream::GStreamerMediaStream { - media_stream::GStreamerMediaStream + pub fn create_audiostream() -> media_stream::GStreamerMediaStream { + media_stream::GStreamerMediaStream::create_audio() + } + + pub fn create_videostream() -> media_stream::GStreamerMediaStream { + media_stream::GStreamerMediaStream::create_video() } } diff --git a/backends/gstreamer/src/media_stream.rs b/backends/gstreamer/src/media_stream.rs index 043c2f8e..2cf51cad 100644 --- a/backends/gstreamer/src/media_stream.rs +++ b/backends/gstreamer/src/media_stream.rs @@ -1 +1,111 @@ -pub struct GStreamerMediaStream; +use glib::ObjectExt; +use gst::{self, BinExtManual, ElementExt, GObjectExtManualGst}; +use servo_media_webrtc::MediaStream; +use std::any::Any; + +lazy_static! { + static ref RTP_CAPS_OPUS: gst::Caps = { + gst::Caps::new_simple( + "application/x-rtp", + &[ + ("media", &"audio"), + ("encoding-name", &"OPUS"), + ("payload", &(97i32)), + ], + ) + }; + static ref RTP_CAPS_VP8: gst::Caps = { + gst::Caps::new_simple( + "application/x-rtp", + &[ + ("media", &"video"), + ("encoding-name", &"VP8"), + ("payload", &(96i32)), + ], + ) + }; +} + +enum StreamType { + Audio, + Video, +} + +pub struct GStreamerMediaStream { + type_: StreamType, + elements: Vec, +} + +impl MediaStream for GStreamerMediaStream { + fn as_any(&self) -> &Any { + self + } +} + +impl GStreamerMediaStream { + pub fn attach_to_pipeline(&self, pipeline: &gst::Pipeline, webrtcbin: &gst::Element) { + let elements: Vec<_> = self.elements.iter().collect(); + pipeline.add_many(&elements[..]).unwrap(); + gst::Element::link_many(&elements[..]).unwrap(); + + let caps = match self.type_ { + StreamType::Audio => &*RTP_CAPS_OPUS, + StreamType::Video => &*RTP_CAPS_VP8, + }; + self.elements.last().as_ref().unwrap().link_filtered(webrtcbin, caps).unwrap(); + } + + pub fn create_video() -> GStreamerMediaStream { + let videotestsrc = gst::ElementFactory::make("videotestsrc", None).unwrap(); + let videoconvert = gst::ElementFactory::make("videoconvert", None).unwrap(); + let queue = gst::ElementFactory::make("queue", None).unwrap(); + let vp8enc = gst::ElementFactory::make("vp8enc", None).unwrap(); + + videotestsrc.set_property_from_str("pattern", "ball"); + videotestsrc.set_property("is-live", &true).unwrap(); + vp8enc.set_property("deadline", &1i64).unwrap(); + + let rtpvp8pay = gst::ElementFactory::make("rtpvp8pay", None).unwrap(); + let queue2 = gst::ElementFactory::make("queue", None).unwrap(); + + GStreamerMediaStream { + type_: StreamType::Video, + elements: vec![ + videotestsrc, + videoconvert, + queue, + vp8enc, + rtpvp8pay, + queue2, + ], + } + } + + pub fn create_audio() -> GStreamerMediaStream { + let audiotestsrc = gst::ElementFactory::make("audiotestsrc", None).unwrap(); + let queue = gst::ElementFactory::make("queue", None).unwrap(); + let audioconvert = gst::ElementFactory::make("audioconvert", None).unwrap(); + let audioresample = gst::ElementFactory::make("audioresample", None).unwrap(); + let queue2 = gst::ElementFactory::make("queue", None).unwrap(); + let opusenc = gst::ElementFactory::make("opusenc", None).unwrap(); + let rtpopuspay = gst::ElementFactory::make("rtpopuspay", None).unwrap(); + let queue3 = gst::ElementFactory::make("queue", None).unwrap(); + + audiotestsrc.set_property_from_str("wave", "red-noise"); + audiotestsrc.set_property("is-live", &true).unwrap(); + + GStreamerMediaStream { + type_: StreamType::Audio, + elements: vec![ + audiotestsrc, + queue, + audioconvert, + audioresample, + queue2, + opusenc, + rtpopuspay, + queue3, + ], + } + } +} diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 396f023f..647321f5 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -3,6 +3,7 @@ use glib::{self, ObjectExt}; use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; use gst_sdp; use gst_webrtc; +use media_stream::GStreamerMediaStream; use servo_media_webrtc::*; use std::sync::{Arc, Mutex}; @@ -12,28 +13,6 @@ use std::sync::{Arc, Mutex}; // - figure out purpose of glib loop const STUN_SERVER: &str = "stun://stun.l.google.com:19302"; -lazy_static! { - static ref RTP_CAPS_OPUS: gst::Caps = { - gst::Caps::new_simple( - "application/x-rtp", - &[ - ("media", &"audio"), - ("encoding-name", &"OPUS"), - ("payload", &(97i32)), - ], - ) - }; - static ref RTP_CAPS_VP8: gst::Caps = { - gst::Caps::new_simple( - "application/x-rtp", - &[ - ("media", &"video"), - ("encoding-name", &"VP8"), - ("payload", &(96i32)), - ], - ) - }; -} #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum MediaType { @@ -106,8 +85,8 @@ impl WebRtcController for GStreamerWebRtcController { } impl GStreamerWebRtcController { - fn start_pipeline(&self) -> Result<(), Error> { - self.0.lock().unwrap().start_pipeline(self.clone()) + fn start_pipeline(&self, audio: &MediaStream, video: &MediaStream) { + self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) } fn set_description(&self, desc: SessionDescription, local: bool) { @@ -199,48 +178,59 @@ struct WebRtcControllerState { } impl WebRtcControllerState { - fn construct_pipeline(&self) -> Result { - let pipeline = self.pipeline.clone(); - + fn construct_pipeline( + pipeline: gst::Pipeline, + audio: &MediaStream, + video: &MediaStream, + ) -> gst::Pipeline { let webrtcbin = gst::ElementFactory::make("webrtcbin", "sendrecv").unwrap(); - pipeline.add(&webrtcbin)?; + pipeline.add(&webrtcbin).unwrap(); webrtcbin.set_property_from_str("stun-server", STUN_SERVER); webrtcbin.set_property_from_str("bundle-policy", "max-bundle"); - add_video_source(&pipeline, &webrtcbin)?; - add_audio_source(&pipeline, &webrtcbin)?; + let audio = audio.as_any().downcast_ref::().unwrap(); + audio.attach_to_pipeline(&pipeline, &webrtcbin); + let video = video.as_any().downcast_ref::().unwrap(); + video.attach_to_pipeline(&pipeline, &webrtcbin); - Ok(pipeline) + pipeline } - fn start_pipeline(&mut self, target: GStreamerWebRtcController) -> Result<(), Error> { - let pipe = self.construct_pipeline()?; + fn start_pipeline( + &mut self, + target: GStreamerWebRtcController, + audio: &MediaStream, + video: &MediaStream + ) { + let pipe = Self::construct_pipeline( + self.pipeline.clone(), + audio, + video, + ); let webrtc = pipe.get_by_name("sendrecv").unwrap(); let app_control_clone = target.clone(); webrtc.connect("on-negotiation-needed", false, move |values| { on_negotiation_needed(&app_control_clone, values).unwrap(); None - })?; + }).unwrap(); let app_control_clone = target.clone(); webrtc.connect("on-ice-candidate", false, move |values| { send_ice_candidate_message(&app_control_clone, values); None - })?; + }).unwrap(); let pipe_clone = pipe.clone(); let app_control_clone = target.clone(); webrtc.connect("pad-added", false, move |values| { on_incoming_stream(&app_control_clone, values, &pipe_clone) - })?; + }).unwrap(); - pipe.set_state(gst::State::Playing).into_result()?; + pipe.set_state(gst::State::Playing).into_result().unwrap(); self.webrtc = Some(webrtc); - - Ok(()) } fn update_state(&mut self, state: AppState) { @@ -248,7 +238,11 @@ impl WebRtcControllerState { } } -pub fn start(signaller: Box) -> GStreamerWebRtcController { +pub fn start( + signaller: Box, + audio: &MediaStream, + video: &MediaStream, +) -> GStreamerWebRtcController { let main_loop = glib::MainLoop::new(None, false); let pipeline = gst::Pipeline::new("main"); //let bus = pipeline.get_bus().unwrap(); @@ -261,7 +255,7 @@ pub fn start(signaller: Box) -> GStreamerWebRtcController { _main_loop: main_loop, }; let controller = GStreamerWebRtcController(Arc::new(Mutex::new(controller))); - controller.start_pipeline().unwrap(); + controller.start_pipeline(audio, video); let controller_clone = controller.clone(); @@ -310,82 +304,6 @@ pub fn start(signaller: Box) -> GStreamerWebRtcController { } }*/ -fn add_video_source(pipeline: &gst::Pipeline, webrtcbin: &gst::Element) -> Result<(), Error> { - let videotestsrc = gst::ElementFactory::make("videotestsrc", None).unwrap(); - let videoconvert = gst::ElementFactory::make("videoconvert", None).unwrap(); - let queue = gst::ElementFactory::make("queue", None).unwrap(); - let vp8enc = gst::ElementFactory::make("vp8enc", None).unwrap(); - - videotestsrc.set_property_from_str("pattern", "ball"); - videotestsrc.set_property("is-live", &true).unwrap(); - vp8enc.set_property("deadline", &1i64).unwrap(); - - let rtpvp8pay = gst::ElementFactory::make("rtpvp8pay", None).unwrap(); - let queue2 = gst::ElementFactory::make("queue", None).unwrap(); - - pipeline.add_many(&[ - &videotestsrc, - &videoconvert, - &queue, - &vp8enc, - &rtpvp8pay, - &queue2, - ])?; - - gst::Element::link_many(&[ - &videotestsrc, - &videoconvert, - &queue, - &vp8enc, - &rtpvp8pay, - &queue2, - ])?; - - queue2.link_filtered(webrtcbin, &*RTP_CAPS_VP8)?; - - Ok(()) -} - -fn add_audio_source(pipeline: &gst::Pipeline, webrtcbin: &gst::Element) -> Result<(), Error> { - let audiotestsrc = gst::ElementFactory::make("audiotestsrc", None).unwrap(); - let queue = gst::ElementFactory::make("queue", None).unwrap(); - let audioconvert = gst::ElementFactory::make("audioconvert", None).unwrap(); - let audioresample = gst::ElementFactory::make("audioresample", None).unwrap(); - let queue2 = gst::ElementFactory::make("queue", None).unwrap(); - let opusenc = gst::ElementFactory::make("opusenc", None).unwrap(); - let rtpopuspay = gst::ElementFactory::make("rtpopuspay", None).unwrap(); - let queue3 = gst::ElementFactory::make("queue", None).unwrap(); - - audiotestsrc.set_property_from_str("wave", "red-noise"); - audiotestsrc.set_property("is-live", &true).unwrap(); - - pipeline.add_many(&[ - &audiotestsrc, - &queue, - &audioconvert, - &audioresample, - &queue2, - &opusenc, - &rtpopuspay, - &queue3, - ])?; - - gst::Element::link_many(&[ - &audiotestsrc, - &queue, - &audioconvert, - &audioresample, - &queue2, - &opusenc, - &rtpopuspay, - &queue3, - ])?; - - queue3.link_filtered(webrtcbin, &*RTP_CAPS_OPUS)?; - - Ok(()) -} - fn send_sdp_offer(app_control: &GStreamerWebRtcController, offer: &gst_webrtc::WebRTCSessionDescription) { if !app_control.assert_app_state_is_at_least( AppState::PeerCallNegotiating, diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 0f1301ea..651cf6d7 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -6,6 +6,7 @@ pub extern crate servo_media_audio as audio; extern crate servo_media_gstreamer; pub extern crate servo_media_player as player; pub extern crate servo_media_webrtc as webrtc; +use std::any::Any; use std::sync::{self, Arc, Mutex, Once}; use audio::context::{AudioContext, AudioContextOptions}; @@ -13,7 +14,7 @@ use audio::decoder::DummyAudioDecoder; use audio::sink::{AudioSinkError, DummyAudioSink}; use audio::AudioBackend; use player::{DummyPlayer, Player, PlayerBackend}; -use webrtc::{WebRtcBackend, WebRtcSignaller}; +use webrtc::{WebRtcBackend, WebRtcSignaller, MediaStream}; pub struct ServoMedia; @@ -21,6 +22,10 @@ static INITIALIZER: Once = sync::ONCE_INIT; static mut INSTANCE: *mut Mutex>> = 0 as *mut _; pub struct DummyMediaStream; +impl MediaStream for DummyMediaStream { + fn as_any(&self) -> &Any { self } +} + pub struct DummyBackend {} impl AudioBackend for DummyBackend { @@ -44,7 +49,11 @@ impl PlayerBackend for DummyBackend { impl DummyBackend { pub fn init() {} - pub fn create_mediastream() -> DummyMediaStream { + pub fn create_audiostream() -> DummyMediaStream { + DummyMediaStream + } + + pub fn create_videostream() -> DummyMediaStream { DummyMediaStream } } @@ -62,8 +71,6 @@ pub type Backend = DummyBackend; pub type WebRtcController = servo_media_gstreamer::webrtc::GStreamerWebRtcController; -pub type MediaStream = servo_media_gstreamer::media_stream::GStreamerMediaStream; - impl ServoMedia { pub fn new() -> Self { Backend::init(); @@ -91,10 +98,18 @@ impl ServoMedia { } pub fn create_webrtc(&self, signaller: Box) -> Box { - Box::new(Backend::start_webrtc_controller(signaller)) + Box::new(Backend::start_webrtc_controller( + signaller, + &*Self::create_audiostream(), + &*Self::create_videostream()), + ) + } + + pub fn create_audiostream() -> Box { + Box::new(Backend::create_audiostream()) } - pub fn create_mediastream(&self) -> Box { - Box::new(Backend::create_mediastream()) + pub fn create_videostream() -> Box { + Box::new(Backend::create_videostream()) } } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index a3a666fa..aa7bc8e5 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -1,5 +1,10 @@ +use std::any::Any; use std::str::FromStr; +pub trait MediaStream: Any { + fn as_any(&self) -> &Any; +} + pub trait WebRtcController: Send { fn notify_signal_server_error(&self); fn set_remote_description(&self, SessionDescription); @@ -17,7 +22,11 @@ pub trait WebRtcSignaller: Send { pub trait WebRtcBackend { type Controller: WebRtcController; - fn start_webrtc_controller(signaller: Box) -> Self::Controller; + fn start_webrtc_controller( + signaller: Box, + audio: &MediaStream, + video: &MediaStream, + ) -> Self::Controller; } /// https://www.w3.org/TR/webrtc/#rtcsdptype From cb8b2a6b53513a9b7eedc3d9c2caebf0a582602e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 15:31:40 -0500 Subject: [PATCH 16/35] fix warning --- backends/gstreamer/src/webrtc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 647321f5..22016667 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -101,7 +101,7 @@ impl GStreamerWebRtcController { let kind = if local { "set-local-description" } else { "set-remote-description" }; - let mut app_control = self.0.lock().unwrap(); + let app_control = self.0.lock().unwrap(); let ret = gst_sdp::SDPMessage::parse_buffer(desc.sdp.as_bytes()).unwrap(); let answer = gst_webrtc::WebRTCSessionDescription::new(ty, ret); From 258eb16dec6e175263725f5f64fef27595e17d08 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 16:07:02 -0500 Subject: [PATCH 17/35] Move offer flow to api user --- Cargo.lock | 4 ++ backends/gstreamer/Cargo.toml | 3 ++ backends/gstreamer/src/lib.rs | 1 + backends/gstreamer/src/webrtc.rs | 88 +++++++++++++++----------------- examples/simple_webrtc.rs | 75 +++++++++++++++++++-------- servo-media/src/lib.rs | 4 +- webrtc/Cargo.toml | 1 + webrtc/src/lib.rs | 19 +++++-- 8 files changed, 123 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8097861c..164ff5d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1704,6 +1704,7 @@ dependencies = [ name = "servo-media-gstreamer" version = "0.1.0" dependencies = [ + "boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1741,6 +1742,9 @@ dependencies = [ [[package]] name = "servo-media-webrtc" version = "0.1.0" +dependencies = [ + "boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "servo_media_android" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 522c6121..2fe4d0e2 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -7,6 +7,9 @@ authors = ["The Servo Project Developers"] regex = "1.0" zip = "0.3.1" +[dependencies] +boxfnonce = "0.1.0" + [dependencies.byte-slice-cast] version = "0.2" diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index a77a2e7b..aa25f571 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -1,3 +1,4 @@ +extern crate boxfnonce; extern crate byte_slice_cast; #[macro_use] diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 22016667..594220df 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -1,8 +1,9 @@ +use boxfnonce::SendBoxFnOnce; use failure::Error; use glib::{self, ObjectExt}; use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; use gst_sdp; -use gst_webrtc; +use gst_webrtc::{self, WebRTCSDPType}; use media_stream::GStreamerMediaStream; use servo_media_webrtc::*; use std::sync::{Arc, Mutex}; @@ -64,24 +65,36 @@ impl WebRtcController for GStreamerWebRtcController { .unwrap(); } - fn set_remote_description(&self, desc: SessionDescription) { + fn set_remote_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { return; } - self.set_description(desc, false); + self.set_description(desc, false, cb); let mut app_control = self.0.lock().unwrap(); app_control.app_state = AppState::PeerCallStarted; } - fn set_local_description(&self, desc: SessionDescription) { + fn set_local_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { return; } - self.set_description(desc, true); + self.set_description(desc, true, cb); } + + fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { + + let app_control_clone = self.clone(); + let this = self.0.lock().unwrap(); + let webrtc = this.webrtc.as_ref().unwrap();; + let promise = gst::Promise::new_with_change_func(move |promise| { + on_offer_created(app_control_clone, promise, cb); + }); + + webrtc.emit("create-offer", &[&None::, &promise]).unwrap(); + } } impl GStreamerWebRtcController { @@ -89,9 +102,7 @@ impl GStreamerWebRtcController { self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) } - fn set_description(&self, desc: SessionDescription, local: bool) { - use gst_webrtc::WebRTCSDPType; - + fn set_description(&self, desc: SessionDescription, local: bool, cb: SendBoxFnOnce<'static, ()>) { let ty = match desc.type_ { SdpType::Answer => WebRTCSDPType::Answer, SdpType::Offer => WebRTCSDPType::Offer, @@ -105,7 +116,9 @@ impl GStreamerWebRtcController { let ret = gst_sdp::SDPMessage::parse_buffer(desc.sdp.as_bytes()).unwrap(); let answer = gst_webrtc::WebRTCSessionDescription::new(ty, ret); - let promise = gst::Promise::new(); + let promise = gst::Promise::new_with_change_func(move |_promise| { + cb.call() + }); app_control .webrtc .as_ref() @@ -211,8 +224,10 @@ impl WebRtcControllerState { let webrtc = pipe.get_by_name("sendrecv").unwrap(); let app_control_clone = target.clone(); - webrtc.connect("on-negotiation-needed", false, move |values| { - on_negotiation_needed(&app_control_clone, values).unwrap(); + webrtc.connect("on-negotiation-needed", false, move |_| { + let mut control = app_control_clone.0.lock().unwrap(); + control.app_state = AppState::PeerCallNegotiating; + control.signaller.on_negotiation_needed(); None }).unwrap(); @@ -304,29 +319,16 @@ pub fn start( } }*/ -fn send_sdp_offer(app_control: &GStreamerWebRtcController, offer: &gst_webrtc::WebRTCSessionDescription) { - if !app_control.assert_app_state_is_at_least( - AppState::PeerCallNegotiating, - "Can't send offer, not in call", - ) { - return; - } - - app_control.0.lock().unwrap().signaller.send_sdp_offer( - offer.get_sdp().as_text().unwrap() - ); -} - fn on_offer_created( - app_control: &GStreamerWebRtcController, - webrtc: &gst::Element, + app_control: GStreamerWebRtcController, promise: &gst::Promise, -) -> Result<(), Error> { + cb: SendBoxFnOnce<'static, (SessionDescription,)>, +) { if !app_control.assert_app_state_is( AppState::PeerCallNegotiating, "Not negotiating call when creating offer", ) { - return Ok(()); + return; } let reply = promise.get_reply().unwrap(); @@ -336,26 +338,20 @@ fn on_offer_created( .unwrap() .get::() .expect("Invalid argument"); - webrtc.emit("set-local-description", &[&offer, &None::])?; - - send_sdp_offer(&app_control, &offer); - - Ok(()) -} -fn on_negotiation_needed(app_control: &GStreamerWebRtcController, values: &[glib::Value]) -> Result<(), Error> { - app_control.0.lock().unwrap().app_state = AppState::PeerCallNegotiating; - - let webrtc = values[0].get::().unwrap(); - let webrtc_clone = webrtc.clone(); - let app_control_clone = app_control.clone(); - let promise = gst::Promise::new_with_change_func(move |promise| { - on_offer_created(&app_control_clone, &webrtc, promise).unwrap(); - }); - - webrtc_clone.emit("create-offer", &[&None::, &promise])?; + let type_ = match offer.get_type() { + WebRTCSDPType::Answer => SdpType::Answer, + WebRTCSDPType::Offer => SdpType::Offer, + WebRTCSDPType::Pranswer => SdpType::Pranswer, + WebRTCSDPType::Rollback => SdpType::Rollback, + _ => panic!("unknown sdp response") + }; - Ok(()) + let desc = SessionDescription { + sdp: offer.get_sdp().as_text().unwrap(), + type_, + }; + cb.call(desc); } fn handle_media_stream( diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index d55ab1a7..88d778c2 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -20,7 +20,7 @@ use servo_media::ServoMedia; use servo_media::webrtc::*; use std::env; use std::net; -use std::sync::{Arc, mpsc}; +use std::sync::{Arc, Mutex, mpsc, Weak}; use std::thread; use websocket::OwnedMessage; @@ -85,7 +85,7 @@ struct State { _uid: u32, peer_id: Option, media: Arc, - webrtc: Option>, + webrtc: Option>, } impl State { @@ -113,8 +113,10 @@ impl State { self.app_state = AppState::PeerConnecting; } if self.peer_id.is_none() { - let signaller = Signaller(self.send_msg_tx.clone()); - self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + let signaller = SignallerWrap::new(self.send_msg_tx.clone()); + let s = signaller.clone(); + self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); + s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); } } @@ -123,39 +125,72 @@ impl State { assert_eq!(self.app_state, AppState::PeerConnecting); self.app_state = AppState::PeerConnected; if self.peer_id.is_some() { - let signaller = Signaller(self.send_msg_tx.clone()); - self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); + let signaller = SignallerWrap::new(self.send_msg_tx.clone()); + let s = signaller.clone(); + self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); + s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); } } } -struct Signaller(mpsc::Sender); +struct Signaller(mpsc::Sender, Option>); -impl WebRtcSignaller for Signaller { +#[derive(Clone)] +struct SignallerWrap(Arc>); + +impl WebRtcSignaller for SignallerWrap { fn close(&self, reason: String) { - let _ = self.0.send(OwnedMessage::Close(Some(websocket::message::CloseData { + let signaller = self.0.lock().unwrap(); + let _ = signaller.0.send(OwnedMessage::Close(Some(websocket::message::CloseData { status_code: 1011, //Internal Error reason: reason, }))); } - fn send_sdp_offer(&self, offer: String) { - let message = serde_json::to_string(&JsonMsg::Sdp { - type_: "offer".to_string(), - sdp: offer, - }).unwrap(); - self.0.send(OwnedMessage::Text(message)).unwrap(); - } - fn on_ice_candidate(&self, candidate: IceCandidate) { + let signaller = self.0.lock().unwrap(); let message = serde_json::to_string(&JsonMsg::Ice { candidate: candidate.candidate, sdp_mline_index: candidate.sdp_mline_index, }).unwrap(); + signaller.0.send(OwnedMessage::Text(message)).unwrap(); + } + + fn on_negotiation_needed(&self) { + let s2 = self.0.clone(); + let signaller = self.0.lock().unwrap(); + let controller = signaller.1.as_ref().unwrap().upgrade().unwrap(); + let c2 = controller.clone(); + thread::spawn(move || { + controller.create_offer((move |offer: SessionDescription| { + thread::spawn(move || { + c2.set_local_description(offer.clone(), (move || { + s2.lock().unwrap().send_sdp(offer); + }).into()); + }); + + }).into()); + }); + } +} + +impl Signaller { + fn send_sdp(&self, desc: SessionDescription) { + let message = serde_json::to_string(&JsonMsg::Sdp { + type_: desc.type_.as_str().into(), + sdp: desc.sdp, + }).unwrap(); self.0.send(OwnedMessage::Text(message)).unwrap(); } } +impl SignallerWrap { + fn new(sender: mpsc::Sender) -> Self { + let signaller = Signaller(sender, None); + SignallerWrap(Arc::new(Mutex::new(signaller))) + } +} + fn receive_loop( mut receiver: websocket::receiver::Reader, send_msg_tx: mpsc::Sender, @@ -208,7 +243,7 @@ fn receive_loop( type_: type_.parse().unwrap(), sdp: sdp.into() }; - state.webrtc.as_ref().unwrap().set_remote_description(desc); + state.webrtc.as_ref().unwrap().set_remote_description(desc, (|| {}).into()); } JsonMsg::Ice { sdp_mline_index, @@ -217,7 +252,7 @@ fn receive_loop( let candidate = IceCandidate { sdp_mline_index, candidate }; - state.webrtc.as_ref().unwrap().add_ice_candidate(candidate) + state.webrtc.as_ref().unwrap().add_ice_candidate(candidate).into() } }; } @@ -236,7 +271,7 @@ fn run_example(servo_media: Arc) { env_logger::init(); let mut args = env::args(); let _ = args.next(); - let server_port = args.next().unwrap().parse::().unwrap(); + let server_port = args.next().expect("Usage: simple_webrtc ").parse::().unwrap(); let server = format!("ws://localhost:{}", server_port); let peer_id = args.next(); diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 651cf6d7..ceec9210 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -97,8 +97,8 @@ impl ServoMedia { Box::new(Backend::make_player()) } - pub fn create_webrtc(&self, signaller: Box) -> Box { - Box::new(Backend::start_webrtc_controller( + pub fn create_webrtc_arc(&self, signaller: Box) -> Arc { + Arc::new(Backend::start_webrtc_controller( signaller, &*Self::create_audiostream(), &*Self::create_videostream()), diff --git a/webrtc/Cargo.toml b/webrtc/Cargo.toml index b32d71bb..b7d344ca 100644 --- a/webrtc/Cargo.toml +++ b/webrtc/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Josh Matthews "] [dependencies] +boxfnonce = "0.1.0" diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index aa7bc8e5..fa8bf360 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -1,21 +1,29 @@ +extern crate boxfnonce; + use std::any::Any; use std::str::FromStr; +use boxfnonce::SendBoxFnOnce; + pub trait MediaStream: Any { fn as_any(&self) -> &Any; } -pub trait WebRtcController: Send { +pub trait WebRtcController: Send + Sync { fn notify_signal_server_error(&self); - fn set_remote_description(&self, SessionDescription); - fn set_local_description(&self, SessionDescription); + /// Invariant: Callback must not reentrantly invoke any methods on the controller + fn set_remote_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); + /// Invariant: Callback must not reentrantly invoke any methods on the controller + fn set_local_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); fn add_ice_candidate(&self, candidate: IceCandidate); + fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); fn trigger_negotiation(&self); } pub trait WebRtcSignaller: Send { - fn send_sdp_offer(&self, offer: String); fn on_ice_candidate(&self, candidate: IceCandidate); + /// Invariant: Must not reentrantly invoke any methods on the controller + fn on_negotiation_needed(&self); fn close(&self, reason: String); } @@ -30,6 +38,7 @@ pub trait WebRtcBackend { } /// https://www.w3.org/TR/webrtc/#rtcsdptype +#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)] pub enum SdpType { Answer, Offer, @@ -64,6 +73,7 @@ impl FromStr for SdpType { /// https://www.w3.org/TR/webrtc/#rtcsessiondescription-class /// /// https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription +#[derive(Clone, Hash, Debug, PartialEq, Eq)] pub struct SessionDescription { pub type_: SdpType, pub sdp: String, @@ -72,6 +82,7 @@ pub struct SessionDescription { /// https://www.w3.org/TR/webrtc/#rtcicecandidate-interface /// /// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate +#[derive(Clone, Hash, Debug, PartialEq, Eq)] pub struct IceCandidate { pub sdp_mline_index: u32, pub candidate: String, From b328045540d5d27fb75f368b8263d58cf3d396aa Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 17 Jan 2019 19:11:04 -0500 Subject: [PATCH 18/35] Support for other side of RTC --- backends/gstreamer/src/webrtc.rs | 43 +++++++++++++++++++++----------- examples/simple_webrtc.rs | 40 ++++++++++++++++++++++++----- webrtc/src/lib.rs | 1 + 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 594220df..46591018 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -77,9 +77,9 @@ impl WebRtcController for GStreamerWebRtcController { } fn set_local_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { - return; - } + // if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { + // return; + // } self.set_description(desc, true, cb); } @@ -90,10 +90,22 @@ impl WebRtcController for GStreamerWebRtcController { let this = self.0.lock().unwrap(); let webrtc = this.webrtc.as_ref().unwrap();; let promise = gst::Promise::new_with_change_func(move |promise| { - on_offer_created(app_control_clone, promise, cb); + on_offer_or_answer_created("offer", app_control_clone, promise, cb); }); webrtc.emit("create-offer", &[&None::, &promise]).unwrap(); + } + + fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { + + let app_control_clone = self.clone(); + let this = self.0.lock().unwrap(); + let webrtc = this.webrtc.as_ref().unwrap();; + let promise = gst::Promise::new_with_change_func(move |promise| { + on_offer_or_answer_created("answer", app_control_clone, promise, cb); + }); + + webrtc.emit("create-answer", &[&None::, &promise]).unwrap(); } } @@ -319,27 +331,30 @@ pub fn start( } }*/ -fn on_offer_created( +fn on_offer_or_answer_created( + ty: &str, app_control: GStreamerWebRtcController, promise: &gst::Promise, cb: SendBoxFnOnce<'static, (SessionDescription,)>, ) { - if !app_control.assert_app_state_is( - AppState::PeerCallNegotiating, - "Not negotiating call when creating offer", - ) { - return; + if ty == "offer" { + if !app_control.assert_app_state_is( + AppState::PeerCallNegotiating, + "Not negotiating call when creating offer/answer", + ) { + return; + } } let reply = promise.get_reply().unwrap(); - let offer = reply - .get_value("offer") + let reply = reply + .get_value(ty) .unwrap() .get::() .expect("Invalid argument"); - let type_ = match offer.get_type() { + let type_ = match reply.get_type() { WebRTCSDPType::Answer => SdpType::Answer, WebRTCSDPType::Offer => SdpType::Offer, WebRTCSDPType::Pranswer => SdpType::Pranswer, @@ -348,7 +363,7 @@ fn on_offer_created( }; let desc = SessionDescription { - sdp: offer.get_sdp().as_text().unwrap(), + sdp: reply.get_sdp().as_text().unwrap(), type_, }; cb.call(desc); diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 88d778c2..0e8ca022 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -86,6 +86,7 @@ struct State { peer_id: Option, media: Arc, webrtc: Option>, + signaller: Option, } impl State { @@ -113,10 +114,11 @@ impl State { self.app_state = AppState::PeerConnecting; } if self.peer_id.is_none() { - let signaller = SignallerWrap::new(self.send_msg_tx.clone()); + let signaller = SignallerWrap::new(self.send_msg_tx.clone(), self.peer_id.is_some()); let s = signaller.clone(); self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); + self.signaller = Some(s); } } @@ -125,15 +127,16 @@ impl State { assert_eq!(self.app_state, AppState::PeerConnecting); self.app_state = AppState::PeerConnected; if self.peer_id.is_some() { - let signaller = SignallerWrap::new(self.send_msg_tx.clone()); + let signaller = SignallerWrap::new(self.send_msg_tx.clone(), self.peer_id.is_some()); let s = signaller.clone(); self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); + self.signaller = Some(s); } } } -struct Signaller(mpsc::Sender, Option>); +struct Signaller(mpsc::Sender, Option>, bool); #[derive(Clone)] struct SignallerWrap(Arc>); @@ -159,6 +162,9 @@ impl WebRtcSignaller for SignallerWrap { fn on_negotiation_needed(&self) { let s2 = self.0.clone(); let signaller = self.0.lock().unwrap(); + if !signaller.2 { + return + } let controller = signaller.1.as_ref().unwrap().upgrade().unwrap(); let c2 = controller.clone(); thread::spawn(move || { @@ -185,8 +191,8 @@ impl Signaller { } impl SignallerWrap { - fn new(sender: mpsc::Sender) -> Self { - let signaller = Signaller(sender, None); + fn new(sender: mpsc::Sender, initiate: bool) -> Self { + let signaller = Signaller(sender, None, initiate); SignallerWrap(Arc::new(Mutex::new(signaller))) } } @@ -243,7 +249,28 @@ fn receive_loop( type_: type_.parse().unwrap(), sdp: sdp.into() }; - state.webrtc.as_ref().unwrap().set_remote_description(desc, (|| {}).into()); + let controller = state.webrtc.as_ref().unwrap(); + if state.peer_id.is_some() { + controller.set_remote_description(desc, (|| {}).into()); + } else { + let c2 = controller.clone(); + let c3 = controller.clone(); + let s2 = state.signaller.clone().unwrap().0; + controller.set_remote_description(desc, (move || { + thread::spawn(move || { + c3.create_answer((move |answer: SessionDescription| { + thread::spawn(move || { + c2.set_local_description(answer.clone(), (move || { + s2.lock().unwrap().send_sdp(answer); + }).into()); + }); + + }).into()); + }); + }).into()); + } + + } JsonMsg::Ice { sdp_mline_index, @@ -302,6 +329,7 @@ fn run_example(servo_media: Arc) { peer_id: peer_id, media: servo_media, webrtc: None, + signaller: None, }; let receive_loop = receive_loop(receiver, send_msg_tx, state); diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index fa8bf360..e2e5aa62 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -17,6 +17,7 @@ pub trait WebRtcController: Send + Sync { fn set_local_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); fn add_ice_candidate(&self, candidate: IceCandidate); fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); + fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); fn trigger_negotiation(&self); } From f2db09d51c2292db2aabbb104ba55f5f91dba958 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 18 Jan 2019 10:36:48 -0500 Subject: [PATCH 19/35] Fix race condition --- backends/gstreamer/src/lib.rs | 8 ++--- backends/gstreamer/src/webrtc.rs | 59 +++----------------------------- examples/simple_webrtc.rs | 2 ++ servo-media/src/lib.rs | 6 +--- webrtc/src/lib.rs | 7 ++-- 5 files changed, 15 insertions(+), 67 deletions(-) diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index aa25f571..91199593 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -30,7 +30,7 @@ extern crate url; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; use servo_media_player::PlayerBackend; -use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller, MediaStream}; +use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller}; pub mod audio_decoder; pub mod audio_sink; @@ -62,12 +62,10 @@ impl PlayerBackend for GStreamerBackend { impl WebRtcBackend for GStreamerBackend { type Controller = webrtc::GStreamerWebRtcController; - fn start_webrtc_controller( + fn construct_webrtc_controller( signaller: Box, - audio: &MediaStream, - video: &MediaStream, ) -> Self::Controller { - webrtc::start(signaller, audio, video) + webrtc::construct(signaller) } } diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 46591018..28c7c3eb 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -41,6 +41,9 @@ enum AppState { pub struct GStreamerWebRtcController(Arc>); impl WebRtcController for GStreamerWebRtcController { + fn init(&self, audio: &MediaStream, video: &MediaStream) { + self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) + } fn trigger_negotiation(&self) { let app_control = self.0.lock().unwrap(); app_control @@ -110,9 +113,6 @@ impl WebRtcController for GStreamerWebRtcController { } impl GStreamerWebRtcController { - fn start_pipeline(&self, audio: &MediaStream, video: &MediaStream) { - self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) - } fn set_description(&self, desc: SessionDescription, local: bool, cb: SendBoxFnOnce<'static, ()>) { let ty = match desc.type_ { @@ -265,10 +265,8 @@ impl WebRtcControllerState { } } -pub fn start( +pub fn construct( signaller: Box, - audio: &MediaStream, - video: &MediaStream, ) -> GStreamerWebRtcController { let main_loop = glib::MainLoop::new(None, false); let pipeline = gst::Pipeline::new("main"); @@ -281,56 +279,9 @@ pub fn start( app_state: AppState::ServerConnected, _main_loop: main_loop, }; - let controller = GStreamerWebRtcController(Arc::new(Mutex::new(controller))); - controller.start_pipeline(audio, video); - - let controller_clone = controller.clone(); - - /*bus.add_watch(move |_, msg| { - use gst::message::MessageView; - - match msg.view() { - MessageView::Error(err) => controller.close_and_quit(&Error::from(err.get_error())), - MessageView::Warning(warning) => { - println!("Warning: \"{}\"", warning.get_debug().unwrap()); - } - MessageView::Application(a) => { - let struc = a.get_structure().unwrap(); - if let Err(err) = handle_application_msg(&controller, struc) { - controller.close_and_quit(&err) - } - } - _ => {} - }; - - glib::Continue(true) - });*/ - - controller_clone + GStreamerWebRtcController(Arc::new(Mutex::new(controller))) } -/*fn handle_application_msg( - app_control: &GStreamerWebRtcController, - struc: &gst::StructureRef, -) -> Result<(), Error> { - match struc.get_name() { - "ws-message" => { - let msg = struc.get_value("body").unwrap(); - app_control.on_message(msg.get().unwrap()) - } - "ws-error" => Err(WsError(app_control.0.lock().unwrap().app_state))?, - "error" => { - let msg: String = struc.get_value("body").unwrap().get().unwrap(); - Err(BusError(msg))? - } - u => { - println!("Got unknown application message {:?}", u); - - Ok(()) - } - } -}*/ - fn on_offer_or_answer_created( ty: &str, app_control: GStreamerWebRtcController, diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 0e8ca022..45d48a79 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -119,6 +119,7 @@ impl State { self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); self.signaller = Some(s); + self.webrtc.as_ref().unwrap().init(&*ServoMedia::create_audiostream(), &*ServoMedia::create_videostream()); } } @@ -132,6 +133,7 @@ impl State { self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); self.signaller = Some(s); + self.webrtc.as_ref().unwrap().init(&*ServoMedia::create_audiostream(), &*ServoMedia::create_videostream()); } } } diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index ceec9210..52c51560 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -98,11 +98,7 @@ impl ServoMedia { } pub fn create_webrtc_arc(&self, signaller: Box) -> Arc { - Arc::new(Backend::start_webrtc_controller( - signaller, - &*Self::create_audiostream(), - &*Self::create_videostream()), - ) + Arc::new(Backend::construct_webrtc_controller(signaller)) } pub fn create_audiostream() -> Box { diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index e2e5aa62..e1d799e3 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -10,6 +10,9 @@ pub trait MediaStream: Any { } pub trait WebRtcController: Send + Sync { + // currently simple_webrtc needs to be able to hook up the signaller after construction + // but before initialization. We split out init() to avoid a race. + fn init(&self, audio: &MediaStream, video: &MediaStream); fn notify_signal_server_error(&self); /// Invariant: Callback must not reentrantly invoke any methods on the controller fn set_remote_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); @@ -31,10 +34,8 @@ pub trait WebRtcSignaller: Send { pub trait WebRtcBackend { type Controller: WebRtcController; - fn start_webrtc_controller( + fn construct_webrtc_controller( signaller: Box, - audio: &MediaStream, - video: &MediaStream, ) -> Self::Controller; } From 429d8bca583995a3a57b9d44560be001801b5c2a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 18 Jan 2019 11:03:12 -0500 Subject: [PATCH 20/35] Clean up app state assertions --- backends/gstreamer/src/webrtc.rs | 46 +++++++++----------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 28c7c3eb..a10dd521 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -40,6 +40,14 @@ enum AppState { #[derive(Clone)] pub struct GStreamerWebRtcController(Arc>); +macro_rules! assert_state { + ($controller:ident, $state:ident, $condition:expr, $string:expr) => { + { + let $state = $controller.0.lock().unwrap().app_state; + assert!($condition, $string); + } + } +} impl WebRtcController for GStreamerWebRtcController { fn init(&self, audio: &MediaStream, video: &MediaStream) { self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) @@ -69,9 +77,7 @@ impl WebRtcController for GStreamerWebRtcController { } fn set_remote_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { - return; - } + assert_state!(self, state, state == AppState::PeerCallNegotiating, "Not ready to handle sdp"); self.set_description(desc, false, cb); @@ -139,26 +145,6 @@ impl GStreamerWebRtcController { .unwrap(); } - fn assert_app_state_is(&self, state: AppState, error_msg: &'static str) -> bool { - if self.0.lock().unwrap().app_state != state { - self.send_bus_error(error_msg); - - false - } else { - true - } - } - - fn assert_app_state_is_at_least(&self, state: AppState, error_msg: &'static str) -> bool { - if self.0.lock().unwrap().app_state < state { - self.send_bus_error(error_msg); - - false - } else { - true - } - } - //#[allow(unused)] fn send_bus_error(&self, body: &str) { eprintln!("Bus error: {}", body); @@ -289,12 +275,8 @@ fn on_offer_or_answer_created( cb: SendBoxFnOnce<'static, (SessionDescription,)>, ) { if ty == "offer" { - if !app_control.assert_app_state_is( - AppState::PeerCallNegotiating, - "Not negotiating call when creating offer/answer", - ) { - return; - } + assert_state!(app_control, state, state == AppState::PeerCallNegotiating, + "Not negotiating call when creating offer/answer") } let reply = promise.get_reply().unwrap(); @@ -417,11 +399,7 @@ fn on_incoming_stream( } fn send_ice_candidate_message(app_control: &GStreamerWebRtcController, values: &[glib::Value]) { - if !app_control - .assert_app_state_is_at_least(AppState::PeerCallNegotiating, "Can't send ICE, not in call") - { - return; - } + assert_state!(app_control, state, state >= AppState::PeerCallNegotiating, "Can't send ICE, not in call"); let _webrtc = values[0].get::().expect("Invalid argument"); let sdp_mline_index = values[1].get::().expect("Invalid argument"); From 92ba45927bcbe80c741912927651ce8b2401f707 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 18 Jan 2019 11:07:30 -0500 Subject: [PATCH 21/35] Fix assertions --- backends/gstreamer/src/webrtc.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index a10dd521..7ed2f6b3 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -33,6 +33,8 @@ enum AppState { PeerConnectionError, PeerConnected, PeerCallNegotiating = 4000, + PeerCallNegotiatingHaveLocal, + PeerCallNegotiatingHaveRemote, PeerCallStarted, PeerCallError, } @@ -48,6 +50,7 @@ macro_rules! assert_state { } } } + impl WebRtcController for GStreamerWebRtcController { fn init(&self, audio: &MediaStream, video: &MediaStream) { self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) @@ -77,20 +80,33 @@ impl WebRtcController for GStreamerWebRtcController { } fn set_remote_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - assert_state!(self, state, state == AppState::PeerCallNegotiating, "Not ready to handle sdp"); + assert_state!(self, state, + state == AppState::PeerCallNegotiating || state == AppState::PeerCallNegotiatingHaveLocal, + "Not ready to handle sdp"); self.set_description(desc, false, cb); let mut app_control = self.0.lock().unwrap(); - app_control.app_state = AppState::PeerCallStarted; + if app_control.app_state == AppState::PeerCallNegotiating { + app_control.app_state = AppState::PeerCallNegotiatingHaveRemote; + } else { + app_control.app_state = AppState::PeerCallStarted; + } } fn set_local_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - // if !self.assert_app_state_is(AppState::PeerCallNegotiating, "Not ready to handle sdp") { - // return; - // } + assert_state!(self, state, + state == AppState::PeerCallNegotiating || state == AppState::PeerCallNegotiatingHaveRemote, + "Not ready to handle sdp"); self.set_description(desc, true, cb); + + let mut app_control = self.0.lock().unwrap(); + if app_control.app_state == AppState::PeerCallNegotiating { + app_control.app_state = AppState::PeerCallNegotiatingHaveLocal; + } else { + app_control.app_state = AppState::PeerCallStarted; + } } fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { @@ -276,7 +292,10 @@ fn on_offer_or_answer_created( ) { if ty == "offer" { assert_state!(app_control, state, state == AppState::PeerCallNegotiating, - "Not negotiating call when creating offer/answer") + "Not negotiating call when creating offer") + } else { + assert_state!(app_control, state, state == AppState::PeerCallNegotiatingHaveRemote, + "No offfer received when creating answer") } let reply = promise.get_reply().unwrap(); From 20461fd9d0cff16c7029b4c063d17b2f64f0a97d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 18 Jan 2019 11:23:43 -0500 Subject: [PATCH 22/35] cleanups --- backends/gstreamer/src/webrtc.rs | 11 +++--- examples/simple_webrtc.rs | 57 ++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 7ed2f6b3..6ab063d7 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -115,7 +115,7 @@ impl WebRtcController for GStreamerWebRtcController { let this = self.0.lock().unwrap(); let webrtc = this.webrtc.as_ref().unwrap();; let promise = gst::Promise::new_with_change_func(move |promise| { - on_offer_or_answer_created("offer", app_control_clone, promise, cb); + on_offer_or_answer_created(SdpType::Offer, app_control_clone, promise, cb); }); webrtc.emit("create-offer", &[&None::, &promise]).unwrap(); @@ -127,7 +127,7 @@ impl WebRtcController for GStreamerWebRtcController { let this = self.0.lock().unwrap(); let webrtc = this.webrtc.as_ref().unwrap();; let promise = gst::Promise::new_with_change_func(move |promise| { - on_offer_or_answer_created("answer", app_control_clone, promise, cb); + on_offer_or_answer_created(SdpType::Answer, app_control_clone, promise, cb); }); webrtc.emit("create-answer", &[&None::, &promise]).unwrap(); @@ -285,12 +285,13 @@ pub fn construct( } fn on_offer_or_answer_created( - ty: &str, + ty: SdpType, app_control: GStreamerWebRtcController, promise: &gst::Promise, cb: SendBoxFnOnce<'static, (SessionDescription,)>, ) { - if ty == "offer" { + debug_assert!(ty == SdpType::Offer || ty == SdpType::Answer); + if ty == SdpType::Offer { assert_state!(app_control, state, state == AppState::PeerCallNegotiating, "Not negotiating call when creating offer") } else { @@ -301,7 +302,7 @@ fn on_offer_or_answer_created( let reply = promise.get_reply().unwrap(); let reply = reply - .get_value(ty) + .get_value(ty.as_str()) .unwrap() .get::() .expect("Invalid argument"); diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 45d48a79..2e8470b2 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -109,36 +109,40 @@ impl State { fn handle_hello(&mut self) { assert_eq!(self.app_state, AppState::ServerRegistering); self.app_state = AppState::ServerRegistered; + // if we know who we want to connect to, request a connection if let Some(ref peer_id) = self.peer_id { self.send_msg_tx.send(OwnedMessage::Text(format!("SESSION {}", peer_id))).unwrap(); self.app_state = AppState::PeerConnecting; - } - if self.peer_id.is_none() { - let signaller = SignallerWrap::new(self.send_msg_tx.clone(), self.peer_id.is_some()); - let s = signaller.clone(); - self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); - s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); - self.signaller = Some(s); - self.webrtc.as_ref().unwrap().init(&*ServoMedia::create_audiostream(), &*ServoMedia::create_videostream()); + } else { + // else just spin up the RTC object and wait + self.start_rtc(); } } fn handle_session_ok(&mut self) { + assert!(self.peer_id.is_some(), + "SESSION OK should only be received by those attempting to connect to an existing peer"); println!("session is ok; creating webrtc objects"); assert_eq!(self.app_state, AppState::PeerConnecting); self.app_state = AppState::PeerConnected; - if self.peer_id.is_some() { - let signaller = SignallerWrap::new(self.send_msg_tx.clone(), self.peer_id.is_some()); - let s = signaller.clone(); - self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); - s.0.lock().unwrap().1 = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); - self.signaller = Some(s); - self.webrtc.as_ref().unwrap().init(&*ServoMedia::create_audiostream(), &*ServoMedia::create_videostream()); - } + self.start_rtc(); + } + + fn start_rtc(&mut self) { + let signaller = SignallerWrap::new(self.send_msg_tx.clone(), self.peer_id.is_some()); + let s = signaller.clone(); + self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); + s.0.lock().unwrap().controller = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); + self.signaller = Some(s); + self.webrtc.as_ref().unwrap().init(&*ServoMedia::create_audiostream(), &*ServoMedia::create_videostream()); } } -struct Signaller(mpsc::Sender, Option>, bool); +struct Signaller { + sender: mpsc::Sender, + controller: Option>, + initiate_negotiation: bool +} #[derive(Clone)] struct SignallerWrap(Arc>); @@ -146,7 +150,7 @@ struct SignallerWrap(Arc>); impl WebRtcSignaller for SignallerWrap { fn close(&self, reason: String) { let signaller = self.0.lock().unwrap(); - let _ = signaller.0.send(OwnedMessage::Close(Some(websocket::message::CloseData { + let _ = signaller.sender.send(OwnedMessage::Close(Some(websocket::message::CloseData { status_code: 1011, //Internal Error reason: reason, }))); @@ -158,16 +162,16 @@ impl WebRtcSignaller for SignallerWrap { candidate: candidate.candidate, sdp_mline_index: candidate.sdp_mline_index, }).unwrap(); - signaller.0.send(OwnedMessage::Text(message)).unwrap(); + signaller.sender.send(OwnedMessage::Text(message)).unwrap(); } fn on_negotiation_needed(&self) { let s2 = self.0.clone(); let signaller = self.0.lock().unwrap(); - if !signaller.2 { + if !signaller.initiate_negotiation { return } - let controller = signaller.1.as_ref().unwrap().upgrade().unwrap(); + let controller = signaller.controller.as_ref().unwrap().upgrade().unwrap(); let c2 = controller.clone(); thread::spawn(move || { controller.create_offer((move |offer: SessionDescription| { @@ -188,13 +192,17 @@ impl Signaller { type_: desc.type_.as_str().into(), sdp: desc.sdp, }).unwrap(); - self.0.send(OwnedMessage::Text(message)).unwrap(); + self.sender.send(OwnedMessage::Text(message)).unwrap(); } } impl SignallerWrap { - fn new(sender: mpsc::Sender, initiate: bool) -> Self { - let signaller = Signaller(sender, None, initiate); + fn new(sender: mpsc::Sender, initiate_negotiation: bool) -> Self { + let signaller = Signaller { + sender, + controller: None, + initiate_negotiation + }; SignallerWrap(Arc::new(Mutex::new(signaller))) } } @@ -232,6 +240,7 @@ fn receive_loop( } OwnedMessage::Text(msg) => { + println!("{:?}", msg); match &*msg { "HELLO" => state.handle_hello(), From dbf4c39b174077686f3e63f7244ed6c0ca44d452 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 17 Jan 2019 19:05:39 -0500 Subject: [PATCH 23/35] Separate creation and integration of media streams from rest of WebRTC pipeline. --- backends/gstreamer/src/media_stream.rs | 2 + backends/gstreamer/src/webrtc.rs | 121 +++++++++++++------------ examples/simple_webrtc.rs | 11 ++- servo-media/src/lib.rs | 4 +- webrtc/src/lib.rs | 23 ++++- 5 files changed, 92 insertions(+), 69 deletions(-) diff --git a/backends/gstreamer/src/media_stream.rs b/backends/gstreamer/src/media_stream.rs index 2cf51cad..07dc2793 100644 --- a/backends/gstreamer/src/media_stream.rs +++ b/backends/gstreamer/src/media_stream.rs @@ -26,6 +26,7 @@ lazy_static! { }; } +#[derive(Debug)] enum StreamType { Audio, Video, @@ -52,6 +53,7 @@ impl GStreamerMediaStream { StreamType::Audio => &*RTP_CAPS_OPUS, StreamType::Video => &*RTP_CAPS_VP8, }; + println!("atttaching a {:?} stream", self.type_); self.elements.last().as_ref().unwrap().link_filtered(webrtcbin, caps).unwrap(); } diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 6ab063d7..2bf801b3 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -1,7 +1,7 @@ use boxfnonce::SendBoxFnOnce; use failure::Error; use glib::{self, ObjectExt}; -use gst::{self, ElementExt, BinExt, PadExt, BinExtManual, GObjectExtManualGst}; +use gst::{self, ElementExt, BinExt, BinExtManual, GObjectExtManualGst, PadDirection, PadExt}; use gst_sdp; use gst_webrtc::{self, WebRTCSDPType}; use media_stream::GStreamerMediaStream; @@ -9,12 +9,9 @@ use servo_media_webrtc::*; use std::sync::{Arc, Mutex}; // TODO: -// - configurable STUN server? // - remove use of failure? // - figure out purpose of glib loop -const STUN_SERVER: &str = "stun://stun.l.google.com:19302"; - #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum MediaType { Audio, @@ -52,21 +49,8 @@ macro_rules! assert_state { } impl WebRtcController for GStreamerWebRtcController { - fn init(&self, audio: &MediaStream, video: &MediaStream) { - self.0.lock().unwrap().start_pipeline(self.clone(), audio, video) - } - fn trigger_negotiation(&self) { - let app_control = self.0.lock().unwrap(); - app_control - .webrtc - .as_ref() - .unwrap() - .emit("on-negotiation-needed", &[]) - .unwrap(); - } - - fn notify_signal_server_error(&self) { - //TODO + fn init(&self) { + self.0.lock().unwrap().start_pipeline(self.clone()) } fn add_ice_candidate(&self, candidate: IceCandidate) { @@ -122,7 +106,6 @@ impl WebRtcController for GStreamerWebRtcController { } fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { - let app_control_clone = self.clone(); let this = self.0.lock().unwrap(); let webrtc = this.webrtc.as_ref().unwrap();; @@ -132,9 +115,39 @@ impl WebRtcController for GStreamerWebRtcController { webrtc.emit("create-answer", &[&None::, &promise]).unwrap(); } + + fn add_stream(&self, stream: &MediaStream) { + println!("adding a stream"); + let (pipeline, webrtc) = { + let mut controller = self.0.lock().unwrap(); + (controller.pipeline.clone(), controller.webrtc.clone().unwrap()) + }; + let stream = stream.as_any().downcast_ref::().unwrap(); + stream.attach_to_pipeline(&pipeline, &webrtc); + self.0.lock().unwrap().prepare_for_negotiation(self.clone()); + } + + fn configure(&self, stun_server: &str, policy: BundlePolicy) { + let data = self.0.lock().unwrap(); + let webrtc = data.webrtc.as_ref().unwrap(); + webrtc.set_property_from_str("stun-server", stun_server); + webrtc.set_property_from_str("bundle-policy", policy.as_str()); + } } impl GStreamerWebRtcController { + fn process_new_stream( + &self, + values: &[glib::Value], + pipe: &gst::Pipeline, + ) -> Option { + let pad = values[1].get::().expect("not a pad??"); + if pad.get_direction() != PadDirection::Src { + // Ignore outgoing pad notifications. + return None; + } + on_incoming_stream(self, values, pipe) + } fn set_description(&self, desc: SessionDescription, local: bool, cb: SendBoxFnOnce<'static, ()>) { let ty = match desc.type_ { @@ -198,6 +211,7 @@ struct WebRtcControllerState { app_state: AppState, pipeline: gst::Pipeline, signaller: Box, + ready_to_negotiate: bool, //send_msg_tx: mpsc::Sender, //peer_id: String, _main_loop: glib::MainLoop, @@ -205,60 +219,46 @@ struct WebRtcControllerState { } impl WebRtcControllerState { - fn construct_pipeline( - pipeline: gst::Pipeline, - audio: &MediaStream, - video: &MediaStream, - ) -> gst::Pipeline { - let webrtcbin = gst::ElementFactory::make("webrtcbin", "sendrecv").unwrap(); - pipeline.add(&webrtcbin).unwrap(); - - webrtcbin.set_property_from_str("stun-server", STUN_SERVER); - webrtcbin.set_property_from_str("bundle-policy", "max-bundle"); - - let audio = audio.as_any().downcast_ref::().unwrap(); - audio.attach_to_pipeline(&pipeline, &webrtcbin); - let video = video.as_any().downcast_ref::().unwrap(); - video.attach_to_pipeline(&pipeline, &webrtcbin); - - pipeline - } - - fn start_pipeline( - &mut self, - target: GStreamerWebRtcController, - audio: &MediaStream, - video: &MediaStream - ) { - let pipe = Self::construct_pipeline( - self.pipeline.clone(), - audio, - video, - ); - let webrtc = pipe.get_by_name("sendrecv").unwrap(); - - let app_control_clone = target.clone(); - webrtc.connect("on-negotiation-needed", false, move |_| { - let mut control = app_control_clone.0.lock().unwrap(); + fn prepare_for_negotiation(&mut self, target: GStreamerWebRtcController) { + if self.ready_to_negotiate { + return; + } + self.ready_to_negotiate = true; + let webrtc = self.webrtc.as_ref().unwrap(); + // If the pipeline starts playing and this signal is present before there are any + // media streams, an invalid SDP offer will be created. Therefore, delay setting up + // the signal and starting the pipeline until after the first stream has been added. + webrtc.connect("on-negotiation-needed", false, move |_values| { + println!("on-negotiation-needed"); + let mut control = target.0.lock().unwrap(); control.app_state = AppState::PeerCallNegotiating; control.signaller.on_negotiation_needed(); None }).unwrap(); + self.pipeline.set_state(gst::State::Playing).into_result().unwrap(); + } + + fn start_pipeline(&mut self, target: GStreamerWebRtcController) { + let webrtc = gst::ElementFactory::make("webrtcbin", "sendrecv").unwrap(); + self.pipeline.add(&webrtc).unwrap(); let app_control_clone = target.clone(); webrtc.connect("on-ice-candidate", false, move |values| { + println!("on-ice-candidate"); send_ice_candidate_message(&app_control_clone, values); None }).unwrap(); - let pipe_clone = pipe.clone(); + let pipe_clone = self.pipeline.clone(); let app_control_clone = target.clone(); webrtc.connect("pad-added", false, move |values| { - on_incoming_stream(&app_control_clone, values, &pipe_clone) + println!("pad-added"); + app_control_clone.process_new_stream( + values, + &pipe_clone, + ) }).unwrap(); - pipe.set_state(gst::State::Playing).into_result().unwrap(); - self.webrtc = Some(webrtc); } @@ -272,13 +272,13 @@ pub fn construct( ) -> GStreamerWebRtcController { let main_loop = glib::MainLoop::new(None, false); let pipeline = gst::Pipeline::new("main"); - //let bus = pipeline.get_bus().unwrap(); let controller = WebRtcControllerState { webrtc: None, pipeline, signaller, app_state: AppState::ServerConnected, + ready_to_negotiate: false, _main_loop: main_loop, }; GStreamerWebRtcController(Arc::new(Mutex::new(controller))) @@ -406,6 +406,7 @@ fn on_incoming_stream( let app_control_clone = app_control.clone(); decodebin .connect("pad-added", false, move |values| { + println!("decodebin pad-added"); on_incoming_decodebin_stream(&app_control_clone, values, &pipe_clone) }) .unwrap(); diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 2e8470b2..3aacd1a9 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -24,6 +24,8 @@ use std::sync::{Arc, Mutex, mpsc, Weak}; use std::thread; use websocket::OwnedMessage; +const STUN_SERVER: &str = "stun://stun.l.google.com:19302"; + #[derive(PartialEq, PartialOrd, Eq, Debug, Copy, Clone, Ord)] #[allow(unused)] enum AppState { @@ -134,7 +136,11 @@ impl State { self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); s.0.lock().unwrap().controller = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); self.signaller = Some(s); - self.webrtc.as_ref().unwrap().init(&*ServoMedia::create_audiostream(), &*ServoMedia::create_videostream()); + let webrtc = self.webrtc.as_ref().unwrap(); + webrtc.init(); + webrtc.add_stream(&*self.media.create_videostream()); + webrtc.add_stream(&*self.media.create_audiostream()); + webrtc.configure(STUN_SERVER, BundlePolicy::MaxBundle); } } @@ -218,9 +224,6 @@ fn receive_loop( Ok(m) => m, Err(e) => { println!("Receive Loop error: {:?}", e); - if let Some(ref mut controller) = state.webrtc { - controller.notify_signal_server_error(); - } let _ = send_msg_tx.send(OwnedMessage::Close(None)); return; } diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 52c51560..57cd6afe 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -101,11 +101,11 @@ impl ServoMedia { Arc::new(Backend::construct_webrtc_controller(signaller)) } - pub fn create_audiostream() -> Box { + pub fn create_audiostream(&self) -> Box { Box::new(Backend::create_audiostream()) } - pub fn create_videostream() -> Box { + pub fn create_videostream(&self) -> Box { Box::new(Backend::create_videostream()) } } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index e1d799e3..aeeaf5a4 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -12,8 +12,8 @@ pub trait MediaStream: Any { pub trait WebRtcController: Send + Sync { // currently simple_webrtc needs to be able to hook up the signaller after construction // but before initialization. We split out init() to avoid a race. - fn init(&self, audio: &MediaStream, video: &MediaStream); - fn notify_signal_server_error(&self); + fn init(&self); + fn configure(&self, stun_server: &str, policy: BundlePolicy); /// Invariant: Callback must not reentrantly invoke any methods on the controller fn set_remote_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); /// Invariant: Callback must not reentrantly invoke any methods on the controller @@ -21,7 +21,7 @@ pub trait WebRtcController: Send + Sync { fn add_ice_candidate(&self, candidate: IceCandidate); fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); - fn trigger_negotiation(&self); + fn add_stream(&self, stream: &MediaStream); } pub trait WebRtcSignaller: Send { @@ -90,3 +90,20 @@ pub struct IceCandidate { pub candidate: String, // XXXManishearth this is missing a bunch } + +/// https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection#RTCBundlePolicy_enum +pub enum BundlePolicy { + Balanced, + MaxCompat, + MaxBundle, +} + +impl BundlePolicy { + pub fn as_str(self) -> &'static str { + match self { + BundlePolicy::Balanced => "balanced", + BundlePolicy::MaxCompat => "max-compat", + BundlePolicy::MaxBundle => "max-bundle", + } + } +} From 43e72795a2682f4eedd85b8bdee3ca35d6a84d94 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 18 Jan 2019 17:04:59 -0500 Subject: [PATCH 24/35] Support creating media streams from media capture sources. --- backends/gstreamer/src/lib.rs | 9 ++ backends/gstreamer/src/media_capture.rs | 158 ++++++++++++++++++++++++ backends/gstreamer/src/media_stream.rs | 30 +++-- examples/simple_webrtc.rs | 16 ++- servo-media/src/lib.rs | 16 +++ webrtc/src/lib.rs | 2 +- 6 files changed, 218 insertions(+), 13 deletions(-) create mode 100644 backends/gstreamer/src/media_capture.rs diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 91199593..1c0d3b7e 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -34,6 +34,7 @@ use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller}; pub mod audio_decoder; pub mod audio_sink; +pub mod media_capture; pub mod media_stream; pub mod player; mod source; @@ -81,4 +82,12 @@ impl GStreamerBackend { pub fn create_videostream() -> media_stream::GStreamerMediaStream { media_stream::GStreamerMediaStream::create_video() } + + pub fn create_audioinput_stream() -> Option { + media_capture::create_audioinput_stream() + } + + pub fn create_videoinput_stream() -> Option { + media_capture::create_videoinput_stream() + } } diff --git a/backends/gstreamer/src/media_capture.rs b/backends/gstreamer/src/media_capture.rs new file mode 100644 index 00000000..859e15e2 --- /dev/null +++ b/backends/gstreamer/src/media_capture.rs @@ -0,0 +1,158 @@ +use crate::media_stream::{GStreamerMediaStream, StreamType}; +use gst::{DeviceMonitor, DeviceMonitorExt, DeviceExt}; +use gst::{Fraction, FractionRange, List, IntRange}; +use gst::caps::{Builder, Caps}; +use std::i32; + +pub enum Constrain { + Value(T), + Range(ConstrainRange) +} + +impl Constrain { + fn add_to_caps(self, name: &str, min: u64, max: u64, builder: Builder) -> Option { + match self { + Constrain::Value(v) => Some(builder.field(name, &(v as i64 as i32))), + Constrain::Range(r) => { + let min = into_i32(r.min.unwrap_or(min)); + let max = into_i32(r.max.unwrap_or(max)); + let range = IntRange::::new(min, max); + if let Some(ideal) = r.ideal { + let ideal = into_i32(ideal); + let array = List::new(&[&ideal, &range]); + Some(builder.field(name, &array)) + } else { + Some(builder.field(name, &range)) + } + } + } + } +} + +fn into_i32(x: u64) -> i32 { + if x > i32::MAX as u64 { + i32::MAX + } else { + x as i64 as i32 + } +} + +impl Constrain { + fn add_to_caps(self, name: &str, min: i32, max: i32, builder: Builder) -> Option { + match self { + Constrain::Value(v) => Some(builder.field("name", &Fraction::approximate_f64(v)?)), + Constrain::Range(r) => { + let min = r.min.and_then(|v| Fraction::approximate_f64(v)).unwrap_or(Fraction::new(min, 1)); + let max = r.max.and_then(|v| Fraction::approximate_f64(v)).unwrap_or(Fraction::new(max, 1)); + let range = FractionRange::new(min, max); + if let Some(ideal) = r.ideal.and_then(|v| Fraction::approximate_f64(v)) { + let array = gst::List::new(&[&ideal, &range]); + Some(builder.field(name, &array)) + } else { + Some(builder.field(name, &range)) + } + } + } + } +} + +pub struct ConstrainRange { + min: Option, + max: Option, + ideal: Option, +} + +pub enum ConstrainBool { + Ideal(bool), + Exact(bool), +} + +#[derive(Default)] +pub struct MediaTrackConstraintSet { + width: Option>, + height: Option>, + aspect: Option>, + frame_rate: Option>, + sample_rate: Option>, +} + +// TODO(Manishearth): Should support a set of constraints +impl MediaTrackConstraintSet { + fn into_caps(self, format: &str) -> Option { + let mut builder = Caps::builder(format); + if let Some(w) = self.width { + builder = w.add_to_caps("width", 0, 1000000, builder)?; + } + if let Some(h) = self.height { + builder = h.add_to_caps("height", 0, 1000000, builder)?; + } + if let Some(aspect) = self.aspect { + builder = aspect.add_to_caps("pixel-aspect-ratio", 0, 1000000, builder)?; + } + if let Some(fr) = self.frame_rate { + builder = fr.add_to_caps("framerate", 0, 1000000, builder)?; + } + if let Some(sr) = self.sample_rate { + builder = sr.add_to_caps("rate", 0, 1000000, builder)?; + } + Some(builder.build()) + } +} + +struct GstMediaDevices { + monitor: DeviceMonitor, +} + +impl GstMediaDevices { + pub fn new() -> Self { + Self { + monitor: DeviceMonitor::new() + } + } + + pub fn get_track(&self, video: bool, constraints: MediaTrackConstraintSet) -> Option { + let (format, filter) = if video { ("video/x-raw", "Video/Source") } else { ("audio/x-raw", "Audio/Source") }; + let caps = constraints.into_caps(format)?; + println!("requesting {:?}", caps); + let f = self.monitor.add_filter(filter, &caps); + let devices = self.monitor.get_devices(); + if f != 0 { + self.monitor.remove_filter(f); + } + if let Some(d) = devices.get(0) { + println!("{:?}", d.get_caps()); + let element = d.create_element(None)?; + Some(GstMediaTrack { + element + }) + } else { + None + } + } +} + +pub struct GstMediaTrack { + element: gst::Element, +} + +fn create_input_stream(stream_type: StreamType) -> Option { + let devices = GstMediaDevices::new(); + let constraints = MediaTrackConstraintSet::default(); + devices + .get_track(stream_type == StreamType::Video, constraints) + .map(|track| { + let f = match stream_type { + StreamType::Audio => GStreamerMediaStream::create_audio_from, + StreamType::Video => GStreamerMediaStream::create_video_from, + }; + f(track.element) + }) +} + +pub fn create_audioinput_stream() -> Option { + create_input_stream(StreamType::Audio) +} + +pub fn create_videoinput_stream() -> Option { + create_input_stream(StreamType::Video) +} diff --git a/backends/gstreamer/src/media_stream.rs b/backends/gstreamer/src/media_stream.rs index 07dc2793..ec5a765b 100644 --- a/backends/gstreamer/src/media_stream.rs +++ b/backends/gstreamer/src/media_stream.rs @@ -26,8 +26,8 @@ lazy_static! { }; } -#[derive(Debug)] -enum StreamType { +#[derive(Debug, PartialEq)] +pub enum StreamType { Audio, Video, } @@ -45,6 +45,7 @@ impl MediaStream for GStreamerMediaStream { impl GStreamerMediaStream { pub fn attach_to_pipeline(&self, pipeline: &gst::Pipeline, webrtcbin: &gst::Element) { + println!("atttaching a {:?} stream", self.type_); let elements: Vec<_> = self.elements.iter().collect(); pipeline.add_many(&elements[..]).unwrap(); gst::Element::link_many(&elements[..]).unwrap(); @@ -53,18 +54,23 @@ impl GStreamerMediaStream { StreamType::Audio => &*RTP_CAPS_OPUS, StreamType::Video => &*RTP_CAPS_VP8, }; - println!("atttaching a {:?} stream", self.type_); self.elements.last().as_ref().unwrap().link_filtered(webrtcbin, caps).unwrap(); + pipeline.set_state(gst::State::Playing).into_result().unwrap(); } pub fn create_video() -> GStreamerMediaStream { let videotestsrc = gst::ElementFactory::make("videotestsrc", None).unwrap(); + videotestsrc.set_property_from_str("pattern", "ball"); + videotestsrc.set_property("is-live", &true).unwrap(); + + Self::create_video_from(videotestsrc) + } + + pub fn create_video_from(source: gst::Element) -> GStreamerMediaStream { let videoconvert = gst::ElementFactory::make("videoconvert", None).unwrap(); let queue = gst::ElementFactory::make("queue", None).unwrap(); let vp8enc = gst::ElementFactory::make("vp8enc", None).unwrap(); - videotestsrc.set_property_from_str("pattern", "ball"); - videotestsrc.set_property("is-live", &true).unwrap(); vp8enc.set_property("deadline", &1i64).unwrap(); let rtpvp8pay = gst::ElementFactory::make("rtpvp8pay", None).unwrap(); @@ -73,7 +79,7 @@ impl GStreamerMediaStream { GStreamerMediaStream { type_: StreamType::Video, elements: vec![ - videotestsrc, + source, videoconvert, queue, vp8enc, @@ -85,6 +91,13 @@ impl GStreamerMediaStream { pub fn create_audio() -> GStreamerMediaStream { let audiotestsrc = gst::ElementFactory::make("audiotestsrc", None).unwrap(); + audiotestsrc.set_property_from_str("wave", "red-noise"); + audiotestsrc.set_property("is-live", &true).unwrap(); + + Self::create_audio_from(audiotestsrc) + } + + pub fn create_audio_from(source: gst::Element) -> GStreamerMediaStream { let queue = gst::ElementFactory::make("queue", None).unwrap(); let audioconvert = gst::ElementFactory::make("audioconvert", None).unwrap(); let audioresample = gst::ElementFactory::make("audioresample", None).unwrap(); @@ -93,13 +106,10 @@ impl GStreamerMediaStream { let rtpopuspay = gst::ElementFactory::make("rtpopuspay", None).unwrap(); let queue3 = gst::ElementFactory::make("queue", None).unwrap(); - audiotestsrc.set_property_from_str("wave", "red-noise"); - audiotestsrc.set_property("is-live", &true).unwrap(); - GStreamerMediaStream { type_: StreamType::Audio, elements: vec![ - audiotestsrc, + source, queue, audioconvert, audioresample, diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 3aacd1a9..3dcbfdeb 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -89,6 +89,7 @@ struct State { media: Arc, webrtc: Option>, signaller: Option, + streams: Vec>, } impl State { @@ -138,8 +139,18 @@ impl State { self.signaller = Some(s); let webrtc = self.webrtc.as_ref().unwrap(); webrtc.init(); - webrtc.add_stream(&*self.media.create_videostream()); - webrtc.add_stream(&*self.media.create_audiostream()); + let video = self + .media + .create_videoinput_stream() + .unwrap_or_else(|| self.media.create_videostream()); + let audio = self + .media + .create_audioinput_stream() + .unwrap_or_else(|| self.media.create_audiostream()); + webrtc.add_stream(&*video); + self.streams.push(video); + webrtc.add_stream(&*audio); + self.streams.push(audio); webrtc.configure(STUN_SERVER, BundlePolicy::MaxBundle); } } @@ -344,6 +355,7 @@ fn run_example(servo_media: Arc) { media: servo_media, webrtc: None, signaller: None, + streams: vec![], }; let receive_loop = receive_loop(receiver, send_msg_tx, state); diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 57cd6afe..0c804c46 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -56,6 +56,14 @@ impl DummyBackend { pub fn create_videostream() -> DummyMediaStream { DummyMediaStream } + + pub fn create_audioinput_stream(&self) -> Option { + Some(DummyMediaStream) + } + + pub fn create_videoinput_stream(&self) -> Option { + Some(DummyMediaStream) + } } #[cfg(any( @@ -108,4 +116,12 @@ impl ServoMedia { pub fn create_videostream(&self) -> Box { Box::new(Backend::create_videostream()) } + + pub fn create_audioinput_stream(&self) -> Option> { + Backend::create_audioinput_stream().map(|s| Box::new(s) as Box) + } + + pub fn create_videoinput_stream(&self) -> Option> { + Backend::create_videoinput_stream().map(|s| Box::new(s) as Box) + } } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index aeeaf5a4..7d10338a 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use boxfnonce::SendBoxFnOnce; -pub trait MediaStream: Any { +pub trait MediaStream: Any + Send { fn as_any(&self) -> &Any; } From 465a6dcf595a7b5aaa35f1302c3613d2f73210aa Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 21 Jan 2019 10:27:57 -0500 Subject: [PATCH 25/35] Ensure that new media stream components are synced with pipeline state when attached. --- backends/gstreamer/src/media_stream.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/gstreamer/src/media_stream.rs b/backends/gstreamer/src/media_stream.rs index ec5a765b..fc8c061b 100644 --- a/backends/gstreamer/src/media_stream.rs +++ b/backends/gstreamer/src/media_stream.rs @@ -49,13 +49,15 @@ impl GStreamerMediaStream { let elements: Vec<_> = self.elements.iter().collect(); pipeline.add_many(&elements[..]).unwrap(); gst::Element::link_many(&elements[..]).unwrap(); + for element in elements { + element.sync_state_with_parent(); + } let caps = match self.type_ { StreamType::Audio => &*RTP_CAPS_OPUS, StreamType::Video => &*RTP_CAPS_VP8, }; self.elements.last().as_ref().unwrap().link_filtered(webrtcbin, caps).unwrap(); - pipeline.set_state(gst::State::Playing).into_result().unwrap(); } pub fn create_video() -> GStreamerMediaStream { From c6458321250dd84536ace99431a1b0d959cde227 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Mon, 21 Jan 2019 12:14:26 -0500 Subject: [PATCH 26/35] Make example only use media capture streams once. --- examples/simple_webrtc.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 3dcbfdeb..afe59164 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -139,14 +139,18 @@ impl State { self.signaller = Some(s); let webrtc = self.webrtc.as_ref().unwrap(); webrtc.init(); - let video = self + let (video, audio) = if self.peer_id.is_some() { + (self .media .create_videoinput_stream() - .unwrap_or_else(|| self.media.create_videostream()); - let audio = self + .unwrap_or_else(|| self.media.create_videostream()), + self .media .create_audioinput_stream() - .unwrap_or_else(|| self.media.create_audiostream()); + .unwrap_or_else(|| self.media.create_audiostream())) + } else { + (self.media.create_videostream(), self.media.create_audiostream()) + }; webrtc.add_stream(&*video); self.streams.push(video); webrtc.add_stream(&*audio); From a66b5314591ed2f9b3abb967caa4821172668013 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 11:10:40 -0800 Subject: [PATCH 27/35] Add event loop to webrtc code --- backends/gstreamer/src/lib.rs | 5 +- backends/gstreamer/src/webrtc.rs | 20 +++++--- examples/simple_webrtc.rs | 86 +++++++++++--------------------- servo-media/src/lib.rs | 7 ++- webrtc/src/lib.rs | 20 +++++--- webrtc/src/thread.rs | 76 ++++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 79 deletions(-) create mode 100644 webrtc/src/thread.rs diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 1c0d3b7e..0663d2ae 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -30,7 +30,7 @@ extern crate url; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; use servo_media_player::PlayerBackend; -use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller}; +use servo_media_webrtc::{WebRtcBackend, WebRtcSignaller, WebRtcController}; pub mod audio_decoder; pub mod audio_sink; @@ -65,8 +65,9 @@ impl WebRtcBackend for GStreamerBackend { fn construct_webrtc_controller( signaller: Box, + thread: WebRtcController, ) -> Self::Controller { - webrtc::construct(signaller) + webrtc::construct(signaller, thread) } } diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 2bf801b3..a7b98c26 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -6,6 +6,7 @@ use gst_sdp; use gst_webrtc::{self, WebRTCSDPType}; use media_stream::GStreamerMediaStream; use servo_media_webrtc::*; +use servo_media_webrtc::WebRtcController as WebRtcThread; use std::sync::{Arc, Mutex}; // TODO: @@ -48,11 +49,7 @@ macro_rules! assert_state { } } -impl WebRtcController for GStreamerWebRtcController { - fn init(&self) { - self.0.lock().unwrap().start_pipeline(self.clone()) - } - +impl WebRtcControllerBackend for GStreamerWebRtcController { fn add_ice_candidate(&self, candidate: IceCandidate) { let app_control = self.0.lock().unwrap(); app_control @@ -210,6 +207,7 @@ struct WebRtcControllerState { webrtc: Option, app_state: AppState, pipeline: gst::Pipeline, + thread: WebRtcThread, signaller: Box, ready_to_negotiate: bool, //send_msg_tx: mpsc::Sender, @@ -232,7 +230,7 @@ impl WebRtcControllerState { println!("on-negotiation-needed"); let mut control = target.0.lock().unwrap(); control.app_state = AppState::PeerCallNegotiating; - control.signaller.on_negotiation_needed(); + control.signaller.on_negotiation_needed(&control.thread); None }).unwrap(); self.pipeline.set_state(gst::State::Playing).into_result().unwrap(); @@ -269,6 +267,7 @@ impl WebRtcControllerState { pub fn construct( signaller: Box, + thread: WebRtcThread, ) -> GStreamerWebRtcController { let main_loop = glib::MainLoop::new(None, false); let pipeline = gst::Pipeline::new("main"); @@ -277,11 +276,15 @@ pub fn construct( webrtc: None, pipeline, signaller, + thread, app_state: AppState::ServerConnected, ready_to_negotiate: false, _main_loop: main_loop, }; - GStreamerWebRtcController(Arc::new(Mutex::new(controller))) + let controller = GStreamerWebRtcController(Arc::new(Mutex::new(controller))); + controller.0.lock().unwrap().start_pipeline(controller.clone()); + controller + } fn on_offer_or_answer_created( @@ -430,5 +433,6 @@ fn send_ice_candidate_message(app_control: &GStreamerWebRtcController, values: & sdp_mline_index, candidate, }; - app_control.0.lock().unwrap().signaller.on_ice_candidate(candidate); + let control = app_control.0.lock().unwrap(); + control.signaller.on_ice_candidate(&control.thread, candidate); } diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index afe59164..97d77421 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -20,7 +20,7 @@ use servo_media::ServoMedia; use servo_media::webrtc::*; use std::env; use std::net; -use std::sync::{Arc, Mutex, mpsc, Weak}; +use std::sync::{Arc, mpsc}; use std::thread; use websocket::OwnedMessage; @@ -87,9 +87,8 @@ struct State { _uid: u32, peer_id: Option, media: Arc, - webrtc: Option>, - signaller: Option, - streams: Vec>, + webrtc: Option, + signaller: Option, } impl State { @@ -132,13 +131,11 @@ impl State { } fn start_rtc(&mut self) { - let signaller = SignallerWrap::new(self.send_msg_tx.clone(), self.peer_id.is_some()); + let signaller = Signaller::new(self.send_msg_tx.clone(), self.peer_id.is_some()); let s = signaller.clone(); - self.webrtc = Some(self.media.create_webrtc_arc(Box::new(signaller))); - s.0.lock().unwrap().controller = Some(Arc::downgrade(self.webrtc.as_ref().unwrap())); + self.webrtc = Some(self.media.create_webrtc(Box::new(signaller))); self.signaller = Some(s); let webrtc = self.webrtc.as_ref().unwrap(); - webrtc.init(); let (video, audio) = if self.peer_id.is_some() { (self .media @@ -151,59 +148,45 @@ impl State { } else { (self.media.create_videostream(), self.media.create_audiostream()) }; - webrtc.add_stream(&*video); - self.streams.push(video); - webrtc.add_stream(&*audio); - self.streams.push(audio); - webrtc.configure(STUN_SERVER, BundlePolicy::MaxBundle); + webrtc.add_stream(video); + webrtc.add_stream(audio); + webrtc.configure(STUN_SERVER.into(), BundlePolicy::MaxBundle); } } +#[derive(Clone)] struct Signaller { sender: mpsc::Sender, - controller: Option>, initiate_negotiation: bool } -#[derive(Clone)] -struct SignallerWrap(Arc>); - -impl WebRtcSignaller for SignallerWrap { +impl WebRtcSignaller for Signaller { fn close(&self, reason: String) { - let signaller = self.0.lock().unwrap(); - let _ = signaller.sender.send(OwnedMessage::Close(Some(websocket::message::CloseData { + let _ = self.sender.send(OwnedMessage::Close(Some(websocket::message::CloseData { status_code: 1011, //Internal Error reason: reason, }))); } - fn on_ice_candidate(&self, candidate: IceCandidate) { - let signaller = self.0.lock().unwrap(); + fn on_ice_candidate(&self, _: &WebRtcController, candidate: IceCandidate) { let message = serde_json::to_string(&JsonMsg::Ice { candidate: candidate.candidate, sdp_mline_index: candidate.sdp_mline_index, }).unwrap(); - signaller.sender.send(OwnedMessage::Text(message)).unwrap(); + self.sender.send(OwnedMessage::Text(message)).unwrap(); } - fn on_negotiation_needed(&self) { - let s2 = self.0.clone(); - let signaller = self.0.lock().unwrap(); - if !signaller.initiate_negotiation { + fn on_negotiation_needed(&self, controller: &WebRtcController) { + if !self.initiate_negotiation { return } - let controller = signaller.controller.as_ref().unwrap().upgrade().unwrap(); let c2 = controller.clone(); - thread::spawn(move || { - controller.create_offer((move |offer: SessionDescription| { - thread::spawn(move || { - c2.set_local_description(offer.clone(), (move || { - s2.lock().unwrap().send_sdp(offer); - }).into()); - }); - - }).into()); - }); + let s2 = self.clone(); + controller.create_offer((move |offer: SessionDescription| { + c2.set_local_description(offer.clone(), (move || { + s2.send_sdp(offer) + }).into()) + }).into()); } } @@ -215,16 +198,11 @@ impl Signaller { }).unwrap(); self.sender.send(OwnedMessage::Text(message)).unwrap(); } -} - -impl SignallerWrap { fn new(sender: mpsc::Sender, initiate_negotiation: bool) -> Self { - let signaller = Signaller { + Signaller { sender, - controller: None, initiate_negotiation - }; - SignallerWrap(Arc::new(Mutex::new(signaller))) + } } } @@ -284,18 +262,13 @@ fn receive_loop( } else { let c2 = controller.clone(); let c3 = controller.clone(); - let s2 = state.signaller.clone().unwrap().0; + let s2 = state.signaller.clone().unwrap(); controller.set_remote_description(desc, (move || { - thread::spawn(move || { - c3.create_answer((move |answer: SessionDescription| { - thread::spawn(move || { - c2.set_local_description(answer.clone(), (move || { - s2.lock().unwrap().send_sdp(answer); - }).into()); - }); - - }).into()); - }); + c3.create_answer((move |answer: SessionDescription| { + c2.set_local_description(answer.clone(), (move || { + s2.send_sdp(answer) + }).into()) + }).into()) }).into()); } @@ -359,7 +332,6 @@ fn run_example(servo_media: Arc) { media: servo_media, webrtc: None, signaller: None, - streams: vec![], }; let receive_loop = receive_loop(receiver, send_msg_tx, state); diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 0c804c46..64aefb22 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -14,7 +14,7 @@ use audio::decoder::DummyAudioDecoder; use audio::sink::{AudioSinkError, DummyAudioSink}; use audio::AudioBackend; use player::{DummyPlayer, Player, PlayerBackend}; -use webrtc::{WebRtcBackend, WebRtcSignaller, MediaStream}; +use webrtc::{WebRtcController, WebRtcSignaller, MediaStream}; pub struct ServoMedia; @@ -77,7 +77,6 @@ pub type Backend = servo_media_gstreamer::GStreamerBackend; )))] pub type Backend = DummyBackend; -pub type WebRtcController = servo_media_gstreamer::webrtc::GStreamerWebRtcController; impl ServoMedia { pub fn new() -> Self { @@ -105,8 +104,8 @@ impl ServoMedia { Box::new(Backend::make_player()) } - pub fn create_webrtc_arc(&self, signaller: Box) -> Arc { - Arc::new(Backend::construct_webrtc_controller(signaller)) + pub fn create_webrtc(&self, signaller: Box) -> WebRtcController { + WebRtcController::new::(signaller) } pub fn create_audiostream(&self) -> Box { diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index 7d10338a..c3a2511e 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -5,14 +5,17 @@ use std::str::FromStr; use boxfnonce::SendBoxFnOnce; +pub mod thread; + pub trait MediaStream: Any + Send { fn as_any(&self) -> &Any; } -pub trait WebRtcController: Send + Sync { - // currently simple_webrtc needs to be able to hook up the signaller after construction - // but before initialization. We split out init() to avoid a race. - fn init(&self); +pub use thread::WebRtcController; + +/// This trait is implemented by backends and should never be used directly by +/// the client. Use WebRtcController instead +pub trait WebRtcControllerBackend: Send + Sync { fn configure(&self, stun_server: &str, policy: BundlePolicy); /// Invariant: Callback must not reentrantly invoke any methods on the controller fn set_remote_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); @@ -25,17 +28,18 @@ pub trait WebRtcController: Send + Sync { } pub trait WebRtcSignaller: Send { - fn on_ice_candidate(&self, candidate: IceCandidate); + fn on_ice_candidate(&self, controller: &WebRtcController, candidate: IceCandidate); /// Invariant: Must not reentrantly invoke any methods on the controller - fn on_negotiation_needed(&self); + fn on_negotiation_needed(&self, controller: &WebRtcController); fn close(&self, reason: String); } pub trait WebRtcBackend { - type Controller: WebRtcController; + type Controller: WebRtcControllerBackend + 'static; fn construct_webrtc_controller( signaller: Box, + thread: WebRtcController, ) -> Self::Controller; } @@ -67,7 +71,7 @@ impl FromStr for SdpType { "offer" => SdpType::Offer, "pranswer" => SdpType::Pranswer, "rollback" => SdpType::Rollback, - _ => return Err(()) + _ => return Err(()), }) } } diff --git a/webrtc/src/thread.rs b/webrtc/src/thread.rs new file mode 100644 index 00000000..0106cbca --- /dev/null +++ b/webrtc/src/thread.rs @@ -0,0 +1,76 @@ +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +use boxfnonce::SendBoxFnOnce; + +use crate::{BundlePolicy, IceCandidate, MediaStream, SessionDescription}; +use crate::{WebRtcControllerBackend, WebRtcSignaller, WebRtcBackend}; + +#[derive(Clone)] +/// Entry point for all client webrtc interactions. +pub struct WebRtcController { + sender: Sender, +} + +impl WebRtcController { + pub fn new(signaller: Box) -> Self { + let (sender, receiver) = channel(); + + let t = WebRtcController { sender }; + + let controller = T::construct_webrtc_controller(signaller, t.clone()); + + thread::spawn(move || { + while let Ok(event) = receiver.recv() { + handle_rtc_event(&controller, event) + } + }); + + t + } + pub fn configure(&self, stun_server: String, policy: BundlePolicy) { + let _ = self.sender.send(RtcThreadEvent::ConfigureStun(stun_server, policy)); + } + pub fn set_remote_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { + let _ = self.sender.send(RtcThreadEvent::SetRemoteDescription(desc, cb)); + } + pub fn set_local_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { + let _ = self.sender.send(RtcThreadEvent::SetLocalDescription(desc, cb)); + } + pub fn add_ice_candidate(&self, candidate: IceCandidate) { + let _ = self.sender.send(RtcThreadEvent::AddIceCandidate(candidate)); + } + pub fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { + let _ = self.sender.send(RtcThreadEvent::CreateOffer(cb)); + } + pub fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { + let _ = self.sender.send(RtcThreadEvent::CreateAnswer(cb)); + } + pub fn add_stream(&self, stream: Box) { + let _ = self.sender.send(RtcThreadEvent::AddStream(stream)); + } +} + +pub enum RtcThreadEvent { + ConfigureStun(String, BundlePolicy), + SetRemoteDescription(SessionDescription, SendBoxFnOnce<'static, ()>), + SetLocalDescription(SessionDescription, SendBoxFnOnce<'static, ()>), + AddIceCandidate(IceCandidate), + CreateOffer(SendBoxFnOnce<'static, (SessionDescription,)>), + CreateAnswer(SendBoxFnOnce<'static, (SessionDescription,)>), + AddStream(Box), +} + +pub fn handle_rtc_event(controller: &WebRtcControllerBackend, event: RtcThreadEvent) { + match event { + RtcThreadEvent::ConfigureStun(server, policy) => controller.configure(&server, policy), + RtcThreadEvent::SetRemoteDescription(desc, cb) => { + controller.set_remote_description(desc, cb) + } + RtcThreadEvent::SetLocalDescription(desc, cb) => controller.set_local_description(desc, cb), + RtcThreadEvent::AddIceCandidate(candidate) => controller.add_ice_candidate(candidate), + RtcThreadEvent::CreateOffer(cb) => controller.create_offer(cb), + RtcThreadEvent::CreateAnswer(cb) => controller.create_answer(cb), + RtcThreadEvent::AddStream(media) => controller.add_stream(&*media), + } +} From 8d11ce0fdd3b813d96c4d2c309f0cc69c19051cd Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 12:31:31 -0800 Subject: [PATCH 28/35] Make backend also use event loop --- backends/gstreamer/src/webrtc.rs | 211 +++++++++++++------------------ webrtc/src/lib.rs | 17 +-- webrtc/src/thread.rs | 23 +++- 3 files changed, 117 insertions(+), 134 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index a7b98c26..29d00af6 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -7,7 +7,8 @@ use gst_webrtc::{self, WebRTCSDPType}; use media_stream::GStreamerMediaStream; use servo_media_webrtc::*; use servo_media_webrtc::WebRtcController as WebRtcThread; -use std::sync::{Arc, Mutex}; +use servo_media_webrtc::thread::InternalEvent; +use std::sync::Mutex; // TODO: // - remove use of failure? @@ -37,22 +38,31 @@ enum AppState { PeerCallError, } -#[derive(Clone)] -pub struct GStreamerWebRtcController(Arc>); - macro_rules! assert_state { ($controller:ident, $state:ident, $condition:expr, $string:expr) => { { - let $state = $controller.0.lock().unwrap().app_state; + let $state = $controller.app_state; assert!($condition, $string); } } } +pub struct GStreamerWebRtcController { + webrtc: Option, + app_state: AppState, + pipeline: gst::Pipeline, + thread: WebRtcThread, + signaller: Box, + ready_to_negotiate: bool, + //send_msg_tx: mpsc::Sender, + //peer_id: String, + _main_loop: glib::MainLoop, + //bus: gst::Bus, +} + impl WebRtcControllerBackend for GStreamerWebRtcController { - fn add_ice_candidate(&self, candidate: IceCandidate) { - let app_control = self.0.lock().unwrap(); - app_control + fn add_ice_candidate(&mut self, candidate: IceCandidate) { + self .webrtc .as_ref() .unwrap() @@ -60,91 +70,84 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { .unwrap(); } - fn set_remote_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { + fn set_remote_description(&mut self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { assert_state!(self, state, state == AppState::PeerCallNegotiating || state == AppState::PeerCallNegotiatingHaveLocal, "Not ready to handle sdp"); self.set_description(desc, false, cb); - let mut app_control = self.0.lock().unwrap(); - if app_control.app_state == AppState::PeerCallNegotiating { - app_control.app_state = AppState::PeerCallNegotiatingHaveRemote; + if self.app_state == AppState::PeerCallNegotiating { + self.app_state = AppState::PeerCallNegotiatingHaveRemote; } else { - app_control.app_state = AppState::PeerCallStarted; + self.app_state = AppState::PeerCallStarted; } } - fn set_local_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { + fn set_local_description(&mut self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { assert_state!(self, state, state == AppState::PeerCallNegotiating || state == AppState::PeerCallNegotiatingHaveRemote, "Not ready to handle sdp"); self.set_description(desc, true, cb); - let mut app_control = self.0.lock().unwrap(); - if app_control.app_state == AppState::PeerCallNegotiating { - app_control.app_state = AppState::PeerCallNegotiatingHaveLocal; + if self.app_state == AppState::PeerCallNegotiating { + self.app_state = AppState::PeerCallNegotiatingHaveLocal; } else { - app_control.app_state = AppState::PeerCallStarted; + self.app_state = AppState::PeerCallStarted; } } - fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { - - let app_control_clone = self.clone(); - let this = self.0.lock().unwrap(); - let webrtc = this.webrtc.as_ref().unwrap();; + fn create_offer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { + let webrtc = self.webrtc.as_ref().unwrap(); + assert_state!(self, state, state == AppState::PeerCallNegotiating, + "Not negotiating call when creating offer"); let promise = gst::Promise::new_with_change_func(move |promise| { - on_offer_or_answer_created(SdpType::Offer, app_control_clone, promise, cb); + on_offer_or_answer_created(SdpType::Offer, promise, cb); }); webrtc.emit("create-offer", &[&None::, &promise]).unwrap(); } - fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { - let app_control_clone = self.clone(); - let this = self.0.lock().unwrap(); - let webrtc = this.webrtc.as_ref().unwrap();; + fn create_answer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { + let webrtc = self.webrtc.as_ref().unwrap(); + assert_state!(self, state, state == AppState::PeerCallNegotiatingHaveRemote, + "No offfer received when creating answer"); let promise = gst::Promise::new_with_change_func(move |promise| { - on_offer_or_answer_created(SdpType::Answer, app_control_clone, promise, cb); + on_offer_or_answer_created(SdpType::Answer, promise, cb); }); webrtc.emit("create-answer", &[&None::, &promise]).unwrap(); } - fn add_stream(&self, stream: &MediaStream) { + fn add_stream(&mut self, stream: &MediaStream) { println!("adding a stream"); - let (pipeline, webrtc) = { - let mut controller = self.0.lock().unwrap(); - (controller.pipeline.clone(), controller.webrtc.clone().unwrap()) - }; let stream = stream.as_any().downcast_ref::().unwrap(); - stream.attach_to_pipeline(&pipeline, &webrtc); - self.0.lock().unwrap().prepare_for_negotiation(self.clone()); + stream.attach_to_pipeline(&self.pipeline, self.webrtc.as_ref().unwrap()); + self.prepare_for_negotiation(); } - fn configure(&self, stun_server: &str, policy: BundlePolicy) { - let data = self.0.lock().unwrap(); - let webrtc = data.webrtc.as_ref().unwrap(); + fn configure(&mut self, stun_server: &str, policy: BundlePolicy) { + let webrtc = self.webrtc.as_ref().unwrap(); webrtc.set_property_from_str("stun-server", stun_server); webrtc.set_property_from_str("bundle-policy", policy.as_str()); } -} -impl GStreamerWebRtcController { - fn process_new_stream( - &self, - values: &[glib::Value], - pipe: &gst::Pipeline, - ) -> Option { - let pad = values[1].get::().expect("not a pad??"); - if pad.get_direction() != PadDirection::Src { - // Ignore outgoing pad notifications. - return None; + fn internal_event(&mut self, e: thread::InternalEvent) { + match e { + InternalEvent::OnNegotiationNeeded => { + self.app_state = AppState::PeerCallNegotiating; + self.signaller.on_negotiation_needed(&self.thread); + } + InternalEvent::OnIceCandidate(candidate) => { + self.signaller.on_ice_candidate(&self.thread, candidate); + } } - on_incoming_stream(self, values, pipe) } +} + +impl GStreamerWebRtcController { + fn set_description(&self, desc: SessionDescription, local: bool, cb: SendBoxFnOnce<'static, ()>) { let ty = match desc.type_ { @@ -156,14 +159,13 @@ impl GStreamerWebRtcController { let kind = if local { "set-local-description" } else { "set-remote-description" }; - let app_control = self.0.lock().unwrap(); let ret = gst_sdp::SDPMessage::parse_buffer(desc.sdp.as_bytes()).unwrap(); let answer = gst_webrtc::WebRTCSessionDescription::new(ty, ret); let promise = gst::Promise::new_with_change_func(move |_promise| { cb.call() }); - app_control + self .webrtc .as_ref() .unwrap() @@ -171,19 +173,6 @@ impl GStreamerWebRtcController { .unwrap(); } - //#[allow(unused)] - fn send_bus_error(&self, body: &str) { - eprintln!("Bus error: {}", body); - /*let mbuilder = - gst::Message::new_application(gst::Structure::new("error", &[("body", &body)])); - let _ = self.0.lock().unwrap().bus.post(&mbuilder.build());*/ - //XXXjdm - } - - #[allow(unused)] - fn update_state(&self, state: AppState) { - self.0.lock().unwrap().update_state(state); - } #[allow(unused)] fn close_and_quit(&self, err: &Error) { @@ -192,9 +181,8 @@ impl GStreamerWebRtcController { // Must not hold mutex while shutting down the pipeline // as something might call into here and take the mutex too let pipeline = { - let app_control = self.0.lock().unwrap(); - app_control.signaller.close(err.to_string()); - app_control.pipeline.clone() + self.signaller.close(err.to_string()); + self.pipeline.clone() }; pipeline.set_state(gst::State::Null).into_result().unwrap(); @@ -203,66 +191,47 @@ impl GStreamerWebRtcController { } } -struct WebRtcControllerState { - webrtc: Option, - app_state: AppState, - pipeline: gst::Pipeline, - thread: WebRtcThread, - signaller: Box, - ready_to_negotiate: bool, - //send_msg_tx: mpsc::Sender, - //peer_id: String, - _main_loop: glib::MainLoop, - //bus: gst::Bus, -} - -impl WebRtcControllerState { - fn prepare_for_negotiation(&mut self, target: GStreamerWebRtcController) { +impl GStreamerWebRtcController { + fn prepare_for_negotiation(&mut self) { if self.ready_to_negotiate { return; } self.ready_to_negotiate = true; let webrtc = self.webrtc.as_ref().unwrap(); + // gstreamer needs Sync on these callbacks for some reason + // https://github.com/sdroege/gstreamer-rs/issues/154 + let thread = Mutex::new(self.thread.clone()); // If the pipeline starts playing and this signal is present before there are any // media streams, an invalid SDP offer will be created. Therefore, delay setting up // the signal and starting the pipeline until after the first stream has been added. webrtc.connect("on-negotiation-needed", false, move |_values| { - println!("on-negotiation-needed"); - let mut control = target.0.lock().unwrap(); - control.app_state = AppState::PeerCallNegotiating; - control.signaller.on_negotiation_needed(&control.thread); + thread.lock().unwrap().internal_event(InternalEvent::OnNegotiationNeeded); None }).unwrap(); self.pipeline.set_state(gst::State::Playing).into_result().unwrap(); } - fn start_pipeline(&mut self, target: GStreamerWebRtcController) { + fn start_pipeline(&mut self) { let webrtc = gst::ElementFactory::make("webrtcbin", "sendrecv").unwrap(); self.pipeline.add(&webrtc).unwrap(); - let app_control_clone = target.clone(); + // gstreamer needs Sync on these callbacks for some reason + // https://github.com/sdroege/gstreamer-rs/issues/154 + let thread = Mutex::new(self.thread.clone()); webrtc.connect("on-ice-candidate", false, move |values| { - println!("on-ice-candidate"); - send_ice_candidate_message(&app_control_clone, values); + thread.lock().unwrap().internal_event(InternalEvent::OnIceCandidate(candidate(values))); None }).unwrap(); let pipe_clone = self.pipeline.clone(); - let app_control_clone = target.clone(); webrtc.connect("pad-added", false, move |values| { println!("pad-added"); - app_control_clone.process_new_stream( - values, - &pipe_clone, - ) + process_new_stream(values, &pipe_clone); + None }).unwrap(); self.webrtc = Some(webrtc); } - - fn update_state(&mut self, state: AppState) { - self.app_state = state; - } } pub fn construct( @@ -272,7 +241,7 @@ pub fn construct( let main_loop = glib::MainLoop::new(None, false); let pipeline = gst::Pipeline::new("main"); - let controller = WebRtcControllerState { + let mut controller = GStreamerWebRtcController { webrtc: None, pipeline, signaller, @@ -281,26 +250,17 @@ pub fn construct( ready_to_negotiate: false, _main_loop: main_loop, }; - let controller = GStreamerWebRtcController(Arc::new(Mutex::new(controller))); - controller.0.lock().unwrap().start_pipeline(controller.clone()); + controller.start_pipeline(); controller } fn on_offer_or_answer_created( ty: SdpType, - app_control: GStreamerWebRtcController, promise: &gst::Promise, cb: SendBoxFnOnce<'static, (SessionDescription,)>, ) { debug_assert!(ty == SdpType::Offer || ty == SdpType::Answer); - if ty == SdpType::Offer { - assert_state!(app_control, state, state == AppState::PeerCallNegotiating, - "Not negotiating call when creating offer") - } else { - assert_state!(app_control, state, state == AppState::PeerCallNegotiatingHaveRemote, - "No offfer received when creating answer") - } let reply = promise.get_reply().unwrap(); @@ -368,7 +328,6 @@ fn handle_media_stream( } fn on_incoming_decodebin_stream( - app_control: &GStreamerWebRtcController, values: &[glib::Value], pipe: &gst::Pipeline, ) -> Option { @@ -391,14 +350,13 @@ fn on_incoming_decodebin_stream( }; if let Err(err) = handled { - app_control.send_bus_error(&format!("Error adding pad with caps {} {:?}", name, err)); + eprintln!("Error adding pad with caps {} {:?}", name, err); } None } fn on_incoming_stream( - app_control: &GStreamerWebRtcController, values: &[glib::Value], pipe: &gst::Pipeline, ) -> Option { @@ -406,11 +364,10 @@ fn on_incoming_stream( let decodebin = gst::ElementFactory::make("decodebin", None).unwrap(); let pipe_clone = pipe.clone(); - let app_control_clone = app_control.clone(); decodebin .connect("pad-added", false, move |values| { println!("decodebin pad-added"); - on_incoming_decodebin_stream(&app_control_clone, values, &pipe_clone) + on_incoming_decodebin_stream(values, &pipe_clone) }) .unwrap(); @@ -422,17 +379,25 @@ fn on_incoming_stream( None } -fn send_ice_candidate_message(app_control: &GStreamerWebRtcController, values: &[glib::Value]) { - assert_state!(app_control, state, state >= AppState::PeerCallNegotiating, "Can't send ICE, not in call"); +fn process_new_stream( + values: &[glib::Value], + pipe: &gst::Pipeline, +) -> Option { + let pad = values[1].get::().expect("not a pad??"); + if pad.get_direction() != PadDirection::Src { + // Ignore outgoing pad notifications. + return None; + } + on_incoming_stream(values, pipe) +} +fn candidate(values: &[glib::Value]) -> IceCandidate { let _webrtc = values[0].get::().expect("Invalid argument"); let sdp_mline_index = values[1].get::().expect("Invalid argument"); let candidate = values[2].get::().expect("Invalid argument"); - let candidate = IceCandidate { + IceCandidate { sdp_mline_index, candidate, - }; - let control = app_control.0.lock().unwrap(); - control.signaller.on_ice_candidate(&control.thread, candidate); + } } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index c3a2511e..3619f4d7 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -15,16 +15,17 @@ pub use thread::WebRtcController; /// This trait is implemented by backends and should never be used directly by /// the client. Use WebRtcController instead -pub trait WebRtcControllerBackend: Send + Sync { - fn configure(&self, stun_server: &str, policy: BundlePolicy); +pub trait WebRtcControllerBackend: Send { + fn configure(&mut self, stun_server: &str, policy: BundlePolicy); /// Invariant: Callback must not reentrantly invoke any methods on the controller - fn set_remote_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); + fn set_remote_description(&mut self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); /// Invariant: Callback must not reentrantly invoke any methods on the controller - fn set_local_description(&self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); - fn add_ice_candidate(&self, candidate: IceCandidate); - fn create_offer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); - fn create_answer(&self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); - fn add_stream(&self, stream: &MediaStream); + fn set_local_description(&mut self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); + fn add_ice_candidate(&mut self, candidate: IceCandidate); + fn create_offer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); + fn create_answer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); + fn add_stream(&mut self, stream: &MediaStream); + fn internal_event(&mut self, event: thread::InternalEvent); } pub trait WebRtcSignaller: Send { diff --git a/webrtc/src/thread.rs b/webrtc/src/thread.rs index 0106cbca..5a4b663f 100644 --- a/webrtc/src/thread.rs +++ b/webrtc/src/thread.rs @@ -18,11 +18,11 @@ impl WebRtcController { let t = WebRtcController { sender }; - let controller = T::construct_webrtc_controller(signaller, t.clone()); + let mut controller = T::construct_webrtc_controller(signaller, t.clone()); thread::spawn(move || { while let Ok(event) = receiver.recv() { - handle_rtc_event(&controller, event) + handle_rtc_event(&mut controller, event) } }); @@ -49,6 +49,11 @@ impl WebRtcController { pub fn add_stream(&self, stream: Box) { let _ = self.sender.send(RtcThreadEvent::AddStream(stream)); } + + /// This should not be invoked by clients + pub fn internal_event(&self, event: InternalEvent) { + let _ = self.sender.send(RtcThreadEvent::InternalEvent(event)); + } } pub enum RtcThreadEvent { @@ -59,9 +64,20 @@ pub enum RtcThreadEvent { CreateOffer(SendBoxFnOnce<'static, (SessionDescription,)>), CreateAnswer(SendBoxFnOnce<'static, (SessionDescription,)>), AddStream(Box), + InternalEvent(InternalEvent), +} + +/// To allow everything to occur on the event loop, +/// the backend may need to send signals to itself +/// +/// This is a somewhat leaky abstraction, but we don't +/// plan on having too many backends anyway +pub enum InternalEvent { + OnNegotiationNeeded, + OnIceCandidate(IceCandidate), } -pub fn handle_rtc_event(controller: &WebRtcControllerBackend, event: RtcThreadEvent) { +pub fn handle_rtc_event(controller: &mut WebRtcControllerBackend, event: RtcThreadEvent) { match event { RtcThreadEvent::ConfigureStun(server, policy) => controller.configure(&server, policy), RtcThreadEvent::SetRemoteDescription(desc, cb) => { @@ -72,5 +88,6 @@ pub fn handle_rtc_event(controller: &WebRtcControllerBackend, event: RtcThreadEv RtcThreadEvent::CreateOffer(cb) => controller.create_offer(cb), RtcThreadEvent::CreateAnswer(cb) => controller.create_answer(cb), RtcThreadEvent::AddStream(media) => controller.add_stream(&*media), + RtcThreadEvent::InternalEvent(e) => controller.internal_event(e), } } From c29d56f1b30665899622447c91bdefa072230dfa Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 12:38:45 -0800 Subject: [PATCH 29/35] remove assert_state macro --- backends/gstreamer/src/webrtc.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 29d00af6..824f56e2 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -38,15 +38,6 @@ enum AppState { PeerCallError, } -macro_rules! assert_state { - ($controller:ident, $state:ident, $condition:expr, $string:expr) => { - { - let $state = $controller.app_state; - assert!($condition, $string); - } - } -} - pub struct GStreamerWebRtcController { webrtc: Option, app_state: AppState, @@ -71,9 +62,9 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { } fn set_remote_description(&mut self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - assert_state!(self, state, - state == AppState::PeerCallNegotiating || state == AppState::PeerCallNegotiatingHaveLocal, - "Not ready to handle sdp"); + assert!(self.app_state == AppState::PeerCallNegotiating || + self.app_state == AppState::PeerCallNegotiatingHaveLocal, + "Not ready to handle sdp"); self.set_description(desc, false, cb); @@ -85,9 +76,9 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { } fn set_local_description(&mut self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - assert_state!(self, state, - state == AppState::PeerCallNegotiating || state == AppState::PeerCallNegotiatingHaveRemote, - "Not ready to handle sdp"); + assert!(self.app_state == AppState::PeerCallNegotiating || + self.app_state == AppState::PeerCallNegotiatingHaveRemote, + "Not ready to handle sdp"); self.set_description(desc, true, cb); @@ -100,8 +91,8 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { fn create_offer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { let webrtc = self.webrtc.as_ref().unwrap(); - assert_state!(self, state, state == AppState::PeerCallNegotiating, - "Not negotiating call when creating offer"); + assert!(self.app_state == AppState::PeerCallNegotiating, + "Not negotiating call when creating offer"); let promise = gst::Promise::new_with_change_func(move |promise| { on_offer_or_answer_created(SdpType::Offer, promise, cb); }); @@ -111,8 +102,8 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { fn create_answer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { let webrtc = self.webrtc.as_ref().unwrap(); - assert_state!(self, state, state == AppState::PeerCallNegotiatingHaveRemote, - "No offfer received when creating answer"); + assert!(self.app_state == AppState::PeerCallNegotiatingHaveRemote, + "No offfer received when creating answer"); let promise = gst::Promise::new_with_change_func(move |promise| { on_offer_or_answer_created(SdpType::Answer, promise, cb); }); From 1c2e924006cb77d5a3f6c8e9b8217360b02eb931 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 12:50:48 -0800 Subject: [PATCH 30/35] Add dummy webrtc backend --- servo-media/src/lib.rs | 11 +++++++++++ webrtc/src/lib.rs | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/servo-media/src/lib.rs b/servo-media/src/lib.rs index 64aefb22..49aa2ba3 100644 --- a/servo-media/src/lib.rs +++ b/servo-media/src/lib.rs @@ -15,6 +15,7 @@ use audio::sink::{AudioSinkError, DummyAudioSink}; use audio::AudioBackend; use player::{DummyPlayer, Player, PlayerBackend}; use webrtc::{WebRtcController, WebRtcSignaller, MediaStream}; +use webrtc::{WebRtcBackend, DummyWebRtcController}; pub struct ServoMedia; @@ -47,6 +48,16 @@ impl PlayerBackend for DummyBackend { } } +impl WebRtcBackend for DummyBackend { + type Controller = DummyWebRtcController; + fn construct_webrtc_controller( + _: Box, + _: WebRtcController, + ) -> Self::Controller { + DummyWebRtcController + } +} + impl DummyBackend { pub fn init() {} pub fn create_audiostream() -> DummyMediaStream { diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index 3619f4d7..785e4035 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -17,9 +17,7 @@ pub use thread::WebRtcController; /// the client. Use WebRtcController instead pub trait WebRtcControllerBackend: Send { fn configure(&mut self, stun_server: &str, policy: BundlePolicy); - /// Invariant: Callback must not reentrantly invoke any methods on the controller fn set_remote_description(&mut self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); - /// Invariant: Callback must not reentrantly invoke any methods on the controller fn set_local_description(&mut self, SessionDescription, cb: SendBoxFnOnce<'static, ()>); fn add_ice_candidate(&mut self, candidate: IceCandidate); fn create_offer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); @@ -28,6 +26,19 @@ pub trait WebRtcControllerBackend: Send { fn internal_event(&mut self, event: thread::InternalEvent); } +pub struct DummyWebRtcController; + +impl WebRtcControllerBackend for DummyWebRtcController { + fn configure(&mut self, _: &str, _: BundlePolicy) {} + fn set_remote_description(&mut self, _: SessionDescription, _: SendBoxFnOnce<'static, ()>) {} + fn set_local_description(&mut self, _: SessionDescription, _: SendBoxFnOnce<'static, ()>) {} + fn add_ice_candidate(&mut self, _: IceCandidate) {} + fn create_offer(&mut self, _: SendBoxFnOnce<'static, (SessionDescription,)>) {} + fn create_answer(&mut self, _: SendBoxFnOnce<'static, (SessionDescription,)>) {} + fn add_stream(&mut self, _: &MediaStream) {} + fn internal_event(&mut self, _: thread::InternalEvent) {} +} + pub trait WebRtcSignaller: Send { fn on_ice_candidate(&self, controller: &WebRtcController, candidate: IceCandidate); /// Invariant: Must not reentrantly invoke any methods on the controller From 61d5841fe4d8edac2ca4686805d2c75bfb1a2e4a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 14:22:27 -0800 Subject: [PATCH 31/35] Improve code for closing the pipeline --- backends/gstreamer/src/webrtc.rs | 27 ++++++++++----------------- examples/simple_webrtc.rs | 4 ++-- webrtc/src/lib.rs | 4 +++- webrtc/src/thread.rs | 17 +++++++++++++++-- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 824f56e2..f2bf746f 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -135,6 +135,16 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { } } } + + + + fn quit(&mut self) { + self.signaller.close(); + + self.pipeline.set_state(gst::State::Null).into_result().unwrap(); + + //main_loop.quit(); + } } impl GStreamerWebRtcController { @@ -163,23 +173,6 @@ impl GStreamerWebRtcController { .emit(kind, &[&answer, &promise]) .unwrap(); } - - - #[allow(unused)] - fn close_and_quit(&self, err: &Error) { - println!("{}\nquitting", err); - - // Must not hold mutex while shutting down the pipeline - // as something might call into here and take the mutex too - let pipeline = { - self.signaller.close(err.to_string()); - self.pipeline.clone() - }; - - pipeline.set_state(gst::State::Null).into_result().unwrap(); - - //main_loop.quit(); - } } impl GStreamerWebRtcController { diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 97d77421..7592a8d7 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -161,10 +161,10 @@ struct Signaller { } impl WebRtcSignaller for Signaller { - fn close(&self, reason: String) { + fn close(&self) { let _ = self.sender.send(OwnedMessage::Close(Some(websocket::message::CloseData { status_code: 1011, //Internal Error - reason: reason, + reason: "explicitly closed".into(), }))); } diff --git a/webrtc/src/lib.rs b/webrtc/src/lib.rs index 785e4035..df0521f7 100644 --- a/webrtc/src/lib.rs +++ b/webrtc/src/lib.rs @@ -24,6 +24,7 @@ pub trait WebRtcControllerBackend: Send { fn create_answer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>); fn add_stream(&mut self, stream: &MediaStream); fn internal_event(&mut self, event: thread::InternalEvent); + fn quit(&mut self); } pub struct DummyWebRtcController; @@ -37,13 +38,14 @@ impl WebRtcControllerBackend for DummyWebRtcController { fn create_answer(&mut self, _: SendBoxFnOnce<'static, (SessionDescription,)>) {} fn add_stream(&mut self, _: &MediaStream) {} fn internal_event(&mut self, _: thread::InternalEvent) {} + fn quit(&mut self) {} } pub trait WebRtcSignaller: Send { fn on_ice_candidate(&self, controller: &WebRtcController, candidate: IceCandidate); /// Invariant: Must not reentrantly invoke any methods on the controller fn on_negotiation_needed(&self, controller: &WebRtcController); - fn close(&self, reason: String); + fn close(&self); } pub trait WebRtcBackend { diff --git a/webrtc/src/thread.rs b/webrtc/src/thread.rs index 5a4b663f..4d304b08 100644 --- a/webrtc/src/thread.rs +++ b/webrtc/src/thread.rs @@ -22,7 +22,10 @@ impl WebRtcController { thread::spawn(move || { while let Ok(event) = receiver.recv() { - handle_rtc_event(&mut controller, event) + if !handle_rtc_event(&mut controller, event) { + // shut down event loop + break; + } } }); @@ -54,6 +57,10 @@ impl WebRtcController { pub fn internal_event(&self, event: InternalEvent) { let _ = self.sender.send(RtcThreadEvent::InternalEvent(event)); } + + pub fn quit(&self) { + let _ = self.sender.send(RtcThreadEvent::Quit); + } } pub enum RtcThreadEvent { @@ -65,6 +72,7 @@ pub enum RtcThreadEvent { CreateAnswer(SendBoxFnOnce<'static, (SessionDescription,)>), AddStream(Box), InternalEvent(InternalEvent), + Quit } /// To allow everything to occur on the event loop, @@ -77,7 +85,7 @@ pub enum InternalEvent { OnIceCandidate(IceCandidate), } -pub fn handle_rtc_event(controller: &mut WebRtcControllerBackend, event: RtcThreadEvent) { +pub fn handle_rtc_event(controller: &mut WebRtcControllerBackend, event: RtcThreadEvent) -> bool { match event { RtcThreadEvent::ConfigureStun(server, policy) => controller.configure(&server, policy), RtcThreadEvent::SetRemoteDescription(desc, cb) => { @@ -89,5 +97,10 @@ pub fn handle_rtc_event(controller: &mut WebRtcControllerBackend, event: RtcThre RtcThreadEvent::CreateAnswer(cb) => controller.create_answer(cb), RtcThreadEvent::AddStream(media) => controller.add_stream(&*media), RtcThreadEvent::InternalEvent(e) => controller.internal_event(e), + RtcThreadEvent::Quit => { + controller.quit(); + return false + } } + true } From 11d229a26d61180cba0ac28258924aad39cd1665 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 14:56:05 -0800 Subject: [PATCH 32/35] make Travis pass --- examples/simple_webrtc.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index 7592a8d7..f02494fd 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -300,7 +300,14 @@ fn run_example(servo_media: Arc) { env_logger::init(); let mut args = env::args(); let _ = args.next(); - let server_port = args.next().expect("Usage: simple_webrtc ").parse::().unwrap(); + let server_port = if let Some(port) = args.next() { + port.parse::().unwrap() + } else { + // we don't panic here so that we can run this + // as a test on Travis + println!("Usage: simple_webrtc "); + return; + }; let server = format!("ws://localhost:{}", server_port); let peer_id = args.next(); From dd46b3d4b12abe9897de5aff8d55367f80382582 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 15:14:22 -0800 Subject: [PATCH 33/35] cleanup --- Cargo.lock | 44 +++++++++++++------------- backends/gstreamer/Cargo.toml | 2 +- backends/gstreamer/src/lib.rs | 1 - backends/gstreamer/src/media_stream.rs | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 164ff5d3..44b779b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -364,7 +364,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -378,7 +378,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -416,7 +416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -607,7 +607,7 @@ dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -631,7 +631,7 @@ dependencies = [ "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -677,7 +677,7 @@ dependencies = [ "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -692,7 +692,7 @@ dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1022,7 +1022,7 @@ dependencies = [ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1079,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1336,7 +1336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1510,7 +1510,7 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1595,7 +1595,7 @@ name = "schannel" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1721,7 +1721,7 @@ dependencies = [ "gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-webrtc 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media-audio 0.1.0", "servo-media-player 0.1.0", @@ -1773,7 +1773,7 @@ name = "shared_library" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1798,7 +1798,7 @@ dependencies = [ "andrew 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1900,7 +1900,7 @@ name = "thread_local" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2012,7 +2012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2263,7 +2263,7 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2284,7 +2284,7 @@ dependencies = [ "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "plane-split 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2390,7 +2390,7 @@ dependencies = [ "cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2416,7 +2416,7 @@ name = "x11-dl" version = "2.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2555,7 +2555,7 @@ dependencies = [ "checksum khronos_api 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62237e6d326bd5871cd21469323bf096de81f1618cd82cbaf5d87825335aeb49" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" +"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 2fe4d0e2..65ec7915 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -59,7 +59,7 @@ version = "0.12" version = "0.11" [dependencies.lazy_static] -version = "*" +version = "1.2.0" [dependencies.servo-media-audio] path = "../../audio" diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 0663d2ae..96df86f0 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -1,7 +1,6 @@ extern crate boxfnonce; extern crate byte_slice_cast; -#[macro_use] extern crate failure; #[macro_use] extern crate glib; diff --git a/backends/gstreamer/src/media_stream.rs b/backends/gstreamer/src/media_stream.rs index fc8c061b..0084b9c7 100644 --- a/backends/gstreamer/src/media_stream.rs +++ b/backends/gstreamer/src/media_stream.rs @@ -50,7 +50,7 @@ impl GStreamerMediaStream { pipeline.add_many(&elements[..]).unwrap(); gst::Element::link_many(&elements[..]).unwrap(); for element in elements { - element.sync_state_with_parent(); + element.sync_state_with_parent().unwrap(); } let caps = match self.type_ { From 8f686071c410d0c3cedf872af721cf1287d9776a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 15:16:14 -0800 Subject: [PATCH 34/35] rustfmt --- backends/gstreamer/src/webrtc.rs | 145 ++++++++++++++++++------------- examples/simple_webrtc.rs | 108 ++++++++++++++--------- webrtc/src/thread.rs | 18 ++-- 3 files changed, 166 insertions(+), 105 deletions(-) diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index f2bf746f..56547c54 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -1,13 +1,13 @@ use boxfnonce::SendBoxFnOnce; use failure::Error; use glib::{self, ObjectExt}; -use gst::{self, ElementExt, BinExt, BinExtManual, GObjectExtManualGst, PadDirection, PadExt}; +use gst::{self, BinExt, BinExtManual, ElementExt, GObjectExtManualGst, PadDirection, PadExt}; use gst_sdp; use gst_webrtc::{self, WebRTCSDPType}; use media_stream::GStreamerMediaStream; -use servo_media_webrtc::*; -use servo_media_webrtc::WebRtcController as WebRtcThread; use servo_media_webrtc::thread::InternalEvent; +use servo_media_webrtc::WebRtcController as WebRtcThread; +use servo_media_webrtc::*; use std::sync::Mutex; // TODO: @@ -53,18 +53,22 @@ pub struct GStreamerWebRtcController { impl WebRtcControllerBackend for GStreamerWebRtcController { fn add_ice_candidate(&mut self, candidate: IceCandidate) { - self - .webrtc + self.webrtc .as_ref() .unwrap() - .emit("add-ice-candidate", &[&candidate.sdp_mline_index, &candidate.candidate]) + .emit( + "add-ice-candidate", + &[&candidate.sdp_mline_index, &candidate.candidate], + ) .unwrap(); } fn set_remote_description(&mut self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - assert!(self.app_state == AppState::PeerCallNegotiating || - self.app_state == AppState::PeerCallNegotiatingHaveLocal, - "Not ready to handle sdp"); + assert!( + self.app_state == AppState::PeerCallNegotiating + || self.app_state == AppState::PeerCallNegotiatingHaveLocal, + "Not ready to handle sdp" + ); self.set_description(desc, false, cb); @@ -76,9 +80,11 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { } fn set_local_description(&mut self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - assert!(self.app_state == AppState::PeerCallNegotiating || - self.app_state == AppState::PeerCallNegotiatingHaveRemote, - "Not ready to handle sdp"); + assert!( + self.app_state == AppState::PeerCallNegotiating + || self.app_state == AppState::PeerCallNegotiatingHaveRemote, + "Not ready to handle sdp" + ); self.set_description(desc, true, cb); @@ -91,29 +97,40 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { fn create_offer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { let webrtc = self.webrtc.as_ref().unwrap(); - assert!(self.app_state == AppState::PeerCallNegotiating, - "Not negotiating call when creating offer"); + assert!( + self.app_state == AppState::PeerCallNegotiating, + "Not negotiating call when creating offer" + ); let promise = gst::Promise::new_with_change_func(move |promise| { on_offer_or_answer_created(SdpType::Offer, promise, cb); }); - webrtc.emit("create-offer", &[&None::, &promise]).unwrap(); + webrtc + .emit("create-offer", &[&None::, &promise]) + .unwrap(); } fn create_answer(&mut self, cb: SendBoxFnOnce<'static, (SessionDescription,)>) { let webrtc = self.webrtc.as_ref().unwrap(); - assert!(self.app_state == AppState::PeerCallNegotiatingHaveRemote, - "No offfer received when creating answer"); + assert!( + self.app_state == AppState::PeerCallNegotiatingHaveRemote, + "No offfer received when creating answer" + ); let promise = gst::Promise::new_with_change_func(move |promise| { on_offer_or_answer_created(SdpType::Answer, promise, cb); }); - webrtc.emit("create-answer", &[&None::, &promise]).unwrap(); - } + webrtc + .emit("create-answer", &[&None::, &promise]) + .unwrap(); + } fn add_stream(&mut self, stream: &MediaStream) { println!("adding a stream"); - let stream = stream.as_any().downcast_ref::().unwrap(); + let stream = stream + .as_any() + .downcast_ref::() + .unwrap(); stream.attach_to_pipeline(&self.pipeline, self.webrtc.as_ref().unwrap()); self.prepare_for_negotiation(); } @@ -136,21 +153,25 @@ impl WebRtcControllerBackend for GStreamerWebRtcController { } } - - fn quit(&mut self) { self.signaller.close(); - self.pipeline.set_state(gst::State::Null).into_result().unwrap(); + self.pipeline + .set_state(gst::State::Null) + .into_result() + .unwrap(); //main_loop.quit(); } } impl GStreamerWebRtcController { - - - fn set_description(&self, desc: SessionDescription, local: bool, cb: SendBoxFnOnce<'static, ()>) { + fn set_description( + &self, + desc: SessionDescription, + local: bool, + cb: SendBoxFnOnce<'static, ()>, + ) { let ty = match desc.type_ { SdpType::Answer => WebRTCSDPType::Answer, SdpType::Offer => WebRTCSDPType::Offer, @@ -158,16 +179,16 @@ impl GStreamerWebRtcController { SdpType::Rollback => WebRTCSDPType::Rollback, }; - let kind = if local { "set-local-description" } else { "set-remote-description" }; + let kind = if local { + "set-local-description" + } else { + "set-remote-description" + }; let ret = gst_sdp::SDPMessage::parse_buffer(desc.sdp.as_bytes()).unwrap(); - let answer = - gst_webrtc::WebRTCSessionDescription::new(ty, ret); - let promise = gst::Promise::new_with_change_func(move |_promise| { - cb.call() - }); - self - .webrtc + let answer = gst_webrtc::WebRTCSessionDescription::new(ty, ret); + let promise = gst::Promise::new_with_change_func(move |_promise| cb.call()); + self.webrtc .as_ref() .unwrap() .emit(kind, &[&answer, &promise]) @@ -188,11 +209,19 @@ impl GStreamerWebRtcController { // If the pipeline starts playing and this signal is present before there are any // media streams, an invalid SDP offer will be created. Therefore, delay setting up // the signal and starting the pipeline until after the first stream has been added. - webrtc.connect("on-negotiation-needed", false, move |_values| { - thread.lock().unwrap().internal_event(InternalEvent::OnNegotiationNeeded); - None - }).unwrap(); - self.pipeline.set_state(gst::State::Playing).into_result().unwrap(); + webrtc + .connect("on-negotiation-needed", false, move |_values| { + thread + .lock() + .unwrap() + .internal_event(InternalEvent::OnNegotiationNeeded); + None + }) + .unwrap(); + self.pipeline + .set_state(gst::State::Playing) + .into_result() + .unwrap(); } fn start_pipeline(&mut self) { @@ -202,17 +231,24 @@ impl GStreamerWebRtcController { // gstreamer needs Sync on these callbacks for some reason // https://github.com/sdroege/gstreamer-rs/issues/154 let thread = Mutex::new(self.thread.clone()); - webrtc.connect("on-ice-candidate", false, move |values| { - thread.lock().unwrap().internal_event(InternalEvent::OnIceCandidate(candidate(values))); - None - }).unwrap(); + webrtc + .connect("on-ice-candidate", false, move |values| { + thread + .lock() + .unwrap() + .internal_event(InternalEvent::OnIceCandidate(candidate(values))); + None + }) + .unwrap(); let pipe_clone = self.pipeline.clone(); - webrtc.connect("pad-added", false, move |values| { - println!("pad-added"); - process_new_stream(values, &pipe_clone); - None - }).unwrap(); + webrtc + .connect("pad-added", false, move |values| { + println!("pad-added"); + process_new_stream(values, &pipe_clone); + None + }) + .unwrap(); self.webrtc = Some(webrtc); } @@ -236,7 +272,6 @@ pub fn construct( }; controller.start_pipeline(); controller - } fn on_offer_or_answer_created( @@ -259,7 +294,7 @@ fn on_offer_or_answer_created( WebRTCSDPType::Offer => SdpType::Offer, WebRTCSDPType::Pranswer => SdpType::Pranswer, WebRTCSDPType::Rollback => SdpType::Rollback, - _ => panic!("unknown sdp response") + _ => panic!("unknown sdp response"), }; let desc = SessionDescription { @@ -340,10 +375,7 @@ fn on_incoming_decodebin_stream( None } -fn on_incoming_stream( - values: &[glib::Value], - pipe: &gst::Pipeline, -) -> Option { +fn on_incoming_stream(values: &[glib::Value], pipe: &gst::Pipeline) -> Option { let webrtc = values[0].get::().expect("Invalid argument"); let decodebin = gst::ElementFactory::make("decodebin", None).unwrap(); @@ -363,10 +395,7 @@ fn on_incoming_stream( None } -fn process_new_stream( - values: &[glib::Value], - pipe: &gst::Pipeline, -) -> Option { +fn process_new_stream(values: &[glib::Value], pipe: &gst::Pipeline) -> Option { let pad = values[1].get::().expect("not a pad??"); if pad.get_direction() != PadDirection::Src { // Ignore outgoing pad notifications. diff --git a/examples/simple_webrtc.rs b/examples/simple_webrtc.rs index f02494fd..ae55c7f7 100644 --- a/examples/simple_webrtc.rs +++ b/examples/simple_webrtc.rs @@ -16,11 +16,11 @@ extern crate servo_media; extern crate websocket; use rand::Rng; -use servo_media::ServoMedia; use servo_media::webrtc::*; +use servo_media::ServoMedia; use std::env; use std::net; -use std::sync::{Arc, mpsc}; +use std::sync::{mpsc, Arc}; use std::thread; use websocket::OwnedMessage; @@ -113,7 +113,9 @@ impl State { self.app_state = AppState::ServerRegistered; // if we know who we want to connect to, request a connection if let Some(ref peer_id) = self.peer_id { - self.send_msg_tx.send(OwnedMessage::Text(format!("SESSION {}", peer_id))).unwrap(); + self.send_msg_tx + .send(OwnedMessage::Text(format!("SESSION {}", peer_id))) + .unwrap(); self.app_state = AppState::PeerConnecting; } else { // else just spin up the RTC object and wait @@ -122,8 +124,10 @@ impl State { } fn handle_session_ok(&mut self) { - assert!(self.peer_id.is_some(), - "SESSION OK should only be received by those attempting to connect to an existing peer"); + assert!( + self.peer_id.is_some(), + "SESSION OK should only be received by those attempting to connect to an existing peer" + ); println!("session is ok; creating webrtc objects"); assert_eq!(self.app_state, AppState::PeerConnecting); self.app_state = AppState::PeerConnected; @@ -137,16 +141,19 @@ impl State { self.signaller = Some(s); let webrtc = self.webrtc.as_ref().unwrap(); let (video, audio) = if self.peer_id.is_some() { - (self - .media - .create_videoinput_stream() - .unwrap_or_else(|| self.media.create_videostream()), - self - .media - .create_audioinput_stream() - .unwrap_or_else(|| self.media.create_audiostream())) + ( + self.media + .create_videoinput_stream() + .unwrap_or_else(|| self.media.create_videostream()), + self.media + .create_audioinput_stream() + .unwrap_or_else(|| self.media.create_audiostream()), + ) } else { - (self.media.create_videostream(), self.media.create_audiostream()) + ( + self.media.create_videostream(), + self.media.create_audiostream(), + ) }; webrtc.add_stream(video); webrtc.add_stream(audio); @@ -157,36 +164,40 @@ impl State { #[derive(Clone)] struct Signaller { sender: mpsc::Sender, - initiate_negotiation: bool + initiate_negotiation: bool, } impl WebRtcSignaller for Signaller { fn close(&self) { - let _ = self.sender.send(OwnedMessage::Close(Some(websocket::message::CloseData { - status_code: 1011, //Internal Error - reason: "explicitly closed".into(), - }))); + let _ = self + .sender + .send(OwnedMessage::Close(Some(websocket::message::CloseData { + status_code: 1011, //Internal Error + reason: "explicitly closed".into(), + }))); } fn on_ice_candidate(&self, _: &WebRtcController, candidate: IceCandidate) { let message = serde_json::to_string(&JsonMsg::Ice { candidate: candidate.candidate, sdp_mline_index: candidate.sdp_mline_index, - }).unwrap(); + }) + .unwrap(); self.sender.send(OwnedMessage::Text(message)).unwrap(); } fn on_negotiation_needed(&self, controller: &WebRtcController) { if !self.initiate_negotiation { - return + return; } let c2 = controller.clone(); let s2 = self.clone(); - controller.create_offer((move |offer: SessionDescription| { - c2.set_local_description(offer.clone(), (move || { - s2.send_sdp(offer) - }).into()) - }).into()); + controller.create_offer( + (move |offer: SessionDescription| { + c2.set_local_description(offer.clone(), (move || s2.send_sdp(offer)).into()) + }) + .into(), + ); } } @@ -195,13 +206,14 @@ impl Signaller { let message = serde_json::to_string(&JsonMsg::Sdp { type_: desc.type_.as_str().into(), sdp: desc.sdp, - }).unwrap(); + }) + .unwrap(); self.sender.send(OwnedMessage::Text(message)).unwrap(); } fn new(sender: mpsc::Sender, initiate_negotiation: bool) -> Self { Signaller { sender, - initiate_negotiation + initiate_negotiation, } } } @@ -254,7 +266,7 @@ fn receive_loop( JsonMsg::Sdp { type_, sdp } => { let desc = SessionDescription { type_: type_.parse().unwrap(), - sdp: sdp.into() + sdp: sdp.into(), }; let controller = state.webrtc.as_ref().unwrap(); if state.peer_id.is_some() { @@ -263,25 +275,37 @@ fn receive_loop( let c2 = controller.clone(); let c3 = controller.clone(); let s2 = state.signaller.clone().unwrap(); - controller.set_remote_description(desc, (move || { - c3.create_answer((move |answer: SessionDescription| { - c2.set_local_description(answer.clone(), (move || { - s2.send_sdp(answer) - }).into()) - }).into()) - }).into()); + controller.set_remote_description( + desc, + (move || { + c3.create_answer( + (move |answer: SessionDescription| { + c2.set_local_description( + answer.clone(), + (move || s2.send_sdp(answer)).into(), + ) + }) + .into(), + ) + }) + .into(), + ); } - - } JsonMsg::Ice { sdp_mline_index, candidate, } => { let candidate = IceCandidate { - sdp_mline_index, candidate + sdp_mline_index, + candidate, }; - state.webrtc.as_ref().unwrap().add_ice_candidate(candidate).into() + state + .webrtc + .as_ref() + .unwrap() + .add_ice_candidate(candidate) + .into() } }; } @@ -329,7 +353,9 @@ fn run_example(servo_media: Arc) { let our_id = rand::thread_rng().gen_range(10, 10_000); println!("Registering id {} with server", our_id); - send_msg_tx.send(OwnedMessage::Text(format!("HELLO {}", our_id))).expect("error sending"); + send_msg_tx + .send(OwnedMessage::Text(format!("HELLO {}", our_id))) + .expect("error sending"); let state = State { app_state: AppState::ServerRegistering, diff --git a/webrtc/src/thread.rs b/webrtc/src/thread.rs index 4d304b08..618d281a 100644 --- a/webrtc/src/thread.rs +++ b/webrtc/src/thread.rs @@ -4,7 +4,7 @@ use std::thread; use boxfnonce::SendBoxFnOnce; use crate::{BundlePolicy, IceCandidate, MediaStream, SessionDescription}; -use crate::{WebRtcControllerBackend, WebRtcSignaller, WebRtcBackend}; +use crate::{WebRtcBackend, WebRtcControllerBackend, WebRtcSignaller}; #[derive(Clone)] /// Entry point for all client webrtc interactions. @@ -32,13 +32,19 @@ impl WebRtcController { t } pub fn configure(&self, stun_server: String, policy: BundlePolicy) { - let _ = self.sender.send(RtcThreadEvent::ConfigureStun(stun_server, policy)); + let _ = self + .sender + .send(RtcThreadEvent::ConfigureStun(stun_server, policy)); } pub fn set_remote_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - let _ = self.sender.send(RtcThreadEvent::SetRemoteDescription(desc, cb)); + let _ = self + .sender + .send(RtcThreadEvent::SetRemoteDescription(desc, cb)); } pub fn set_local_description(&self, desc: SessionDescription, cb: SendBoxFnOnce<'static, ()>) { - let _ = self.sender.send(RtcThreadEvent::SetLocalDescription(desc, cb)); + let _ = self + .sender + .send(RtcThreadEvent::SetLocalDescription(desc, cb)); } pub fn add_ice_candidate(&self, candidate: IceCandidate) { let _ = self.sender.send(RtcThreadEvent::AddIceCandidate(candidate)); @@ -72,7 +78,7 @@ pub enum RtcThreadEvent { CreateAnswer(SendBoxFnOnce<'static, (SessionDescription,)>), AddStream(Box), InternalEvent(InternalEvent), - Quit + Quit, } /// To allow everything to occur on the event loop, @@ -99,7 +105,7 @@ pub fn handle_rtc_event(controller: &mut WebRtcControllerBackend, event: RtcThre RtcThreadEvent::InternalEvent(e) => controller.internal_event(e), RtcThreadEvent::Quit => { controller.quit(); - return false + return false; } } true From ff68fa45ede04d69afa2a77ae4a9d5d18411bd4c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 25 Jan 2019 15:39:09 -0800 Subject: [PATCH 35/35] remove failure. only success remains. --- Cargo.lock | 64 -------------------------------- backends/gstreamer/Cargo.toml | 3 -- backends/gstreamer/src/lib.rs | 1 - backends/gstreamer/src/webrtc.rs | 6 +-- 4 files changed, 3 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44b779b2..cabc39e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,27 +77,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "backtrace" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.5.2" @@ -475,26 +454,6 @@ dependencies = [ "winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fixedbitset" version = "0.1.9" @@ -1556,11 +1515,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-demangle" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rusttype" version = "0.7.3" @@ -1706,7 +1660,6 @@ version = "0.1.0" dependencies = [ "boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1845,17 +1798,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synstructure" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tempdir" version = "0.3.7" @@ -2454,8 +2396,6 @@ dependencies = [ "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" -"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff" @@ -2500,8 +2440,6 @@ dependencies = [ "checksum env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d7e69c283751083d53d01eac767407343b8b69c4bd70058e08adc2637cb257" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2ebdf55fb9d6329046e026329a55ef8fbaae5ea833f56e170beb3125a8a5f" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -2612,7 +2550,6 @@ dependencies = [ "checksum regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbbea44c5490a1e84357ff28b7d518b4619a159fed5d25f6c1de2d19cc42814" "checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rusttype 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "436c67ae0d0d24f14e1177c3ed96780ee16db82b405f0fba1bb80b46c9a30625" "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" @@ -2637,7 +2574,6 @@ dependencies = [ "checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" "checksum syn 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e13df71f29f9440b50261a5882c86eac334f1badb3134ec26f0de2f1418e44" "checksum syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3391038ebc3e4ab24eb028cb0ef2f2dc4ba0cbf72ee895ed6a6fad730640b5bc" -"checksum synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec37f4fab4bafaf6b5621c1d54e6aa5d4d059a8f84929e87abfdd7f9f04c6db2" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 65ec7915..82407e1f 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -16,9 +16,6 @@ version = "0.2" [dependencies.glib] version = "0.6" -[dependencies.failure] -version = "*" - [dependencies.glib-sys] version = "0.7" diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 96df86f0..70015729 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -1,7 +1,6 @@ extern crate boxfnonce; extern crate byte_slice_cast; -extern crate failure; #[macro_use] extern crate glib; extern crate glib_sys as glib_ffi; diff --git a/backends/gstreamer/src/webrtc.rs b/backends/gstreamer/src/webrtc.rs index 56547c54..9f5372bb 100644 --- a/backends/gstreamer/src/webrtc.rs +++ b/backends/gstreamer/src/webrtc.rs @@ -1,5 +1,4 @@ use boxfnonce::SendBoxFnOnce; -use failure::Error; use glib::{self, ObjectExt}; use gst::{self, BinExt, BinExtManual, ElementExt, GObjectExtManualGst, PadDirection, PadExt}; use gst_sdp; @@ -9,9 +8,10 @@ use servo_media_webrtc::thread::InternalEvent; use servo_media_webrtc::WebRtcController as WebRtcThread; use servo_media_webrtc::*; use std::sync::Mutex; +use std::error::Error; // TODO: -// - remove use of failure? +// - add a proper error enum // - figure out purpose of glib loop #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -308,7 +308,7 @@ fn handle_media_stream( pad: &gst::Pad, pipe: &gst::Pipeline, media_type: MediaType, -) -> Result<(), Error> { +) -> Result<(), Box> { println!("Trying to handle stream {:?}", media_type); let (q, conv, sink) = match media_type {