diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..79c0e4e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = tab +indent_size = 4 +max_line_length = 120 + +# YAML doesn't support hard tabs 🙃 +[**.yml] +indent_style = space +indent_size = 2 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 1ffb218..ec423cd 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -21,7 +21,25 @@ jobs: # We need gstreamer installed to compile this repo - name: Setup GStreamer - uses: blinemedical/setup-gstreamer@v1 + run: | + sudo apt-get update + sudo apt-get remove libunwind-* + sudo apt-get install -y \ + libgstreamer1.0-dev \ + libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev \ + gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly \ + gstreamer1.0-libav \ + gstreamer1.0-tools \ + gstreamer1.0-x \ + gstreamer1.0-alsa \ + gstreamer1.0-gl \ + gstreamer1.0-gtk3 \ + gstreamer1.0-qt5 \ + gstreamer1.0-pulseaudio # Make sure u guys don't write bad code - run: cargo test --verbose diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..b3c42a2 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,4 @@ +# i die on this hill +hard_tabs = true + +max_width = 120 diff --git a/CHANGELOG.md b/CHANGELOG.md index eda176d..4f91aea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.1.7](https://github.com/kixelated/moq-rs/compare/moq-gst-v0.1.6...moq-gst-v0.1.7) - 2025-01-30 + +### Other + +- update Cargo.lock dependencies + +## [0.1.6](https://github.com/kixelated/moq-rs/compare/moq-gst-v0.1.5...moq-gst-v0.1.6) - 2025-01-16 + +### Other + +- update Cargo.lock dependencies + +## [0.1.5](https://github.com/kixelated/moq-rs/compare/moq-gst-v0.1.4...moq-gst-v0.1.5) - 2025-01-16 + +### Other + +- Support fetching fingerprint via native clients. ([#286](https://github.com/kixelated/moq-rs/pull/286)) +- Initial WASM contribute ([#283](https://github.com/kixelated/moq-rs/pull/283)) + +## [0.1.4](https://github.com/kixelated/moq-rs/compare/moq-gst-v0.1.3...moq-gst-v0.1.4) - 2025-01-13 + +### Other + +- update Cargo.lock dependencies + +## [0.1.3](https://github.com/kixelated/moq-rs/compare/moq-gst-v0.1.2...moq-gst-v0.1.3) - 2025-01-13 + +### Other + +- updated the following local packages: moq-native + +## [0.1.2](https://github.com/kixelated/moq-rs/compare/moq-gst-v0.1.1...moq-gst-v0.1.2) - 2024-12-04 + +### Other + +- updated the following local packages: moq-karp + ## [0.1.1](https://github.com/kixelated/moq-gst/compare/v0.1.0...v0.1.1) - 2024-11-09 ### Other diff --git a/Cargo.lock b/Cargo.lock index 5ca0c19..84b875a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,7 @@ dependencies = [ "aws-lc-sys", "mirai-annotations", "paste", + "untrusted 0.7.1", "zeroize", ] @@ -213,9 +214,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" @@ -721,7 +722,7 @@ dependencies = [ "paste", "pin-project-lite", "smallvec", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -822,12 +823,79 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -1018,6 +1086,12 @@ dependencies = [ "serde", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1058,7 +1132,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.68", "walkdir", ] @@ -1079,10 +1153,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1100,9 +1175,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.162" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" @@ -1157,6 +1232,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1190,9 +1271,21 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" +[[package]] +name = "moq-async" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "750145254aab3430ae0f79ee013da54fe9adcdb0faca35ff6fad3a5a256b46ed" +dependencies = [ + "futures", + "tokio", + "tracing", + "wasm-bindgen-futures", +] + [[package]] name = "moq-gst" -version = "0.1.1" +version = "0.1.7" dependencies = [ "anyhow", "env_logger", @@ -1201,16 +1294,16 @@ dependencies = [ "gstreamer-base", "moq-karp", "moq-native", - "moq-transfork", "once_cell", "tokio", + "url", ] [[package]] name = "moq-karp" -version = "0.8.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c84b42dbdc0414b8a22f6521bbaa0fefa4913d393206803c40991d915f9e95" +checksum = "97030f802c169a391c7d7a2d2d7738092de156880fd2eb966a74e192869deb17" dependencies = [ "anyhow", "bytes", @@ -1219,6 +1312,7 @@ dependencies = [ "futures", "hex", "lazy_static", + "moq-async", "moq-native", "moq-transfork", "mp4-atom", @@ -1226,17 +1320,18 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror", + "thiserror 2.0.11", "tokio", "tracing", "url", + "web-time", ] [[package]] name = "moq-native" -version = "0.5.6" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905cc2a2193bdbe1c48d3c8f08f7044fbb5b550d720fa7572b101afee7686bde" +checksum = "6a05fc047ab47d360ca9cce39568e13476b394ccff9c8310683c5ac0c9e6544a" dependencies = [ "anyhow", "clap", @@ -1244,10 +1339,13 @@ dependencies = [ "hex", "moq-transfork", "quinn", + "rcgen", + "reqwest", "ring", "rustls", "rustls-native-certs 0.8.0", "rustls-pemfile", + "time", "tokio", "tracing", "tracing-subscriber", @@ -1258,13 +1356,15 @@ dependencies = [ [[package]] name = "moq-transfork" -version = "0.4.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7bca71d1b85893f79ffc0dd9f1f25627019879ec6ae6cff398954862859f34a" +checksum = "17d5ea0074eeb9a3fff7de2aa3694bbdbafa547c5ed4a781e21f7c166ab1e00f" dependencies = [ "bytes", "futures", - "thiserror", + "moq-async", + "num_enum", + "thiserror 2.0.11", "tokio", "tracing", "wasm-bindgen-futures", @@ -1273,14 +1373,14 @@ dependencies = [ [[package]] name = "mp4-atom" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952d37eb0f265505e2b4888d1a58bf3ddea0047f623c06f656d03bcc3184caab" +checksum = "4e6ca41187fd83535ec10045e7bd4e6ee508b5eb0488c3bce66bca9182d26a96" dependencies = [ "bytes", "num", "paste", - "thiserror", + "thiserror 1.0.68", "tokio", "tracing", ] @@ -1390,6 +1490,27 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "object" version = "0.36.5" @@ -1455,6 +1576,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1535,7 +1666,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls", "socket2", - "thiserror", + "thiserror 1.0.68", "tokio", "tracing", ] @@ -1553,7 +1684,7 @@ dependencies = [ "rustls", "rustls-platform-verifier", "slab", - "thiserror", + "thiserror 1.0.68", "tinyvec", "tracing", ] @@ -1611,6 +1742,19 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.7" @@ -1664,6 +1808,42 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "ring" version = "0.17.8" @@ -1675,7 +1855,7 @@ dependencies = [ "getrandom", "libc", "spin", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -1803,9 +1983,15 @@ dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "ryu" version = "1.0.18" @@ -1901,6 +2087,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "3.11.0" @@ -2015,6 +2213,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -2060,7 +2267,16 @@ version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.68", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] @@ -2074,6 +2290,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -2142,9 +2369,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -2160,9 +2387,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -2203,6 +2430,33 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.40" @@ -2265,6 +2519,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "unicode-ident" version = "1.0.13" @@ -2277,6 +2537,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[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" @@ -2334,6 +2600,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2342,24 +2617,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -2380,9 +2655,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2390,9 +2665,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -2403,15 +2678,40 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-streams" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b009237ac7dbc6e1cc55bb5f0e511f6895b086899cb42ad3645d524c9aea1a" +dependencies = [ + "thiserror 1.0.68", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2419,12 +2719,13 @@ dependencies = [ [[package]] name = "web-transport" -version = "0.6.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a55e06e224351ec132a7acbbbd66375380a38dbf9376be23f4d623d6e8591e7" +checksum = "bb58dedc815e32a60ea6f239654bcc9b5bba00bd31ff882b67e0eacff719e401" dependencies = [ "bytes", - "thiserror", + "thiserror 2.0.11", + "url", "web-transport-quinn", "web-transport-wasm", ] @@ -2437,23 +2738,26 @@ checksum = "6a3806ea43df5817f0d90618c842d28db5946bc18a5db0659b2275c2be48d472" dependencies = [ "bytes", "http", - "thiserror", + "thiserror 1.0.68", "url", ] [[package]] name = "web-transport-quinn" -version = "0.3.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3020b51cda10472a365e42d9a701916d4f04d74cc743de08246ef6a421c2d137" +checksum = "61937694cad3742f278b38af267bb84b749efaca0c94ab1fcacadfb6aa544065" dependencies = [ + "aws-lc-rs", "bytes", "futures", "http", "log", "quinn", "quinn-proto", - "thiserror", + "rustls", + "rustls-native-certs 0.8.0", + "thiserror 2.0.11", "tokio", "url", "web-transport-proto", @@ -2461,16 +2765,17 @@ dependencies = [ [[package]] name = "web-transport-wasm" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972d6ef19b807640a81eb5a7979f9d520fa99bf28c091654053b0a4dce1fc62a" +checksum = "6d707071216133d89c5ce876c7b5ba48fb874ef6555ba56b9cf4a0fbb8e66ac0" dependencies = [ "bytes", "js-sys", - "thiserror", + "thiserror 2.0.11", "url", "wasm-bindgen", "wasm-bindgen-futures", + "web-streams", "web-sys", ] @@ -2481,7 +2786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ "ring", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -2545,6 +2850,36 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -2648,6 +2983,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.7.4" diff --git a/Cargo.toml b/Cargo.toml index db56969..1e41e9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "moq-gst" -description = "Media over QUIC - gstreamer plugin" +description = "Media over QUIC - Gstreamer plugin" authors = ["Luke Curley"] -repository = "https://github.com/kixelated/moq-gst" +repository = "https://github.com/kixelated/moq-rs" license = "MIT OR Apache-2.0" -version = "0.1.1" +version = "0.1.7" edition = "2021" keywords = ["quic", "http3", "webtransport", "media", "live"] @@ -14,9 +14,8 @@ categories = ["multimedia", "network-programming", "web-programming"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -moq-transfork = "0.4" -moq-native = "0.5" -moq-karp = "0.8" +moq-native = "0.6" +moq-karp = "0.13" gst = { package = "gstreamer", version = "0.23" } gst-base = { package = "gstreamer-base", version = "0.23" } @@ -24,6 +23,7 @@ once_cell = "1" tokio = { version = "1", features = ["full"] } env_logger = "0.9" anyhow = { version = "1", features = ["backtrace"] } +url = "2" [build-dependencies] gst-plugin-version-helper = "0.8" diff --git a/build.rs b/build.rs index cda12e5..6d87290 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,3 @@ fn main() { - gst_plugin_version_helper::info() + gst_plugin_version_helper::info() } diff --git a/src/lib.rs b/src/lib.rs index 159e548..404d694 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,18 +3,18 @@ use gst::glib; mod sink; pub fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - sink::register(plugin)?; - Ok(()) + sink::register(plugin)?; + Ok(()) } gst::plugin_define!( - moq, - env!("CARGO_PKG_DESCRIPTION"), - plugin_init, - concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")), - "MIT/Apache-2.0", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_REPOSITORY"), - env!("BUILD_REL_DATE") + moq, + env!("CARGO_PKG_DESCRIPTION"), + plugin_init, + concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")), + "MIT/Apache-2.0", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_REPOSITORY"), + env!("BUILD_REL_DATE") ); diff --git a/src/sink/imp.rs b/src/sink/imp.rs index 7a0ae93..7496da8 100644 --- a/src/sink/imp.rs +++ b/src/sink/imp.rs @@ -4,206 +4,181 @@ use gst::prelude::*; use gst::subclass::prelude::*; use gst_base::subclass::prelude::*; +use moq_karp::moq_transfork; + use moq_native::{quic, tls}; use once_cell::sync::Lazy; use std::sync::Arc; use std::sync::Mutex; +use url::Url; pub static RUNTIME: Lazy = Lazy::new(|| { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .worker_threads(1) - .build() - .unwrap() + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(1) + .build() + .unwrap() }); -#[derive(Default)] +#[derive(Default, Clone)] struct Settings { - pub url: Option, - pub broadcast: String, - pub tls_disable_verify: bool, + pub src: Option, + pub tls_disable_verify: bool, } #[derive(Default)] struct State { - pub media: Option, - pub session: Option, - pub published: bool, // true if the media has been published + pub media: Option, } #[derive(Default)] pub struct MoqSink { - settings: Mutex, - state: Arc>, + settings: Mutex, + state: Arc>, } #[glib::object_subclass] impl ObjectSubclass for MoqSink { - const NAME: &'static str = "MoqSink"; - type Type = super::MoqSink; - type ParentType = gst_base::BaseSink; + const NAME: &'static str = "MoqSink"; + type Type = super::MoqSink; + type ParentType = gst_base::BaseSink; - fn new() -> Self { - Self::default() - } + fn new() -> Self { + Self::default() + } } impl ObjectImpl for MoqSink { - fn properties() -> &'static [glib::ParamSpec] { - static PROPERTIES: Lazy> = Lazy::new(|| { - vec![ - glib::ParamSpecString::builder("url") - .nick("URL") - .blurb("Connect to the subscriber at the given URL") - .build(), - // TODO array of paths - glib::ParamSpecString::builder("broadcast") - .nick("Broadcast") - .blurb("Publish the broadcast under the given path") - .build(), - glib::ParamSpecBoolean::builder("tls-disable-verify") - .nick("TLS disable verify") - .blurb("Disable TLS verification") - .default_value(false) - .build(), - ] - }); - PROPERTIES.as_ref() - } - - fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { - let mut settings = self.settings.lock().unwrap(); - - match pspec.name() { - "url" => settings.url = Some(value.get().unwrap()), - "broadcast" => settings.broadcast = value.get().unwrap(), - "tls-disable-verify" => settings.tls_disable_verify = value.get().unwrap(), - _ => unimplemented!(), - } - } - - fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { - let settings = self.settings.lock().unwrap(); - - match pspec.name() { - "url" => settings.url.to_value(), - "broadcast" => settings.broadcast.to_value(), - "tls-disable-verify" => settings.tls_disable_verify.to_value(), - _ => unimplemented!(), - } - } + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![ + glib::ParamSpecString::builder("src") + .nick("Source URL") + .blurb("Connect to the given URL") + .build(), + glib::ParamSpecBoolean::builder("tls-disable-verify") + .nick("TLS disable verify") + .blurb("Disable TLS verification") + .default_value(false) + .build(), + ] + }); + PROPERTIES.as_ref() + } + + fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + let mut settings = self.settings.lock().unwrap(); + + match pspec.name() { + "src" => settings.src = Some(value.get().unwrap()), + "tls-disable-verify" => settings.tls_disable_verify = value.get().unwrap(), + _ => unimplemented!(), + } + } + + fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + let settings = self.settings.lock().unwrap(); + + match pspec.name() { + "src" => settings.src.to_value(), + "tls-disable-verify" => settings.tls_disable_verify.to_value(), + _ => unimplemented!(), + } + } } impl GstObjectImpl for MoqSink {} impl ElementImpl for MoqSink { - fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { - static ELEMENT_METADATA: Lazy = Lazy::new(|| { - gst::subclass::ElementMetadata::new( - "MoQ Sink", - "Sink", - "Transmits media over the network via MoQ", - "Luke Curley ", - ) - }); - - Some(&*ELEMENT_METADATA) - } - - fn pad_templates() -> &'static [gst::PadTemplate] { - static PAD_TEMPLATES: Lazy> = Lazy::new(|| { - let caps = gst::Caps::builder("video/quicktime") - .field("variant", "iso-fragmented") - .build(); - - let pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - - vec![pad_template] - }); - PAD_TEMPLATES.as_ref() - } + fn metadata() -> Option<&'static gst::subclass::ElementMetadata> { + static ELEMENT_METADATA: Lazy = Lazy::new(|| { + gst::subclass::ElementMetadata::new( + "MoQ Sink", + "Sink", + "Transmits media over the network via MoQ", + "Luke Curley ", + ) + }); + + Some(&*ELEMENT_METADATA) + } + + fn pad_templates() -> &'static [gst::PadTemplate] { + static PAD_TEMPLATES: Lazy> = Lazy::new(|| { + let caps = gst::Caps::builder("video/quicktime") + .field("variant", "iso-fragmented") + .build(); + + let pad_template = + gst::PadTemplate::new("sink", gst::PadDirection::Sink, gst::PadPresence::Always, &caps).unwrap(); + + vec![pad_template] + }); + PAD_TEMPLATES.as_ref() + } } impl BaseSinkImpl for MoqSink { - fn start(&self) -> Result<(), gst::ErrorMessage> { - let _guard = RUNTIME.enter(); - self.setup() - .map_err(|e| gst::error_msg!(gst::ResourceError::Failed, ["Failed to connect: {}", e])) - } - - fn stop(&self) -> Result<(), gst::ErrorMessage> { - Ok(()) - } - - fn render(&self, buffer: &gst::Buffer) -> Result { - let _guard = RUNTIME.enter(); - let data = buffer.map_readable().map_err(|_| gst::FlowError::Error)?; + fn start(&self) -> Result<(), gst::ErrorMessage> { + let _guard = RUNTIME.enter(); + self.setup() + .map_err(|e| gst::error_msg!(gst::ResourceError::Failed, ["Failed to connect: {}", e])) + } - let mut state = self.state.lock().unwrap(); - let mut media = state.media.take().expect("not initialized"); + fn stop(&self) -> Result<(), gst::ErrorMessage> { + Ok(()) + } - // TODO avoid full media parsing? gst should be able to provide the necessary info - media.parse(data.as_slice()).expect("failed to parse"); + fn render(&self, buffer: &gst::Buffer) -> Result { + let _guard = RUNTIME.enter(); + let data = buffer.map_readable().map_err(|_| gst::FlowError::Error)?; - if !state.published { - if let Some(session) = state.session.as_mut() { - media.publish(session).expect("failed to publish"); - state.published = true; - } - } + let mut state = self.state.lock().unwrap(); + let mut media = state.media.take().expect("not initialized"); - state.media = Some(media); + // TODO avoid full media parsing? gst should be able to provide the necessary info + media.parse(data.as_slice()).expect("failed to parse"); + state.media = Some(media); - Ok(gst::FlowSuccess::Ok) - } + Ok(gst::FlowSuccess::Ok) + } } impl MoqSink { - fn setup(&self) -> anyhow::Result<()> { - let settings = self.settings.lock().unwrap(); - let broadcast = moq_transfork::Path::default().push(&settings.broadcast); - - let broadcast = moq_karp::produce::Resumable::new(broadcast).broadcast(); - let media = moq_karp::cmaf::Import::new(broadcast); - - let url = settings.url.clone().context("missing url")?; - let url = url.parse().context("invalid URL")?; - - // TODO support TLS certs and other options - let config = quic::Args { - bind: "[::]:0".parse().unwrap(), - tls: tls::Args { - disable_verify: settings.tls_disable_verify, - ..Default::default() - }, - } - .load()?; - - let client = quic::Endpoint::new(config)?.client; - - let mut state = self.state.lock().unwrap(); - state.media = Some(media); - - let state = self.state.clone(); - - // We have to perform the connect in a background task because we can't block the main thread - tokio::spawn(async move { - let session = client.connect(&url).await.expect("failed to connect"); - let session = moq_transfork::Session::connect(session) - .await - .expect("failed to connect"); - - state.lock().unwrap().session = Some(session); - - // TODO figure out how to close gstreamer gracefully on session close - }); - - Ok(()) - } + fn setup(&self) -> anyhow::Result<()> { + let settings = self.settings.lock().unwrap(); + let src = settings.src.clone().context("missing src")?; + let src = Url::parse(&src).context("invalid URL")?; + + // TODO support TLS certs and other options + let config = quic::Args { + bind: "[::]:0".parse().unwrap(), + tls: tls::Args { + disable_verify: settings.tls_disable_verify, + ..Default::default() + }, + } + .load()?; + let client = quic::Endpoint::new(config)?.client; + + RUNTIME.block_on(async move { + let session = client.connect(src.clone()).await.expect("failed to connect"); + let session = moq_transfork::Session::connect(session) + .await + .expect("failed to connect"); + + let path = src + .path_segments() + .expect("missing path") + .collect::(); + + let broadcast = moq_karp::BroadcastProducer::new(session, path).unwrap(); + let media = moq_karp::cmaf::Import::new(broadcast); + + let mut state = self.state.lock().unwrap(); + state.media = Some(media); + }); + + Ok(()) + } } diff --git a/src/sink/mod.rs b/src/sink/mod.rs index 3c87bda..a669e23 100644 --- a/src/sink/mod.rs +++ b/src/sink/mod.rs @@ -4,15 +4,10 @@ use gst::prelude::*; mod imp; glib::wrapper! { - pub struct MoqSink(ObjectSubclass) @extends gst_base::BaseSink, gst::Element, gst::Object; + pub struct MoqSink(ObjectSubclass) @extends gst_base::BaseSink, gst::Element, gst::Object; } pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - env_logger::init(); - gst::Element::register( - Some(plugin), - "moqsink", - gst::Rank::NONE, - MoqSink::static_type(), - ) + env_logger::init(); + gst::Element::register(Some(plugin), "moqsink", gst::Rank::NONE, MoqSink::static_type()) }