Compare commits

...

2 Commits

7 changed files with 605 additions and 91 deletions

517
composeApp/Cargo.lock generated
View File

@ -29,6 +29,20 @@ dependencies = [
"cpufeatures 0.2.17", "cpufeatures 0.2.17",
] ]
[[package]]
name = "aes-gcm"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
dependencies = [
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.103" version = "1.0.103"
@ -198,12 +212,24 @@ version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "base16ct"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.22.1" version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]] [[package]]
name = "basic-toml" name = "basic-toml"
version = "0.1.10" version = "0.1.10"
@ -243,6 +269,15 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "block-padding"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.20.3" version = "3.20.3"
@ -316,6 +351,15 @@ dependencies = [
"thiserror 2.0.18", "thiserror 2.0.18",
] ]
[[package]]
name = "cbc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [
"cipher",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.4.3" version = "1.4.3"
@ -350,6 +394,17 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]]
name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures 0.2.17",
]
[[package]] [[package]]
name = "chacha20" name = "chacha20"
version = "0.10.1" version = "0.10.1"
@ -361,6 +416,19 @@ dependencies = [
"rand_core 0.10.1", "rand_core 0.10.1",
] ]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
"chacha20 0.9.1",
"cipher",
"poly1305",
"zeroize",
]
[[package]] [[package]]
name = "cipher" name = "cipher"
version = "0.4.4" version = "0.4.4"
@ -369,6 +437,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [ dependencies = [
"crypto-common", "crypto-common",
"inout", "inout",
"zeroize",
] ]
[[package]] [[package]]
@ -379,6 +448,7 @@ dependencies = [
"bytes", "bytes",
"discord-rich-presence", "discord-rich-presence",
"lofty", "lofty",
"log",
"parking_lot", "parking_lot",
"rtc", "rtc",
"thiserror 2.0.18", "thiserror 2.0.18",
@ -396,6 +466,12 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.17" version = "0.2.17"
@ -453,6 +529,18 @@ version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
[[package]]
name = "crypto-bigint"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
dependencies = [
"generic-array",
"rand_core 0.6.4",
"subtle",
"zeroize",
]
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.7" version = "0.1.7"
@ -473,12 +561,49 @@ dependencies = [
"cipher", "cipher",
] ]
[[package]]
name = "curve25519-dalek"
version = "4.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [
"cfg-if",
"cpufeatures 0.2.17",
"curve25519-dalek-derive",
"fiat-crypto",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.11.0" version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
[[package]]
name = "der"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
"const-oid",
"pem-rfc7468",
"zeroize",
]
[[package]] [[package]]
name = "der-parser" name = "der-parser"
version = "9.0.0" version = "9.0.0"
@ -520,6 +645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"const-oid",
"crypto-common", "crypto-common",
"subtle", "subtle",
] ]
@ -550,6 +676,41 @@ dependencies = [
"syn 3.0.2", "syn 3.0.2",
] ]
[[package]]
name = "ecdsa"
version = "0.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
dependencies = [
"der",
"digest",
"elliptic-curve",
"rfc6979",
"signature",
"spki",
]
[[package]]
name = "elliptic-curve"
version = "0.13.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [
"base16ct",
"crypto-bigint",
"digest",
"ff",
"generic-array",
"group",
"hkdf",
"pem-rfc7468",
"pkcs8",
"rand_core 0.6.4",
"sec1",
"subtle",
"zeroize",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@ -592,6 +753,22 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
[[package]]
name = "ff"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "fiat-crypto"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]] [[package]]
name = "find-msvc-tools" name = "find-msvc-tools"
version = "0.1.11" version = "0.1.11"
@ -722,6 +899,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
"zeroize",
] ]
[[package]] [[package]]
@ -747,6 +925,16 @@ dependencies = [
"rand_core 0.10.1", "rand_core 0.10.1",
] ]
[[package]]
name = "ghash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.3" version = "0.3.3"
@ -764,6 +952,17 @@ dependencies = [
"scroll", "scroll",
] ]
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core 0.6.4",
"subtle",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.17.1" version = "0.17.1"
@ -782,6 +981,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hkdf"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
dependencies = [
"hmac",
]
[[package]] [[package]]
name = "hmac" name = "hmac"
version = "0.12.1" version = "0.12.1"
@ -911,6 +1119,7 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [ dependencies = [
"block-padding",
"generic-array", "generic-array",
] ]
@ -1158,6 +1367,36 @@ version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "p256"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2",
]
[[package]]
name = "p384"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2",
]
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@ -1203,6 +1442,15 @@ dependencies = [
"serde_core", "serde_core",
] ]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
dependencies = [
"base64ct",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.3.2" version = "2.3.2"
@ -1215,12 +1463,45 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"spki",
]
[[package]] [[package]]
name = "plain" name = "plain"
version = "0.2.3" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures 0.2.17",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "polyval"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
"cfg-if",
"cpufeatures 0.2.17",
"opaque-debug",
"universal-hash",
]
[[package]] [[package]]
name = "potential_utf" name = "potential_utf"
version = "0.1.6" version = "0.1.6"
@ -1236,6 +1517,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "primeorder"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
dependencies = [
"elliptic-curve",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@ -1308,7 +1598,7 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
dependencies = [ dependencies = [
"chacha20", "chacha20 0.10.1",
"getrandom 0.4.3", "getrandom 0.4.3",
"rand_core 0.10.1", "rand_core 0.10.1",
] ]
@ -1360,6 +1650,16 @@ dependencies = [
"bytecheck", "bytecheck",
] ]
[[package]]
name = "rfc6979"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [
"hmac",
"subtle",
]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.14" version = "0.17.14"
@ -1406,15 +1706,16 @@ dependencies = [
[[package]] [[package]]
name = "rtc" name = "rtc"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9005c36795ad076abd36db3ea9ae0275a60395944647d58c1f2bc3e118dddba"
dependencies = [ dependencies = [
"bytes", "bytes",
"hex", "hex",
"log", "log",
"pem",
"rand", "rand",
"rcgen", "rcgen",
"rtc-crypto", "ring",
"rtc-datachannel", "rtc-datachannel",
"rtc-dtls", "rtc-dtls",
"rtc-ice", "rtc-ice",
@ -1433,31 +1734,16 @@ dependencies = [
"sansio", "sansio",
"serde", "serde",
"serde_json", "serde_json",
"sha2",
"unicase", "unicase",
"url", "url",
"x509-parser 0.16.0",
]
[[package]]
name = "rtc-crypto"
version = "0.21.0-beta.1"
dependencies = [
"aes",
"ccm",
"ctr",
"hmac",
"md-5",
"rand",
"ring",
"sha1",
"subtle",
"thiserror 2.0.18",
"zeroize",
] ]
[[package]] [[package]]
name = "rtc-datachannel" name = "rtc-datachannel"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b61c7b8e9892094cba8a6c7fb8120ae863d32d432b00e560177b3d7ae6d2c6"
dependencies = [ dependencies = [
"bytes", "bytes",
"log", "log",
@ -1468,30 +1754,47 @@ dependencies = [
[[package]] [[package]]
name = "rtc-dtls" name = "rtc-dtls"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c737b1dd17a0ff63884a2f466b9588f0cffadfce5a724c0c368764d7c27f9c74"
dependencies = [ dependencies = [
"aes",
"bytecheck", "bytecheck",
"byteorder", "byteorder",
"bytes", "bytes",
"cbc",
"ccm",
"chacha20poly1305",
"der-parser 9.0.0", "der-parser 9.0.0",
"hmac",
"log", "log",
"pem", "p256",
"p384",
"rand",
"rand_core 0.6.4",
"rcgen", "rcgen",
"ring",
"rkyv", "rkyv",
"rtc-crypto",
"rtc-shared", "rtc-shared",
"rustls", "rustls",
"sec1",
"sha1",
"sha2",
"subtle",
"x25519-dalek",
"x509-parser 0.16.0", "x509-parser 0.16.0",
] ]
[[package]] [[package]]
name = "rtc-ice" name = "rtc-ice"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c06eeabd250a7693e1e8b28222b78c4a81a7c6ca7fe3cb99bbdff2f6c0ff0ab"
dependencies = [ dependencies = [
"bytes", "bytes",
"crc", "crc",
"log", "log",
"rtc-crypto", "rand",
"rtc-mdns", "rtc-mdns",
"rtc-shared", "rtc-shared",
"rtc-stun", "rtc-stun",
@ -1503,19 +1806,35 @@ dependencies = [
[[package]] [[package]]
name = "rtc-interceptor" name = "rtc-interceptor"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ec2776ab86c0c03c3de8ec742aa13ccc3b2c82317590d0624f251bd37eae3b9"
dependencies = [ dependencies = [
"log", "log",
"rand", "rand",
"rtc-interceptor-derive",
"rtc-rtcp", "rtc-rtcp",
"rtc-rtp", "rtc-rtp",
"rtc-shared", "rtc-shared",
"sansio", "sansio",
] ]
[[package]]
name = "rtc-interceptor-derive"
version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc31da3875839bc18e00997354a582e6decacdb23d39f8c004fc4fe2fd3fcd8b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]] [[package]]
name = "rtc-mdns" name = "rtc-mdns"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cd53120b83321c8b8310cce9512c685d2d6356acef34647a99ea420e6f2249"
dependencies = [ dependencies = [
"bytes", "bytes",
"log", "log",
@ -1526,7 +1845,9 @@ dependencies = [
[[package]] [[package]]
name = "rtc-media" name = "rtc-media"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0411e44fcdc1363487ae0c6a4612ec908b9b09175d05499c5de0b3c81f0b5e5"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
@ -1538,7 +1859,9 @@ dependencies = [
[[package]] [[package]]
name = "rtc-rtcp" name = "rtc-rtcp"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fceaadac17b114140368dd68478d186ccfc293970f79cb8dd28f94dbbc0300be"
dependencies = [ dependencies = [
"bytes", "bytes",
"rtc-shared", "rtc-shared",
@ -1546,7 +1869,9 @@ dependencies = [
[[package]] [[package]]
name = "rtc-rtp" name = "rtc-rtp"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "babb45ac2263340e2bb412d1921aa07ca441ae9b5589477221d1a50d98750ba3"
dependencies = [ dependencies = [
"bytes", "bytes",
"memchr", "memchr",
@ -1557,7 +1882,9 @@ dependencies = [
[[package]] [[package]]
name = "rtc-sctp" name = "rtc-sctp"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2513391b524b88b041277faba617e0531ad726729861ea8933015393fd68ab05"
dependencies = [ dependencies = [
"bytes", "bytes",
"crc32c", "crc32c",
@ -1571,7 +1898,9 @@ dependencies = [
[[package]] [[package]]
name = "rtc-sdp" name = "rtc-sdp"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42d136a422965289e3d32d8e110789d8fa2ac669a4474a4084fa1eeac32758ee"
dependencies = [ dependencies = [
"rand", "rand",
"rtc-shared", "rtc-shared",
@ -1580,12 +1909,19 @@ dependencies = [
[[package]] [[package]]
name = "rtc-shared" name = "rtc-shared"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ce81c72adbce3a2f2ad8e2b97674d2482be83cb3bfd9a153341b04b1a87ca24"
dependencies = [ dependencies = [
"aes",
"aes-gcm",
"bitflags 1.3.2", "bitflags 1.3.2",
"bytes", "bytes",
"nix", "nix",
"p256",
"rand", "rand",
"rcgen",
"sec1",
"serde", "serde",
"substring", "substring",
"thiserror 2.0.18", "thiserror 2.0.18",
@ -1595,38 +1931,50 @@ dependencies = [
[[package]] [[package]]
name = "rtc-srtp" name = "rtc-srtp"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b880d5f6d436b3215c7bcfd3fb5ffe2a752fea0236440ccd98b6bf1c3561df8"
dependencies = [ dependencies = [
"aes",
"byteorder", "byteorder",
"bytes", "bytes",
"rtc-crypto", "ctr",
"hmac",
"ring",
"rtc-rtcp", "rtc-rtcp",
"rtc-rtp", "rtc-rtp",
"rtc-shared", "rtc-shared",
"sha1",
"subtle",
] ]
[[package]] [[package]]
name = "rtc-stun" name = "rtc-stun"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06b19c36a200df6071b92a25583a19ab0f9c6d5ad036d8c3ff5d392802cc926e"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
"crc", "crc",
"lazy_static", "lazy_static",
"md-5",
"rand", "rand",
"rtc-crypto", "ring",
"rtc-shared", "rtc-shared",
"sansio", "sansio",
"subtle",
"url", "url",
] ]
[[package]] [[package]]
name = "rtc-turn" name = "rtc-turn"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebf0b5fbb94085c86be7277c38ae8f1c21ec75ab47ba975be0984409732020dd"
dependencies = [ dependencies = [
"bytes", "bytes",
"log", "log",
"rtc-crypto",
"rtc-shared", "rtc-shared",
"rtc-stun", "rtc-stun",
"sansio", "sansio",
@ -1741,6 +2089,20 @@ dependencies = [
"syn 2.0.119", "syn 2.0.119",
] ]
[[package]]
name = "sec1"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
dependencies = [
"base16ct",
"der",
"generic-array",
"pkcs8",
"subtle",
"zeroize",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.28" version = "1.0.28"
@ -1816,12 +2178,33 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures 0.2.17",
"digest",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "2.0.1" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "signature"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
"rand_core 0.6.4",
]
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.10" version = "0.3.10"
@ -1868,6 +2251,16 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.1" version = "1.2.1"
@ -2217,6 +2610,16 @@ dependencies = [
"weedle2", "weedle2",
] ]
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.9.0" version = "0.9.0"
@ -2320,7 +2723,9 @@ dependencies = [
[[package]] [[package]]
name = "webrtc" name = "webrtc"
version = "0.21.0-beta.1" version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3daa8f2f6366331ae3275a6c02a855c6fb3faa1d16960498d7daaf61c96e76bd"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-channel", "async-channel",
@ -2468,6 +2873,18 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
[[package]]
name = "x25519-dalek"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
dependencies = [
"curve25519-dalek",
"rand_core 0.6.4",
"serde",
"zeroize",
]
[[package]] [[package]]
name = "x509-parser" name = "x509-parser"
version = "0.16.0" version = "0.16.0"
@ -2562,6 +2979,20 @@ name = "zeroize"
version = "1.9.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]] [[package]]
name = "zerotrie" name = "zerotrie"

View File

@ -9,8 +9,9 @@ lofty = "0.24.0"
discord-rich-presence = "1.1.0" discord-rich-presence = "1.1.0"
thiserror = "2.0" thiserror = "2.0"
parking_lot = "0.12" parking_lot = "0.12"
webrtc = { path = "../build/webrtc-rs" } log = "0.4"
rtc = { path = "../build/webrtc-rs/rtc" } webrtc = "0.20.4"
rtc = "0.20.4"
async-trait = "0.1" async-trait = "0.1"
bytes = "1" bytes = "1"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }

View File

@ -74,6 +74,9 @@ class JamSessionService(
private val _localParticipantId = MutableStateFlow<String?>(null) private val _localParticipantId = MutableStateFlow<String?>(null)
val localParticipantId: StateFlow<String?> = _localParticipantId.asStateFlow() val localParticipantId: StateFlow<String?> = _localParticipantId.asStateFlow()
private val _isConnected = MutableStateFlow(false)
val isConnected: StateFlow<Boolean> = _isConnected.asStateFlow()
private val _incomingMessages = MutableSharedFlow<JamMessage>(extraBufferCapacity = 64) private val _incomingMessages = MutableSharedFlow<JamMessage>(extraBufferCapacity = 64)
val incomingMessages = _incomingMessages.asSharedFlow() val incomingMessages = _incomingMessages.asSharedFlow()
@ -121,7 +124,7 @@ class JamSessionService(
log.i { "Generating invite $inviteId" } log.i { "Generating invite $inviteId" }
val pc = createWebrtcPeerConnection( val pc = createWebrtcPeerConnection(
iceServers = listOf(defaultIceServer()), iceServers = defaultIceServers(),
handler = guestEventHandler(inviteId), handler = guestEventHandler(inviteId),
) )
@ -174,18 +177,25 @@ class JamSessionService(
return true return true
} }
suspend fun joinSession(offerSdp: String): String { suspend fun joinSession(offerSdp: String, hostName: String? = null): String {
log.i { "Joining jam session" } log.i { "Joining jam session" }
val participantName = resolveParticipantName(defaultPrefix = "Guest") val participantName = resolveParticipantName(defaultPrefix = "Guest")
val pc = createWebrtcPeerConnection( val pc = createWebrtcPeerConnection(
iceServers = listOf(defaultIceServer()), iceServers = defaultIceServers(),
handler = eventHandler, handler = eventHandler,
) )
hostConnection = pc hostConnection = pc
_role.value = JamRole.Guest _role.value = JamRole.Guest
_localParticipantId.value = "guest" _localParticipantId.value = "guest"
_participants.value = listOf(
JamParticipant(
id = "host",
displayName = hostName?.ifBlank { null } ?: "Host",
isHost = true,
)
)
_isActive.value = true _isActive.value = true
// The data channel arrives in-band from the host's offer via on_data_channel; // The data channel arrives in-band from the host's offer via on_data_channel;
@ -226,6 +236,7 @@ class JamSessionService(
_role.value = null _role.value = null
_participants.value = emptyList() _participants.value = emptyList()
_isActive.value = false _isActive.value = false
_isConnected.value = false
_localParticipantId.value = null _localParticipantId.value = null
} }
@ -254,10 +265,28 @@ class JamSessionService(
sendMessage(JamMessage.SuggestPlaylist(tracks)) sendMessage(JamMessage.SuggestPlaylist(tracks))
} }
private fun defaultIceServer() = IceServerConfig( /**
urls = listOf("stun:stun.l.google.com:19302"), * ICE servers for global peer-to-peer jam sessions: multiple STUN servers for
username = "", * NAT traversal plus a TURN relay for symmetric NATs and strict firewalls.
credential = "", * Unreachable servers no longer stall offer/answer creation the webrtc
* driver completes gathering once every STUN client has answered or timed out,
* and [WebrtcPeerConnection] bounds the wait anyway.
*/
private fun defaultIceServers(): List<IceServerConfig> = listOf(
IceServerConfig(
urls = listOf(
"stun:stun.cloudflare.com:3478",
"stun:stun1.l.google.com:19302",
"stun:stun.l.google.com:19302",
),
username = "",
credential = "",
),
IceServerConfig(
urls = listOf("turn:openrelay.metered.ca:80"),
username = "openrelayproject",
credential = "openrelayproject",
),
) )
private suspend fun resolveParticipantName(defaultPrefix: String): String { private suspend fun resolveParticipantName(defaultPrefix: String): String {
@ -271,10 +300,12 @@ class JamSessionService(
* attributed back to that guest (needed for kick-on-leave and targeted sends). * attributed back to that guest (needed for kick-on-leave and targeted sends).
*/ */
private fun guestEventHandler(guestId: String) = object : WebrtcEventHandler { private fun guestEventHandler(guestId: String) = object : WebrtcEventHandler {
override fun onIceCandidate(candidate: String) {} override fun onIceCandidate(candidate: String) {
log.i { "[$guestId] ICE candidate: $candidate" }
}
override fun onIceGatheringStateChange(state: String) { override fun onIceGatheringStateChange(state: String) {
log.d { "[$guestId] ICE gathering state: $state" } log.i { "[$guestId] ICE gathering state: $state" }
} }
override fun onConnectionStateChange(state: String) { override fun onConnectionStateChange(state: String) {
@ -283,6 +314,7 @@ class JamSessionService(
override fun onDataChannelOpen(label: String) { override fun onDataChannelOpen(label: String) {
log.i { "[$guestId] Data channel '$label' open" } log.i { "[$guestId] Data channel '$label' open" }
_isConnected.value = true
} }
override fun onDataChannelMessage(label: String, data: String) { override fun onDataChannelMessage(label: String, data: String) {
@ -295,10 +327,12 @@ class JamSessionService(
} }
private val eventHandler = object : WebrtcEventHandler { private val eventHandler = object : WebrtcEventHandler {
override fun onIceCandidate(candidate: String) {} override fun onIceCandidate(candidate: String) {
log.i { "ICE candidate: $candidate" }
}
override fun onIceGatheringStateChange(state: String) { override fun onIceGatheringStateChange(state: String) {
log.d { "ICE gathering state: $state" } log.i { "ICE gathering state: $state" }
} }
override fun onConnectionStateChange(state: String) { override fun onConnectionStateChange(state: String) {
@ -307,6 +341,7 @@ class JamSessionService(
override fun onDataChannelOpen(label: String) { override fun onDataChannelOpen(label: String) {
log.i { "Data channel '$label' open" } log.i { "Data channel '$label' open" }
_isConnected.value = true
} }
override fun onDataChannelMessage(label: String, data: String) { override fun onDataChannelMessage(label: String, data: String) {

View File

@ -128,17 +128,19 @@ fun HomeScreen(viewModel: HomeScreenViewModel) {
Text("Browse") Text("Browse")
}, },
actions = { actions = {
IconButton(onClick = { navigationCommands.navigateTo(Routes.Devices) }) { if (!isDesktop) {
Icon( IconButton(onClick = { navigationCommands.navigateTo(Routes.Devices) }) {
imageVector = Iconsax.IconsaxMirroringScreen, Icon(
contentDescription = "Devices", imageVector = Iconsax.IconsaxMirroringScreen,
) contentDescription = "Devices",
} )
IconButton(onClick = { navigationCommands.navigateTo(Routes.Jam) }) { }
Icon( IconButton(onClick = { navigationCommands.navigateTo(Routes.Jam) }) {
imageVector = Iconsax.User, Icon(
contentDescription = "Group Jam", imageVector = Iconsax.User,
) contentDescription = "Group Jam",
)
}
} }
}, },
) )
@ -355,7 +357,7 @@ private fun HomeSection(
if (!subtitle.isNullOrEmpty()) Text( if (!subtitle.isNullOrEmpty()) Text(
text = subtitle, text = subtitle,
style = MaterialTheme.typography.labelMedium.copy( style = MaterialTheme.typography.labelMedium.copy(
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
), ),
modifier = Modifier.padding(horizontal = 16.dp), modifier = Modifier.padding(horizontal = 16.dp),

View File

@ -53,6 +53,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import dev.krtirtho.spotube.core.jam.JamRole import dev.krtirtho.spotube.core.jam.JamRole
import dev.krtirtho.spotube.core.navigation.NavigationCommands import dev.krtirtho.spotube.core.navigation.NavigationCommands
import dev.krtirtho.spotube.core.ui.component.ApplicationMainBar import dev.krtirtho.spotube.core.ui.component.ApplicationMainBar
import dev.krtirtho.spotube.modules.shell.LocalAppShellBottomInset
import org.koin.compose.viewmodel.koinViewModel import org.koin.compose.viewmodel.koinViewModel
@Composable @Composable
@ -61,6 +62,7 @@ fun JamScreen(
) { ) {
val viewModel = koinViewModel<JamViewModel>() val viewModel = koinViewModel<JamViewModel>()
val state by viewModel.uiState.collectAsStateWithLifecycle() val state by viewModel.uiState.collectAsStateWithLifecycle()
val shellBottomInset = LocalAppShellBottomInset.current
Scaffold( Scaffold(
topBar = { topBar = {
@ -75,6 +77,7 @@ fun JamScreen(
.fillMaxSize() .fillMaxSize()
.padding(innerPadding) .padding(innerPadding)
.padding(16.dp) .padding(16.dp)
.padding(bottom = shellBottomInset)
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
) { ) {
@ -292,23 +295,35 @@ private fun GuestSessionView(
ParticipantsSection(state.participants) ParticipantsSection(state.participants)
val answerLink = state.answerLink val answerLink = state.answerLink
if (answerLink == null) { when {
Text( state.isConnected -> {
text = "Connecting to the session...", Text(
style = MaterialTheme.typography.bodyMedium, text = "Connected to the session",
color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodyMedium,
) color = MaterialTheme.colorScheme.primary,
} else { )
Text( }
text = "Almost there! Send your answer back to the host:",
style = MaterialTheme.typography.titleSmall, answerLink == null -> {
) Text(
ShareableLinkBox( text = "Connecting to the session...",
label = "Answer link", style = MaterialTheme.typography.bodyMedium,
link = answerLink, color = MaterialTheme.colorScheme.onSurfaceVariant,
onCopy = { clipboard.setText(AnnotatedString(answerLink)) }, )
onShare = { onShare(answerLink) }, }
)
else -> {
Text(
text = "Almost there! Send your answer back to the host:",
style = MaterialTheme.typography.titleSmall,
)
ShareableLinkBox(
label = "Answer link",
link = answerLink,
onCopy = { clipboard.setText(AnnotatedString(answerLink)) },
onShare = { onShare(answerLink) },
)
}
} }
LeaveButton(onLeave) LeaveButton(onLeave)

View File

@ -37,6 +37,7 @@ import kotlinx.coroutines.launch
data class JamUiState( data class JamUiState(
val isActive: Boolean = false, val isActive: Boolean = false,
val isConnected: Boolean = false,
val role: JamRole? = null, val role: JamRole? = null,
val participants: List<JamParticipant> = emptyList(), val participants: List<JamParticipant> = emptyList(),
/** Host: deep link containing this session's SDP offer, ready to share. */ /** Host: deep link containing this session's SDP offer, ready to share. */
@ -69,6 +70,7 @@ class JamViewModel(
_uiState.update { _uiState.update {
it.copy( it.copy(
isActive = active, isActive = active,
isConnected = jamSession.isConnected.value,
role = jamSession.role.value, role = jamSession.role.value,
participants = jamSession.participants.value, participants = jamSession.participants.value,
inviteLink = if (!active) null else it.inviteLink, inviteLink = if (!active) null else it.inviteLink,
@ -84,6 +86,11 @@ class JamViewModel(
_uiState.update { it.copy(participants = participants) } _uiState.update { it.copy(participants = participants) }
} }
} }
viewModelScope.launch {
jamSession.isConnected.collect { connected ->
_uiState.update { it.copy(isConnected = connected) }
}
}
viewModelScope.launch { viewModelScope.launch {
deepLinks.pendingLink.collect { link -> deepLinks.pendingLink.collect { link ->
handleDeepLink(link) handleDeepLink(link)
@ -119,16 +126,17 @@ class JamViewModel(
fun joinWithIncomingInvite() { fun joinWithIncomingInvite() {
val sdp = _uiState.value.incomingOfferSdp ?: return val sdp = _uiState.value.incomingOfferSdp ?: return
join(sdp) join(sdp, _uiState.value.incomingHostName)
} }
fun joinWithPasted(input: String) { fun joinWithPasted(input: String) {
val sdp = JamInviteCodec.extractSdp(input) val parsed = JamInviteCodec.parse(input)
val sdp = parsed?.sdp ?: JamInviteCodec.extractSdp(input)
if (sdp == null) { if (sdp == null) {
_uiState.update { it.copy(error = "That doesn't look like a valid jam invite.") } _uiState.update { it.copy(error = "That doesn't look like a valid jam invite.") }
return return
} }
join(sdp) join(sdp, (parsed as? JamInviteLink.HostInvite)?.peerName)
} }
/** /**
@ -171,10 +179,10 @@ class JamViewModel(
_uiState.update { it.copy(incomingOfferSdp = null, incomingHostName = null) } _uiState.update { it.copy(incomingOfferSdp = null, incomingHostName = null) }
} }
private fun join(offerSdp: String) { private fun join(offerSdp: String, hostName: String? = null) {
viewModelScope.launch { viewModelScope.launch {
runCatching { runCatching {
val answer = jamSession.joinSession(offerSdp) val answer = jamSession.joinSession(offerSdp, hostName)
JamInviteCodec.buildGuestAnswer(localName(), answer) JamInviteCodec.buildGuestAnswer(localName(), answer)
}.onSuccess { link -> }.onSuccess { link ->
_uiState.update { _uiState.update {

View File

@ -16,9 +16,12 @@
*/ */
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use parking_lot::Mutex; use parking_lot::Mutex;
use rtc::ice::mdns::MulticastDnsMode;
use rtc::peer_connection::configuration::interceptor_registry::register_default_interceptors; use rtc::peer_connection::configuration::interceptor_registry::register_default_interceptors;
use rtc::peer_connection::configuration::setting_engine::SettingEngine;
use webrtc::data_channel::{DataChannel, DataChannelEvent, RTCDataChannelInit}; use webrtc::data_channel::{DataChannel, DataChannelEvent, RTCDataChannelInit};
use webrtc::peer_connection::{ use webrtc::peer_connection::{
MediaEngine, PeerConnection, PeerConnectionBuilder, PeerConnectionEventHandler, MediaEngine, PeerConnection, PeerConnectionBuilder, PeerConnectionEventHandler,
@ -111,6 +114,13 @@ pub async fn create_webrtc_peer_connection(
) )
.build(); .build();
// mDNS adds a multicast UDP socket per peer connection. On some platforms
// (notably Android) that socket can stall and ICE gathering then never
// completes. Real-IP host candidates (no mDNS) work fine alongside STUN/TURN,
// so mDNS is disabled.
let mut setting_engine = SettingEngine::default();
setting_engine.set_multicast_dns_mode(MulticastDnsMode::Disabled);
let (gather_tx, gather_rx) = channel::<()>(1); let (gather_tx, gather_rx) = channel::<()>(1);
let pc_handler = Arc::new(PeerHandlerBridge { let pc_handler = Arc::new(PeerHandlerBridge {
handler: Arc::clone(&handler), handler: Arc::clone(&handler),
@ -119,6 +129,7 @@ pub async fn create_webrtc_peer_connection(
let pc = PeerConnectionBuilder::new() let pc = PeerConnectionBuilder::new()
.with_configuration(config) .with_configuration(config)
.with_setting_engine(setting_engine)
.with_media_engine(media_engine) .with_media_engine(media_engine)
.with_interceptor_registry(registry) .with_interceptor_registry(registry)
.with_handler(pc_handler) .with_handler(pc_handler)
@ -138,9 +149,20 @@ impl WebrtcPeerConnection {
/// Waits for ICE gathering to reach `Complete` so the local SDP includes all /// Waits for ICE gathering to reach `Complete` so the local SDP includes all
/// candidates (non-trickle exchange). Must be called after `set_local_description`, /// candidates (non-trickle exchange). Must be called after `set_local_description`,
/// which is what starts gathering. /// which is what starts gathering.
///
/// Bounded by a timeout so a stalled gatherer (e.g. a platform that never reports
/// completion) can never hang `create_offer`/`create_answer` forever — the SDP
/// with the candidates gathered so far is returned instead.
async fn wait_for_ice_gathering(&self) { async fn wait_for_ice_gathering(&self) {
let mut gather_rx = self.gather_rx.lock().clone(); let mut gather_rx = self.gather_rx.lock().clone();
let _ = gather_rx.recv().await; match tokio::time::timeout(Duration::from_secs(5), gather_rx.recv()).await {
Ok(_) => {}
Err(_) => {
log::warn!(
"ICE gathering did not complete within 5s; returning SDP with the candidates gathered so far"
);
}
}
} }
} }