diff --git a/Cargo.lock b/Cargo.lock index c77ae4e6..b4e6dc6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -352,7 +352,7 @@ dependencies = [ "hex", "http 0.2.12", "hyper 0.14.28", - "ring", + "ring 0.17.8", "time", "tokio", "tracing", @@ -611,7 +611,7 @@ dependencies = [ "once_cell", "p256", "percent-encoding", - "ring", + "ring 0.17.8", "sha2", "subtle", "time", @@ -1744,7 +1744,7 @@ dependencies = [ "futures-core", "futures-sink", "nanorand", - "spin", + "spin 0.9.8", ] [[package]] @@ -2208,11 +2208,11 @@ dependencies = [ "byte-slice-cast", "ebur128", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "hrtf", "nnnoiseless", "num-traits", @@ -2239,10 +2239,10 @@ dependencies = [ "futures", "gio", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", "percent-encoding", "rand", @@ -2261,9 +2261,9 @@ dependencies = [ "cdg", "cdg_renderer", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "image", "once_cell", @@ -2277,9 +2277,9 @@ dependencies = [ "byte-slice-cast", "claxon", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", ] @@ -2296,9 +2296,9 @@ dependencies = [ "chrono", "either", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", "pango", @@ -2319,10 +2319,10 @@ dependencies = [ "byte-slice-cast", "csound", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", ] @@ -2332,8 +2332,8 @@ version = "0.13.0-alpha.1" dependencies = [ "dav1d", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "num_cpus", "once_cell", @@ -2346,11 +2346,11 @@ dependencies = [ "gio", "gst-plugin-gtk4", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "gtk4", "once_cell", @@ -2364,8 +2364,8 @@ dependencies = [ "byte-slice-cast", "ffv1", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", ] @@ -2375,8 +2375,8 @@ name = "gst-plugin-file" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", "url", ] @@ -2388,9 +2388,9 @@ dependencies = [ "byteorder", "flavors", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "nom", "num-rational", "once_cell", @@ -2405,11 +2405,11 @@ dependencies = [ "chrono", "dash-mpd", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-pbutils", "gstreamer-video", "m3u8-rs", @@ -2425,8 +2425,8 @@ dependencies = [ "atomic_refcell", "gif", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", ] @@ -2437,9 +2437,9 @@ version = "0.13.0-alpha.1" dependencies = [ "anyhow", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", ] @@ -2453,9 +2453,9 @@ dependencies = [ "gdk4-win32", "gdk4-x11", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-allocators", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-gl", "gstreamer-gl-egl", "gstreamer-gl-wayland", @@ -2474,10 +2474,10 @@ dependencies = [ "chrono", "gio", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-pbutils", "gstreamer-video", "m3u8-rs", @@ -2491,10 +2491,10 @@ version = "0.13.0-alpha.1" dependencies = [ "byte-slice-cast", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "num-traits", "once_cell", @@ -2507,9 +2507,9 @@ dependencies = [ "anyhow", "futures", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-utils", "once_cell", "pretty_assertions", @@ -2523,8 +2523,8 @@ name = "gst-plugin-json" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", "serde", "serde_json", @@ -2537,9 +2537,9 @@ dependencies = [ "atomic_refcell", "byte-slice-cast", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "lewton", "once_cell", ] @@ -2551,9 +2551,9 @@ dependencies = [ "gio", "gst-plugin-gtk4", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gtk4", "num-rational", "once_cell", @@ -2566,9 +2566,9 @@ version = "0.13.0-alpha.1" dependencies = [ "anyhow", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-pbutils", "gstreamer-video", "once_cell", @@ -2587,9 +2587,9 @@ dependencies = [ "data-encoding", "glib", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "libloading", "once_cell", @@ -2605,8 +2605,8 @@ dependencies = [ "cairo-rs", "chrono", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-rtp", "gstreamer-video", "once_cell", @@ -2623,7 +2623,7 @@ dependencies = [ "atomic_refcell", "glib", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", ] @@ -2633,22 +2633,42 @@ name = "gst-plugin-png" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", "parking_lot", "png", ] +[[package]] +name = "gst-plugin-quic" +version = "0.13.0-alpha.1" +dependencies = [ + "bytes", + "futures", + "gst-plugin-version-helper", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", + "once_cell", + "quinn", + "rcgen", + "rustls", + "rustls-pemfile 1.0.4", + "serial_test", + "thiserror", + "tokio", +] + [[package]] name = "gst-plugin-raptorq" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-rtp", "once_cell", "rand", @@ -2661,8 +2681,8 @@ version = "0.13.0-alpha.1" dependencies = [ "atomic_refcell", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "once_cell", "rav1e", @@ -2673,8 +2693,8 @@ name = "gst-plugin-regex" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", "regex", ] @@ -2686,8 +2706,8 @@ dependencies = [ "bytes", "futures", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "headers 0.4.0", "http-body-util", "hyper 1.3.1", @@ -2709,10 +2729,10 @@ dependencies = [ "byte-slice-cast", "chrono", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-rtp", "gstreamer-video", "hex", @@ -2734,7 +2754,7 @@ dependencies = [ "data-encoding", "futures", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-net", "gstreamer-pbutils", @@ -2755,10 +2775,10 @@ version = "0.13.0-alpha.1" dependencies = [ "clap", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", - "gstreamer-base", - "gstreamer-check", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "hex", "once_cell", "pretty_assertions", @@ -2776,8 +2796,8 @@ dependencies = [ "anyhow", "futures", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "librespot", "once_cell", "tokio", @@ -2789,7 +2809,7 @@ name = "gst-plugin-textahead" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", ] @@ -2798,8 +2818,8 @@ name = "gst-plugin-textwrap" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "hyphenation", "once_cell", "textwrap", @@ -2818,10 +2838,10 @@ dependencies = [ "futures", "gio", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-net", "gstreamer-rtp", "once_cell", @@ -2844,9 +2864,9 @@ dependencies = [ "gio", "gst-plugin-gtk4", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-check", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "gtk4", "once_cell", @@ -2859,7 +2879,7 @@ version = "0.13.0-alpha.1" dependencies = [ "anyhow", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "once_cell", "regex", "signal-hook", @@ -2871,9 +2891,9 @@ version = "0.13.0-alpha.1" dependencies = [ "byte-slice-cast", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "num-traits", "once_cell", @@ -2886,7 +2906,7 @@ dependencies = [ "anyhow", "clap", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "more-asserts", "once_cell", @@ -2912,9 +2932,9 @@ dependencies = [ "color-thief", "dssim-core", "gst-plugin-version-helper", - "gstreamer", - "gstreamer-base", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "image", "image_hasher", @@ -2927,8 +2947,8 @@ name = "gst-plugin-webp" version = "0.13.0-alpha.1" dependencies = [ "gst-plugin-version-helper", - "gstreamer", - "gstreamer-check", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video", "libwebp-sys2", "once_cell", @@ -2959,10 +2979,10 @@ dependencies = [ "gst-plugin-rtp", "gst-plugin-version-helper", "gst-plugin-webrtc-signalling-protocol", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-audio", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-net", "gstreamer-rtp", "gstreamer-sdp", @@ -3031,7 +3051,7 @@ dependencies = [ "bytes", "futures", "gst-plugin-version-helper", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-sdp", "gstreamer-webrtc", "once_cell", @@ -3050,7 +3070,7 @@ dependencies = [ "futures-core", "futures-util", "glib", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "itertools 0.12.1", "libc", "muldiv", @@ -3066,13 +3086,37 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gstreamer" +version = "0.23.0" +source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs#b7b5352353e147fccc00ff684dffb65c21a6e6b1" +dependencies = [ + "cfg-if", + "futures-channel", + "futures-core", + "futures-util", + "glib", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", + "itertools 0.12.1", + "libc", + "muldiv", + "num-integer", + "num-rational", + "once_cell", + "option-operations", + "paste", + "pin-project-lite", + "smallvec", + "thiserror", +] + [[package]] name = "gstreamer-allocators" version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-allocators-sys", "libc", "once_cell", @@ -3085,7 +3129,7 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gobject-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3098,9 +3142,9 @@ dependencies = [ "futures-core", "futures-sink", "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app-sys", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", ] @@ -3110,8 +3154,8 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib-sys", - "gstreamer-base-sys", - "gstreamer-sys", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3123,9 +3167,9 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "cfg-if", "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio-sys", - "gstreamer-base", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "once_cell", "serde", @@ -3139,8 +3183,8 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gobject-sys", - "gstreamer-base-sys", - "gstreamer-sys", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3153,8 +3197,21 @@ dependencies = [ "atomic_refcell", "cfg-if", "glib", - "gstreamer", - "gstreamer-base-sys", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "libc", +] + +[[package]] +name = "gstreamer-base" +version = "0.23.0" +source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs#b7b5352353e147fccc00ff684dffb65c21a6e6b1" +dependencies = [ + "atomic_refcell", + "cfg-if", + "glib", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", "libc", ] @@ -3165,7 +3222,19 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gobject-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-base-sys" +version = "0.23.0" +source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs#b7b5352353e147fccc00ff684dffb65c21a6e6b1" +dependencies = [ + "glib-sys", + "gobject-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", "libc", "system-deps", ] @@ -3176,8 +3245,18 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", - "gstreamer-check-sys", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-check-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", +] + +[[package]] +name = "gstreamer-check" +version = "0.23.0" +source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs#b7b5352353e147fccc00ff684dffb65c21a6e6b1" +dependencies = [ + "glib", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", + "gstreamer-check-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", ] [[package]] @@ -3187,7 +3266,19 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gobject-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-check-sys" +version = "0.23.0" +source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs#b7b5352353e147fccc00ff684dffb65c21a6e6b1" +dependencies = [ + "glib-sys", + "gobject-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs)", "libc", "system-deps", ] @@ -3198,8 +3289,8 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-gl-sys", "gstreamer-video", "libc", @@ -3212,7 +3303,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-gl", "gstreamer-gl-egl-sys", "libc", @@ -3236,8 +3327,8 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gobject-sys", - "gstreamer-base-sys", - "gstreamer-sys", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video-sys", "libc", "system-deps", @@ -3249,7 +3340,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-gl", "gstreamer-gl-wayland-sys", "libc", @@ -3272,7 +3363,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-gl", "gstreamer-gl-x11-sys", "libc", @@ -3296,7 +3387,7 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "gio", "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-net-sys", ] @@ -3307,7 +3398,7 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "gio-sys", "glib-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3318,7 +3409,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-audio", "gstreamer-pbutils-sys", "gstreamer-video", @@ -3334,7 +3425,7 @@ dependencies = [ "glib-sys", "gobject-sys", "gstreamer-audio-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video-sys", "libc", "system-deps", @@ -3346,7 +3437,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-rtp-sys", "libc", ] @@ -3357,8 +3448,8 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib-sys", - "gstreamer-base-sys", - "gstreamer-sys", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3369,7 +3460,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-sdp-sys", ] @@ -3379,7 +3470,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3395,12 +3486,23 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gstreamer-sys" +version = "0.23.0" +source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs#b7b5352353e147fccc00ff684dffb65c21a6e6b1" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "gstreamer-utils" version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-app", "gstreamer-video", "once_cell", @@ -3415,8 +3517,8 @@ dependencies = [ "cfg-if", "futures-channel", "glib", - "gstreamer", - "gstreamer-base", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-base 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-video-sys", "libc", "once_cell", @@ -3431,8 +3533,8 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gobject-sys", - "gstreamer-base-sys", - "gstreamer-sys", + "gstreamer-base-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3443,7 +3545,7 @@ version = "0.23.0" source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main#e117010bc001f87551713c528bf3abff5c9848ae" dependencies = [ "glib", - "gstreamer", + "gstreamer 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "gstreamer-sdp", "gstreamer-webrtc-sys", "libc", @@ -3456,7 +3558,7 @@ source = "git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main# dependencies = [ "glib-sys", "gstreamer-sdp-sys", - "gstreamer-sys", + "gstreamer-sys 0.23.0 (git+https://gitlab.freedesktop.org/gstreamer/gstreamer-rs?branch=main)", "libc", "system-deps", ] @@ -3783,7 +3885,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -4113,7 +4215,7 @@ checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" dependencies = [ "base64 0.21.7", "js-sys", - "ring", + "ring 0.17.8", "serde", "serde_json", ] @@ -4606,7 +4708,7 @@ dependencies = [ "log", "memchr", "mime", - "spin", + "spin 0.9.8", "version_check", ] @@ -5045,6 +5147,16 @@ dependencies = [ "hmac 0.11.0", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.0", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -5272,7 +5384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", - "heck 0.4.1", + "heck 0.5.0", "itertools 0.12.1", "log", "multimap 0.10.0", @@ -5359,6 +5471,54 @@ dependencies = [ "serde", ] +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand", + "ring 0.16.20", + "rustc-hash", + "rustls", + "rustls-native-certs", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2 0.5.6", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -5470,6 +5630,18 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rcgen" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48406db8ac1f3cbc7dcdb56ec355343817958a356ff430259bb07baf7607e1e1" +dependencies = [ + "pem", + "ring 0.17.8", + "time", + "yasna", +] + [[package]] name = "realfft" version = "3.3.0" @@ -5644,6 +5816,21 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -5654,8 +5841,8 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -5711,6 +5898,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -5764,7 +5957,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -5812,8 +6005,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -5867,8 +6060,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -6212,6 +6405,12 @@ dependencies = [ "serde", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -6821,6 +7020,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -7329,6 +7534,15 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zerocopy" version = "0.6.6" diff --git a/Cargo.toml b/Cargo.toml index 9d803a18..8b68ca78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ members = [ "net/webrtc", "net/webrtc/protocol", "net/webrtc/signalling", + "net/quic", "text/ahead", "text/json", diff --git a/net/quic/Cargo.toml b/net/quic/Cargo.toml new file mode 100644 index 00000000..f2b486c3 --- /dev/null +++ b/net/quic/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "gst-plugin-quic" +version.workspace = true +authors = ["Sanchayan Maity +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 +#![allow(clippy::non_send_fields_in_send_ty, unused_doc_comments)] + +/** + * plugin-quic: + * + * Since: plugins-rs-0.11.0 + */ +use gst::glib; +mod quicsink; +mod quicsrc; +mod utils; + +fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + quicsink::register(plugin)?; + quicsrc::register(plugin)?; + + Ok(()) +} + +gst::plugin_define!( + quic, + env!("CARGO_PKG_DESCRIPTION"), + plugin_init, + concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")), + "MPL", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_REPOSITORY"), + env!("BUILD_REL_DATE") +); diff --git a/net/quic/src/quicsink/imp.rs b/net/quic/src/quicsink/imp.rs new file mode 100644 index 00000000..ee53b804 --- /dev/null +++ b/net/quic/src/quicsink/imp.rs @@ -0,0 +1,472 @@ +// Copyright (C) 2024, Asymptotic Inc. +// Author: Sanchayan Maity +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use crate::utils::{ + client_endpoint, make_socket_addr, wait, WaitError, CONNECTION_CLOSE_CODE, CONNECTION_CLOSE_MSG, +}; +use bytes::Bytes; +use futures::future; +use gst::{glib, prelude::*, subclass::prelude::*}; +use gst_base::subclass::prelude::*; +use once_cell::sync::Lazy; +use quinn::{Connection, SendStream}; +use std::net::SocketAddr; +use std::sync::Mutex; + +static DEFAULT_SERVER_NAME: &str = "localhost"; +static DEFAULT_SERVER_ADDR: &str = "127.0.0.1:5000"; +static DEFAULT_CLIENT_ADDR: &str = "127.0.0.1:5001"; +const DEFAULT_TIMEOUT: u32 = 15; +const DEFAULT_SECURE_CONNECTION: bool = true; + +static CAT: Lazy = Lazy::new(|| { + gst::DebugCategory::new("quicsink", gst::DebugColorFlags::empty(), Some("QUIC Sink")) +}); + +struct Started { + connection: Connection, + stream: Option, +} + +#[derive(Default)] +enum State { + #[default] + Stopped, + Started(Started), +} + +#[derive(Clone, Debug)] +struct Settings { + client_address: SocketAddr, + server_address: SocketAddr, + server_name: String, + timeout: u32, + secure_conn: bool, + use_datagram: bool, +} + +impl Default for Settings { + fn default() -> Self { + Settings { + client_address: DEFAULT_CLIENT_ADDR.parse::().unwrap(), + server_address: DEFAULT_SERVER_ADDR.parse::().unwrap(), + server_name: DEFAULT_SERVER_NAME.to_string(), + timeout: DEFAULT_TIMEOUT, + secure_conn: DEFAULT_SECURE_CONNECTION, + use_datagram: false, + } + } +} + +pub struct QuicSink { + settings: Mutex, + state: Mutex, + canceller: Mutex>, +} + +impl Default for QuicSink { + fn default() -> Self { + Self { + settings: Mutex::new(Settings::default()), + state: Mutex::new(State::default()), + canceller: Mutex::new(None), + } + } +} + +impl GstObjectImpl for QuicSink {} + +impl ElementImpl for QuicSink { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "QUIC Sink", + "Source/Network/QUIC", + "Send data over the network via QUIC", + "Sanchayan Maity ", + ) + }); + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy> = Lazy::new(|| { + let sink_pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &gst::Caps::new_any(), + ) + .unwrap(); + + vec![sink_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } +} + +impl ObjectImpl for QuicSink { + fn constructed(&self) { + self.parent_constructed(); + } + + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![ + glib::ParamSpecString::builder("server-name") + .nick("QUIC server name") + .blurb("Name of the QUIC server which is in server certificate") + .build(), + glib::ParamSpecString::builder("server-address") + .nick("QUIC server address") + .blurb("Address of the QUIC server to connect to e.g. 127.0.0.1:5000") + .build(), + glib::ParamSpecString::builder("client-address") + .nick("QUIC client address") + .blurb("Address to be used by this QUIC client e.g. 127.0.0.1:5001") + .build(), + glib::ParamSpecUInt::builder("timeout") + .nick("Timeout") + .blurb("Value in seconds to timeout QUIC endpoint requests (0 = No timeout).") + .maximum(3600) + .default_value(DEFAULT_TIMEOUT) + .readwrite() + .build(), + glib::ParamSpecBoolean::builder("secure-connection") + .nick("Use secure connection") + .blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.") + .default_value(DEFAULT_SECURE_CONNECTION) + .build(), + glib::ParamSpecBoolean::builder("use-datagram") + .nick("Use datagram") + .blurb("Use datagram for lower latency, unreliable messaging") + .default_value(false) + .build(), + ] + }); + + PROPERTIES.as_ref() + } + + fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + match pspec.name() { + "server-name" => { + let mut settings = self.settings.lock().unwrap(); + settings.server_name = value.get::().expect("type checked upstream"); + } + "server-address" => { + let addr = value.get::().expect("type checked upstream"); + let addr = make_socket_addr(&addr); + match addr { + Ok(server_address) => { + let mut settings = self.settings.lock().unwrap(); + settings.server_address = server_address; + } + Err(e) => gst::element_imp_error!( + self, + gst::ResourceError::Failed, + ["Invalid server address: {}", e] + ), + } + } + "client-address" => { + let addr = value.get::().expect("type checked upstream"); + let addr = make_socket_addr(&addr); + match addr { + Ok(client_address) => { + let mut settings = self.settings.lock().unwrap(); + settings.client_address = client_address; + } + Err(e) => gst::element_imp_error!( + self, + gst::ResourceError::Failed, + ["Invalid client address: {}", e] + ), + } + } + "timeout" => { + let mut settings = self.settings.lock().unwrap(); + settings.timeout = value.get().expect("type checked upstream"); + } + "secure-connection" => { + let mut settings = self.settings.lock().unwrap(); + settings.secure_conn = value.get().expect("type checked upstream"); + } + "use-datagram" => { + let mut settings = self.settings.lock().unwrap(); + settings.use_datagram = value.get().expect("type checked upstream"); + } + _ => unimplemented!(), + } + } + + fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + match pspec.name() { + "server-name" => { + let settings = self.settings.lock().unwrap(); + settings.server_name.to_value() + } + "server-address" => { + let settings = self.settings.lock().unwrap(); + settings.server_address.to_string().to_value() + } + "client-address" => { + let settings = self.settings.lock().unwrap(); + settings.client_address.to_string().to_value() + } + "timeout" => { + let settings = self.settings.lock().unwrap(); + settings.timeout.to_value() + } + "secure-connection" => { + let settings = self.settings.lock().unwrap(); + settings.secure_conn.to_value() + } + "use-datagram" => { + let settings = self.settings.lock().unwrap(); + settings.use_datagram.to_value() + } + _ => unimplemented!(), + } + } +} + +#[glib::object_subclass] +impl ObjectSubclass for QuicSink { + const NAME: &'static str = "GstQUICSink"; + type Type = super::QuicSink; + type ParentType = gst_base::BaseSink; +} + +impl BaseSinkImpl for QuicSink { + fn start(&self) -> Result<(), gst::ErrorMessage> { + let settings = self.settings.lock().unwrap(); + let timeout = settings.timeout; + drop(settings); + + let mut state = self.state.lock().unwrap(); + + if let State::Started { .. } = *state { + unreachable!("QuicSink is already started"); + } + + match wait(&self.canceller, self.establish_connection(), timeout) { + Ok(Ok((c, s))) => { + *state = State::Started(Started { + connection: c, + stream: s, + }); + + gst::info!(CAT, imp: self, "Started"); + + Ok(()) + } + Ok(Err(e)) => match e { + WaitError::FutureAborted => { + gst::warning!(CAT, imp: self, "Connection aborted"); + Ok(()) + } + WaitError::FutureError(err) => { + gst::error!(CAT, imp: self, "Connection request failed: {}", err); + Err(gst::error_msg!( + gst::ResourceError::Failed, + ["Connection request failed: {}", err] + )) + } + }, + Err(e) => { + gst::error!(CAT, imp: self, "Failed to establish a connection: {:?}", e); + Err(gst::error_msg!( + gst::ResourceError::Failed, + ["Failed to establish a connection: {:?}", e] + )) + } + } + } + + fn stop(&self) -> Result<(), gst::ErrorMessage> { + let settings = self.settings.lock().unwrap(); + let timeout = settings.timeout; + let use_datagram = settings.use_datagram; + drop(settings); + + let mut state = self.state.lock().unwrap(); + + if let State::Started(ref mut state) = *state { + let connection = &state.connection; + let mut close_msg = CONNECTION_CLOSE_MSG.to_string(); + + if !use_datagram { + let send = &mut state.stream.as_mut().unwrap(); + + // Shutdown stream gracefully + match wait(&self.canceller, send.finish(), timeout) { + Ok(r) => { + if let Err(e) = r { + close_msg = format!("Stream finish request error: {}", e); + gst::error!(CAT, imp: self, "{}", close_msg); + } + } + Err(e) => match e { + WaitError::FutureAborted => { + close_msg = "Stream finish request aborted".to_string(); + gst::warning!(CAT, imp: self, "{}", close_msg); + } + WaitError::FutureError(e) => { + close_msg = format!("Stream finish request future error: {}", e); + gst::error!(CAT, imp: self, "{}", close_msg); + } + }, + }; + } + + connection.close(CONNECTION_CLOSE_CODE.into(), close_msg.as_bytes()); + } + + *state = State::Stopped; + + gst::info!(CAT, imp: self, "Stopped"); + + Ok(()) + } + + fn render(&self, buffer: &gst::Buffer) -> Result { + if let State::Stopped = *self.state.lock().unwrap() { + gst::element_imp_error!(self, gst::CoreError::Failed, ["Not started yet"]); + return Err(gst::FlowError::Error); + } + + gst::trace!(CAT, imp: self, "Rendering {:?}", buffer); + + let map = buffer.map_readable().map_err(|_| { + gst::element_imp_error!(self, gst::CoreError::Failed, ["Failed to map buffer"]); + gst::FlowError::Error + })?; + + match self.send_buffer(&map) { + Ok(_) => Ok(gst::FlowSuccess::Ok), + Err(err) => match err { + Some(error_message) => { + gst::error!(CAT, imp: self, "Data sending failed: {}", error_message); + self.post_error_message(error_message); + Err(gst::FlowError::Error) + } + _ => { + gst::info!(CAT, imp: self, "Send interrupted. Flushing..."); + Err(gst::FlowError::Flushing) + } + }, + } + } +} + +impl QuicSink { + fn send_buffer(&self, src: &[u8]) -> Result<(), Option> { + let settings = self.settings.lock().unwrap(); + let timeout = settings.timeout; + let use_datagram = settings.use_datagram; + drop(settings); + + let mut state = self.state.lock().unwrap(); + + let (conn, stream) = match *state { + State::Started(Started { + ref connection, + ref mut stream, + }) => (connection, stream), + State::Stopped => { + return Err(Some(gst::error_msg!( + gst::LibraryError::Failed, + ["Cannot send before start()"] + ))); + } + }; + + if use_datagram { + match conn.send_datagram(Bytes::copy_from_slice(src)) { + Ok(_) => Ok(()), + Err(e) => Err(Some(gst::error_msg!( + gst::ResourceError::Failed, + ["Sending data failed: {}", e] + ))), + } + } else { + let send = &mut stream.as_mut().unwrap(); + + match wait(&self.canceller, send.write_all(src), timeout) { + Ok(Ok(_)) => Ok(()), + Ok(Err(e)) => Err(Some(gst::error_msg!( + gst::ResourceError::Failed, + ["Sending data failed: {}", e] + ))), + Err(e) => match e { + WaitError::FutureAborted => { + gst::warning!(CAT, imp: self, "Sending aborted"); + Ok(()) + } + WaitError::FutureError(e) => Err(Some(gst::error_msg!( + gst::ResourceError::Failed, + ["Sending data failed: {}", e] + ))), + }, + } + } + } + + async fn establish_connection(&self) -> Result<(Connection, Option), WaitError> { + let client_addr; + let server_addr; + let server_name; + let use_datagram; + let secure_conn; + + { + let settings = self.settings.lock().unwrap(); + client_addr = settings.client_address; + server_addr = settings.server_address; + server_name = settings.server_name.clone(); + use_datagram = settings.use_datagram; + secure_conn = settings.secure_conn; + } + + let endpoint = client_endpoint(client_addr, secure_conn).map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Failed to configure endpoint: {}", err] + )) + })?; + + let connection = endpoint + .connect(server_addr, &server_name) + .unwrap() + .await + .map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Connection error: {}", err] + )) + })?; + + let stream = if !use_datagram { + let res = connection.open_uni().await.map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Failed to open stream: {}", err] + )) + })?; + + Some(res) + } else { + None + }; + + Ok((connection, stream)) + } +} diff --git a/net/quic/src/quicsink/mod.rs b/net/quic/src/quicsink/mod.rs new file mode 100644 index 00000000..728932ae --- /dev/null +++ b/net/quic/src/quicsink/mod.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2024, Asymptotic Inc. +// Author: Sanchayan Maity +//G +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use gst::glib; +use gst::prelude::*; + +pub mod imp; + +glib::wrapper! { + pub struct QuicSink(ObjectSubclass) @extends gst_base::BaseSink, gst::Element, gst::Object; +} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "quicsink", + gst::Rank::MARGINAL, + QuicSink::static_type(), + ) +} diff --git a/net/quic/src/quicsrc/imp.rs b/net/quic/src/quicsrc/imp.rs new file mode 100644 index 00000000..3dc666a3 --- /dev/null +++ b/net/quic/src/quicsrc/imp.rs @@ -0,0 +1,583 @@ +// Copyright (C) 2024, Asymptotic Inc. +// Author: Sanchayan Maity +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use super::QuicPrivateKeyType; +use crate::utils::{ + make_socket_addr, server_endpoint, wait, WaitError, CONNECTION_CLOSE_CODE, CONNECTION_CLOSE_MSG, +}; +use bytes::Bytes; +use futures::future; +use gst::{glib, prelude::*, subclass::prelude::*}; +use gst_base::prelude::*; +use gst_base::subclass::base_src::CreateSuccess; +use gst_base::subclass::prelude::*; +use once_cell::sync::Lazy; +use quinn::{Connection, ConnectionError, RecvStream}; +use std::net::SocketAddr; +use std::path::PathBuf; +use std::sync::Mutex; + +static DEFAULT_SERVER_NAME: &str = "localhost"; +static DEFAULT_SERVER_ADDR: &str = "127.0.0.1:5000"; +const DEFAULT_TIMEOUT: u32 = 15; +const DEFAULT_PRIVATE_KEY_TYPE: QuicPrivateKeyType = QuicPrivateKeyType::Pkcs8; +const DEFAULT_SECURE_CONNECTION: bool = true; + +static CAT: Lazy = Lazy::new(|| { + gst::DebugCategory::new( + "quicsrc", + gst::DebugColorFlags::empty(), + Some("QUIC Source"), + ) +}); + +struct Started { + connection: Connection, + stream: Option, +} + +#[derive(Default)] +enum State { + #[default] + Stopped, + Started(Started), +} + +#[derive(Clone, Debug)] +struct Settings { + server_address: SocketAddr, + server_name: String, + timeout: u32, + secure_conn: bool, + caps: gst::Caps, + use_datagram: bool, + certificate_path: Option, + private_key_type: QuicPrivateKeyType, +} + +impl Default for Settings { + fn default() -> Self { + Settings { + server_address: DEFAULT_SERVER_ADDR.parse::().unwrap(), + server_name: DEFAULT_SERVER_NAME.to_string(), + timeout: DEFAULT_TIMEOUT, + secure_conn: DEFAULT_SECURE_CONNECTION, + caps: gst::Caps::new_any(), + use_datagram: false, + certificate_path: None, + private_key_type: DEFAULT_PRIVATE_KEY_TYPE, + } + } +} + +pub struct QuicSrc { + settings: Mutex, + state: Mutex, + canceller: Mutex>, +} + +impl Default for QuicSrc { + fn default() -> Self { + Self { + settings: Mutex::new(Settings::default()), + state: Mutex::new(State::default()), + canceller: Mutex::new(None), + } + } +} + +impl GstObjectImpl for QuicSrc {} + +impl ElementImpl for QuicSrc { + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy = Lazy::new(|| { + #[cfg(feature = "doc")] + QuicPrivateKeyType::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); + gst::subclass::ElementMetadata::new( + "QUIC Source", + "Source/Network/QUIC", + "Receive data over the network via QUIC", + "Sanchayan Maity ", + ) + }); + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy> = Lazy::new(|| { + let sink_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &gst::Caps::new_any(), + ) + .unwrap(); + + vec![sink_pad_template] + }); + + PAD_TEMPLATES.as_ref() + } + + fn change_state( + &self, + transition: gst::StateChange, + ) -> Result { + if transition == gst::StateChange::NullToReady { + let settings = self.settings.lock().unwrap(); + + /* + * Fail the state change if a secure connection was requested but + * no certificate path was provided. + */ + if settings.secure_conn && settings.certificate_path.is_none() { + gst::error!( + CAT, + imp: self, + "Certificate path not provided for secure connection" + ); + return Err(gst::StateChangeError); + } + } + + self.parent_change_state(transition) + } +} + +impl ObjectImpl for QuicSrc { + fn constructed(&self) { + self.parent_constructed(); + self.obj().set_format(gst::Format::Bytes); + } + + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![ + glib::ParamSpecString::builder("server-name") + .nick("QUIC server name") + .blurb("Name of the QUIC server which is in server certificate") + .build(), + glib::ParamSpecString::builder("server-address") + .nick("QUIC server address") + .blurb("Address of the QUIC server to connect to e.g. 127.0.0.1:5000") + .build(), + glib::ParamSpecUInt::builder("timeout") + .nick("Timeout") + .blurb("Value in seconds to timeout QUIC endpoint requests (0 = No timeout).") + .maximum(3600) + .default_value(DEFAULT_TIMEOUT) + .readwrite() + .build(), + glib::ParamSpecBoolean::builder("secure-connection") + .nick("Use secure connection") + .blurb("Use certificates for QUIC connection. False: Insecure connection, True: Secure connection.") + .default_value(DEFAULT_SECURE_CONNECTION) + .build(), + glib::ParamSpecString::builder("certificate-path") + .nick("Certificate Path") + .blurb("Path where the certificate files cert.pem and privkey.pem are stored") + .build(), + glib::ParamSpecBoxed::builder::("caps") + .nick("caps") + .blurb("The caps of the source pad") + .build(), + glib::ParamSpecBoolean::builder("use-datagram") + .nick("Use datagram") + .blurb("Use datagram for lower latency, unreliable messaging") + .default_value(false) + .build(), + glib::ParamSpecEnum::builder_with_default::("private-key-type", DEFAULT_PRIVATE_KEY_TYPE) + .nick("Whether PKCS8 or RSA key type is considered for private key") + .blurb("Read given private key as PKCS8 or RSA") + .build(), + ] + }); + + PROPERTIES.as_ref() + } + + fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + match pspec.name() { + "server-name" => { + let mut settings = self.settings.lock().unwrap(); + settings.server_name = value.get::().expect("type checked upstream"); + } + "server-address" => { + let addr = value.get::().expect("type checked upstream"); + let addr = make_socket_addr(&addr); + match addr { + Ok(server_address) => { + let mut settings = self.settings.lock().unwrap(); + settings.server_address = server_address; + } + Err(e) => gst::element_imp_error!( + self, + gst::ResourceError::Failed, + ["Invalid server address: {}", e] + ), + } + } + "caps" => { + let mut settings = self.settings.lock().unwrap(); + settings.caps = value + .get::>() + .expect("type checked upstream") + .unwrap_or_else(gst::Caps::new_any); + + let srcpad = self.obj().static_pad("src").expect("source pad expected"); + srcpad.mark_reconfigure(); + } + "timeout" => { + let mut settings = self.settings.lock().unwrap(); + settings.timeout = value.get().expect("type checked upstream"); + } + "secure-connection" => { + let mut settings = self.settings.lock().unwrap(); + settings.secure_conn = value.get().expect("type checked upstream"); + } + "certificate-path" => { + let value: String = value.get().unwrap(); + let mut settings = self.settings.lock().unwrap(); + settings.certificate_path = Some(value.into()); + } + "use-datagram" => { + let mut settings = self.settings.lock().unwrap(); + settings.use_datagram = value.get().expect("type checked upstream"); + } + "private-key-type" => { + let mut settings = self.settings.lock().unwrap(); + settings.private_key_type = value + .get::() + .expect("type checked upstream"); + } + _ => unimplemented!(), + } + } + + fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + match pspec.name() { + "server-name" => { + let settings = self.settings.lock().unwrap(); + settings.server_name.to_value() + } + "server-address" => { + let settings = self.settings.lock().unwrap(); + settings.server_address.to_string().to_value() + } + "caps" => { + let settings = self.settings.lock().unwrap(); + settings.caps.to_value() + } + "timeout" => { + let settings = self.settings.lock().unwrap(); + settings.timeout.to_value() + } + "secure-connection" => { + let settings = self.settings.lock().unwrap(); + settings.secure_conn.to_value() + } + "certificate-path" => { + let settings = self.settings.lock().unwrap(); + let certpath = settings.certificate_path.as_ref(); + certpath.and_then(|file| file.to_str()).to_value() + } + "use-datagram" => { + let settings = self.settings.lock().unwrap(); + settings.use_datagram.to_value() + } + "private-key-type" => { + let settings = self.settings.lock().unwrap(); + settings.private_key_type.to_value() + } + _ => unimplemented!(), + } + } +} + +#[glib::object_subclass] +impl ObjectSubclass for QuicSrc { + const NAME: &'static str = "GstQUICSrc"; + type Type = super::QuicSrc; + type ParentType = gst_base::BaseSrc; +} + +impl BaseSrcImpl for QuicSrc { + fn is_seekable(&self) -> bool { + false + } + + fn start(&self) -> Result<(), gst::ErrorMessage> { + let settings = self.settings.lock().unwrap(); + let timeout = settings.timeout; + drop(settings); + + let mut state = self.state.lock().unwrap(); + + if let State::Started { .. } = *state { + unreachable!("QuicSrc already started"); + } + + match wait(&self.canceller, self.wait_for_connection(), timeout) { + Ok(Ok((c, s))) => { + *state = State::Started(Started { + connection: c, + stream: s, + }); + + gst::info!(CAT, imp: self, "Started"); + + Ok(()) + } + Ok(Err(e)) | Err(e) => match e { + WaitError::FutureAborted => { + gst::warning!(CAT, imp: self, "Connection aborted"); + Ok(()) + } + WaitError::FutureError(err) => { + gst::error!(CAT, imp: self, "Connection request failed: {}", err); + Err(gst::error_msg!( + gst::ResourceError::Failed, + ["Connection request failed: {}", err] + )) + } + }, + } + } + + fn stop(&self) -> Result<(), gst::ErrorMessage> { + self.cancel(); + + let mut state = self.state.lock().unwrap(); + + if let State::Started(ref mut state) = *state { + let connection = &state.connection; + + connection.close( + CONNECTION_CLOSE_CODE.into(), + CONNECTION_CLOSE_MSG.as_bytes(), + ); + } + + *state = State::Stopped; + + Ok(()) + } + + fn query(&self, query: &mut gst::QueryRef) -> bool { + if let gst::QueryViewMut::Scheduling(q) = query.view_mut() { + q.set( + gst::SchedulingFlags::SEQUENTIAL | gst::SchedulingFlags::BANDWIDTH_LIMITED, + 1, + -1, + 0, + ); + q.add_scheduling_modes(&[gst::PadMode::Pull, gst::PadMode::Push]); + return true; + } + + BaseSrcImplExt::parent_query(self, query) + } + + fn create( + &self, + offset: u64, + buffer: Option<&mut gst::BufferRef>, + length: u32, + ) -> Result { + let data = self.get(offset, u64::from(length)); + + match data { + Ok(bytes) => { + if bytes.is_empty() { + gst::debug!(CAT, imp: self, "End of stream"); + return Err(gst::FlowError::Eos); + } + + if let Some(buffer) = buffer { + if let Err(copied_bytes) = buffer.copy_from_slice(0, bytes.as_ref()) { + buffer.set_size(copied_bytes); + } + Ok(CreateSuccess::FilledBuffer) + } else { + Ok(CreateSuccess::NewBuffer(gst::Buffer::from_slice(bytes))) + } + } + Err(None) => Err(gst::FlowError::Flushing), + Err(Some(err)) => { + gst::error!(CAT, imp: self, "Could not GET: {}", err); + Err(gst::FlowError::Error) + } + } + } + + fn unlock(&self) -> Result<(), gst::ErrorMessage> { + self.cancel(); + Ok(()) + } + + fn caps(&self, filter: Option<&gst::Caps>) -> Option { + let settings = self.settings.lock().unwrap(); + + let mut tmp_caps = settings.caps.clone(); + + gst::debug!(CAT, imp: self, "Advertising our own caps: {:?}", &tmp_caps); + + if let Some(filter_caps) = filter { + gst::debug!( + CAT, + imp: self, + "Intersecting with filter caps: {:?}", + &filter_caps + ); + + tmp_caps = filter_caps.intersect_with_mode(&tmp_caps, gst::CapsIntersectMode::First); + }; + + gst::debug!(CAT, imp: self, "Returning caps: {:?}", &tmp_caps); + + Some(tmp_caps) + } +} + +impl QuicSrc { + fn get(&self, _offset: u64, length: u64) -> Result> { + let settings = self.settings.lock().unwrap(); + let timeout = settings.timeout; + let use_datagram = settings.use_datagram; + drop(settings); + + let mut state = self.state.lock().unwrap(); + + let (conn, stream) = match *state { + State::Started(Started { + ref connection, + ref mut stream, + }) => (connection, stream), + State::Stopped => { + return Err(Some(gst::error_msg!( + gst::LibraryError::Failed, + ["Cannot get data before start"] + ))); + } + }; + + let future = async { + if use_datagram { + match conn.read_datagram().await { + Ok(bytes) => Ok(bytes), + Err(err) => match err { + ConnectionError::ApplicationClosed(_) + | ConnectionError::ConnectionClosed(_) => Ok(Bytes::new()), + _ => Err(WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Datagram read error: {}", err] + ))), + }, + } + } else { + let recv = stream.as_mut().unwrap(); + + match recv.read_chunk(length as usize, true).await { + Ok(Some(chunk)) => Ok(chunk.bytes), + Ok(None) => Ok(Bytes::new()), + Err(err) => Err(WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Stream read error: {}", err] + ))), + } + } + }; + + match wait(&self.canceller, future, timeout) { + Ok(Ok(bytes)) => Ok(bytes), + Ok(Err(e)) | Err(e) => match e { + WaitError::FutureAborted => { + gst::warning!(CAT, imp: self, "Read from stream request aborted"); + Err(None) + } + WaitError::FutureError(e) => { + gst::error!(CAT, imp: self, "Failed to read from stream: {}", e); + Err(Some(e)) + } + }, + } + } + + fn cancel(&self) { + let mut canceller = self.canceller.lock().unwrap(); + + if let Some(c) = canceller.take() { + c.abort() + }; + } + + async fn wait_for_connection(&self) -> Result<(Connection, Option), WaitError> { + let server_addr; + let server_name; + let use_datagram; + let secure_conn; + let cert_path; + let private_key_type; + + { + let settings = self.settings.lock().unwrap(); + server_addr = settings.server_address; + server_name = settings.server_name.clone(); + use_datagram = settings.use_datagram; + secure_conn = settings.secure_conn; + cert_path = settings.certificate_path.clone(); + private_key_type = settings.private_key_type; + } + + let endpoint = server_endpoint( + server_addr, + &server_name, + secure_conn, + cert_path, + private_key_type, + ) + .map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Failed to configure endpoint: {}", err] + )) + })?; + + let incoming_conn = endpoint.accept().await.unwrap(); + + let connection = incoming_conn.await.map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Connection error: {}", err] + )) + })?; + + let stream = if !use_datagram { + let res = connection.accept_uni().await.map_err(|err| { + WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Failed to open stream: {}", err] + )) + })?; + + Some(res) + } else { + None + }; + + gst::info!( + CAT, + imp: self, + "Remote connection accepted: {}", + connection.remote_address() + ); + + Ok((connection, stream)) + } +} diff --git a/net/quic/src/quicsrc/mod.rs b/net/quic/src/quicsrc/mod.rs new file mode 100644 index 00000000..2eca4854 --- /dev/null +++ b/net/quic/src/quicsrc/mod.rs @@ -0,0 +1,36 @@ +// Copyright (C) 2024, Asymptotic Inc. +// Author: Sanchayan Maity +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use gst::glib; +use gst::prelude::*; + +mod imp; + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, glib::Enum)] +#[repr(u32)] +#[enum_type(name = "GstQuicPrivateKeyType")] +pub enum QuicPrivateKeyType { + #[enum_value(name = "PKCS8: PKCS #8 Private Key.", nick = "pkcs8")] + Pkcs8, + #[enum_value(name = "RSA: RSA Private Key.", nick = "rsa")] + Rsa, +} + +glib::wrapper! { + pub struct QuicSrc(ObjectSubclass) @extends gst_base::BaseSrc, gst::Element, gst::Object; +} + +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "quicsrc", + gst::Rank::MARGINAL, + QuicSrc::static_type(), + ) +} diff --git a/net/quic/src/utils.rs b/net/quic/src/utils.rs new file mode 100644 index 00000000..0932408a --- /dev/null +++ b/net/quic/src/utils.rs @@ -0,0 +1,252 @@ +// Copyright (C) 2024, Asymptotic Inc. +// Author: Sanchayan Maity +//G +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use crate::quicsrc::QuicPrivateKeyType; +use futures::future; +use futures::prelude::*; +use gst::ErrorMessage; +use once_cell::sync::Lazy; +use quinn::{ClientConfig, Endpoint, ServerConfig}; +use std::error::Error; +use std::fs::File; +use std::io::BufReader; +use std::net::{AddrParseError, SocketAddr}; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use thiserror::Error; +use tokio::runtime; + +pub const CONNECTION_CLOSE_CODE: u32 = 0; +pub const CONNECTION_CLOSE_MSG: &str = "Stopped"; + +#[derive(Error, Debug)] +pub enum WaitError { + #[error("Future aborted")] + FutureAborted, + #[error("Future returned an error: {0}")] + FutureError(ErrorMessage), +} + +pub static RUNTIME: Lazy = Lazy::new(|| { + runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(1) + .thread_name("gst-quic-runtime") + .build() + .unwrap() +}); + +pub fn wait( + canceller: &Mutex>, + future: F, + timeout: u32, +) -> Result +where + F: Send + Future, + T: Send + 'static, +{ + let mut canceller_guard = canceller.lock().unwrap(); + let (abort_handle, abort_registration) = future::AbortHandle::new_pair(); + + if canceller_guard.is_some() { + return Err(WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Old Canceller should not exist"] + ))); + } + + canceller_guard.replace(abort_handle); + drop(canceller_guard); + + let future = async { + if timeout == 0 { + Ok(future.await) + } else { + let res = tokio::time::timeout(Duration::from_secs(timeout.into()), future).await; + + match res { + Ok(r) => Ok(r), + Err(e) => Err(gst::error_msg!( + gst::ResourceError::Read, + ["Request timeout, elapsed: {}", e.to_string()] + )), + } + } + }; + + let future = async { + match future::Abortable::new(future, abort_registration).await { + Ok(Ok(res)) => Ok(res), + + Ok(Err(err)) => Err(WaitError::FutureError(gst::error_msg!( + gst::ResourceError::Failed, + ["Future resolved with an error {:?}", err] + ))), + + Err(future::Aborted) => Err(WaitError::FutureAborted), + } + }; + + let res = RUNTIME.block_on(future); + + canceller_guard = canceller.lock().unwrap(); + *canceller_guard = None; + + res +} + +/* + * Following functions are taken from Quinn documentation/repository + */ +pub fn make_socket_addr(addr: &str) -> Result { + addr.parse::() +} + +struct SkipServerVerification; + +impl SkipServerVerification { + pub fn new() -> Arc { + Arc::new(Self) + } +} + +impl rustls::client::ServerCertVerifier for SkipServerVerification { + fn verify_server_cert( + &self, + _end_entity: &rustls::Certificate, + _intermediates: &[rustls::Certificate], + _server_name: &rustls::ServerName, + _scts: &mut dyn Iterator, + _ocsp_response: &[u8], + _now: std::time::SystemTime, + ) -> Result { + Ok(rustls::client::ServerCertVerified::assertion()) + } +} + +fn configure_client(secure_conn: bool) -> Result> { + if secure_conn { + Ok(ClientConfig::with_native_roots()) + } else { + let crypto = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_custom_certificate_verifier(SkipServerVerification::new()) + .with_no_client_auth(); + + Ok(ClientConfig::new(Arc::new(crypto))) + } +} + +fn read_certs_from_file( + certificate_path: Option, + private_key_type: QuicPrivateKeyType, +) -> Result<(Vec, rustls::PrivateKey), Box> { + /* + * NOTE: + * + * Certificate file here should correspond to fullchain.pem where + * fullchain.pem = cert.pem + chain.pem. + * fullchain.pem DOES NOT include a CA's Root Certificates. + * + * One typically uses chain.pem (or the first certificate in it) when asked + * for a CA bundle or CA certificate. + * + * One typically uses fullchain.pem when asked for the entire certificate + * chain in a single file. For example, this is the case of modern day + * Apache and nginx. + */ + let cert_file = certificate_path + .clone() + .expect("Expected path to certificates be valid") + .join("fullchain.pem"); + let key_file = certificate_path + .expect("Expected path to certificates be valid") + .join("privkey.pem"); + + let certs: Vec = { + let cert_file = File::open(cert_file.as_path())?; + let mut cert_file_rdr = BufReader::new(cert_file); + let cert_vec = rustls_pemfile::certs(&mut cert_file_rdr)?; + cert_vec.into_iter().map(rustls::Certificate).collect() + }; + + let key: rustls::PrivateKey = { + let key_file = File::open(key_file.as_path())?; + let mut key_file_rdr = BufReader::new(key_file); + let mut key_vec; + + // If the file starts with "BEGIN RSA PRIVATE KEY" + if let QuicPrivateKeyType::Rsa = private_key_type { + key_vec = rustls_pemfile::rsa_private_keys(&mut key_file_rdr)?; + } else { + // If the file starts with "BEGIN PRIVATE KEY" + key_vec = rustls_pemfile::pkcs8_private_keys(&mut key_file_rdr)?; + } + + assert_eq!(key_vec.len(), 1); + + rustls::PrivateKey(key_vec.remove(0)) + }; + + Ok((certs, key)) +} + +fn configure_server( + server_name: &str, + secure_conn: bool, + certificate_path: Option, + private_key_type: QuicPrivateKeyType, +) -> Result<(ServerConfig, Vec), Box> { + let (cert, key) = if secure_conn { + read_certs_from_file(certificate_path, private_key_type).unwrap() + } else { + let cert = rcgen::generate_simple_self_signed(vec![server_name.into()]).unwrap(); + let cert_der = cert.serialize_der().unwrap(); + let priv_key = cert.serialize_private_key_der(); + let priv_key = rustls::PrivateKey(priv_key); + let cert_chain = vec![rustls::Certificate(cert_der)]; + + (cert_chain, priv_key) + }; + + let mut server_config = ServerConfig::with_single_cert(cert.clone(), key)?; + Arc::get_mut(&mut server_config.transport) + .unwrap() + .max_concurrent_bidi_streams(0_u8.into()) + .max_concurrent_uni_streams(1_u8.into()); + + Ok((server_config, cert)) +} + +pub fn server_endpoint( + server_addr: SocketAddr, + server_name: &str, + secure_conn: bool, + certificate_path: Option, + private_key_type: QuicPrivateKeyType, +) -> Result> { + let (server_config, _) = + configure_server(server_name, secure_conn, certificate_path, private_key_type)?; + let endpoint = Endpoint::server(server_config, server_addr)?; + + Ok(endpoint) +} + +pub fn client_endpoint( + client_addr: SocketAddr, + secure_conn: bool, +) -> Result> { + let client_cfg = configure_client(secure_conn)?; + let mut endpoint = Endpoint::client(client_addr)?; + + endpoint.set_default_client_config(client_cfg); + + Ok(endpoint) +} diff --git a/net/quic/tests/quic.rs b/net/quic/tests/quic.rs new file mode 100644 index 00000000..11be17ac --- /dev/null +++ b/net/quic/tests/quic.rs @@ -0,0 +1,111 @@ +// Copyright (C) 2024, Asymptotic Inc. +// Author: Sanchayan Maity +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use gst::prelude::*; +use serial_test::serial; +use std::thread; + +fn init() { + use std::sync::Once; + static INIT: Once = Once::new(); + + INIT.call_once(|| { + gst::init().unwrap(); + gstquic::plugin_register_static().expect("QUIC source sink send receive tests"); + }); +} + +fn make_buffer(content: &[u8]) -> gst::Buffer { + let mut buf = gst::Buffer::from_slice(content.to_owned()); + buf.make_mut().set_pts(gst::ClockTime::from_mseconds(200)); + buf +} + +#[test] +#[serial] +fn test_send_receive_without_datagram() { + init(); + + let content = "Hello, world!\n".as_bytes(); + + thread::spawn(move || { + let mut h1 = gst_check::Harness::new("quicsink"); + + h1.set_src_caps(gst::Caps::builder("text/plain").build()); + + h1.play(); + + assert!(h1.push(make_buffer(content)) == Ok(gst::FlowSuccess::Ok)); + + h1.push_event(gst::event::Eos::new()); + + h1.element().unwrap().set_state(gst::State::Null).unwrap(); + + drop(h1); + }); + + let mut h2 = gst_check::Harness::new("quicsrc"); + + h2.play(); + + let buf = h2.pull_until_eos().unwrap().unwrap(); + + assert_eq!( + content, + buf.into_mapped_buffer_readable().unwrap().as_slice() + ); + + h2.element().unwrap().set_state(gst::State::Null).unwrap(); + + drop(h2); +} + +#[test] +#[serial] +fn test_send_receive_with_datagram() { + init(); + + let content = "Hello, world!\n".as_bytes(); + + // Use a different port address compared to the default that will be used + // in the other test. We get a address already in use error otherwise. + thread::spawn(move || { + let mut h1 = gst_check::Harness::new_empty(); + + h1.add_parse(format!("quicsrc use-datagram=true server-address=127.0.0.1:6000").as_str()); + h1.play(); + + let buf = h1.pull_until_eos().unwrap().unwrap(); + + assert_eq!( + content, + buf.into_mapped_buffer_readable().unwrap().as_slice() + ); + + h1.element().unwrap().set_state(gst::State::Null).unwrap(); + + drop(h1); + }); + + let mut h2 = gst_check::Harness::new_empty(); + + h2.add_parse(format!("quicsink use-datagram=true client-address=127.0.0.1:6001 server-address=127.0.0.1:6000").as_str()); + + h2.set_src_caps(gst::Caps::builder("text/plain").build()); + + h2.play(); + + assert!(h2.push(make_buffer(content)) == Ok(gst::FlowSuccess::Ok)); + + h2.push_event(gst::event::Eos::new()); + + h2.element().unwrap().set_state(gst::State::Null).unwrap(); + + drop(h2); +}