-
+
Examples
+
-
-
-
diff --git a/js/package-lock.json b/js/package-lock.json
index 35d04070..4c021e5d 100644
--- a/js/package-lock.json
+++ b/js/package-lock.json
@@ -8,6 +8,9 @@
"name": "js",
"version": "1.0.0",
"license": "ISC",
+ "dependencies": {
+ "@types/dom-mediacapture-transform": "^0.1.11"
+ },
"devDependencies": {
"prettier": "^3.2.5",
"vite": "^4.4.10",
@@ -22,6 +25,7 @@
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -38,6 +42,7 @@
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -54,6 +59,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -70,6 +76,7 @@
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -86,6 +93,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -102,6 +110,7 @@
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -118,6 +127,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -134,6 +144,7 @@
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -150,6 +161,7 @@
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -166,6 +178,7 @@
"ia32"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -182,6 +195,7 @@
"loong64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -198,6 +212,7 @@
"mips64el"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -214,6 +229,7 @@
"ppc64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -230,6 +246,7 @@
"riscv64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -246,6 +263,7 @@
"s390x"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -262,6 +280,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -278,6 +297,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"netbsd"
@@ -294,6 +314,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"openbsd"
@@ -310,6 +331,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"sunos"
@@ -326,6 +348,7 @@
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -342,6 +365,7 @@
"ia32"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -358,6 +382,7 @@
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -366,11 +391,27 @@
"node": ">=12"
}
},
+ "node_modules/@types/dom-mediacapture-transform": {
+ "version": "0.1.11",
+ "resolved": "https://registry.npmjs.org/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.11.tgz",
+ "integrity": "sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/dom-webcodecs": "*"
+ }
+ },
+ "node_modules/@types/dom-webcodecs": {
+ "version": "0.1.14",
+ "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.14.tgz",
+ "integrity": "sha512-ba9aF0qARLLQpLihONIRbj8VvAdUxO+5jIxlscVcDAQTcJmq5qVr781+ino5qbQUJUmO21cLP2eLeXYWzao5Vg==",
+ "license": "MIT"
+ },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -386,6 +427,7 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -402,6 +444,7 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -413,7 +456,8 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/esbuild": {
"version": "0.18.20",
@@ -421,6 +465,7 @@
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
"dev": true,
"hasInstallScript": true,
+ "license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
@@ -457,6 +502,7 @@
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -472,6 +518,7 @@
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -484,13 +531,15 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -500,6 +549,7 @@
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
},
@@ -508,9 +558,9 @@
}
},
"node_modules/nanoid": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
- "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
@@ -518,6 +568,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -529,18 +580,20 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/narrowing/-/narrowing-1.5.0.tgz",
"integrity": "sha512-DUu4XdKgkfAPTAL28k79pdnshDE2W5T24QAnidSPo2F/W1TX6CjNzmEeXQfE5O1lxQvC0GYI6ZRDsLcyzugEYA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/postcss": {
- "version": "8.4.31",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
- "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+ "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
"funding": [
{
@@ -556,20 +609,22 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "nanoid": "^3.3.6",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "nanoid": "^3.3.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prettier": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
- "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
+ "license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -581,10 +636,11 @@
}
},
"node_modules/rollup": {
- "version": "3.29.4",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
- "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "version": "3.29.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz",
+ "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
"dev": true,
+ "license": "MIT",
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -597,10 +653,11 @@
}
},
"node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -610,6 +667,7 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -618,19 +676,21 @@
}
},
"node_modules/universalify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
- "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/vite": {
- "version": "4.4.10",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.10.tgz",
- "integrity": "sha512-TzIjiqx9BEXF8yzYdF2NTf1kFFbjMjUSV0LFZ3HyHoI3SGSPLnnFUKiIQtL3gl2AjHvMrprOvQ3amzaHgQlAxw==",
+ "version": "4.5.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.9.tgz",
+ "integrity": "sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.27",
@@ -686,6 +746,7 @@
"resolved": "https://registry.npmjs.org/vite-plugin-wasm-pack/-/vite-plugin-wasm-pack-0.1.12.tgz",
"integrity": "sha512-WliYvQp9HXluir4OKGbngkcKxtYtifU11cqLurRRJGsl770Sjr1iIkp5RuvU3IC1poT4A57Z2/YgAKI2Skm7ZA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"fs-extra": "^10.0.0",
diff --git a/js/package.json b/js/package.json
index 28bfff5e..2af9c9a5 100644
--- a/js/package.json
+++ b/js/package.json
@@ -16,5 +16,8 @@
"prettier": "^3.2.5",
"vite": "^4.4.10",
"vite-plugin-wasm-pack": "^0.1.12"
+ },
+ "dependencies": {
+ "@types/dom-mediacapture-transform": "^0.1.11"
}
}
diff --git a/js/tsconfig.json b/js/tsconfig.json
new file mode 100644
index 00000000..5a862bef
--- /dev/null
+++ b/js/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "strict": true,
+ "jsx": "preserve",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "types": ["@types/dom-mediacapture-transform"]
+ },
+ "include": ["examples/**/*.ts", "examples/**/*.tsx"],
+ "exclude": ["node_modules"]
+}
diff --git a/js/vite.config.js b/js/vite.config.js
index 9a6b86ba..5ff904c2 100644
--- a/js/vite.config.js
+++ b/js/vite.config.js
@@ -1,11 +1,12 @@
import { defineConfig } from 'vite'
-import wasmPack from 'vite-plugin-wasm-pack'
export default defineConfig({
- // pass your local crate path to the plugin
- // plugins: [wasmPack('../rust-wasm-vite')]
- // server: {
- // headers: {
- // }
- // }
+ build: {
+ rollupOptions: {
+ input: {
+ main: 'src/pages/index.html',
+ about: 'src/pages/about.html'
+ }
+ }
+ }
})
diff --git a/moqt-client-sample/src/lib.rs b/moqt-client-sample/src/lib.rs
index 3c3f7aa9..2fbc859d 100644
--- a/moqt-client-sample/src/lib.rs
+++ b/moqt-client-sample/src/lib.rs
@@ -13,20 +13,25 @@ use moqt_core::{
announce_error::AnnounceError,
announce_ok::AnnounceOk,
client_setup::ClientSetup,
+ group_order::GroupOrder,
server_setup::ServerSetup,
- setup_parameters::{MaxSubscribeID, Role, RoleCase, SetupParameter},
- subscribe::{FilterType, GroupOrder, Subscribe},
+ setup_parameters::{MaxSubscribeID, SetupParameter},
+ subscribe::{FilterType, Subscribe},
+ subscribe_announces::SubscribeAnnounces,
+ subscribe_announces_error::SubscribeAnnouncesError,
+ subscribe_announces_ok::SubscribeAnnouncesOk,
subscribe_error::{SubscribeError, SubscribeErrorCode},
- subscribe_namespace::SubscribeNamespace,
- subscribe_namespace_error::SubscribeNamespaceError,
- subscribe_namespace_ok::SubscribeNamespaceOk,
subscribe_ok::SubscribeOk,
unannounce::UnAnnounce,
unsubscribe::Unsubscribe,
- version_specific_parameters::{AuthorizationInfo, VersionSpecificParameter},
+ version_specific_parameters::{
+ AuthorizationInfo, DeliveryTimeout, MaxCacheDuration, VersionSpecificParameter,
+ },
},
messages::{
- data_streams::{datagram, subgroup_stream, track_stream, DataStreams},
+ data_streams::{
+ datagram, datagram_status, object_status::ObjectStatus, subgroup_stream, DataStreams,
+ },
moqt_payload::MOQTPayload,
},
models::subscriptions::{
@@ -147,11 +152,11 @@ impl MOQTClient {
.borrow_mut()
.set_subscribe_response_callback(callback);
}
- #[wasm_bindgen(js_name = onSubscribeNamespaceResponse)]
- pub fn set_subscribe_namespace_response_callback(&mut self, callback: js_sys::Function) {
+ #[wasm_bindgen(js_name = onSubscribeAnnouncesResponse)]
+ pub fn set_subscribe_announces_response_callback(&mut self, callback: js_sys::Function) {
self.callbacks
.borrow_mut()
- .set_subscribe_namespace_response_callback(callback);
+ .set_subscribe_announces_response_callback(callback);
}
#[wasm_bindgen(js_name = onDatagramObject)]
@@ -161,18 +166,11 @@ impl MOQTClient {
.set_datagram_object_callback(callback);
}
- #[wasm_bindgen(js_name = onTrackStreamHeader)]
- pub fn set_track_stream_header_callback(&mut self, callback: js_sys::Function) {
+ #[wasm_bindgen(js_name = onDatagramObjectStatus)]
+ pub fn set_datagram_object_status_callback(&mut self, callback: js_sys::Function) {
self.callbacks
.borrow_mut()
- .set_track_stream_header_callback(callback);
- }
-
- #[wasm_bindgen(js_name = onTrackStreamObject)]
- pub fn set_track_stream_object_callback(&mut self, callback: js_sys::Function) {
- self.callbacks
- .borrow_mut()
- .set_track_stream_object_callback(callback);
+ .set_datagram_object_status_callback(callback);
}
#[wasm_bindgen(js_name = onSubgroupStreamHeader)]
@@ -183,33 +181,28 @@ impl MOQTClient {
}
#[wasm_bindgen(js_name = onSubgroupStreamObject)]
- pub fn set_subgroup_stream_object_callback(&mut self, callback: js_sys::Function) {
+ pub fn set_subgroup_stream_object_callback(
+ &mut self,
+ track_alias: u64,
+ callback: js_sys::Function,
+ ) {
self.callbacks
.borrow_mut()
- .set_subgroup_stream_object_callback(callback);
+ .set_subgroup_stream_object_callback(track_alias, callback);
}
#[wasm_bindgen(js_name = sendSetupMessage)]
pub async fn send_setup_message(
&mut self,
- role_value: u8,
versions: Vec
,
max_subscribe_id: u64,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
- let role = RoleCase::try_from(role_value).unwrap();
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
let versions = versions.iter().map(|v| *v as u32).collect::>();
- let mut setup_parameters: Vec =
- vec![SetupParameter::Role(Role::new(role))];
-
- match role {
- RoleCase::Publisher | RoleCase::PubSub => {
- setup_parameters.push(SetupParameter::MaxSubscribeID(MaxSubscribeID::new(
- max_subscribe_id,
- )));
- }
- _ => {}
- }
+ let setup_parameters = vec![SetupParameter::MaxSubscribeID(MaxSubscribeID::new(
+ max_subscribe_id,
+ ))];
let client_setup_message = ClientSetup::new(versions, setup_parameters);
let mut client_setup_message_buf = BytesMut::new();
@@ -231,26 +224,13 @@ impl MOQTClient {
// Setup nodes along with the role
Ok(ok) => {
log(std::format!("sent: client_setup: {:#x?}", client_setup_message).as_str());
- match role {
- RoleCase::Publisher => {
- self.subscription_node
- .borrow_mut()
- .setup_as_publisher(max_subscribe_id);
- }
- RoleCase::Subscriber => {
- self.subscription_node
- .borrow_mut()
- .setup_as_subscriber(max_subscribe_id);
- }
- RoleCase::PubSub => {
- self.subscription_node
- .borrow_mut()
- .setup_as_publisher(max_subscribe_id);
- self.subscription_node
- .borrow_mut()
- .setup_as_subscriber(max_subscribe_id);
- }
- }
+ self.subscription_node
+ .borrow_mut()
+ .setup_as_publisher(max_subscribe_id);
+ self.subscription_node
+ .borrow_mut()
+ .setup_as_subscriber(max_subscribe_id);
+
Ok(ok)
}
Err(e) => Err(e),
@@ -267,7 +247,8 @@ impl MOQTClient {
track_namespace: js_sys::Array,
auth_info: String, // param[0]
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
let auth_info_parameter =
VersionSpecificParameter::AuthorizationInfo(AuthorizationInfo::new(auth_info));
@@ -315,7 +296,8 @@ impl MOQTClient {
&self,
track_namespace: js_sys::Array,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
let length = track_namespace.length();
let mut track_namespace_vec: Vec = Vec::with_capacity(length as usize);
for i in 0..length {
@@ -359,7 +341,8 @@ impl MOQTClient {
&self,
track_namespace: js_sys::Array,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
// TODO: construct UnAnnounce
let length = track_namespace.length();
let mut track_namespace_vec: Vec = Vec::with_capacity(length as usize);
@@ -401,6 +384,7 @@ impl MOQTClient {
// tmp impl
#[wasm_bindgen(js_name = sendSubscribeMessage)]
+ #[allow(clippy::too_many_arguments)]
pub async fn send_subscribe_message(
&self,
subscribe_id: u64,
@@ -413,10 +397,10 @@ impl MOQTClient {
start_group: u64,
start_object: u64,
end_group: u64,
- end_object: u64,
auth_info: String,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
// This is equal to `Now example`
let auth_info =
VersionSpecificParameter::AuthorizationInfo(AuthorizationInfo::new(auth_info));
@@ -438,14 +422,18 @@ impl MOQTClient {
(Some(start_group), Some(start_object))
}
};
- let (end_group, end_object) = match filter_type {
+ let end_group = match filter_type {
FilterType::LatestObject | FilterType::LatestGroup | FilterType::AbsoluteStart => {
- (None, None)
+ None
}
- FilterType::AbsoluteRange => (Some(end_group), Some(end_object)),
+ FilterType::AbsoluteRange => Some(end_group),
};
- let version_specific_parameters = vec![auth_info];
+ let max_cache_duration =
+ VersionSpecificParameter::MaxCacheDuration(MaxCacheDuration::new(1000000));
+ let delivery_timeout =
+ VersionSpecificParameter::DeliveryTimeout(DeliveryTimeout::new(100000));
+ let version_specific_parameters = vec![auth_info, max_cache_duration, delivery_timeout];
let subscribe_message = Subscribe::new(
subscribe_id,
track_alias,
@@ -457,7 +445,6 @@ impl MOQTClient {
start_group,
start_object,
end_group,
- end_object,
version_specific_parameters,
)
.unwrap();
@@ -493,7 +480,6 @@ impl MOQTClient {
start_group,
start_object,
end_group,
- end_object,
);
Ok(ok)
@@ -513,7 +499,8 @@ impl MOQTClient {
auth_info: String,
fowarding_preference: String,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
let auth_info =
VersionSpecificParameter::AuthorizationInfo(AuthorizationInfo::new(auth_info));
let subscription = self
@@ -577,16 +564,14 @@ impl MOQTClient {
*self.datagram_writer.borrow_mut() = Some(datagram_writer);
}
"track" => {
- let send_uni_stream = WritableStream::from(
- JsFuture::from(
- self.transport
- .borrow()
- .as_ref()
- .unwrap()
- .create_unidirectional_stream(),
- )
- .await?,
- );
+ let send_uni_stream = self
+ .transport
+ .borrow()
+ .as_ref()
+ .unwrap()
+ .create_unidirectional_stream();
+ let send_uni_stream =
+ WritableStream::from(JsFuture::from(send_uni_stream).await?);
let send_uni_stream_writer = send_uni_stream.get_writer()?;
let writer_key = (subscribe_id, None);
@@ -609,13 +594,14 @@ impl MOQTClient {
}
}
- #[wasm_bindgen(js_name = sendSubscribeNamespaceMessage)]
- pub async fn send_subscribe_namespace_message(
+ #[wasm_bindgen(js_name = sendSubscribeAnnouncesMessage)]
+ pub async fn send_subscribe_announces_message(
&self,
track_namespace_prefix: js_sys::Array,
auth_info: String,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
let auth_info =
VersionSpecificParameter::AuthorizationInfo(AuthorizationInfo::new(auth_info));
let length = track_namespace_prefix.length();
@@ -629,21 +615,21 @@ impl MOQTClient {
}
let version_specific_parameters = vec![auth_info];
- let subscribe_namespace_message =
- SubscribeNamespace::new(track_namespace_prefix_vec, version_specific_parameters);
- let mut subscribe_namespace_message_buf = BytesMut::new();
- subscribe_namespace_message.packetize(&mut subscribe_namespace_message_buf);
+ let subscribe_announces_message =
+ SubscribeAnnounces::new(track_namespace_prefix_vec, version_specific_parameters);
+ let mut subscribe_announces_message_buf = BytesMut::new();
+ subscribe_announces_message.packetize(&mut subscribe_announces_message_buf);
let mut buf = Vec::new();
// Message Type
buf.extend(write_variable_integer(
- u8::from(ControlMessageType::SubscribeNamespace) as u64,
+ u8::from(ControlMessageType::SubscribeAnnounces) as u64,
));
// Message Payload and Payload Length
buf.extend(write_variable_integer(
- subscribe_namespace_message_buf.len() as u64,
+ subscribe_announces_message_buf.len() as u64,
));
- buf.extend(subscribe_namespace_message_buf);
+ buf.extend(subscribe_announces_message_buf);
let buffer = js_sys::Uint8Array::new_with_length(buf.len() as u32);
buffer.copy_from(&buf);
@@ -651,8 +637,8 @@ impl MOQTClient {
match JsFuture::from(writer.write_with_chunk(&buffer)).await {
Ok(ok) => {
log(std::format!(
- "sent: subscribe_namespace: {:#x?}",
- subscribe_namespace_message
+ "sent: subscribe_announces: {:#x?}",
+ subscribe_announces_message
)
.as_str());
Ok(ok)
@@ -671,7 +657,8 @@ impl MOQTClient {
error_code: u64,
reason_phrase: String,
) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
// Find unused subscribe_id and track_alias automatically
let valid_track_alias = self
.subscription_node
@@ -718,7 +705,8 @@ impl MOQTClient {
#[wasm_bindgen(js_name = sendUnsubscribeMessage)]
pub async fn send_unsubscribe_message(&self, subscribe_id: u64) -> Result {
- if let Some(writer) = &*self.control_stream_writer.borrow() {
+ let writer = self.control_stream_writer.borrow().clone();
+ if let Some(writer) = writer {
let unsubscribe_message = Unsubscribe::new(subscribe_id);
let mut unsubscribe_message_buf = BytesMut::new();
unsubscribe_message.packetize(&mut unsubscribe_message_buf);
@@ -750,26 +738,26 @@ impl MOQTClient {
#[wasm_bindgen(js_name = sendDatagramObject)]
pub async fn send_datagram_object(
&self,
- subscribe_id: u64,
track_alias: u64,
group_id: u64,
object_id: u64,
publisher_priority: u8,
object_payload: Vec,
) -> Result {
- if let Some(writer) = &*self.datagram_writer.borrow() {
+ let writer = self.datagram_writer.borrow().clone();
+ if let Some(writer) = writer {
+ let extension_headers = vec![];
let datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- None,
+ extension_headers,
object_payload,
)
.unwrap();
let mut datagram_object_buf = BytesMut::new();
- let _ = datagram_object.packetize(&mut datagram_object_buf);
+ datagram_object.packetize(&mut datagram_object_buf);
let mut buf = Vec::new();
// Message Type
@@ -791,69 +779,40 @@ impl MOQTClient {
}
}
} else {
- return Err(JsValue::from_str("datagram_writer is None"));
+ Err(JsValue::from_str("datagram_writer is None"))
}
}
- #[wasm_bindgen(js_name = sendTrackStreamHeaderMessage)]
- pub async fn send_track_stream_header_message(
+ #[wasm_bindgen(js_name = sendDatagramObjectStatus)]
+ pub async fn send_datagram_object_status(
&self,
- subscribe_id: u64,
track_alias: u64,
+ group_id: u64,
+ object_id: u64,
publisher_priority: u8,
+ object_status: u8,
) -> Result {
- let stream_writers = self.stream_writers.borrow();
- let writer_key = (subscribe_id, None);
- if let Some(writer) = stream_writers.get(&writer_key) {
- let track_stream_header_message =
- track_stream::Header::new(subscribe_id, track_alias, publisher_priority).unwrap();
- let mut track_stream_header_message_buf = BytesMut::new();
- let _ = track_stream_header_message.packetize(&mut track_stream_header_message_buf);
+ let writer = self.datagram_writer.borrow().clone();
+ if let Some(writer) = writer {
+ let extension_headers = vec![];
+ let datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ ObjectStatus::try_from(object_status).unwrap(),
+ )
+ .unwrap();
+ let mut datagram_object_buf = BytesMut::new();
+ datagram_object.packetize(&mut datagram_object_buf);
let mut buf = Vec::new();
// Message Type
buf.extend(write_variable_integer(
- u8::from(DataStreamType::StreamHeaderTrack) as u64,
+ u8::from(DataStreamType::ObjectDatagramStatus) as u64,
));
- buf.extend(track_stream_header_message_buf);
-
- let buffer = js_sys::Uint8Array::new_with_length(buf.len() as u32);
- buffer.copy_from(&buf);
- match JsFuture::from(writer.write_with_chunk(&buffer)).await {
- Ok(ok) => {
- log(std::format!(
- "sent: track_stream_header: {:#x?}",
- track_stream_header_message
- )
- .as_str());
- Ok(ok)
- }
- Err(e) => Err(e),
- }
- } else {
- return Err(JsValue::from_str("stream_writer is None"));
- }
- }
-
- #[wasm_bindgen(js_name = sendTrackStreamObject)]
- pub async fn send_track_stream_object(
- &self,
- subscribe_id: u64,
- group_id: u64,
- object_id: u64,
- object_payload: Vec,
- ) -> Result {
- let stream_writers = self.stream_writers.borrow();
- let writer_key = (subscribe_id, None);
- if let Some(writer) = stream_writers.get(&writer_key) {
- let track_stream_object =
- track_stream::Object::new(group_id, object_id, None, object_payload).unwrap();
- let mut track_stream_object_buf = BytesMut::new();
- let _ = track_stream_object.packetize(&mut track_stream_object_buf);
-
- let mut buf = Vec::new();
- // Message Payload and Payload Length
- buf.extend(track_stream_object_buf);
+ buf.extend(datagram_object_buf);
let buffer = js_sys::Uint8Array::new_with_length(buf.len() as u32);
buffer.copy_from(&buf);
@@ -868,52 +827,64 @@ impl MOQTClient {
}
}
} else {
- return Err(JsValue::from_str("stream_writer is None"));
+ Err(JsValue::from_str("datagram_writer is None"))
}
}
#[wasm_bindgen(js_name = sendSubgroupStreamHeaderMessage)]
pub async fn send_subgroup_stream_header_message(
&self,
- subscribe_id: u64,
track_alias: u64,
group_id: u64,
subgroup_id: u64,
publisher_priority: u8,
) -> Result {
- let mut stream_writers = self.stream_writers.borrow_mut();
+ let subscribe_id = self
+ .subscription_node
+ .borrow()
+ .get_publishing_subscribe_id_by_track_alias(track_alias)
+ .unwrap();
let writer_key = (subscribe_id, Some((group_id, subgroup_id)));
- if stream_writers.get(&writer_key).is_none() {
- let send_uni_stream = WritableStream::from(
- JsFuture::from(
- self.transport
- .borrow()
- .as_ref()
- .unwrap()
- .create_unidirectional_stream(),
- )
- .await?,
- );
+
+ let writer = {
+ let stream_writers = self.stream_writers.borrow_mut();
+
+ if !stream_writers.contains_key(&writer_key) {
+ // 新しいwriterを作成
+ let _ = {
+ let transport = self.transport.borrow();
+ transport.as_ref().unwrap().create_unidirectional_stream()
+ };
+ };
+ stream_writers.get(&writer_key).cloned()
+ };
+ let writer = if let Some(writer) = writer {
+ writer
+ } else {
+ let uni_stream_future = {
+ let transport = self.transport.borrow();
+ transport.as_ref().unwrap().create_unidirectional_stream()
+ };
+ let send_uni_stream = WritableStream::from(JsFuture::from(uni_stream_future).await?);
let send_uni_stream_writer = send_uni_stream.get_writer()?;
- stream_writers.insert(writer_key, send_uni_stream_writer);
- }
- let writer = stream_writers.get(&writer_key).unwrap();
- let subgroup_stream_header_message = subgroup_stream::Header::new(
- subscribe_id,
- track_alias,
- group_id,
- subgroup_id,
- publisher_priority,
- )
- .unwrap();
+ // 作成したwriterを保存
+ self.stream_writers
+ .borrow_mut()
+ .insert(writer_key, send_uni_stream_writer.clone());
+ send_uni_stream_writer
+ };
+
+ let subgroup_stream_header_message =
+ subgroup_stream::Header::new(track_alias, group_id, subgroup_id, publisher_priority)
+ .unwrap();
let mut subgroup_stream_header_message_buf = BytesMut::new();
- let _ = subgroup_stream_header_message.packetize(&mut subgroup_stream_header_message_buf);
+ subgroup_stream_header_message.packetize(&mut subgroup_stream_header_message_buf);
let mut buf = Vec::new();
// Message Type
buf.extend(write_variable_integer(
- u8::from(DataStreamType::StreamHeaderSubgroup) as u64,
+ u8::from(DataStreamType::SubgroupHeader) as u64,
));
buf.extend(subgroup_stream_header_message_buf);
@@ -925,19 +896,34 @@ impl MOQTClient {
#[wasm_bindgen(js_name = sendSubgroupStreamObject)]
pub async fn send_subgroup_stream_object(
&self,
- subscribe_id: u64,
+ track_alias: u64,
group_id: u64,
subgroup_id: u64,
object_id: u64,
+ object_status: Option,
object_payload: Vec,
) -> Result {
- let stream_writers = self.stream_writers.borrow();
+ let subscribe_id = self
+ .subscription_node
+ .borrow()
+ .get_publishing_subscribe_id_by_track_alias(track_alias)
+ .unwrap();
let writer_key = (subscribe_id, Some((group_id, subgroup_id)));
- if let Some(writer) = stream_writers.get(&writer_key) {
- let subgroup_stream_object =
- subgroup_stream::Object::new(object_id, None, object_payload).unwrap();
+ let writer = {
+ let stream_writers = self.stream_writers.borrow();
+ stream_writers.get(&writer_key).cloned()
+ };
+ if let Some(writer) = writer {
+ let extension_headers = vec![];
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status.map(|status| ObjectStatus::try_from(status).unwrap()),
+ object_payload,
+ )
+ .unwrap();
let mut subgroup_stream_object_buf = BytesMut::new();
- let _ = subgroup_stream_object.packetize(&mut subgroup_stream_object_buf);
+ subgroup_stream_object.packetize(&mut subgroup_stream_object_buf);
let mut buf = Vec::new();
// Message Payload and Payload Length
@@ -947,7 +933,15 @@ impl MOQTClient {
buffer.copy_from(&buf);
match JsFuture::from(writer.write_with_chunk(&buffer)).await {
Ok(ok) => {
- log(std::format!("sent: object id: {:#?}", object_id).as_str());
+ log(std::format!(
+ "sent: trackAlias: {:#?} object . group_id: {:#?} subgroup_id: {:#?} object_id: {:#?} object_status: {:#?}",
+ track_alias,
+ group_id,
+ subgroup_id,
+ object_id,
+ object_status,
+ )
+ .as_str());
Ok(ok)
}
Err(e) => {
@@ -956,7 +950,7 @@ impl MOQTClient {
}
}
} else {
- return Err(JsValue::from_str("stream_writer is None"));
+ Err(JsValue::from_str("stream_writer is None"))
}
}
@@ -1010,8 +1004,7 @@ impl MOQTClient {
// For receiving object messages as streams
let incoming_uni_stream = transport.incoming_unidirectional_streams();
- let incoming_uni_stream_reader =
- ReadableStreamDefaultReader::new(&&incoming_uni_stream.into())?;
+ let incoming_uni_stream_reader = ReadableStreamDefaultReader::new(&incoming_uni_stream)?;
let callbacks = self.callbacks.clone();
*self.stream_writers.borrow_mut() = HashMap::new();
@@ -1109,15 +1102,15 @@ async fn bi_directional_stream_read_thread(
async fn control_message_handler(
callbacks: Rc>,
subscription_node: Rc>,
- mut buf: &mut BytesMut,
+ buf: &mut BytesMut,
) -> Result<()> {
- let message_type_value = read_variable_integer_from_buffer(&mut buf);
+ let message_type_value = read_variable_integer_from_buffer(buf);
// TODO: Check stream type
match message_type_value {
Ok(v) => {
let message_type = ControlMessageType::try_from(v as u8)?;
- let payload_length = read_variable_integer_from_buffer(&mut buf)?;
+ let payload_length = read_variable_integer_from_buffer(buf)?;
let mut payload_buf = buf.split_to(payload_length as usize);
log(std::format!("message_type_value: {:#?}", message_type).as_str());
@@ -1125,16 +1118,11 @@ async fn control_message_handler(
match message_type {
ControlMessageType::ServerSetup => {
let server_setup_message = ServerSetup::depacketize(&mut payload_buf)?;
-
log(
std::format!("recv: server_setup_message: {:#x?}", server_setup_message)
.as_str(),
);
-
if let Some(callback) = callbacks.borrow().setup_callback() {
- callback
- .call1(&JsValue::null(), &JsValue::from("called2"))
- .unwrap();
let v = serde_wasm_bindgen::to_value(&server_setup_message).unwrap();
callback.call1(&JsValue::null(), &(v)).unwrap();
}
@@ -1155,7 +1143,7 @@ async fn control_message_handler(
.as_str(),
);
- let _ = subscription_node
+ subscription_node
.borrow_mut()
.set_namespace(announce_ok_message.track_namespace().clone());
@@ -1217,7 +1205,7 @@ async fn control_message_handler(
.as_str(),
);
- let _ = subscription_node
+ subscription_node
.borrow_mut()
.activate_as_subscriber(subscribe_ok_message.subscribe_id());
@@ -1239,42 +1227,42 @@ async fn control_message_handler(
callback.call1(&JsValue::null(), &(v)).unwrap();
}
}
- ControlMessageType::SubscribeNamespaceOk => {
- let subscribe_namespace_ok_message =
- SubscribeNamespaceOk::depacketize(&mut payload_buf)?;
+ ControlMessageType::SubscribeAnnouncesOk => {
+ let subscribe_announces_ok_message =
+ SubscribeAnnouncesOk::depacketize(&mut payload_buf)?;
log(std::format!(
- "recv: subscribe_namespace_ok_message: {:#x?}",
- subscribe_namespace_ok_message
+ "recv: subscribe_announces_ok_message: {:#x?}",
+ subscribe_announces_ok_message
)
.as_str());
- let _ = subscription_node.borrow_mut().set_namespace_prefix(
- subscribe_namespace_ok_message
+ subscription_node.borrow_mut().set_namespace_prefix(
+ subscribe_announces_ok_message
.track_namespace_prefix()
.clone(),
);
if let Some(callback) =
- callbacks.borrow().subscribe_namespace_response_callback()
+ callbacks.borrow().subscribe_announces_response_callback()
{
let v =
- serde_wasm_bindgen::to_value(&subscribe_namespace_ok_message).unwrap();
+ serde_wasm_bindgen::to_value(&subscribe_announces_ok_message).unwrap();
callback.call1(&JsValue::null(), &(v)).unwrap();
}
}
- ControlMessageType::SubscribeNamespaceError => {
- let subscribe_namespace_error_message =
- SubscribeNamespaceError::depacketize(&mut payload_buf)?;
+ ControlMessageType::SubscribeAnnouncesError => {
+ let subscribe_announces_error_message =
+ SubscribeAnnouncesError::depacketize(&mut payload_buf)?;
log(std::format!(
- "recv: subscribe_namespace_error_message: {:#x?}",
- subscribe_namespace_error_message
+ "recv: subscribe_announces_error_message: {:#x?}",
+ subscribe_announces_error_message
)
.as_str());
if let Some(callback) =
- callbacks.borrow().subscribe_namespace_response_callback()
+ callbacks.borrow().subscribe_announces_response_callback()
{
- let v = serde_wasm_bindgen::to_value(&subscribe_namespace_error_message)
+ let v = serde_wasm_bindgen::to_value(&subscribe_announces_error_message)
.unwrap();
callback.call1(&JsValue::null(), &(v)).unwrap();
}
@@ -1321,7 +1309,7 @@ async fn datagram_read_thread(
buf.put_u8(i);
}
- while buf.len() > 0 {
+ while !buf.is_empty() {
if let Err(e) = datagram_handler(callbacks.clone(), &mut buf).await {
log(std::format!("error: {:#?}", e).as_str());
break;
@@ -1336,69 +1324,77 @@ async fn uni_directional_stream_read_thread(
callbacks: Rc>,
reader: &ReadableStreamDefaultReader,
) -> Result<(), JsValue> {
- use moqt_core::data_stream_type::DataStreamType;
-
log("uni_directional_stream_read_thread");
- let mut header_read = false;
+ let mut subgroup_stream_header: Option = None;
let mut data_stream_type = DataStreamType::ObjectDatagram;
let mut buf = BytesMut::new();
-
- loop {
- let ret = reader.read();
- let ret = JsFuture::from(ret).await?;
-
- let ret_value = js_sys::Reflect::get(&ret, &JsValue::from_str("value"))?;
- let ret_done = js_sys::Reflect::get(&ret, &JsValue::from_str("done"))?;
- let ret_done = js_sys::Boolean::from(ret_done).value_of();
-
- if ret_done {
+ let mut is_end_of_stream = false;
+
+ while !is_end_of_stream {
+ let ret = JsFuture::from(reader.read()).await?;
+ let is_done =
+ js_sys::Boolean::from(js_sys::Reflect::get(&ret, &JsValue::from_str("done"))?)
+ .value_of();
+ if is_done {
break;
}
+ let value =
+ js_sys::Uint8Array::from(js_sys::Reflect::get(&ret, &JsValue::from_str("value"))?)
+ .to_vec();
- let ret_value = js_sys::Uint8Array::from(ret_value).to_vec();
-
- for i in ret_value {
+ for i in value {
buf.put_u8(i);
}
- while buf.len() > 0 {
- if !header_read {
- data_stream_type = match object_header_handler(callbacks.clone(), &mut buf).await {
- Ok(v) => v,
- Err(_e) => {
- break;
- }
- };
-
- header_read = true;
- } else {
- match data_stream_type {
- DataStreamType::ObjectDatagram => {
- let msg = "format error".to_string();
- log(std::format!("{}", msg).as_str());
- return Err(js_sys::Error::new(&msg).into());
- }
- DataStreamType::StreamHeaderTrack => {
- if let Err(e) =
- track_stream_object_handler(callbacks.clone(), &mut buf).await
- {
- log(std::format!("error: {:#?}", e).as_str());
+ while !buf.is_empty() {
+ if subgroup_stream_header.is_none() {
+ let (_data_stream_type, _subgroup_stream_header) =
+ match object_header_handler(callbacks.clone(), &mut buf).await {
+ Ok(v) => v,
+ Err(_e) => {
break;
}
- }
- DataStreamType::StreamHeaderSubgroup => {
- if let Err(e) =
- subgroup_stream_object_handler(callbacks.clone(), &mut buf).await
- {
- log(std::format!("error: {:#?}", e).as_str());
+ };
+ data_stream_type = _data_stream_type;
+ subgroup_stream_header = _subgroup_stream_header;
+ continue;
+ }
+
+ match data_stream_type {
+ DataStreamType::ObjectDatagram | DataStreamType::ObjectDatagramStatus => {
+ let msg = "format error".to_string();
+ log(std::format!("{:#?}", msg).as_str());
+ return Err(js_sys::Error::new(&msg).into());
+ }
+ DataStreamType::SubgroupHeader => {
+ match subgroup_stream_object_handler(
+ callbacks.clone(),
+ subgroup_stream_header.clone().unwrap(),
+ &mut buf,
+ )
+ .await
+ {
+ Ok(object) => {
+ if object.object_status() == Some(ObjectStatus::EndOfGroup) {
+ is_end_of_stream = true;
+ break;
+ }
+ }
+ Err(_e) => {
+ // log(std::format!("error: {:#?}", e).as_str());
break;
}
}
}
+ DataStreamType::FetchHeader => {
+ unimplemented!();
+ }
}
}
}
+ JsFuture::from(reader.cancel()).await?;
+ log("End of unidirectional stream");
Ok(())
}
@@ -1407,35 +1403,18 @@ async fn uni_directional_stream_read_thread(
async fn object_header_handler(
callbacks: Rc>,
buf: &mut BytesMut,
-) -> Result {
+) -> Result<(DataStreamType, Option)> {
let mut read_cur = Cursor::new(&buf[..]);
let header_type_value = read_variable_integer(&mut read_cur);
- let data_stream_type = match header_type_value {
+ let (data_stream_type, subgroup_stream_header) = match header_type_value {
Ok(v) => {
let data_stream_type = DataStreamType::try_from(v as u8)?;
log(std::format!("data_stream_type_value: {:#x?}", data_stream_type).as_str());
- match data_stream_type {
- DataStreamType::StreamHeaderTrack => {
- let track_stream_header = track_stream::Header::depacketize(&mut read_cur)?;
- buf.advance(read_cur.position() as usize);
-
- log(
- std::format!("recv: track_stream_header: {:#x?}", track_stream_header)
- .as_str(),
- );
-
- if let Some(callback) = callbacks.borrow().track_stream_header_callback() {
- callback
- .call1(&JsValue::null(), &JsValue::from("called2"))
- .unwrap();
- let v = serde_wasm_bindgen::to_value(&track_stream_header).unwrap();
- callback.call1(&JsValue::null(), &(v)).unwrap();
- }
- }
- DataStreamType::StreamHeaderSubgroup => {
+ let subgroup_stream_header = match data_stream_type {
+ DataStreamType::SubgroupHeader => {
let subgroup_stream_header =
subgroup_stream::Header::depacketize(&mut read_cur)?;
buf.advance(read_cur.position() as usize);
@@ -1446,20 +1425,19 @@ async fn object_header_handler(
);
if let Some(callback) = callbacks.borrow().subgroup_stream_header_callback() {
- callback
- .call1(&JsValue::null(), &JsValue::from("called2"))
- .unwrap();
let v = serde_wasm_bindgen::to_value(&subgroup_stream_header).unwrap();
callback.call1(&JsValue::null(), &(v)).unwrap();
}
+ Some(subgroup_stream_header)
}
_ => {
// TODO: impl rest of message type
log(std::format!("data_stream_type: {:#?}", data_stream_type).as_str());
+ None
}
};
- data_stream_type
+ (data_stream_type, subgroup_stream_header)
}
Err(e) => {
log("data_stream_type_value is None");
@@ -1467,11 +1445,13 @@ async fn object_header_handler(
}
};
- Ok(data_stream_type)
+ Ok((data_stream_type, subgroup_stream_header))
}
#[cfg(feature = "web_sys_unstable_apis")]
async fn datagram_handler(callbacks: Rc>, buf: &mut BytesMut) -> Result<()> {
+ use moqt_core::messages::data_streams::datagram_status;
+
let mut read_cur = Cursor::new(&buf[..]);
let header_type_value = read_variable_integer(&mut read_cur);
@@ -1481,31 +1461,49 @@ async fn datagram_handler(callbacks: Rc>, buf: &mut Bytes
log(std::format!("data_stream_type_value: {:#x?}", data_stream_type).as_str());
- if data_stream_type == DataStreamType::ObjectDatagram {
- let datagram_object = match datagram::Object::depacketize(&mut read_cur) {
- Ok(v) => {
- log(std::format!("object_id: {:#?}", v.object_id()).as_str());
- buf.advance(read_cur.position() as usize);
- v
- }
- Err(e) => {
- read_cur.set_position(0);
- log(std::format!("retry because: {:#?}", e).as_str());
- return Err(e);
+ match data_stream_type {
+ DataStreamType::ObjectDatagram => {
+ let datagram_object = match datagram::Object::depacketize(&mut read_cur) {
+ Ok(v) => {
+ buf.advance(read_cur.position() as usize);
+ v
+ }
+ Err(e) => {
+ read_cur.set_position(0);
+ log(std::format!("retry because: {:#?}", e).as_str());
+ return Err(e);
+ }
+ };
+
+ if let Some(callback) = callbacks.borrow().datagram_object_callback() {
+ let v = serde_wasm_bindgen::to_value(&datagram_object).unwrap();
+ callback.call1(&JsValue::null(), &(v)).unwrap();
}
- };
+ }
+ DataStreamType::ObjectDatagramStatus => {
+ let datagram_object = match datagram_status::Object::depacketize(&mut read_cur)
+ {
+ Ok(v) => {
+ buf.advance(read_cur.position() as usize);
+ v
+ }
+ Err(e) => {
+ read_cur.set_position(0);
+ log(std::format!("retry because: {:#?}", e).as_str());
+ return Err(e);
+ }
+ };
- if let Some(callback) = callbacks.borrow().datagram_object_callback() {
- callback
- .call1(&JsValue::null(), &JsValue::from("called2"))
- .unwrap();
- let v = serde_wasm_bindgen::to_value(&datagram_object).unwrap();
- callback.call1(&JsValue::null(), &(v)).unwrap();
+ if let Some(callback) = callbacks.borrow().datagram_object_status_callback() {
+ let v = serde_wasm_bindgen::to_value(&datagram_object).unwrap();
+ callback.call1(&JsValue::null(), &(v)).unwrap();
+ }
+ }
+ _ => {
+ let msg = "format error".to_string();
+ log(std::format!("msg: {}", msg).as_str());
+ return Err(anyhow::anyhow!(msg));
}
- } else {
- let msg = "format error".to_string();
- log(std::format!("{}", msg).as_str());
- return Err(anyhow::anyhow!(msg));
}
}
Err(e) => {
@@ -1517,64 +1515,34 @@ async fn datagram_handler(callbacks: Rc>, buf: &mut Bytes
Ok(())
}
-#[cfg(feature = "web_sys_unstable_apis")]
-async fn track_stream_object_handler(
- callbacks: Rc>,
- buf: &mut BytesMut,
-) -> Result<()> {
- let mut read_cur = Cursor::new(&buf[..]);
- let track_stream_object = match track_stream::Object::depacketize(&mut read_cur) {
- Ok(v) => {
- log(std::format!("object_id: {:#?}", v.object_id()).as_str());
- buf.advance(read_cur.position() as usize);
- v
- }
- Err(e) => {
- read_cur.set_position(0);
- log(std::format!("retry because: {:#?}", e).as_str());
- return Err(e);
- }
- };
-
- if let Some(callback) = callbacks.borrow().track_stream_object_callback() {
- callback
- .call1(&JsValue::null(), &JsValue::from("called2"))
- .unwrap();
- let v = serde_wasm_bindgen::to_value(&track_stream_object).unwrap();
- callback.call1(&JsValue::null(), &(v)).unwrap();
- }
-
- Ok(())
-}
-
#[cfg(feature = "web_sys_unstable_apis")]
async fn subgroup_stream_object_handler(
callbacks: Rc>,
+ subgroup_stream_header: subgroup_stream::Header,
buf: &mut BytesMut,
-) -> Result<()> {
+) -> Result {
let mut read_cur = Cursor::new(&buf[..]);
let subgroup_stream_object = match subgroup_stream::Object::depacketize(&mut read_cur) {
Ok(v) => {
- log(std::format!("object_id: {:#?}", v.object_id()).as_str());
buf.advance(read_cur.position() as usize);
v
}
Err(e) => {
read_cur.set_position(0);
- log(std::format!("retry because: {:#?}", e).as_str());
+ // log(std::format!("retry because: {:#?}", e).as_str());
return Err(e);
}
};
- if let Some(callback) = callbacks.borrow().subgroup_stream_object_callback() {
- callback
- .call1(&JsValue::null(), &JsValue::from("called2"))
- .unwrap();
+ if let Some(callback) = callbacks
+ .borrow()
+ .get_subgroup_stream_object_callback(subgroup_stream_header.track_alias())
+ {
let v = serde_wasm_bindgen::to_value(&subgroup_stream_object).unwrap();
callback.call1(&JsValue::null(), &(v)).unwrap();
}
- Ok(())
+ Ok(subgroup_stream_object)
}
#[cfg(feature = "web_sys_unstable_apis")]
@@ -1620,6 +1588,7 @@ impl SubscriptionNode {
}
}
+ #[allow(clippy::too_many_arguments)]
fn set_subscribing_subscription(
&mut self,
subscribe_id: u64,
@@ -1632,7 +1601,6 @@ impl SubscriptionNode {
start_group: Option,
start_object: Option,
end_group: Option,
- end_object: Option,
) {
if let Some(consumer) = &mut self.consumer {
let _ = consumer.set_subscription(
@@ -1646,11 +1614,11 @@ impl SubscriptionNode {
start_group,
start_object,
end_group,
- end_object,
);
}
}
+ #[allow(clippy::too_many_arguments)]
fn set_publishing_subscription(
&mut self,
subscribe_id: u64,
@@ -1663,7 +1631,6 @@ impl SubscriptionNode {
start_group: Option,
start_object: Option,
end_group: Option,
- end_object: Option,
) {
if let Some(producer) = &mut self.producer {
let _ = producer.set_subscription(
@@ -1677,7 +1644,6 @@ impl SubscriptionNode {
start_group,
start_object,
end_group,
- end_object,
);
}
}
@@ -1736,7 +1702,6 @@ impl SubscriptionNode {
subscribe_message.start_group(),
subscribe_message.start_object(),
subscribe_message.end_group(),
- subscribe_message.end_object(),
);
Ok(())
@@ -1761,6 +1726,16 @@ impl SubscriptionNode {
let _ = consumer.activate_subscription(subscribe_id);
}
}
+
+ fn get_publishing_subscribe_id_by_track_alias(&self, track_alias: u64) -> Option {
+ if let Some(producer) = &self.producer {
+ producer
+ .get_subscribe_id_by_track_alias(track_alias)
+ .unwrap()
+ } else {
+ None
+ }
+ }
}
// Due to the lifetime issue of `spawn_local`, it needs to be kept separate from MOQTClient.
@@ -1772,13 +1747,12 @@ struct MOQTCallbacks {
announce_responce_callback: Option,
subscribe_callback: Option,
subscribe_response_callback: Option,
- subscribe_namespace_response_callback: Option,
+ subscribe_announces_response_callback: Option,
unsubscribe_callback: Option,
datagram_object_callback: Option,
- track_stream_header_callback: Option,
- track_stream_object_callback: Option,
+ datagram_object_status_callback: Option,
subgroup_stream_header_callback: Option,
- subgroup_stream_object_callback: Option,
+ subgroup_stream_object_callbacks: HashMap,
}
#[cfg(feature = "web_sys_unstable_apis")]
@@ -1790,13 +1764,12 @@ impl MOQTCallbacks {
announce_responce_callback: None,
subscribe_callback: None,
subscribe_response_callback: None,
- subscribe_namespace_response_callback: None,
+ subscribe_announces_response_callback: None,
unsubscribe_callback: None,
datagram_object_callback: None,
- track_stream_header_callback: None,
- track_stream_object_callback: None,
+ datagram_object_status_callback: None,
subgroup_stream_header_callback: None,
- subgroup_stream_object_callback: None,
+ subgroup_stream_object_callbacks: HashMap::new(),
}
}
@@ -1840,12 +1813,12 @@ impl MOQTCallbacks {
self.subscribe_response_callback = Some(callback);
}
- pub fn subscribe_namespace_response_callback(&self) -> Option {
- self.subscribe_namespace_response_callback.clone()
+ pub fn subscribe_announces_response_callback(&self) -> Option {
+ self.subscribe_announces_response_callback.clone()
}
- pub fn set_subscribe_namespace_response_callback(&mut self, callback: js_sys::Function) {
- self.subscribe_namespace_response_callback = Some(callback);
+ pub fn set_subscribe_announces_response_callback(&mut self, callback: js_sys::Function) {
+ self.subscribe_announces_response_callback = Some(callback);
}
pub fn set_unsubscribe_callback(&mut self, callback: js_sys::Function) {
@@ -1860,20 +1833,12 @@ impl MOQTCallbacks {
self.datagram_object_callback = Some(callback);
}
- pub fn track_stream_header_callback(&self) -> Option {
- self.track_stream_header_callback.clone()
- }
-
- pub fn set_track_stream_header_callback(&mut self, callback: js_sys::Function) {
- self.track_stream_header_callback = Some(callback);
- }
-
- pub fn track_stream_object_callback(&self) -> Option {
- self.track_stream_object_callback.clone()
+ pub fn datagram_object_status_callback(&self) -> Option {
+ self.datagram_object_status_callback.clone()
}
- pub fn set_track_stream_object_callback(&mut self, callback: js_sys::Function) {
- self.track_stream_object_callback = Some(callback);
+ pub fn set_datagram_object_status_callback(&mut self, callback: js_sys::Function) {
+ self.datagram_object_status_callback = Some(callback);
}
pub fn subgroup_stream_header_callback(&self) -> Option {
@@ -1884,11 +1849,20 @@ impl MOQTCallbacks {
self.subgroup_stream_header_callback = Some(callback);
}
- pub fn subgroup_stream_object_callback(&self) -> Option {
- self.subgroup_stream_object_callback.clone()
+ pub fn get_subgroup_stream_object_callback(
+ &self,
+ track_alias: u64,
+ ) -> Option<&js_sys::Function> {
+ let callback = self.subgroup_stream_object_callbacks.get(&track_alias);
+ callback
}
- pub fn set_subgroup_stream_object_callback(&mut self, callback: js_sys::Function) {
- self.subgroup_stream_object_callback = Some(callback);
+ pub fn set_subgroup_stream_object_callback(
+ &mut self,
+ track_alias: u64,
+ callback: js_sys::Function,
+ ) {
+ self.subgroup_stream_object_callbacks
+ .insert(track_alias, callback);
}
}
diff --git a/moqt-core/src/lib.rs b/moqt-core/src/lib.rs
index bce21bd1..93083259 100644
--- a/moqt-core/src/lib.rs
+++ b/moqt-core/src/lib.rs
@@ -1,4 +1,3 @@
mod modules;
pub use modules::pubsub_relation_manager_repository::PubSubRelationManagerRepository;
-pub use modules::send_stream_dispatcher_repository::SendStreamDispatcherRepository;
pub use modules::*;
diff --git a/moqt-core/src/modules.rs b/moqt-core/src/modules.rs
index 362a2597..832e1a5a 100644
--- a/moqt-core/src/modules.rs
+++ b/moqt-core/src/modules.rs
@@ -4,6 +4,5 @@ pub mod data_stream_type;
pub mod messages;
pub mod models;
pub mod pubsub_relation_manager_repository;
-pub mod send_stream_dispatcher_repository;
pub mod variable_bytes;
pub mod variable_integer;
diff --git a/moqt-core/src/modules/constants.rs b/moqt-core/src/modules/constants.rs
index 3fb4d9f9..f5096676 100644
--- a/moqt-core/src/modules/constants.rs
+++ b/moqt-core/src/modules/constants.rs
@@ -1,7 +1,7 @@
use num_enum::IntoPrimitive;
-// for draft-ietf-moq-transport-06
-pub const MOQ_TRANSPORT_VERSION: u32 = 0xff000006;
+// for draft-ietf-moq-transport-10
+pub const MOQ_TRANSPORT_VERSION: u32 = 0xff00000a;
#[derive(Debug, IntoPrimitive, PartialEq, Clone, Copy)]
#[repr(u8)]
@@ -22,9 +22,3 @@ pub enum UnderlayType {
WebTransport,
Both,
}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum StreamDirection {
- Uni,
- Bi,
-}
diff --git a/moqt-core/src/modules/control_message_type.rs b/moqt-core/src/modules/control_message_type.rs
index 8582552b..5fb2ae18 100644
--- a/moqt-core/src/modules/control_message_type.rs
+++ b/moqt-core/src/modules/control_message_type.rs
@@ -17,11 +17,15 @@ pub enum ControlMessageType {
TrackStatusRequest = 0x0d,
TrackStatus = 0x0e,
GoAway = 0x10,
- SubscribeNamespace = 0x11,
- SubscribeNamespaceOk = 0x12,
- SubscribeNamespaceError = 0x13,
- UnSubscribeNamespace = 0x14,
+ SubscribeAnnounces = 0x11,
+ SubscribeAnnouncesOk = 0x12,
+ SubscribeAnnouncesError = 0x13,
+ UnSubscribeAnnounces = 0x14,
MaxSubscribeId = 0x15,
+ Fetch = 0x16,
+ FetchCancel = 0x17,
+ FetchOk = 0x18,
+ FetchError = 0x19,
ClientSetup = 0x40,
ServerSetup = 0x41,
}
diff --git a/moqt-core/src/modules/data_stream_type.rs b/moqt-core/src/modules/data_stream_type.rs
index 93e898d3..a11e1de8 100644
--- a/moqt-core/src/modules/data_stream_type.rs
+++ b/moqt-core/src/modules/data_stream_type.rs
@@ -4,6 +4,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[repr(u8)]
pub enum DataStreamType {
ObjectDatagram = 0x1,
- StreamHeaderTrack = 0x2,
- StreamHeaderSubgroup = 0x4,
+ ObjectDatagramStatus = 0x2,
+ SubgroupHeader = 0x4,
+ FetchHeader = 0x5,
}
diff --git a/moqt-core/src/modules/messages/control_messages.rs b/moqt-core/src/modules/messages/control_messages.rs
index 207ad804..104dd0ad 100644
--- a/moqt-core/src/modules/messages/control_messages.rs
+++ b/moqt-core/src/modules/messages/control_messages.rs
@@ -3,14 +3,15 @@ pub mod announce_error;
pub mod announce_ok;
pub mod client_setup;
pub mod go_away;
+pub mod group_order;
pub mod server_setup;
pub mod setup_parameters;
pub mod subscribe;
+pub mod subscribe_announces;
+pub mod subscribe_announces_error;
+pub mod subscribe_announces_ok;
pub mod subscribe_done;
pub mod subscribe_error;
-pub mod subscribe_namespace;
-pub mod subscribe_namespace_error;
-pub mod subscribe_namespace_ok;
pub mod subscribe_ok;
pub mod unannounce;
pub mod unsubscribe;
diff --git a/moqt-core/src/modules/messages/control_messages/client_setup.rs b/moqt-core/src/modules/messages/control_messages/client_setup.rs
index 8b54bf60..1d63d1e8 100644
--- a/moqt-core/src/modules/messages/control_messages/client_setup.rs
+++ b/moqt-core/src/modules/messages/control_messages/client_setup.rs
@@ -82,7 +82,7 @@ mod test {
messages::{
control_messages::{
client_setup::ClientSetup,
- setup_parameters::{Role, RoleCase, SetupParameter},
+ setup_parameters::{MaxSubscribeID, SetupParameter},
},
moqt_payload::MOQTPayload,
},
@@ -92,8 +92,7 @@ mod test {
#[test]
fn packetize() {
let supported_versions = vec![MOQ_TRANSPORT_VERSION];
- let role_parameter = Role::new(RoleCase::Subscriber);
- let setup_parameters = vec![SetupParameter::Role(role_parameter.clone())];
+ let setup_parameters = vec![SetupParameter::MaxSubscribeID(MaxSubscribeID::new(2000))];
let client_setup = ClientSetup::new(supported_versions, setup_parameters.clone());
let mut buf = BytesMut::new();
client_setup.packetize(&mut buf);
@@ -101,11 +100,12 @@ mod test {
let expected_bytes_array = [
1, // Number of Supported Versions (i)
192, // Supported Version (i): Length(11 of 2MSB)
- 0, 0, 0, 255, 0, 0, 6, // Supported Version(i): Value(0xff000006) in 62bit
- 1, // Number of Parameters (i)
- 0, // SETUP Parameters (..): Type(Role)
- 1, // SETUP Parameters (..): Length
- 2, // SETUP Parameters (..): Role(Subscriber)
+ 0, 0, 0, 255, 0, 0, 10, // Supported Version(i): Value(0xff000008) in 62bit
+ 1, // Number of Parameters (i)
+ 2, // Parameter Type (i): Type(MaxSubscribeID)
+ 2, // Parameter Length (i)
+ 71, // Parameter Value (..): Length(01 of 2MSB)
+ 208, // Parameter Value (..): Value(2000) in 62bit
];
assert_eq!(buf.as_ref(), expected_bytes_array);
@@ -116,19 +116,19 @@ mod test {
let bytes_array = [
1, // Number of Supported Versions (i)
192, // Supported Version (i): Length(11 of 2MSB)
- 0, 0, 0, 255, 0, 0, 6, // Supported Version(i): Value(0xff000006) in 62bit
- 1, // Number of Parameters (i)
- 0, // SETUP Parameters (..): Type(Role)
- 1, // SETUP Parameters (..): Length
- 2, // SETUP Parameters (..): Role(Subscriber)
+ 0, 0, 0, 255, 0, 0, 10, // Supported Version(i): Value(0xff000008) in 62bit
+ 1, // Number of Parameters (i)
+ 2, // Parameter Type (i): Type(MaxSubscribeID)
+ 2, // Parameter Length (i)
+ 71, // Parameter Value (..): Length(01 of 2MSB)
+ 208, // Parameter Value (..): Value(2000) in 62bit
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
let depacketized_client_setup = ClientSetup::depacketize(&mut buf).unwrap();
let supported_versions = vec![MOQ_TRANSPORT_VERSION];
- let role_parameter = Role::new(RoleCase::Subscriber);
- let setup_parameters = vec![SetupParameter::Role(role_parameter.clone())];
+ let setup_parameters = vec![SetupParameter::MaxSubscribeID(MaxSubscribeID::new(2000))];
let expected_client_setup =
ClientSetup::new(supported_versions, setup_parameters.clone());
diff --git a/moqt-core/src/modules/messages/control_messages/group_order.rs b/moqt-core/src/modules/messages/control_messages/group_order.rs
new file mode 100644
index 00000000..546cfce0
--- /dev/null
+++ b/moqt-core/src/modules/messages/control_messages/group_order.rs
@@ -0,0 +1,9 @@
+use num_enum::{IntoPrimitive, TryFromPrimitive};
+use serde::Serialize;
+#[derive(Debug, Serialize, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive, Copy)]
+#[repr(u8)]
+pub enum GroupOrder {
+ Original = 0x0, // Use the original publisher's Group Order
+ Ascending = 0x1,
+ Descending = 0x2,
+}
diff --git a/moqt-core/src/modules/messages/control_messages/server_setup.rs b/moqt-core/src/modules/messages/control_messages/server_setup.rs
index 8984f81e..a6f323d1 100644
--- a/moqt-core/src/modules/messages/control_messages/server_setup.rs
+++ b/moqt-core/src/modules/messages/control_messages/server_setup.rs
@@ -69,7 +69,7 @@ mod tests {
messages::{
control_messages::{
server_setup::ServerSetup,
- setup_parameters::{Role, RoleCase, SetupParameter},
+ setup_parameters::{MaxSubscribeID, SetupParameter},
},
moqt_payload::MOQTPayload,
},
@@ -79,19 +79,19 @@ mod tests {
#[test]
fn packetize() {
let selected_version = MOQ_TRANSPORT_VERSION;
- let role_parameter = Role::new(RoleCase::PubSub);
- let setup_parameters = vec![SetupParameter::Role(role_parameter.clone())];
+ let setup_parameters = vec![SetupParameter::MaxSubscribeID(MaxSubscribeID::new(2000))];
let server_setup = ServerSetup::new(selected_version, setup_parameters.clone());
let mut buf = BytesMut::new();
server_setup.packetize(&mut buf);
let expected_bytes_array = [
192, // Selected Version (i): Length(11 of 2MSB)
- 0, 0, 0, 255, 0, 0, 6, // Supported Version(i): Value(0xff000006) in 62bit
- 1, // Number of Parameters (i)
- 0, // SETUP Parameters (..): Type(Role)
- 1, // SETUP Parameters (..): Length
- 3, // SETUP Parameters (..): Value(PubSub)
+ 0, 0, 0, 255, 0, 0, 10, // Supported Version(i): Value(0xff000a) in 62bit
+ 1, // Number of Parameters (i)
+ 2, // Parameter Type (i): Type(MaxSubscribeID)
+ 2, // Parameter Length (i)
+ 71, // Parameter Value (..): Length(01 of 2MSB)
+ 208, // Parameter Value (..): Value(2000) in 62bit
];
assert_eq!(buf.as_ref(), expected_bytes_array);
@@ -101,19 +101,19 @@ mod tests {
fn depacketize() {
let bytes_array = [
192, // Selected Version (i): Length(11 of 2MSB)
- 0, 0, 0, 255, 0, 0, 6, // Supported Version(i): Value(0xff000006) in 62bit
- 1, // Number of Parameters (i)
- 0, // SETUP Parameters (..): Type(Role)
- 1, // SETUP Parameters (..): Length
- 3, // SETUP Parameters (..): Value(PubSub)
+ 0, 0, 0, 255, 0, 0, 10, // Supported Version(i): Value(0xff00000a) in 62bit
+ 1, // Number of Parameters (i)
+ 2, // Parameter Type (i): Type(MaxSubscribeID)
+ 2, // Parameter Length (i)
+ 71, // Parameter Value (..): Length(01 of 2MSB)
+ 208, // Parameter Value (..): Value(2000) in 62bit
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
let depacketized_server_setup = ServerSetup::depacketize(&mut buf).unwrap();
let selected_version = MOQ_TRANSPORT_VERSION;
- let role_parameter = Role::new(RoleCase::PubSub);
- let setup_parameters = vec![SetupParameter::Role(role_parameter.clone())];
+ let setup_parameters = vec![SetupParameter::MaxSubscribeID(MaxSubscribeID::new(2000))];
let expected_server_setup =
ServerSetup::new(selected_version, setup_parameters.clone());
diff --git a/moqt-core/src/modules/messages/control_messages/setup_parameters.rs b/moqt-core/src/modules/messages/control_messages/setup_parameters.rs
index 2eec4742..a063f413 100644
--- a/moqt-core/src/modules/messages/control_messages/setup_parameters.rs
+++ b/moqt-core/src/modules/messages/control_messages/setup_parameters.rs
@@ -2,7 +2,7 @@ use crate::{
messages::moqt_payload::MOQTPayload,
variable_integer::{read_variable_integer_from_buffer, write_variable_integer},
};
-use anyhow::{bail, ensure, Context, Result};
+use anyhow::{bail, Context, Result};
use bytes::BytesMut;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use serde::Serialize;
@@ -10,7 +10,6 @@ use std::any::Any;
#[derive(Debug, Serialize, Clone, PartialEq)]
pub enum SetupParameter {
- Role(Role),
Path(Path),
MaxSubscribeID(MaxSubscribeID),
Unknown(u8),
@@ -27,27 +26,6 @@ impl MOQTPayload for SetupParameter {
}
match key? {
- SetupParameterType::Role => {
- let length = u8::try_from(read_variable_integer_from_buffer(buf)?)
- .context("role value length")?;
-
- // TODO: return TerminationError
- ensure!(
- length == 1,
- "Invalid value length in ROLE parameter {:#04x}",
- length
- );
-
- let value = RoleCase::try_from(u8::try_from(
- read_variable_integer_from_buffer(buf).context("role value")?,
- )?);
- if let Err(err) = value {
- bail!("Invalid value in ROLE parameter {:?}", err);
- }
-
- Ok(SetupParameter::Role(Role::new(value?)))
- }
-
// Not implemented as only WebTransport is supported now.
SetupParameterType::Path => {
// let value = String::from_utf8(read_variable_bytes_from_buffer(buf)?)?;
@@ -55,7 +33,6 @@ impl MOQTPayload for SetupParameter {
unimplemented!("Not implemented as only WebTransport is supported.")
}
-
SetupParameterType::MaxSubscribeID => {
let length = read_variable_integer_from_buffer(buf)?;
let value = read_variable_integer_from_buffer(buf).context("max subscribe id")?;
@@ -72,25 +49,16 @@ impl MOQTPayload for SetupParameter {
fn packetize(&self, buf: &mut BytesMut) {
match self {
- SetupParameter::Role(param) => {
- buf.extend(write_variable_integer(u8::from(param.key) as u64));
- buf.extend(write_variable_integer(param.length));
- // The value is of type varint.
- buf.extend(write_variable_integer(u8::from(param.value) as u64));
- }
-
// Not implemented as only WebTransport is supported now.
SetupParameter::Path(_param) => {
unimplemented!("Not implemented as only WebTransport is supported.")
}
-
SetupParameter::MaxSubscribeID(param) => {
buf.extend(write_variable_integer(u8::from(param.key) as u64));
buf.extend(write_variable_integer(param.length));
// The value is of type varint (from MAX_SUBSCRIBE_ID message format).
buf.extend(write_variable_integer(param.value));
}
-
SetupParameter::Unknown(_) => unimplemented!("Unknown SETUP parameter"),
}
}
@@ -103,36 +71,10 @@ impl MOQTPayload for SetupParameter {
#[derive(Debug, Clone, Copy, IntoPrimitive, TryFromPrimitive, Serialize, PartialEq)]
#[repr(u8)]
pub enum SetupParameterType {
- Role = 0x00,
Path = 0x01,
MaxSubscribeID = 0x02,
}
-#[derive(Debug, Clone, Copy, IntoPrimitive, TryFromPrimitive, Serialize, PartialEq)]
-#[repr(u8)]
-pub enum RoleCase {
- Publisher = 0x01,
- Subscriber = 0x02,
- PubSub = 0x03,
-}
-
-#[derive(Debug, Serialize, Clone, PartialEq)]
-pub struct Role {
- pub key: SetupParameterType,
- pub length: u64,
- pub value: RoleCase,
-}
-
-impl Role {
- pub fn new(role: RoleCase) -> Self {
- Role {
- key: SetupParameterType::Role,
- length: 0x01,
- value: role,
- }
- }
-}
-
#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct Path {
pub key: SetupParameterType,
@@ -174,27 +116,10 @@ mod tests {
use bytes::BytesMut;
use crate::messages::{
- control_messages::setup_parameters::{MaxSubscribeID, Role, RoleCase, SetupParameter},
+ control_messages::setup_parameters::{MaxSubscribeID, SetupParameter},
moqt_payload::MOQTPayload,
};
- #[test]
- fn packetize_role() {
- let role_parameter = Role::new(RoleCase::Publisher);
- let setup_parameter = SetupParameter::Role(role_parameter);
-
- let mut buf = BytesMut::new();
- setup_parameter.packetize(&mut buf);
-
- let expected_bytes_array = [
- 0, // Parameter Type (i): Role
- 1, // Parameter Length (i)
- 1, // Parameter Value (..): Role(Publisher)
- ];
-
- assert_eq!(buf.as_ref(), expected_bytes_array);
- }
-
#[test]
fn packetize_max_subscribe_id() {
let max_subscribe_id = MaxSubscribeID::new(2000);
@@ -213,22 +138,6 @@ mod tests {
assert_eq!(buf.as_ref(), expected_bytes_array);
}
- #[test]
- fn depacketize_role() {
- let bytes_array = [
- 0, // Parameter Type (i): Role
- 1, // Parameter Length (i)
- 2, // Parameter Value (..): Role(Subscriber)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let depacketized_setup_parameter = SetupParameter::depacketize(&mut buf).unwrap();
-
- let role_parameter = Role::new(RoleCase::Subscriber);
- let expected_setup_parameter = SetupParameter::Role(role_parameter);
- assert_eq!(depacketized_setup_parameter, expected_setup_parameter);
- }
-
#[test]
fn depacketize_max_subscribe_id() {
let bytes_array = [
@@ -284,34 +193,6 @@ mod tests {
setup_parameter.packetize(&mut buf);
}
- #[test]
- fn depacketize_role_invalid_length() {
- let bytes_array = [
- 0, // Parameter Type (i): Type(Role)
- 99, // Parameter Type (i): Length(Wrong)
- 1, // Parameter Type (i): Role(Publisher)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let depacketized_setup_parameter = SetupParameter::depacketize(&mut buf);
-
- assert!(depacketized_setup_parameter.is_err());
- }
-
- #[test]
- fn depacketize_role_invalid_value() {
- let bytes_array = [
- 0, // Parameter Type (i): Type(Role)
- 1, // Parameter Type (i): Length
- 99, // Parameter Type (i): Role(Wrong)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let depacketized_setup_parameter = SetupParameter::depacketize(&mut buf);
-
- assert!(depacketized_setup_parameter.is_err());
- }
-
#[test]
#[should_panic]
fn depacketize_path() {
diff --git a/moqt-core/src/modules/messages/control_messages/subscribe.rs b/moqt-core/src/modules/messages/control_messages/subscribe.rs
index 67fd385e..edd85958 100644
--- a/moqt-core/src/modules/messages/control_messages/subscribe.rs
+++ b/moqt-core/src/modules/messages/control_messages/subscribe.rs
@@ -1,10 +1,12 @@
use crate::{
messages::{
- control_messages::version_specific_parameters::VersionSpecificParameter,
+ control_messages::{
+ group_order::GroupOrder, version_specific_parameters::VersionSpecificParameter,
+ },
moqt_payload::MOQTPayload,
},
variable_bytes::{
- read_fixed_length_bytes_from_buffer, read_variable_bytes_from_buffer, write_variable_bytes,
+ read_bytes_from_buffer, read_variable_bytes_from_buffer, write_variable_bytes,
},
variable_integer::{read_variable_integer_from_buffer, write_variable_integer},
};
@@ -15,14 +17,7 @@ use serde::Serialize;
use std::any::Any;
use tracing;
-#[derive(Debug, Serialize, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive, Copy)]
-#[repr(u8)]
-pub enum GroupOrder {
- Original = 0x0, // Use the original publisher's Group Order
- Ascending = 0x1,
- Descending = 0x2,
-}
-
+// TODO: Remove LatestGroup since it is not exist in the draft-10
#[derive(Debug, Serialize, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive, Copy)]
#[repr(u8)]
pub enum FilterType {
@@ -44,7 +39,6 @@ pub struct Subscribe {
start_group: Option,
start_object: Option,
end_group: Option,
- end_object: Option,
number_of_parameters: u64,
subscribe_parameters: Vec,
}
@@ -62,12 +56,11 @@ impl Subscribe {
start_group: Option,
start_object: Option,
end_group: Option,
- end_object: Option,
subscribe_parameters: Vec,
) -> anyhow::Result {
- // If FilterType is LatestGroup or LatestObject, start_group/start_object/end_group/end_object must be None
- // If FilterType is AbsoluteStart, start_group/start_object must be needed and end_group/end_object must be None
- // If FilterType is AbsoluteRange, start_group/start_object/end_group/end_object must be needed
+ // If FilterType is LatestGroup or LatestObject, start_group/start_object/end_group must be None
+ // If FilterType is AbsoluteStart, start_group/start_object must be needed and end_group must be None
+ // If FilterType is AbsoluteRange, start_group/start_object/end_group must be needed
match filter_type {
FilterType::LatestGroup | FilterType::LatestObject => {
if start_group.is_some() {
@@ -76,8 +69,6 @@ impl Subscribe {
bail!("start_object must be None for LatestGroup or LatestObject");
} else if end_group.is_some() {
bail!("end_group must be None for LatestGroup or LatestObject");
- } else if end_object.is_some() {
- bail!("end_object must be None for LatestGroup or LatestObject");
}
}
FilterType::AbsoluteStart => {
@@ -87,8 +78,6 @@ impl Subscribe {
bail!("start_object must be Some for AbsoluteStart");
} else if end_group.is_some() {
bail!("end_group must be None for AbsoluteStart");
- } else if end_object.is_some() {
- bail!("end_object must be None for AbsoluteStart");
}
}
FilterType::AbsoluteRange => {
@@ -98,8 +87,6 @@ impl Subscribe {
bail!("start_object must be Some for AbsoluteRange");
} else if end_group.is_none() {
bail!("end_group must be Some for AbsoluteRange");
- } else if end_object.is_none() {
- bail!("end_object must be Some for AbsoluteRange");
}
}
}
@@ -116,7 +103,6 @@ impl Subscribe {
start_group,
start_object,
end_group,
- end_object,
number_of_parameters,
subscribe_parameters,
})
@@ -162,10 +148,6 @@ impl Subscribe {
self.end_group
}
- pub fn end_object(&self) -> Option {
- self.end_object
- }
-
pub fn subscribe_parameters(&self) -> &Vec {
&self.subscribe_parameters
}
@@ -188,9 +170,8 @@ impl MOQTPayload for Subscribe {
}
let track_name =
String::from_utf8(read_variable_bytes_from_buffer(buf)?).context("track name")?;
- let subscriber_priority =
- read_fixed_length_bytes_from_buffer(buf, 1).context("subscriber priority")?[0];
- let group_order_u8 = read_fixed_length_bytes_from_buffer(buf, 1)?[0];
+ let subscriber_priority = read_bytes_from_buffer(buf, 1).context("subscriber priority")?[0];
+ let group_order_u8 = read_bytes_from_buffer(buf, 1)?[0];
// Values larger than 0x2 are a Protocol Violation.
let group_order = match GroupOrder::try_from(group_order_u8).context("group order") {
@@ -219,12 +200,11 @@ impl MOQTPayload for Subscribe {
_ => (None, None),
};
- let (end_group, end_object) = match filter_type {
- FilterType::AbsoluteRange => (
- Some(read_variable_integer_from_buffer(buf).context("end group")?),
- Some(read_variable_integer_from_buffer(buf).context("end object")?),
- ),
- _ => (None, None),
+ let end_group = match filter_type {
+ FilterType::AbsoluteRange => {
+ Some(read_variable_integer_from_buffer(buf).context("end group")?)
+ }
+ _ => None,
};
let number_of_parameters =
read_variable_integer_from_buffer(buf).context("number of parameters")?;
@@ -251,7 +231,6 @@ impl MOQTPayload for Subscribe {
start_group,
start_object,
end_group,
- end_object,
number_of_parameters,
subscribe_parameters,
})
@@ -280,7 +259,6 @@ impl MOQTPayload for Subscribe {
buf.extend(write_variable_integer(self.start_group.unwrap()));
buf.extend(write_variable_integer(self.start_object.unwrap()));
buf.extend(write_variable_integer(self.end_group.unwrap()));
- buf.extend(write_variable_integer(self.end_object.unwrap()));
}
_ => {}
}
@@ -324,7 +302,6 @@ mod tests {
let start_group = None;
let start_object = None;
let end_group = None;
- let end_object = None;
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -341,7 +318,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
)
.unwrap();
@@ -383,7 +359,6 @@ mod tests {
let start_group = Some(0);
let start_object = Some(0);
let end_group = None;
- let end_object = None;
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -400,7 +375,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
)
.unwrap();
@@ -444,7 +418,6 @@ mod tests {
let start_group = Some(0);
let start_object = Some(0);
let end_group = Some(10);
- let end_object = Some(100);
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -461,7 +434,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
)
.unwrap();
@@ -486,7 +458,6 @@ mod tests {
0, // Start Group (i)
0, // Start Object (i)
10, // End Group (i)
- 64, 100, // End Object (i)
1, // Track Request Parameters (..): Number of Parameters
2, // Parameter Type (i): AuthorizationInfo
4, // Parameter Length
@@ -530,7 +501,6 @@ mod tests {
let start_group = None;
let start_object = None;
let end_group = None;
- let end_object = None;
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -546,7 +516,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
)
.unwrap();
@@ -591,7 +560,6 @@ mod tests {
let start_group = Some(0);
let start_object = Some(0);
let end_group = None;
- let end_object = None;
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -607,7 +575,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
)
.unwrap();
@@ -634,7 +601,6 @@ mod tests {
0, // Start Group (i)
0, // Start Object (i)
10, // End Group (i)
- 64, 100, // End Object (i)
1, // Track Request Parameters (..): Number of Parameters
2, // Parameter Type (i): AuthorizationInfo
4, // Parameter Length
@@ -654,7 +620,6 @@ mod tests {
let start_group = Some(0);
let start_object = Some(0);
let end_group = Some(10);
- let end_object = Some(100);
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -670,7 +635,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
)
.unwrap();
@@ -701,7 +665,6 @@ mod tests {
let start_group = Some(0);
let start_object = Some(0);
let end_group = None;
- let end_object = None;
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -718,7 +681,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
);
@@ -737,7 +699,6 @@ mod tests {
let start_group = None;
let start_object = None;
let end_group = Some(1);
- let end_object = Some(1);
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -754,7 +715,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
);
@@ -773,7 +733,6 @@ mod tests {
let start_group = Some(0);
let start_object = Some(0);
let end_group = Some(1);
- let end_object = Some(1);
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
@@ -790,7 +749,6 @@ mod tests {
start_group,
start_object,
end_group,
- end_object,
subscribe_parameters,
);
diff --git a/moqt-core/src/modules/messages/control_messages/subscribe_namespace.rs b/moqt-core/src/modules/messages/control_messages/subscribe_announces.rs
similarity index 90%
rename from moqt-core/src/modules/messages/control_messages/subscribe_namespace.rs
rename to moqt-core/src/modules/messages/control_messages/subscribe_announces.rs
index 2ebbc586..1045582c 100644
--- a/moqt-core/src/modules/messages/control_messages/subscribe_namespace.rs
+++ b/moqt-core/src/modules/messages/control_messages/subscribe_announces.rs
@@ -12,19 +12,19 @@ use serde::Serialize;
use std::any::Any;
#[derive(Debug, Serialize, Clone, PartialEq)]
-pub struct SubscribeNamespace {
+pub struct SubscribeAnnounces {
track_namespace_prefix: Vec,
number_of_parameters: u64,
parameters: Vec,
}
-impl SubscribeNamespace {
+impl SubscribeAnnounces {
pub fn new(
track_namespace_prefix: Vec,
parameters: Vec,
) -> Self {
let number_of_parameters = parameters.len() as u64;
- SubscribeNamespace {
+ SubscribeAnnounces {
track_namespace_prefix,
number_of_parameters,
parameters,
@@ -40,7 +40,7 @@ impl SubscribeNamespace {
}
}
-impl MOQTPayload for SubscribeNamespace {
+impl MOQTPayload for SubscribeAnnounces {
fn depacketize(buf: &mut BytesMut) -> Result {
let track_namespace_prefix_tuple_length =
u8::try_from(read_variable_integer_from_buffer(buf)?)
@@ -65,7 +65,7 @@ impl MOQTPayload for SubscribeNamespace {
}
}
- Ok(SubscribeNamespace {
+ Ok(SubscribeAnnounces {
track_namespace_prefix: track_namespace_prefix_tuple,
number_of_parameters,
parameters,
@@ -87,7 +87,7 @@ impl MOQTPayload for SubscribeNamespace {
parameter.packetize(buf);
}
}
- /// Method to enable downcasting from MOQTPayload to SubscribeNamespace
+ /// Method to enable downcasting from MOQTPayload to SubscribeAnnounces
fn as_any(&self) -> &dyn Any {
self
}
@@ -98,7 +98,7 @@ mod tests {
mod success {
use crate::messages::{
control_messages::{
- subscribe_namespace::SubscribeNamespace,
+ subscribe_announces::SubscribeAnnounces,
version_specific_parameters::{AuthorizationInfo, VersionSpecificParameter},
},
moqt_payload::MOQTPayload,
@@ -112,10 +112,10 @@ mod tests {
AuthorizationInfo::new("test".to_string()),
);
let parameters = vec![version_specific_parameter];
- let subscribe_namespace =
- SubscribeNamespace::new(track_namespace_prefix.clone(), parameters);
+ let subscribe_announces =
+ SubscribeAnnounces::new(track_namespace_prefix.clone(), parameters);
let mut buf = BytesMut::new();
- subscribe_namespace.packetize(&mut buf);
+ subscribe_announces.packetize(&mut buf);
let expected_bytes_array = [
2, // Track Namespace Prefix(tuple): Number of elements
@@ -146,17 +146,17 @@ mod tests {
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
- let subscribe_namespace = SubscribeNamespace::depacketize(&mut buf).unwrap();
+ let subscribe_announces = SubscribeAnnounces::depacketize(&mut buf).unwrap();
let track_namespace_prefix = Vec::from(["test".to_string(), "test".to_string()]);
let version_specific_parameter = VersionSpecificParameter::AuthorizationInfo(
AuthorizationInfo::new("test".to_string()),
);
let parameters = vec![version_specific_parameter];
- let expected_subscribe_namespace =
- SubscribeNamespace::new(track_namespace_prefix, parameters);
+ let expected_subscribe_announces =
+ SubscribeAnnounces::new(track_namespace_prefix, parameters);
- assert_eq!(subscribe_namespace, expected_subscribe_namespace);
+ assert_eq!(subscribe_announces, expected_subscribe_announces);
}
}
}
diff --git a/moqt-core/src/modules/messages/control_messages/subscribe_namespace_error.rs b/moqt-core/src/modules/messages/control_messages/subscribe_announces_error.rs
similarity index 79%
rename from moqt-core/src/modules/messages/control_messages/subscribe_namespace_error.rs
rename to moqt-core/src/modules/messages/control_messages/subscribe_announces_error.rs
index f5662d00..4d241521 100644
--- a/moqt-core/src/modules/messages/control_messages/subscribe_namespace_error.rs
+++ b/moqt-core/src/modules/messages/control_messages/subscribe_announces_error.rs
@@ -9,19 +9,19 @@ use serde::Serialize;
use std::any::Any;
#[derive(Debug, Serialize, Clone, PartialEq)]
-pub struct SubscribeNamespaceError {
+pub struct SubscribeAnnouncesError {
track_namespace_prefix: Vec,
error_code: u64,
reason_phrase: String,
}
-impl SubscribeNamespaceError {
+impl SubscribeAnnouncesError {
pub fn new(
track_namespace_prefix: Vec,
error_code: u64,
reason_phrase: String,
) -> Self {
- SubscribeNamespaceError {
+ SubscribeAnnouncesError {
track_namespace_prefix,
error_code,
reason_phrase,
@@ -41,7 +41,7 @@ impl SubscribeNamespaceError {
}
}
-impl MOQTPayload for SubscribeNamespaceError {
+impl MOQTPayload for SubscribeAnnouncesError {
fn depacketize(buf: &mut BytesMut) -> Result {
let track_namespace_prefix_tuple_length =
u8::try_from(read_variable_integer_from_buffer(buf)?)
@@ -56,7 +56,7 @@ impl MOQTPayload for SubscribeNamespaceError {
let reason_phrase =
String::from_utf8(read_variable_bytes_from_buffer(buf)?).context("reason phrase")?;
- Ok(SubscribeNamespaceError {
+ Ok(SubscribeAnnouncesError {
track_namespace_prefix: track_namespace_prefix_tuple,
error_code,
reason_phrase,
@@ -78,7 +78,7 @@ impl MOQTPayload for SubscribeNamespaceError {
&self.reason_phrase.as_bytes().to_vec(),
));
}
- /// Method to enable downcasting from MOQTPayload to SubscribeNamespaceError
+ /// Method to enable downcasting from MOQTPayload to SubscribeAnnouncesError
fn as_any(&self) -> &dyn Any {
self
}
@@ -88,7 +88,7 @@ impl MOQTPayload for SubscribeNamespaceError {
mod tests {
mod success {
use crate::messages::{
- control_messages::subscribe_namespace_error::SubscribeNamespaceError,
+ control_messages::subscribe_announces_error::SubscribeAnnouncesError,
moqt_payload::MOQTPayload,
};
use bytes::BytesMut;
@@ -97,14 +97,14 @@ mod tests {
fn packetize() {
let track_namespace_prefix = Vec::from(["test".to_string(), "test".to_string()]);
let error_code: u64 = 1;
- let reason_phrase = "subscribe namespace overlap".to_string();
- let subscribe_namespace_error = SubscribeNamespaceError::new(
+ let reason_phrase = "subscribe announces overlap".to_string();
+ let subscribe_announces_error = SubscribeAnnouncesError::new(
track_namespace_prefix.clone(),
error_code,
reason_phrase.clone(),
);
let mut buf = BytesMut::new();
- subscribe_namespace_error.packetize(&mut buf);
+ subscribe_announces_error.packetize(&mut buf);
let expected_bytes_array = [
2, // Track Namespace Prefix(tuple): Number of elements
@@ -114,9 +114,9 @@ mod tests {
116, 101, 115, 116, // Track Namespace Prefix(b): Value("test")
1, // Error Code (i)
27, // Reason Phrase (b): length
- 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 110, 97, 109, 101, 115, 112, 97, 99,
- 101, 32, 111, 118, 101, 114, 108, 97,
- 112, // Reason Phrase (b): Value("subscribe namespace overlap")
+ 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 97, 110, 110, 111, 117, 110, 99, 101,
+ 115, 32, 111, 118, 101, 114, 108, 97,
+ 112, // Reason Phrase (b): Value("subscribe announces overlap")
];
assert_eq!(buf.as_ref(), expected_bytes_array.as_slice());
}
@@ -131,26 +131,26 @@ mod tests {
116, 101, 115, 116, // Track Namespace Prefix(b): Value("test")
1, // Error Code (i)
27, // Reason Phrase (b): length
- 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 110, 97, 109, 101, 115, 112, 97, 99,
- 101, 32, 111, 118, 101, 114, 108, 97,
- 112, // Reason Phrase (b): Value("subscribe namespace overlap")
+ 115, 117, 98, 115, 99, 114, 105, 98, 101, 32, 97, 110, 110, 111, 117, 110, 99, 101,
+ 115, 32, 111, 118, 101, 114, 108, 97,
+ 112, // Reason Phrase (b): Value("subscribe announces overlap")
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
- let subscribe_namespace_error = SubscribeNamespaceError::depacketize(&mut buf).unwrap();
+ let subscribe_announces_error = SubscribeAnnouncesError::depacketize(&mut buf).unwrap();
let track_namespace_prefix = Vec::from(["test".to_string(), "test".to_string()]);
let error_code: u64 = 1;
- let reason_phrase = "subscribe namespace overlap".to_string();
- let expected_subscribe_namespace_error = SubscribeNamespaceError::new(
+ let reason_phrase = "subscribe announces overlap".to_string();
+ let expected_subscribe_announces_error = SubscribeAnnouncesError::new(
track_namespace_prefix.clone(),
error_code,
reason_phrase.clone(),
);
assert_eq!(
- subscribe_namespace_error,
- expected_subscribe_namespace_error
+ subscribe_announces_error,
+ expected_subscribe_announces_error
);
}
}
diff --git a/moqt-core/src/modules/messages/control_messages/subscribe_namespace_ok.rs b/moqt-core/src/modules/messages/control_messages/subscribe_announces_ok.rs
similarity index 84%
rename from moqt-core/src/modules/messages/control_messages/subscribe_namespace_ok.rs
rename to moqt-core/src/modules/messages/control_messages/subscribe_announces_ok.rs
index e011a202..788546bf 100644
--- a/moqt-core/src/modules/messages/control_messages/subscribe_namespace_ok.rs
+++ b/moqt-core/src/modules/messages/control_messages/subscribe_announces_ok.rs
@@ -9,13 +9,13 @@ use serde::Serialize;
use std::any::Any;
#[derive(Debug, Serialize, Clone, PartialEq)]
-pub struct SubscribeNamespaceOk {
+pub struct SubscribeAnnouncesOk {
track_namespace_prefix: Vec,
}
-impl SubscribeNamespaceOk {
+impl SubscribeAnnouncesOk {
pub fn new(track_namespace_prefix: Vec) -> Self {
- SubscribeNamespaceOk {
+ SubscribeAnnouncesOk {
track_namespace_prefix,
}
}
@@ -25,7 +25,7 @@ impl SubscribeNamespaceOk {
}
}
-impl MOQTPayload for SubscribeNamespaceOk {
+impl MOQTPayload for SubscribeAnnouncesOk {
fn depacketize(buf: &mut BytesMut) -> Result {
let track_namespace_prefix_tuple_length =
u8::try_from(read_variable_integer_from_buffer(buf)?)
@@ -37,7 +37,7 @@ impl MOQTPayload for SubscribeNamespaceOk {
track_namespace_prefix_tuple.push(track_namespace_prefix);
}
- Ok(SubscribeNamespaceOk {
+ Ok(SubscribeAnnouncesOk {
track_namespace_prefix: track_namespace_prefix_tuple,
})
}
@@ -53,7 +53,7 @@ impl MOQTPayload for SubscribeNamespaceOk {
));
}
}
- /// Method to enable downcasting from MOQTPayload to SubscribeNamespaceOk
+ /// Method to enable downcasting from MOQTPayload to SubscribeAnnouncesOk
fn as_any(&self) -> &dyn Any {
self
}
@@ -63,7 +63,7 @@ impl MOQTPayload for SubscribeNamespaceOk {
mod tests {
mod success {
use crate::messages::{
- control_messages::subscribe_namespace_ok::SubscribeNamespaceOk,
+ control_messages::subscribe_announces_ok::SubscribeAnnouncesOk,
moqt_payload::MOQTPayload,
};
use bytes::BytesMut;
@@ -71,9 +71,9 @@ mod tests {
#[test]
fn packetize() {
let track_namespace_prefix = Vec::from(["test".to_string(), "test".to_string()]);
- let subscribe_namespace_ok = SubscribeNamespaceOk::new(track_namespace_prefix.clone());
+ let subscribe_announces_ok = SubscribeAnnouncesOk::new(track_namespace_prefix.clone());
let mut buf = BytesMut::new();
- subscribe_namespace_ok.packetize(&mut buf);
+ subscribe_announces_ok.packetize(&mut buf);
let expected_bytes_array = [
2, // Track Namespace Prefix(tuple): Number of elements
@@ -96,12 +96,12 @@ mod tests {
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
- let subscribe_namespace_ok = SubscribeNamespaceOk::depacketize(&mut buf).unwrap();
+ let subscribe_announces_ok = SubscribeAnnouncesOk::depacketize(&mut buf).unwrap();
let track_namespace_prefix = Vec::from(["test".to_string(), "test".to_string()]);
- let expected_subscribe_namespace_ok = SubscribeNamespaceOk::new(track_namespace_prefix);
+ let expected_subscribe_announces_ok = SubscribeAnnouncesOk::new(track_namespace_prefix);
- assert_eq!(subscribe_namespace_ok, expected_subscribe_namespace_ok);
+ assert_eq!(subscribe_announces_ok, expected_subscribe_announces_ok);
}
}
}
diff --git a/moqt-core/src/modules/messages/control_messages/subscribe_done.rs b/moqt-core/src/modules/messages/control_messages/subscribe_done.rs
index aeb0340b..d4fd949d 100644
--- a/moqt-core/src/modules/messages/control_messages/subscribe_done.rs
+++ b/moqt-core/src/modules/messages/control_messages/subscribe_done.rs
@@ -1,7 +1,7 @@
use crate::{
messages::moqt_payload::MOQTPayload,
variable_bytes::{
- read_fixed_length_bytes_from_buffer, read_variable_bytes_from_buffer, write_variable_bytes,
+ read_bytes_from_buffer, read_variable_bytes_from_buffer, write_variable_bytes,
},
variable_integer::{read_variable_integer_from_buffer, write_variable_integer},
};
@@ -60,15 +60,14 @@ impl MOQTPayload for SubscribeDone {
let status_code = StatusCode::try_from(status_code_u64).context("status code")?;
let reason_phrase =
String::from_utf8(read_variable_bytes_from_buffer(buf)?).context("reason phrase")?;
- let content_exists =
- match read_fixed_length_bytes_from_buffer(buf, 1).context("content_exists")?[0] {
- 0 => false,
- 1 => true,
- _ => {
- // TODO: return Termination Error Code
- bail!("Invalid content_exists value: Protocol Violation");
- }
- };
+ let content_exists = match read_bytes_from_buffer(buf, 1).context("content_exists")?[0] {
+ 0 => false,
+ 1 => true,
+ _ => {
+ // TODO: return Termination Error Code
+ bail!("Invalid content_exists value: Protocol Violation");
+ }
+ };
let (final_group_id, final_object_id) = match content_exists {
true => {
diff --git a/moqt-core/src/modules/messages/control_messages/subscribe_ok.rs b/moqt-core/src/modules/messages/control_messages/subscribe_ok.rs
index cca3df67..b23f633d 100644
--- a/moqt-core/src/modules/messages/control_messages/subscribe_ok.rs
+++ b/moqt-core/src/modules/messages/control_messages/subscribe_ok.rs
@@ -1,11 +1,11 @@
use crate::{
messages::{
control_messages::{
- subscribe::GroupOrder, version_specific_parameters::VersionSpecificParameter,
+ group_order::GroupOrder, version_specific_parameters::VersionSpecificParameter,
},
moqt_payload::MOQTPayload,
},
- variable_bytes::read_fixed_length_bytes_from_buffer,
+ variable_bytes::read_bytes_from_buffer,
variable_integer::{read_variable_integer_from_buffer, write_variable_integer},
};
use anyhow::bail;
@@ -85,7 +85,7 @@ impl MOQTPayload for SubscribeOk {
{
let subscribe_id = read_variable_integer_from_buffer(buf).context("subscribe_id")?;
let expires = read_variable_integer_from_buffer(buf).context("expires")?;
- let group_order_u8 = read_fixed_length_bytes_from_buffer(buf, 1)?[0];
+ let group_order_u8 = read_bytes_from_buffer(buf, 1)?[0];
// Values larger than 0x2 are a Protocol Violation.
let group_order = match GroupOrder::try_from(group_order_u8).context("group order") {
@@ -96,15 +96,14 @@ impl MOQTPayload for SubscribeOk {
}
};
- let content_exists =
- match read_fixed_length_bytes_from_buffer(buf, 1).context("content_exists")?[0] {
- 0 => false,
- 1 => true,
- _ => {
- // TODO: return Termination Error Code
- bail!("Invalid content_exists value: Protocol Violation");
- }
- };
+ let content_exists = match read_bytes_from_buffer(buf, 1).context("content_exists")?[0] {
+ 0 => false,
+ 1 => true,
+ _ => {
+ // TODO: return Termination Error Code
+ bail!("Invalid content_exists value: Protocol Violation");
+ }
+ };
let (largest_group_id, largest_object_id) = if content_exists {
let largest_group_id =
diff --git a/moqt-core/src/modules/messages/control_messages/version_specific_parameters.rs b/moqt-core/src/modules/messages/control_messages/version_specific_parameters.rs
index 73b4d0cf..c67ad3d7 100644
--- a/moqt-core/src/modules/messages/control_messages/version_specific_parameters.rs
+++ b/moqt-core/src/modules/messages/control_messages/version_specific_parameters.rs
@@ -1,10 +1,8 @@
use crate::{
messages::moqt_payload::MOQTPayload,
- variable_bytes::{
- convert_bytes_to_integer, read_fixed_length_bytes_from_buffer, write_fixed_length_bytes,
- },
+ variable_bytes::{bytes_to_integer, read_bytes_from_buffer, write_bytes},
variable_integer::{
- get_length_from_variable_integer_first_byte, read_variable_integer_from_buffer,
+ get_2msb_length_from_first_byte, get_2msb_value, read_variable_integer_from_buffer,
write_variable_integer,
},
};
@@ -32,7 +30,7 @@ impl MOQTPayload for VersionSpecificParameter {
read_variable_integer_from_buffer(buf)?,
)?);
let parameter_length = read_variable_integer_from_buffer(buf)?;
- let parameter_value = read_fixed_length_bytes_from_buffer(buf, parameter_length as usize)?;
+ let parameter_value = read_bytes_from_buffer(buf, parameter_length as usize)?;
if let Err(err) = parameter_type {
// If it appears in some other type of message, it MUST be ignored.
@@ -53,7 +51,7 @@ impl MOQTPayload for VersionSpecificParameter {
}
VersionSpecificParameterType::DeliveryTimeout => {
// The value is of type varint.
- let parameter_value: u64 = convert_bytes_to_integer(parameter_value)?;
+ let parameter_value: u64 = bytes_to_integer(parameter_value)?;
Ok(VersionSpecificParameter::DeliveryTimeout(
DeliveryTimeout::new(parameter_value),
@@ -61,7 +59,7 @@ impl MOQTPayload for VersionSpecificParameter {
}
VersionSpecificParameterType::MaxCacheDuration => {
// The value is of type varint.
- let parameter_value: u64 = convert_bytes_to_integer(parameter_value)?;
+ let parameter_value: u64 = bytes_to_integer(parameter_value)?;
Ok(VersionSpecificParameter::MaxCacheDuration(
MaxCacheDuration::new(parameter_value),
@@ -76,7 +74,7 @@ impl MOQTPayload for VersionSpecificParameter {
buf.extend(write_variable_integer(u64::from(param.parameter_type)));
buf.extend(write_variable_integer(param.length as u64));
// The value is an ASCII string.
- buf.extend(write_fixed_length_bytes(¶m.value.as_bytes().to_vec()));
+ buf.extend(write_bytes(¶m.value.as_bytes().to_vec()));
}
VersionSpecificParameter::DeliveryTimeout(param) => {
buf.extend(write_variable_integer(u64::from(param.parameter_type)));
@@ -142,12 +140,13 @@ pub struct DeliveryTimeout {
impl DeliveryTimeout {
pub fn new(value: u64) -> Self {
let first_byte = (value & 0xFF) as u8; // 0xFF: Bit mask to get the first byte
- let length = get_length_from_variable_integer_first_byte(first_byte);
+ let length = get_2msb_length_from_first_byte(first_byte);
+ let first_two_bits_masked_value = get_2msb_value(value);
DeliveryTimeout {
parameter_type: VersionSpecificParameterType::DeliveryTimeout,
length,
- value,
+ value: first_two_bits_masked_value,
}
}
}
@@ -162,12 +161,13 @@ pub struct MaxCacheDuration {
impl MaxCacheDuration {
pub fn new(value: u64) -> Self {
let first_byte = (value & 0xFF) as u8; // 0xFF: Bit mask to get the first byte
- let length = get_length_from_variable_integer_first_byte(first_byte);
+ let length = get_2msb_length_from_first_byte(first_byte);
+ let first_two_bits_masked_value = get_2msb_value(value);
MaxCacheDuration {
parameter_type: VersionSpecificParameterType::MaxCacheDuration,
length,
- value,
+ value: first_two_bits_masked_value,
}
}
}
diff --git a/moqt-core/src/modules/messages/data_streams.rs b/moqt-core/src/modules/messages/data_streams.rs
index 209db364..319e08e7 100644
--- a/moqt-core/src/modules/messages/data_streams.rs
+++ b/moqt-core/src/modules/messages/data_streams.rs
@@ -1,7 +1,8 @@
pub mod datagram;
+pub mod datagram_status;
+pub mod extension_header;
pub mod object_status;
pub mod subgroup_stream;
-pub mod track_stream;
use anyhow::Result;
use bytes::BytesMut;
@@ -12,3 +13,9 @@ pub trait DataStreams: Send + Sync {
Self: Sized;
fn packetize(&self, buf: &mut BytesMut);
}
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum DatagramObject {
+ ObjectDatagram(datagram::Object),
+ ObjectDatagramStatus(datagram_status::Object),
+}
diff --git a/moqt-core/src/modules/messages/data_streams/datagram.rs b/moqt-core/src/modules/messages/data_streams/datagram.rs
index 5b19fec9..f2531cfb 100644
--- a/moqt-core/src/modules/messages/data_streams/datagram.rs
+++ b/moqt-core/src/modules/messages/data_streams/datagram.rs
@@ -1,66 +1,52 @@
+use super::extension_header::ExtensionHeader;
use crate::{
- messages::data_streams::{object_status::ObjectStatus, DataStreams},
- variable_bytes::read_fixed_length_bytes,
+ messages::data_streams::DataStreams,
+ variable_bytes::{read_all_variable_bytes, read_bytes},
variable_integer::{read_variable_integer, write_variable_integer},
};
-use anyhow::{bail, Context, Result};
-use bytes::BytesMut;
+use anyhow::{Context, Result};
+use bytes::{Buf, BytesMut};
use serde::Serialize;
/// Implementation of object message per QUIC Datagram.
/// Type of Data Streams: OBJECT_DATAGRAM (0x1)
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct Object {
- subscribe_id: u64,
track_alias: u64,
group_id: u64,
object_id: u64,
publisher_priority: u8,
- object_payload_length: u64,
- object_status: Option,
+ extension_headers_length: u64,
+ extension_headers: Vec,
object_payload: Vec,
}
impl Object {
pub fn new(
- subscribe_id: u64,
track_alias: u64,
group_id: u64,
object_id: u64,
publisher_priority: u8,
- object_status: Option,
+ extension_headers: Vec,
object_payload: Vec,
) -> Result {
- let object_payload_length = object_payload.len() as u64;
-
- if object_status.is_some() && object_payload_length != 0 {
- bail!("The Object Status field is only sent if the Object Payload Length is zero.");
- }
-
- // Any object with a status code other than zero MUST have an empty payload.
- if let Some(status) = object_status {
- if status != ObjectStatus::Normal && object_payload_length != 0 {
- // TODO: return Termination Error Code
- bail!("Any object with a status code other than zero MUST have an empty payload.");
- }
+ // length of total byte of extension headers
+ let mut extension_headers_length = 0;
+ for header in &extension_headers {
+ extension_headers_length += header.byte_length() as u64;
}
Ok(Object {
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_payload_length,
- object_status,
+ extension_headers_length,
+ extension_headers,
object_payload,
})
}
- pub fn subscribe_id(&self) -> u64 {
- self.subscribe_id
- }
-
pub fn track_alias(&self) -> u64 {
self.track_alias
}
@@ -77,8 +63,8 @@ impl Object {
self.publisher_priority
}
- pub fn object_status(&self) -> Option {
- self.object_status
+ pub fn extension_headers(&self) -> &Vec {
+ &self.extension_headers
}
pub fn object_payload(&self) -> Vec {
@@ -91,67 +77,51 @@ impl DataStreams for Object {
where
Self: Sized,
{
- let subscribe_id = read_variable_integer(read_cur).context("subscribe id")?;
let track_alias = read_variable_integer(read_cur).context("track alias")?;
let group_id = read_variable_integer(read_cur).context("group id")?;
let object_id = read_variable_integer(read_cur).context("object id")?;
- let publisher_priority =
- read_fixed_length_bytes(read_cur, 1).context("publisher priority")?[0];
- let object_payload_length =
- read_variable_integer(read_cur).context("object payload length")?;
-
- // If the length of the remaining buf is larger than object_payload_length, object_status exists.
- // The Object Status field is only sent if the Object Payload Length is zero.
- let object_status = if object_payload_length == 0 {
- let object_status_u64 = read_variable_integer(read_cur)?;
- let object_status =
- match ObjectStatus::try_from(object_status_u64 as u8).context("object status") {
- Ok(status) => status,
- Err(err) => {
- // Any other value SHOULD be treated as a Protocol Violation and terminate the session with a Protocol Violation
- // TODO: return Termination Error Code
- bail!(err);
- }
- };
-
- Some(object_status)
- } else {
- None
- };
+ let publisher_priority = read_bytes(read_cur, 1).context("publisher priority")?[0];
- let object_payload = if object_payload_length > 0 {
- read_fixed_length_bytes(read_cur, object_payload_length as usize)
- .context("object payload")?
- } else {
- vec![]
- };
+ let extension_headers_length =
+ read_variable_integer(read_cur).context("extension headers length")?;
+
+ let mut extension_headers_vec = vec![];
+ let extension_headers =
+ read_bytes(read_cur, extension_headers_length as usize).context("extension headers")?;
+ let mut extension_headers_cur = std::io::Cursor::new(&extension_headers[..]);
+
+ while extension_headers_cur.has_remaining() {
+ let extension_header = ExtensionHeader::depacketize(&mut extension_headers_cur)
+ .context("extension header")?;
+ extension_headers_vec.push(extension_header);
+ }
+
+ let object_payload = read_all_variable_bytes(read_cur).context("object payload")?;
tracing::trace!("Depacketized Datagram Object message.");
Ok(Object {
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_payload_length,
- object_status,
+ extension_headers_length,
+ extension_headers: extension_headers_vec,
object_payload,
})
}
fn packetize(&self, buf: &mut BytesMut) {
- buf.extend(write_variable_integer(self.subscribe_id));
buf.extend(write_variable_integer(self.track_alias));
buf.extend(write_variable_integer(self.group_id));
buf.extend(write_variable_integer(self.object_id));
buf.extend(self.publisher_priority.to_be_bytes());
- buf.extend(write_variable_integer(self.object_payload_length));
- if self.object_status.is_some() {
- buf.extend(write_variable_integer(
- u8::from(self.object_status.unwrap()) as u64,
- ));
+
+ buf.extend(write_variable_integer(self.extension_headers_length));
+ for header in &self.extension_headers {
+ header.packetize(buf);
}
+
buf.extend(&self.object_payload);
tracing::trace!("Packetized Datagram Object message.");
@@ -161,27 +131,29 @@ impl DataStreams for Object {
#[cfg(test)]
mod tests {
mod success {
- use crate::messages::data_streams::{datagram, object_status::ObjectStatus, DataStreams};
+ use crate::messages::data_streams::{
+ datagram,
+ extension_header::{ExtensionHeader, ExtensionHeaderValue, Value, ValueWithLength},
+ DataStreams,
+ };
use bytes::BytesMut;
use std::io::Cursor;
#[test]
fn packetize_datagram_object_normal() {
- let subscribe_id = 0;
let track_alias = 1;
let group_id = 2;
let object_id = 3;
let publisher_priority = 4;
- let object_status = None;
+ let extension_headers = vec![];
let object_payload = vec![0, 1, 2];
let datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_status,
+ extension_headers,
object_payload,
)
.unwrap();
@@ -190,12 +162,11 @@ mod tests {
datagram_object.packetize(&mut buf);
let expected_bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 3, // Object Payload Length (i)
+ 0, // Extension Headers Length (i)
0, 1, 2, // Object Payload (..)
];
@@ -203,22 +174,60 @@ mod tests {
}
#[test]
- fn packetize_datagram_object_normal_and_empty_payload() {
- let subscribe_id = 0;
+ fn depacketize_datagram_object_normal() {
+ let bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 0, // Extension Headers Length (i)
+ 0, 1, 2, // Object Payload (..)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_datagram_object =
+ datagram::Object::depacketize(&mut read_cur).unwrap();
+
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let extension_headers = vec![];
+ let object_payload = vec![0, 1, 2];
+
+ let expected_datagram_object = datagram::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_payload,
+ )
+ .unwrap();
+
+ assert_eq!(depacketized_datagram_object, expected_datagram_object);
+ }
+
+ #[test]
+ fn packetize_datagram_stream_object_with_even_type_extension_header() {
let track_alias = 1;
let group_id = 2;
let object_id = 3;
let publisher_priority = 4;
- let object_status = Some(ObjectStatus::Normal);
- let object_payload = vec![];
+ let header_type = 4;
+ let value = 1;
+ let header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_payload = vec![0, 1, 2];
let datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_status,
+ extension_headers,
object_payload,
)
.unwrap();
@@ -227,35 +236,38 @@ mod tests {
datagram_object.packetize(&mut buf);
let expected_bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 0, // Object Payload Length (i)
- 0, // Object Status (i)
+ 2, // Extension Headers Length (i)
+ 4, // Header Type (i)
+ 1, // Header Value (i)
+ 0, 1, 2, // Object Payload (..)
];
assert_eq!(buf.as_ref(), expected_bytes_array);
}
#[test]
- fn packetize_datagram_object_not_normal() {
- let subscribe_id = 0;
+ fn packetize_datagram_stream_object_with_odd_type_extension_header() {
let track_alias = 1;
let group_id = 2;
let object_id = 3;
let publisher_priority = 4;
- let object_status = Some(ObjectStatus::EndOfGroup);
- let object_payload = vec![];
+ let header_type = 1;
+ let value = vec![1, 2, 3];
+ let header_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_payload = vec![0, 1, 2];
let datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_status,
+ extension_headers,
object_payload,
)
.unwrap();
@@ -264,27 +276,83 @@ mod tests {
datagram_object.packetize(&mut buf);
let expected_bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 0, // Object Payload Length (i)
- 3, // Object Status (i)
+ 5, // Extension Headers Length (i)
+ 1, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ 0, 1, 2, // Object Payload (..)
];
assert_eq!(buf.as_ref(), expected_bytes_array);
}
#[test]
- fn depacketize_datagram_object_normal() {
+ fn packetize_datagram_stream_object_with_mixed_type_extension_headers() {
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let even_header_type = 12;
+ let even_value = 1;
+ let even_header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(even_value));
+ let odd_header_type = 9;
+ let odd_value = vec![1, 2, 3];
+ let odd_header_value =
+ ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(odd_value));
+
+ let extension_headers = vec![
+ ExtensionHeader::new(odd_header_type, odd_header_value).unwrap(),
+ ExtensionHeader::new(even_header_type, even_header_value).unwrap(),
+ ];
+ let object_payload = vec![0, 1, 2];
+
+ let datagram_object = datagram::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_payload,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ datagram_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 7, // Extension Headers Length (i)
+ //{
+ 9, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ // }{
+ 12, // Header Type (i)
+ 1, // Header Value (i)
+ // }
+ 0, 1, 2, // Object Payload (..)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn depacketize_datagram_stream_object_with_even_type_extension_header() {
let bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 3, // Object Payload Length (i)
+ 2, // Extension Headers Length (i)
+ 4, // Header Type (i)
+ 1, // Header Value (i)
0, 1, 2, // Object Payload (..)
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
@@ -293,21 +361,23 @@ mod tests {
let depacketized_datagram_object =
datagram::Object::depacketize(&mut read_cur).unwrap();
- let subscribe_id = 0;
let track_alias = 1;
let group_id = 2;
let object_id = 3;
let publisher_priority = 4;
- let object_status = None;
+ let header_type = 4;
+ let value = 1;
+ let header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
let object_payload = vec![0, 1, 2];
let expected_datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_status,
+ extension_headers,
object_payload,
)
.unwrap();
@@ -316,15 +386,17 @@ mod tests {
}
#[test]
- fn depacketize_datagram_object_normal_and_empty_payload() {
+ fn depacketize_datagram_stream_object_with_odd_type_extension_header() {
let bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 0, // Object Payload Length (i)
- 0, // Object Status (i)
+ 5, // Extension Headers Length (i)
+ 1, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ 0, 1, 2, // Object Payload (..)
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
@@ -332,21 +404,23 @@ mod tests {
let depacketized_datagram_object =
datagram::Object::depacketize(&mut read_cur).unwrap();
- let subscribe_id = 0;
let track_alias = 1;
let group_id = 2;
let object_id = 3;
let publisher_priority = 4;
- let object_status = Some(ObjectStatus::Normal);
- let object_payload = vec![];
+ let header_type = 1;
+ let value = vec![1, 2, 3];
+ let header_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_payload = vec![0, 1, 2];
let expected_datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_status,
+ extension_headers,
object_payload,
)
.unwrap();
@@ -355,15 +429,22 @@ mod tests {
}
#[test]
- fn depacketize_datagram_object_not_normal() {
+ fn depacketize_datagram_stream_object_with_mixed_type_extension_headers() {
let bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 0, // Object Payload Length (i)
- 1, // Object Status (i)
+ 7, // Extension Headers Length (i)
+ //{
+ 9, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ // }{
+ 12, // Header Type (i)
+ 1, // Header Value (i)
+ // }
+ 0, 1, 2, // Object Payload (..)
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
@@ -371,21 +452,30 @@ mod tests {
let depacketized_datagram_object =
datagram::Object::depacketize(&mut read_cur).unwrap();
- let subscribe_id = 0;
let track_alias = 1;
let group_id = 2;
let object_id = 3;
let publisher_priority = 4;
- let object_status = Some(ObjectStatus::DoesNotExist);
- let object_payload = vec![];
+ let even_header_type = 12;
+ let even_value = 1;
+ let even_header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(even_value));
+ let odd_header_type = 9;
+ let odd_value = vec![1, 2, 3];
+ let odd_header_value =
+ ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(odd_value));
+
+ let extension_headers = vec![
+ ExtensionHeader::new(odd_header_type, odd_header_value).unwrap(),
+ ExtensionHeader::new(even_header_type, even_header_value).unwrap(),
+ ];
+ let object_payload = vec![0, 1, 2];
let expected_datagram_object = datagram::Object::new(
- subscribe_id,
track_alias,
group_id,
object_id,
publisher_priority,
- object_status,
+ extension_headers,
object_payload,
)
.unwrap();
@@ -398,41 +488,16 @@ mod tests {
use bytes::BytesMut;
use std::io::Cursor;
- use crate::messages::data_streams::{datagram, object_status::ObjectStatus, DataStreams};
-
- #[test]
- fn packetize_datagram_object_not_normal_and_not_empty_payload() {
- let subscribe_id = 0;
- let track_alias = 1;
- let group_id = 2;
- let object_id = 3;
- let publisher_priority = 4;
- let object_status = Some(ObjectStatus::EndOfTrackAndGroup);
- let object_payload = vec![0, 1, 2];
-
- let datagram_object = datagram::Object::new(
- subscribe_id,
- track_alias,
- group_id,
- object_id,
- publisher_priority,
- object_status,
- object_payload,
- );
-
- assert!(datagram_object.is_err());
- }
+ use crate::messages::data_streams::{datagram, DataStreams};
#[test]
- fn depacketize_datagram_object_wrong_object_status() {
+ fn depacketize_datagram_object_with_empty_payload() {
let bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Object ID (i)
4, // Subscriber Priority (8)
- 0, // Object Payload Length (i)
- 2, // Object Status (i)
+ 0, // Extension Headers Length (i)
];
let mut buf = BytesMut::with_capacity(bytes_array.len());
buf.extend_from_slice(&bytes_array);
diff --git a/moqt-core/src/modules/messages/data_streams/datagram_status.rs b/moqt-core/src/modules/messages/data_streams/datagram_status.rs
new file mode 100644
index 00000000..6ec6deeb
--- /dev/null
+++ b/moqt-core/src/modules/messages/data_streams/datagram_status.rs
@@ -0,0 +1,521 @@
+use super::{extension_header::ExtensionHeader, object_status::ObjectStatus};
+use crate::{
+ messages::data_streams::DataStreams,
+ variable_bytes::read_bytes,
+ variable_integer::{read_variable_integer, write_variable_integer},
+};
+use anyhow::{bail, Context, Result};
+use bytes::{Buf, BytesMut};
+use serde::Serialize;
+
+/// Implementation of object message per QUIC Datagram.
+/// Type of Data Streams: OBJECT_DATAGRAM_STATUS (0x2)
+#[derive(Debug, Clone, Serialize, PartialEq)]
+pub struct Object {
+ track_alias: u64,
+ group_id: u64,
+ object_id: u64,
+ publisher_priority: u8,
+ extension_headers_length: u64,
+ extension_headers: Vec,
+ object_status: ObjectStatus,
+}
+
+impl Object {
+ pub fn new(
+ track_alias: u64,
+ group_id: u64,
+ object_id: u64,
+ publisher_priority: u8,
+ extension_headers: Vec,
+ object_status: ObjectStatus,
+ ) -> Result {
+ // length of total byte of extension headers
+ let mut extension_headers_length = 0;
+ for header in &extension_headers {
+ extension_headers_length += header.byte_length() as u64;
+ }
+
+ Ok(Object {
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers_length,
+ extension_headers,
+ object_status,
+ })
+ }
+
+ pub fn track_alias(&self) -> u64 {
+ self.track_alias
+ }
+
+ pub fn group_id(&self) -> u64 {
+ self.group_id
+ }
+
+ pub fn object_id(&self) -> u64 {
+ self.object_id
+ }
+
+ pub fn publisher_priority(&self) -> u8 {
+ self.publisher_priority
+ }
+
+ pub fn extension_headers(&self) -> &Vec {
+ &self.extension_headers
+ }
+
+ pub fn object_status(&self) -> ObjectStatus {
+ self.object_status
+ }
+}
+
+impl DataStreams for Object {
+ fn depacketize(read_cur: &mut std::io::Cursor<&[u8]>) -> Result
+ where
+ Self: Sized,
+ {
+ let track_alias = read_variable_integer(read_cur).context("track alias")?;
+ let group_id = read_variable_integer(read_cur).context("group id")?;
+ let object_id = read_variable_integer(read_cur).context("object id")?;
+ let publisher_priority = read_bytes(read_cur, 1).context("publisher priority")?[0];
+
+ let extension_headers_length =
+ read_variable_integer(read_cur).context("extension headers length")?;
+
+ let mut extension_headers_vec = vec![];
+ let extension_headers =
+ read_bytes(read_cur, extension_headers_length as usize).context("extension headers")?;
+ let mut extension_headers_cur = std::io::Cursor::new(&extension_headers[..]);
+
+ while extension_headers_cur.has_remaining() {
+ let extension_header = ExtensionHeader::depacketize(&mut extension_headers_cur)
+ .context("extension header")?;
+ extension_headers_vec.push(extension_header);
+ }
+
+ let object_status_u64 = read_variable_integer(read_cur)?;
+ let object_status =
+ match ObjectStatus::try_from(object_status_u64 as u8).context("object status") {
+ Ok(status) => status,
+ Err(err) => {
+ // Any other value SHOULD be treated as a Protocol Violation and terminate the session with a Protocol Violation
+ // TODO: return Termination Error Code
+ bail!(err);
+ }
+ };
+
+ tracing::trace!("Depacketized Datagram Object message.");
+
+ Ok(Object {
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers_length,
+ extension_headers: extension_headers_vec,
+ object_status,
+ })
+ }
+
+ fn packetize(&self, buf: &mut BytesMut) {
+ buf.extend(write_variable_integer(self.track_alias));
+ buf.extend(write_variable_integer(self.group_id));
+ buf.extend(write_variable_integer(self.object_id));
+ buf.extend(self.publisher_priority.to_be_bytes());
+
+ buf.extend(write_variable_integer(self.extension_headers_length));
+ for header in &self.extension_headers {
+ header.packetize(buf);
+ }
+
+ buf.extend(write_variable_integer(u8::from(self.object_status) as u64));
+
+ tracing::trace!("Packetized Datagram Object message.");
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ mod success {
+ use crate::messages::data_streams::{
+ datagram_status,
+ extension_header::{ExtensionHeader, ExtensionHeaderValue, Value, ValueWithLength},
+ object_status::ObjectStatus,
+ DataStreams,
+ };
+ use bytes::BytesMut;
+ use std::io::Cursor;
+
+ #[test]
+ fn packetize_datagram_status() {
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let extension_headers = vec![];
+ let object_status = ObjectStatus::Normal;
+
+ let datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ datagram_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 0, // Extension Headers Length (i)
+ 0, // Object Status (i)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn depacketize_datagram_status() {
+ let bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 0, // Extension Headers Length (i)
+ 1, // Object Status (i)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_datagram_object =
+ datagram_status::Object::depacketize(&mut read_cur).unwrap();
+
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let extension_headers = vec![];
+ let object_status = ObjectStatus::DoesNotExist;
+
+ let expected_datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ assert_eq!(depacketized_datagram_object, expected_datagram_object);
+ }
+
+ #[test]
+ fn packetize_datagram_status_with_even_type_extension_header() {
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let header_type = 4;
+ let value = 1;
+ let header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = ObjectStatus::EndOfGroup;
+
+ let datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ datagram_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 2, // Extension Headers Length (i)
+ 4, // Header Type (i)
+ 1, // Header Value (i)
+ 3, // Object Status (i)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn packetize_datagram_status_with_odd_type_extension_header() {
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let header_type = 1;
+ let value = vec![1, 2, 3];
+ let header_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = ObjectStatus::EndOfTrackAndGroup;
+
+ let datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ datagram_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 5, // Extension Headers Length (i)
+ 1, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ 4, // Object Status (i)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn packetize_datagram_status_with_mixed_type_extension_headers() {
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let even_header_type = 12;
+ let even_value = 1;
+ let even_header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(even_value));
+ let odd_header_type = 9;
+ let odd_value = vec![1, 2, 3];
+ let odd_header_value =
+ ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(odd_value));
+
+ let extension_headers = vec![
+ ExtensionHeader::new(odd_header_type, odd_header_value).unwrap(),
+ ExtensionHeader::new(even_header_type, even_header_value).unwrap(),
+ ];
+ let object_status = ObjectStatus::EndOfTrack;
+
+ let datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ datagram_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 7, // Extension Headers Length (i)
+ //{
+ 9, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ // }{
+ 12, // Header Type (i)
+ 1, // Header Value (i)
+ // }
+ 5, // Object Status (i)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn depacketize_datagram_status_with_even_type_extension_header() {
+ let bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 2, // Extension Headers Length (i)
+ 4, // Header Type (i)
+ 1, // Header Value (i)
+ 0, // Object Status (i)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_datagram_object =
+ datagram_status::Object::depacketize(&mut read_cur).unwrap();
+
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let header_type = 4;
+ let value = 1;
+ let header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = ObjectStatus::Normal;
+
+ let expected_datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ assert_eq!(depacketized_datagram_object, expected_datagram_object);
+ }
+
+ #[test]
+ fn depacketize_datagram_status_with_odd_type_extension_header() {
+ let bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 5, // Extension Headers Length (i)
+ 1, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ 0, // Object Status (i)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_datagram_object =
+ datagram_status::Object::depacketize(&mut read_cur).unwrap();
+
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let header_type = 1;
+ let value = vec![1, 2, 3];
+ let header_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = ObjectStatus::Normal;
+
+ let expected_datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ assert_eq!(depacketized_datagram_object, expected_datagram_object);
+ }
+
+ #[test]
+ fn depacketize_datagram_status_with_mixed_type_extension_headers() {
+ let bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 7, // Extension Headers Length (i)
+ //{
+ 9, // Header Type (i)
+ 3, // Header Value Length (i)
+ 1, 2, 3, // Header Value (..)
+ // }{
+ 12, // Header Type (i)
+ 1, // Header Value (i)
+ // }
+ 0, // Object Status (i)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_datagram_object =
+ datagram_status::Object::depacketize(&mut read_cur).unwrap();
+
+ let track_alias = 1;
+ let group_id = 2;
+ let object_id = 3;
+ let publisher_priority = 4;
+ let even_header_type = 12;
+ let even_value = 1;
+ let even_header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(even_value));
+ let odd_header_type = 9;
+ let odd_value = vec![1, 2, 3];
+ let odd_header_value =
+ ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(odd_value));
+
+ let extension_headers = vec![
+ ExtensionHeader::new(odd_header_type, odd_header_value).unwrap(),
+ ExtensionHeader::new(even_header_type, even_header_value).unwrap(),
+ ];
+ let object_status = ObjectStatus::Normal;
+
+ let expected_datagram_object = datagram_status::Object::new(
+ track_alias,
+ group_id,
+ object_id,
+ publisher_priority,
+ extension_headers,
+ object_status,
+ )
+ .unwrap();
+
+ assert_eq!(depacketized_datagram_object, expected_datagram_object);
+ }
+ }
+
+ mod failure {
+ use bytes::BytesMut;
+ use std::io::Cursor;
+
+ use crate::messages::data_streams::{datagram_status, DataStreams};
+
+ #[test]
+ fn depacketize_datagram_status_with_unknown_status() {
+ let bytes_array = [
+ 1, // Track Alias (i)
+ 2, // Group ID (i)
+ 3, // Object ID (i)
+ 4, // Subscriber Priority (8)
+ 0, // Extension Headers Length (i)
+ 20, // Object Status (i)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_datagram_object = datagram_status::Object::depacketize(&mut read_cur);
+
+ assert!(depacketized_datagram_object.is_err());
+ }
+ }
+}
diff --git a/moqt-core/src/modules/messages/data_streams/extension_header.rs b/moqt-core/src/modules/messages/data_streams/extension_header.rs
new file mode 100644
index 00000000..c082c311
--- /dev/null
+++ b/moqt-core/src/modules/messages/data_streams/extension_header.rs
@@ -0,0 +1,172 @@
+use crate::{
+ messages::data_streams::DataStreams,
+ variable_bytes::read_bytes,
+ variable_integer::{read_variable_integer, write_variable_integer},
+};
+use anyhow::{bail, Context, Result};
+use bytes::BytesMut;
+use serde::Serialize;
+
+#[derive(Debug, Clone, Serialize, PartialEq)]
+pub struct ExtensionHeader {
+ header_type: u64,
+ value: ExtensionHeaderValue,
+}
+
+#[derive(Debug, Clone, Serialize, PartialEq)]
+pub enum ExtensionHeaderValue {
+ EvenTypeValue(Value),
+ OddTypeValue(ValueWithLength),
+}
+
+impl ExtensionHeader {
+ pub fn new(header_type: u64, value: ExtensionHeaderValue) -> Result {
+ if header_type % 2 == 0 && matches!(value, ExtensionHeaderValue::OddTypeValue(_)) {
+ bail!("Mismatched value type: expected even, but got odd");
+ }
+
+ if header_type % 2 != 0 && matches!(value, ExtensionHeaderValue::EvenTypeValue(_)) {
+ bail!("Mismatched value type: expected odd, but got even");
+ }
+
+ Ok(ExtensionHeader { header_type, value })
+ }
+
+ pub fn byte_length(&self) -> usize {
+ let mut len = write_variable_integer(self.header_type).len();
+ match &self.value {
+ ExtensionHeaderValue::EvenTypeValue(value) => len += value.byte_length(),
+ ExtensionHeaderValue::OddTypeValue(value_with_length) => {
+ len += value_with_length.byte_length()
+ }
+ }
+ len
+ }
+}
+
+impl DataStreams for ExtensionHeader {
+ fn depacketize(read_cur: &mut std::io::Cursor<&[u8]>) -> Result
+ where
+ Self: Sized,
+ {
+ let header_type = read_variable_integer(read_cur).context("header type")?;
+ if header_type % 2 == 0 {
+ let value = ExtensionHeaderValue::EvenTypeValue(Value::depacketize(read_cur)?);
+ Ok(ExtensionHeader { header_type, value })
+ } else {
+ let value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::depacketize(read_cur)?);
+ Ok(ExtensionHeader { header_type, value })
+ }
+ }
+
+ fn packetize(&self, buf: &mut BytesMut) {
+ buf.extend(write_variable_integer(self.header_type));
+ match &self.value {
+ ExtensionHeaderValue::EvenTypeValue(value) => value.packetize(buf),
+ ExtensionHeaderValue::OddTypeValue(value_with_length) => {
+ value_with_length.packetize(buf)
+ }
+ }
+ }
+}
+
+#[derive(Debug, Clone, Serialize, PartialEq)]
+pub struct Value {
+ header_value: u64,
+}
+
+#[derive(Debug, Clone, Serialize, PartialEq)]
+pub struct ValueWithLength {
+ header_length: u64,
+ header_value: Vec,
+}
+
+impl Value {
+ pub fn new(header_value: u64) -> Self {
+ Value { header_value }
+ }
+
+ pub fn byte_length(&self) -> usize {
+ write_variable_integer(self.header_value).len()
+ }
+}
+
+impl DataStreams for Value {
+ fn depacketize(read_cur: &mut std::io::Cursor<&[u8]>) -> Result
+ where
+ Self: Sized,
+ {
+ let header_value = read_variable_integer(read_cur).context("header length")?;
+
+ Ok(Value { header_value })
+ }
+
+ fn packetize(&self, buf: &mut BytesMut) {
+ buf.extend(write_variable_integer(self.header_value));
+ }
+}
+
+impl ValueWithLength {
+ pub fn new(header_value: Vec) -> Self {
+ ValueWithLength {
+ header_length: header_value.len() as u64,
+ header_value,
+ }
+ }
+
+ pub fn byte_length(&self) -> usize {
+ let mut len = write_variable_integer(self.header_length).len();
+ len += self.header_value.len();
+ len
+ }
+}
+
+impl DataStreams for ValueWithLength {
+ fn depacketize(read_cur: &mut std::io::Cursor<&[u8]>) -> Result
+ where
+ Self: Sized,
+ {
+ let header_length = read_variable_integer(read_cur).context("header length")?;
+ let header_value = if header_length > 0 {
+ read_bytes(read_cur, header_length as usize).context("header value")?
+ } else {
+ vec![]
+ };
+
+ Ok(ValueWithLength {
+ header_length,
+ header_value,
+ })
+ }
+
+ fn packetize(&self, buf: &mut BytesMut) {
+ buf.extend(write_variable_integer(self.header_length));
+ buf.extend(&self.header_value);
+ }
+}
+
+#[cfg(test)]
+mod failure {
+ use super::ValueWithLength;
+ use crate::messages::data_streams::extension_header::{
+ ExtensionHeader, ExtensionHeaderValue, Value,
+ };
+
+ #[test]
+ fn new_odd_value_with_even_type() {
+ let even_header_type = 0;
+ let odd_type_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(vec![0]));
+ let extension_header = ExtensionHeader::new(even_header_type, odd_type_value);
+
+ assert!(extension_header.is_err());
+ }
+
+ #[test]
+ fn new_even_value_with_odd_type() {
+ let odd_header_type = 1;
+ let even_type_value = ExtensionHeaderValue::EvenTypeValue(Value::new(0));
+ let extension_header = ExtensionHeader::new(odd_header_type, even_type_value);
+
+ assert!(extension_header.is_err());
+ }
+}
diff --git a/moqt-core/src/modules/messages/data_streams/object_status.rs b/moqt-core/src/modules/messages/data_streams/object_status.rs
index cf2c9ae6..e8625af3 100644
--- a/moqt-core/src/modules/messages/data_streams/object_status.rs
+++ b/moqt-core/src/modules/messages/data_streams/object_status.rs
@@ -8,5 +8,5 @@ pub enum ObjectStatus {
DoesNotExist = 0x1,
EndOfGroup = 0x3,
EndOfTrackAndGroup = 0x4,
- EndOfSubgroup = 0x5,
+ EndOfTrack = 0x5,
}
diff --git a/moqt-core/src/modules/messages/data_streams/subgroup_stream.rs b/moqt-core/src/modules/messages/data_streams/subgroup_stream.rs
index bf421117..d71cb059 100644
--- a/moqt-core/src/modules/messages/data_streams/subgroup_stream.rs
+++ b/moqt-core/src/modules/messages/data_streams/subgroup_stream.rs
@@ -1,19 +1,18 @@
-use super::object_status::ObjectStatus;
+use super::{extension_header::ExtensionHeader, object_status::ObjectStatus};
use crate::{
messages::data_streams::DataStreams,
- variable_bytes::read_fixed_length_bytes,
+ variable_bytes::read_bytes,
variable_integer::{read_variable_integer, write_variable_integer},
};
use anyhow::{bail, Context, Result};
-use bytes::BytesMut;
+use bytes::{Buf, BytesMut};
use serde::Serialize;
/// Implementation of header message on QUIC Stream per Subgroup.
/// Object messages are sent following this message.
-/// Type of Data Streams:STREAM_HEADER_SUBGROUP (0x4)
+/// Type of Data Streams:SUBGROUP_HEADER (0x4)
#[derive(Debug, Clone, Serialize, PartialEq, Default)]
pub struct Header {
- subscribe_id: u64,
track_alias: u64,
group_id: u64,
subgroup_id: u64,
@@ -22,14 +21,12 @@ pub struct Header {
impl Header {
pub fn new(
- subscribe_id: u64,
track_alias: u64,
group_id: u64,
subgroup_id: u64,
publisher_priority: u8,
) -> Result {
Ok(Header {
- subscribe_id,
track_alias,
group_id,
subgroup_id,
@@ -37,10 +34,6 @@ impl Header {
})
}
- pub fn subscribe_id(&self) -> u64 {
- self.subscribe_id
- }
-
pub fn track_alias(&self) -> u64 {
self.track_alias
}
@@ -63,17 +56,14 @@ impl DataStreams for Header {
where
Self: Sized,
{
- let subscribe_id = read_variable_integer(read_cur).context("subscribe id")?;
let track_alias = read_variable_integer(read_cur).context("track alias")?;
let group_id = read_variable_integer(read_cur).context("group id")?;
let subgroup_id = read_variable_integer(read_cur).context("subgroup id")?;
- let publisher_priority =
- read_fixed_length_bytes(read_cur, 1).context("publisher priority")?[0];
+ let publisher_priority = read_bytes(read_cur, 1).context("publisher priority")?[0];
tracing::trace!("Depacketized Subgroup Stream Header message.");
Ok(Header {
- subscribe_id,
track_alias,
group_id,
subgroup_id,
@@ -82,7 +72,6 @@ impl DataStreams for Header {
}
fn packetize(&self, buf: &mut BytesMut) {
- buf.extend(write_variable_integer(self.subscribe_id));
buf.extend(write_variable_integer(self.track_alias));
buf.extend(write_variable_integer(self.group_id));
buf.extend(write_variable_integer(self.subgroup_id));
@@ -97,6 +86,8 @@ impl DataStreams for Header {
#[derive(Debug, Clone, Serialize, PartialEq)]
pub struct Object {
object_id: u64,
+ extension_headers_length: u64,
+ extension_headers: Vec,
object_payload_length: u64,
object_status: Option,
object_payload: Vec,
@@ -105,6 +96,7 @@ pub struct Object {
impl Object {
pub fn new(
object_id: u64,
+ extension_headers: Vec,
object_status: Option,
object_payload: Vec,
) -> Result {
@@ -122,8 +114,16 @@ impl Object {
}
}
+ // length of total byte of extension headers
+ let mut extension_headers_length = 0;
+ for header in &extension_headers {
+ extension_headers_length += header.byte_length() as u64;
+ }
+
Ok(Object {
object_id,
+ extension_headers_length,
+ extension_headers,
object_payload_length,
object_status,
object_payload,
@@ -145,6 +145,20 @@ impl DataStreams for Object {
Self: Sized,
{
let object_id = read_variable_integer(read_cur).context("object id")?;
+ let extension_headers_length =
+ read_variable_integer(read_cur).context("extension headers length")?;
+
+ let mut extension_headers_vec = vec![];
+ let extension_headers =
+ read_bytes(read_cur, extension_headers_length as usize).context("extension headers")?;
+ let mut extension_headers_cur = std::io::Cursor::new(&extension_headers[..]);
+
+ while extension_headers_cur.has_remaining() {
+ let extension_header = ExtensionHeader::depacketize(&mut extension_headers_cur)
+ .context("extension header")?;
+ extension_headers_vec.push(extension_header);
+ }
+
let object_payload_length =
read_variable_integer(read_cur).context("object payload length")?;
@@ -167,8 +181,7 @@ impl DataStreams for Object {
};
let object_payload = if object_payload_length > 0 {
- read_fixed_length_bytes(read_cur, object_payload_length as usize)
- .context("object payload")?
+ read_bytes(read_cur, object_payload_length as usize).context("object payload")?
} else {
vec![]
};
@@ -177,6 +190,8 @@ impl DataStreams for Object {
Ok(Object {
object_id,
+ extension_headers_length,
+ extension_headers: extension_headers_vec,
object_payload_length,
object_status,
object_payload,
@@ -185,6 +200,12 @@ impl DataStreams for Object {
fn packetize(&self, buf: &mut BytesMut) {
buf.extend(write_variable_integer(self.object_id));
+
+ buf.extend(write_variable_integer(self.extension_headers_length));
+ for header in &self.extension_headers {
+ header.packetize(buf);
+ }
+
buf.extend(write_variable_integer(self.object_payload_length));
if self.object_status.is_some() {
buf.extend(write_variable_integer(
@@ -200,24 +221,23 @@ impl DataStreams for Object {
#[cfg(test)]
mod tests {
mod success {
- use bytes::BytesMut;
- use std::io::Cursor;
-
+ use crate::messages::data_streams::extension_header::{
+ ExtensionHeader, ExtensionHeaderValue, Value, ValueWithLength,
+ };
use crate::messages::data_streams::{
- object_status::ObjectStatus,
- {subgroup_stream, DataStreams},
+ object_status::ObjectStatus, subgroup_stream, DataStreams,
};
+ use bytes::BytesMut;
+ use std::io::Cursor;
#[test]
fn packetize_subgroup_stream_header() {
- let subscribe_id = 0;
let track_alias = 1;
let group_id = 2;
let subgroup_id = 3;
let publisher_priority = 4;
let subgroup_stream_header = subgroup_stream::Header::new(
- subscribe_id,
track_alias,
group_id,
subgroup_id,
@@ -229,7 +249,6 @@ mod tests {
subgroup_stream_header.packetize(&mut buf);
let expected_bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Subgroup ID (i)
@@ -242,7 +261,6 @@ mod tests {
#[test]
fn depacketize_subgroup_stream_header() {
let bytes_array = [
- 0, // Subscribe ID (i)
1, // Track Alias (i)
2, // Group ID (i)
3, // Subgroup ID (i)
@@ -254,14 +272,12 @@ mod tests {
let depacketized_subgroup_stream_header =
subgroup_stream::Header::depacketize(&mut read_cur).unwrap();
- let subscribe_id = 0;
let track_alias = 1;
let group_id = 2;
let subgroup_id = 3;
let publisher_priority = 4;
let expected_subgroup_stream_header = subgroup_stream::Header::new(
- subscribe_id,
track_alias,
group_id,
subgroup_id,
@@ -278,18 +294,25 @@ mod tests {
#[test]
fn packetize_subgroup_stream_object_normal() {
let object_id = 0;
+ let extension_headers = vec![];
let object_status = None;
let object_payload = vec![0, 1, 2];
- let subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload).unwrap();
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
let mut buf = BytesMut::new();
subgroup_stream_object.packetize(&mut buf);
let expected_bytes_array = [
0, // Object ID (i)
- 3, // Object Payload Length (i
+ 0, // Extension Headers Length (i)
+ 3, // Object Payload Length (i)
0, 1, 2, // Object Payload (..)
];
@@ -299,17 +322,24 @@ mod tests {
#[test]
fn packetize_subgroup_stream_object_normal_and_empty_payload() {
let object_id = 0;
+ let extension_headers = vec![];
let object_status = Some(ObjectStatus::Normal);
let object_payload = vec![];
- let subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload).unwrap();
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
let mut buf = BytesMut::new();
subgroup_stream_object.packetize(&mut buf);
let expected_bytes_array = [
0, // Object ID (i)
+ 0, // Extension Headers Length (i)
0, // Object Payload Length (i)
0, // Object Status (i)
];
@@ -320,17 +350,24 @@ mod tests {
#[test]
fn packetize_subgroup_stream_object_not_normal() {
let object_id = 0;
+ let extension_headers = vec![];
let object_status = Some(ObjectStatus::EndOfGroup);
let object_payload = vec![];
- let subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload).unwrap();
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
let mut buf = BytesMut::new();
subgroup_stream_object.packetize(&mut buf);
let expected_bytes_array = [
0, // Object ID (i)
+ 0, // Extension Headers Length (i)
0, // Object Payload Length (i)
3, // Object Status (i)
];
@@ -342,6 +379,7 @@ mod tests {
fn depacketize_subgroup_stream_object_normal() {
let bytes_array = [
0, // Object ID (i)
+ 0, // Extension Headers Length (i)
0, // Object Payload Length (i)
0, // Object Status (i)
];
@@ -352,11 +390,17 @@ mod tests {
subgroup_stream::Object::depacketize(&mut read_cur).unwrap();
let object_id = 0;
+ let extension_headers = vec![];
let object_status = Some(ObjectStatus::Normal);
let object_payload = vec![];
- let expected_subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload).unwrap();
+ let expected_subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
assert_eq!(
depacketized_subgroup_stream_object,
@@ -368,6 +412,7 @@ mod tests {
fn depacketize_subgroup_stream_object_normal_and_empty_payload() {
let bytes_array = [
0, // Object ID (i)
+ 0, // Extension Headers Length (i)
0, // Object Payload Length (i)
0, // Object Status (i)
];
@@ -378,11 +423,17 @@ mod tests {
subgroup_stream::Object::depacketize(&mut read_cur).unwrap();
let object_id = 0;
+ let extension_headers = vec![];
let object_status = Some(ObjectStatus::Normal);
let object_payload = vec![];
- let expected_subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload).unwrap();
+ let expected_subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
assert_eq!(
depacketized_subgroup_stream_object,
@@ -394,6 +445,7 @@ mod tests {
fn depacketize_subgroup_stream_object_not_normal() {
let bytes_array = [
0, // Object ID (i)
+ 0, // Extension Headers Length (i)
0, // Object Payload Length (i)
1, // Object Status (i)
];
@@ -404,17 +456,289 @@ mod tests {
subgroup_stream::Object::depacketize(&mut read_cur).unwrap();
let object_id = 0;
+ let extension_headers = vec![];
let object_status = Some(ObjectStatus::DoesNotExist);
let object_payload = vec![];
- let expected_subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload).unwrap();
+ let expected_subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
+
+ assert_eq!(
+ depacketized_subgroup_stream_object,
+ expected_subgroup_stream_object
+ );
+ }
+
+ #[test]
+ fn packetize_subgroup_stream_object_with_even_type_extension_header() {
+ let object_id = 0;
+ let header_type = 0;
+ let value = 1;
+ let header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = None;
+ let object_payload = vec![1, 2, 3];
+
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ subgroup_stream_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 0, // Object ID (i)
+ 2, // Extension Headers Length (i)
+ 0, // Header Type (i)
+ 1, // Header Value (i)
+ 3, // Object Payload Length (i)
+ 1, 2, 3, // Object Payload (..)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn packetize_subgroup_stream_object_with_odd_type_extension_header() {
+ let object_id = 0;
+ let header_type = 1;
+ let value = vec![116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53, 54];
+ let header_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = Some(ObjectStatus::Normal);
+ let object_payload = vec![];
+
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ subgroup_stream_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 0, // Object ID (i)
+ 16, // Extension Headers Length (i)
+ 1, // Header Type (i)
+ 14, // Header Length (i)
+ 116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53,
+ 54, // Header Value (..)
+ 0, // Object Payload Length (i)
+ 0, // Object Status (i)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn packetize_subgroup_stream_object_with_mixed_type_extension_headers() {
+ let object_id = 0;
+
+ let even_header_type = 4;
+ let even_value = 3;
+ let even_header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(even_value));
+
+ let odd_header_type = 5;
+ let odd_value = vec![116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53, 54];
+ let odd_header_value =
+ ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(odd_value));
+
+ let extension_headers = vec![
+ ExtensionHeader::new(even_header_type, even_header_value).unwrap(),
+ ExtensionHeader::new(odd_header_type, odd_header_value).unwrap(),
+ ];
+ let object_status = Some(ObjectStatus::Normal);
+ let object_payload = vec![];
+
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
+
+ let mut buf = BytesMut::new();
+ subgroup_stream_object.packetize(&mut buf);
+
+ let expected_bytes_array = [
+ 0, // Object ID (i)
+ 18, // Extension Headers Length (i)
+ // {
+ 4, // Header Type (i)
+ 3, // Header Value (i)
+ // }{
+ 5, // Header Type (i)
+ 14, // Header Length (i)
+ 116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53,
+ 54, // Header Value (..)
+ // }
+ 0, // Object Payload Length (i)
+ 0, // Object Status (i)
+ ];
+
+ assert_eq!(buf.as_ref(), expected_bytes_array);
+ }
+
+ #[test]
+ fn depacketize_subgroup_stream_object_with_even_type_extension_header() {
+ let bytes_array = [
+ 0, // Object ID (i)
+ 2, // Extension Headers Length (i)
+ 0, // Header Type (i)
+ 1, // Header Value (i)
+ 0, // Object Payload Length (i)
+ 0, // Object Status (i)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_subgroup_stream_object =
+ subgroup_stream::Object::depacketize(&mut read_cur).unwrap();
+
+ let object_id = 0;
+ let header_type = 0;
+ let value = 1;
+ let header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = Some(ObjectStatus::Normal);
+ let object_payload = vec![];
+
+ let expected_subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
+
+ assert_eq!(
+ depacketized_subgroup_stream_object,
+ expected_subgroup_stream_object
+ );
+ }
+
+ #[test]
+ fn depacketize_subgroup_stream_object_with_odd_type_extension_header() {
+ let bytes_array = [
+ 0, // Object ID (i)
+ 16, // Extension Headers Length (i)
+ 1, // Header Type (i)
+ 14, // Header Length (i)
+ 116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53,
+ 54, // Header Value (..)
+ 3, // Object Payload Length (i)
+ 1, 2, 3, // Object Payload (..)
+ ];
+ let mut buf = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_subgroup_stream_object =
+ subgroup_stream::Object::depacketize(&mut read_cur).unwrap();
+
+ let object_id = 0;
+ let header_type = 1;
+ let value = vec![116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53, 54];
+ let header_value = ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(value));
+
+ let extension_headers = vec![ExtensionHeader::new(header_type, header_value).unwrap()];
+ let object_status = None;
+ let object_payload = vec![1, 2, 3];
+
+ let expected_subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
assert_eq!(
depacketized_subgroup_stream_object,
expected_subgroup_stream_object
);
}
+
+ #[test]
+ fn depacketize_subgroup_stream_object_with_mixed_type_extension_headers() {
+ let bytes_array = [
+ 0, // Object ID (i)
+ 18, // Extension Headers Length (i)
+ // {
+ 4, // Header Type (i)
+ 3, // Header Value (i)
+ // }{
+ 5, // Header Type (i)
+ 14, // Header Length (i)
+ 116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53,
+ 54, // Header Value (..)
+ // }
+ 0, // Object Payload Length (i)
+ 0, // Object Status (i)
+ ];
+
+ let object_id = 0;
+
+ let even_header_type = 4;
+ let even_value = 3;
+ let even_header_value = ExtensionHeaderValue::EvenTypeValue(Value::new(even_value));
+
+ let odd_header_type = 5;
+ let odd_value = vec![116, 114, 97, 99, 101, 73, 68, 58, 49, 50, 51, 52, 53, 54];
+ let odd_header_value =
+ ExtensionHeaderValue::OddTypeValue(ValueWithLength::new(odd_value));
+
+ let extension_headers = vec![
+ ExtensionHeader::new(even_header_type, even_header_value).unwrap(),
+ ExtensionHeader::new(odd_header_type, odd_header_value).unwrap(),
+ ];
+ let object_status = Some(ObjectStatus::Normal);
+ let object_payload = vec![];
+
+ let expected_subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ )
+ .unwrap();
+
+ println!(
+ "expected_subgroup_stream_object: {:?}",
+ expected_subgroup_stream_object
+ );
+
+ let mut buf: BytesMut = BytesMut::with_capacity(bytes_array.len());
+ buf.extend_from_slice(&bytes_array);
+ let mut read_cur = Cursor::new(&buf[..]);
+ let depacketized_subgroup_stream_object =
+ subgroup_stream::Object::depacketize(&mut read_cur);
+
+ println!(
+ "depacketized_subgroup_stream_object: {:?}",
+ depacketized_subgroup_stream_object
+ );
+
+ assert_eq!(
+ depacketized_subgroup_stream_object.unwrap(),
+ expected_subgroup_stream_object
+ );
+ }
}
mod failure {
@@ -428,11 +752,16 @@ mod tests {
#[test]
fn packetize_subgroup_stream_object_not_normal_and_not_empty_payload() {
let object_id = 0;
+ let extension_headers = vec![];
let object_status = Some(ObjectStatus::EndOfTrackAndGroup);
let object_payload = vec![0, 1, 2];
- let subgroup_stream_object =
- subgroup_stream::Object::new(object_id, object_status, object_payload);
+ let subgroup_stream_object = subgroup_stream::Object::new(
+ object_id,
+ extension_headers,
+ object_status,
+ object_payload,
+ );
assert!(subgroup_stream_object.is_err());
}
@@ -441,6 +770,7 @@ mod tests {
fn depacketize_subgroup_stream_object_wrong_object_status() {
let bytes_array = [
0, // Object ID (i)
+ 0, // Extension Headers Length (i)
0, // Object Payload Length (i)
2, // Object Status (i)
];
diff --git a/moqt-core/src/modules/messages/data_streams/track_stream.rs b/moqt-core/src/modules/messages/data_streams/track_stream.rs
deleted file mode 100644
index cddbac9e..00000000
--- a/moqt-core/src/modules/messages/data_streams/track_stream.rs
+++ /dev/null
@@ -1,439 +0,0 @@
-use crate::{
- messages::data_streams::DataStreams,
- variable_bytes::read_fixed_length_bytes,
- variable_integer::{read_variable_integer, write_variable_integer},
-};
-use anyhow::{bail, Context, Result};
-use bytes::BytesMut;
-use serde::Serialize;
-
-use super::object_status::ObjectStatus;
-
-/// Implementation of header message on QUIC Stream per Track.
-/// TrackObject messages are sent following this message.
-/// Type of Data Streams: STREAM_HEADER_TRACK (0x2)
-#[derive(Debug, Clone, Serialize, PartialEq, Default)]
-pub struct Header {
- subscribe_id: u64,
- track_alias: u64,
- publisher_priority: u8,
-}
-
-impl Header {
- pub fn new(subscribe_id: u64, track_alias: u64, publisher_priority: u8) -> Result {
- Ok(Header {
- subscribe_id,
- track_alias,
- publisher_priority,
- })
- }
-
- pub fn subscribe_id(&self) -> u64 {
- self.subscribe_id
- }
-
- pub fn track_alias(&self) -> u64 {
- self.track_alias
- }
-
- pub fn publisher_priority(&self) -> u8 {
- self.publisher_priority
- }
-}
-
-impl DataStreams for Header {
- fn depacketize(read_cur: &mut std::io::Cursor<&[u8]>) -> Result
- where
- Self: Sized,
- {
- let subscribe_id = read_variable_integer(read_cur).context("subscribe id")?;
- let track_alias = read_variable_integer(read_cur).context("track alias")?;
- let publisher_priority =
- read_fixed_length_bytes(read_cur, 1).context("publisher priority")?[0];
-
- tracing::trace!("Depacketized Track Stream Header message.");
-
- Ok(Header {
- subscribe_id,
- track_alias,
- publisher_priority,
- })
- }
-
- fn packetize(&self, buf: &mut BytesMut) {
- buf.extend(write_variable_integer(self.subscribe_id));
- buf.extend(write_variable_integer(self.track_alias));
- buf.extend(self.publisher_priority.to_be_bytes());
-
- tracing::trace!("Packetized Track Stream Header message.");
- }
-}
-
-/// Implementation of object message on QUIC Stream per Track.
-/// This message is sent following TrackHeader message.
-#[derive(Debug, Clone, Serialize, PartialEq)]
-pub struct Object {
- group_id: u64,
- object_id: u64,
- object_payload_length: u64,
- object_status: Option,
- object_payload: Vec,
-}
-
-impl Object {
- pub fn new(
- group_id: u64,
- object_id: u64,
- object_status: Option,
- object_payload: Vec,
- ) -> Result {
- let object_payload_length = object_payload.len() as u64;
-
- if object_status.is_some() && object_payload_length != 0 {
- bail!("The Object Status field is only sent if the Object Payload Length is zero.");
- }
-
- // Any object with a status code other than zero MUST have an empty payload.
- if let Some(status) = object_status {
- if status != ObjectStatus::Normal && object_payload_length != 0 {
- // TODO: return Termination Error Code
- bail!("Any object with a status code other than zero MUST have an empty payload.");
- }
- }
-
- Ok(Object {
- group_id,
- object_id,
- object_payload_length,
- object_status,
- object_payload,
- })
- }
-
- pub fn group_id(&self) -> u64 {
- self.group_id
- }
-
- pub fn object_id(&self) -> u64 {
- self.object_id
- }
-
- pub fn object_status(&self) -> Option {
- self.object_status
- }
-}
-
-impl DataStreams for Object {
- fn depacketize(read_cur: &mut std::io::Cursor<&[u8]>) -> Result
- where
- Self: Sized,
- {
- let group_id = read_variable_integer(read_cur).context("group id")?;
- let object_id = read_variable_integer(read_cur).context("object id")?;
- let object_payload_length =
- read_variable_integer(read_cur).context("object payload length")?;
-
- // If the length of the remaining buf is larger than object_payload_length, object_status exists.
- let object_status = if object_payload_length == 0 {
- let object_status_u64 = read_variable_integer(read_cur)?;
- let object_status =
- match ObjectStatus::try_from(object_status_u64 as u8).context("object status") {
- Ok(status) => status,
- Err(err) => {
- // Any other value SHOULD be treated as a Protocol Violation and terminate the session with a Protocol Violation
- // TODO: return Termination Error Code
- bail!(err);
- }
- };
-
- Some(object_status)
- } else {
- None
- };
-
- let object_payload = if object_payload_length > 0 {
- read_fixed_length_bytes(read_cur, object_payload_length as usize)
- .context("object payload")?
- } else {
- vec![]
- };
-
- tracing::trace!("Depacketized Track Stream Object message.");
-
- Ok(Object {
- group_id,
- object_id,
- object_payload_length,
- object_status,
- object_payload,
- })
- }
-
- fn packetize(&self, buf: &mut BytesMut) {
- buf.extend(write_variable_integer(self.group_id));
- buf.extend(write_variable_integer(self.object_id));
- buf.extend(write_variable_integer(self.object_payload_length));
- if self.object_status.is_some() {
- buf.extend(write_variable_integer(
- u8::from(self.object_status.unwrap()) as u64,
- ));
- }
- buf.extend(&self.object_payload);
-
- tracing::trace!("Packetized Track Stream Object message.");
- }
-}
-
-#[cfg(test)]
-mod tests {
- mod success {
- use crate::messages::data_streams::{
- object_status::ObjectStatus, track_stream, track_stream::DataStreams,
- };
- use bytes::BytesMut;
- use std::io::Cursor;
-
- #[test]
- fn packetize_track_stream_header() {
- let subscribe_id = 0;
- let track_alias = 1;
- let publisher_priority = 2;
-
- let track_stream_header =
- track_stream::Header::new(subscribe_id, track_alias, publisher_priority).unwrap();
-
- let mut buf = BytesMut::new();
- track_stream_header.packetize(&mut buf);
-
- let expected_bytes_array = [
- 0, // Subscribe ID (i)
- 1, // Track Alias (i)
- 2, // Subscriber Priority (8)
- ];
-
- assert_eq!(buf.as_ref(), expected_bytes_array);
- }
-
- #[test]
- fn depacketize_track_stream_header() {
- let bytes_array = [
- 0, // Subscribe ID (i)
- 1, // Track Alias (i)
- 2, // Subscriber Priority (8)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let mut read_cur = Cursor::new(&buf[..]);
- let depacketized_track_stream_header =
- track_stream::Header::depacketize(&mut read_cur).unwrap();
-
- let subscribe_id = 0;
- let track_alias = 1;
- let publisher_priority = 2;
-
- let expected_track_stream_header =
- track_stream::Header::new(subscribe_id, track_alias, publisher_priority).unwrap();
-
- assert_eq!(
- depacketized_track_stream_header,
- expected_track_stream_header
- );
- }
-
- #[test]
- fn packetize_track_stream_object_normal() {
- let group_id = 0;
- let object_id = 1;
- let object_status = None;
- let object_payload = vec![0, 1, 2];
-
- let track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload)
- .unwrap();
-
- let mut buf = BytesMut::new();
- track_stream_object.packetize(&mut buf);
-
- let expected_bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 3, // Object Payload Length (i)
- 0, 1, 2, // Object Payload (..)
- ];
-
- assert_eq!(buf.as_ref(), expected_bytes_array);
- }
-
- #[test]
- fn packetize_track_stream_object_normal_and_empty_payload() {
- let group_id = 0;
- let object_id = 1;
- let object_status = Some(ObjectStatus::Normal);
- let object_payload = vec![];
-
- let track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload)
- .unwrap();
-
- let mut buf = BytesMut::new();
- track_stream_object.packetize(&mut buf);
-
- let expected_bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 0, // Object Payload Length (i)
- 0, // Object Status (i)
- ];
-
- assert_eq!(buf.as_ref(), expected_bytes_array);
- }
-
- #[test]
- fn packetize_track_stream_object_not_normal() {
- let group_id = 0;
- let object_id = 1;
- let object_status = Some(ObjectStatus::EndOfGroup);
- let object_payload = vec![];
-
- let track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload)
- .unwrap();
-
- let mut buf = BytesMut::new();
- track_stream_object.packetize(&mut buf);
-
- let expected_bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 0, // Object Payload Length (i)
- 3, // Object Status (i)
- ];
-
- assert_eq!(buf.as_ref(), expected_bytes_array);
- }
-
- #[test]
- fn depacketize_track_stream_object_normal() {
- let bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 3, // Object Payload Length (i)
- 0, 1, 2, // Object Payload (..)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let mut read_cur = Cursor::new(&buf[..]);
- let depacketized_track_stream_object =
- track_stream::Object::depacketize(&mut read_cur).unwrap();
-
- let group_id = 0;
- let object_id = 1;
- let object_status = None;
- let object_payload = vec![0, 1, 2];
-
- let expected_track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload)
- .unwrap();
-
- assert_eq!(
- depacketized_track_stream_object,
- expected_track_stream_object
- );
- }
-
- #[test]
- fn depacketize_track_stream_object_normal_and_empty_payload() {
- let bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 0, // Object Payload Length (i)
- 0, // Object Status (i)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let mut read_cur = Cursor::new(&buf[..]);
- let depacketized_track_stream_object =
- track_stream::Object::depacketize(&mut read_cur).unwrap();
-
- let group_id = 0;
- let object_id = 1;
- let object_status = Some(ObjectStatus::Normal);
- let object_payload = vec![];
-
- let expected_track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload)
- .unwrap();
-
- assert_eq!(
- depacketized_track_stream_object,
- expected_track_stream_object
- );
- }
-
- #[test]
- fn depacketize_track_stream_object_not_normal() {
- let bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 0, // Object Payload Length (i)
- 1, // Object Status (i)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let mut read_cur = Cursor::new(&buf[..]);
- let depacketized_track_stream_object =
- track_stream::Object::depacketize(&mut read_cur).unwrap();
-
- let group_id = 0;
- let object_id = 1;
- let object_status = Some(ObjectStatus::DoesNotExist);
- let object_payload = vec![];
-
- let expected_track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload)
- .unwrap();
-
- assert_eq!(
- depacketized_track_stream_object,
- expected_track_stream_object
- );
- }
- }
-
- mod failure {
- use bytes::BytesMut;
- use std::io::Cursor;
-
- use crate::messages::data_streams::{
- object_status::ObjectStatus, track_stream, DataStreams,
- };
- #[test]
- fn packetize_track_stream_object_not_normal_and_not_empty_payload() {
- let group_id = 0;
- let object_id = 1;
- let object_status = Some(ObjectStatus::EndOfTrackAndGroup);
- let object_payload = vec![0, 1, 2];
-
- let track_stream_object =
- track_stream::Object::new(group_id, object_id, object_status, object_payload);
-
- assert!(track_stream_object.is_err());
- }
-
- #[test]
- fn depacketize_track_stream_object_wrong_object_status() {
- let bytes_array = [
- 0, // Group ID (i)
- 1, // Object ID (i)
- 0, // Object Payload Length (i)
- 2, // Object Status (i)
- ];
- let mut buf = BytesMut::with_capacity(bytes_array.len());
- buf.extend_from_slice(&bytes_array);
- let mut read_cur = Cursor::new(&buf[..]);
- let depacketized_track_stream_object = track_stream::Object::depacketize(&mut read_cur);
-
- assert!(depacketized_track_stream_object.is_err());
- }
- }
-}
diff --git a/moqt-core/src/modules/models.rs b/moqt-core/src/modules/models.rs
index 5a741dbb..5d4401a4 100644
--- a/moqt-core/src/modules/models.rs
+++ b/moqt-core/src/modules/models.rs
@@ -1,2 +1,3 @@
+pub mod range;
pub mod subscriptions;
pub mod tracks;
diff --git a/moqt-core/src/modules/models/range.rs b/moqt-core/src/modules/models/range.rs
new file mode 100644
index 00000000..d885c70d
--- /dev/null
+++ b/moqt-core/src/modules/models/range.rs
@@ -0,0 +1,91 @@
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ObjectRange {
+ start: Option,
+ end: Option,
+}
+
+impl ObjectRange {
+ pub fn new(
+ start_group: Option,
+ start_object: Option,
+ end_group: Option,
+ end_object: Option,
+ ) -> Self {
+ let start = match (start_group, start_object) {
+ (Some(group_id), Some(object_id)) => Some(ObjectStart::new(group_id, object_id)),
+ _ => None,
+ };
+
+ let end = end_group.map(|group_id| ObjectEnd::new(group_id, end_object));
+
+ // TODO: Validate that start is before end
+
+ Self { start, end }
+ }
+
+ pub fn start_group(&self) -> Option {
+ let start = self.start.as_ref()?;
+ Some(start.group_id())
+ }
+
+ pub fn start_object(&self) -> Option {
+ let start = self.start.as_ref()?;
+ Some(start.object_id())
+ }
+
+ pub fn end_group(&self) -> Option {
+ let end = self.end.as_ref()?;
+ Some(end.group_id())
+ }
+
+ pub fn end_object(&self) -> Option {
+ let end = self.end.as_ref()?;
+ end.object_id()
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ObjectStart {
+ group_id: u64,
+ object_id: u64,
+}
+
+impl ObjectStart {
+ pub fn new(group_id: u64, object_id: u64) -> Self {
+ Self {
+ group_id,
+ object_id,
+ }
+ }
+
+ pub fn group_id(&self) -> u64 {
+ self.group_id
+ }
+
+ pub fn object_id(&self) -> u64 {
+ self.object_id
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ObjectEnd {
+ group_id: u64,
+ object_id: Option,
+}
+
+impl ObjectEnd {
+ pub fn new(group_id: u64, object_id: Option) -> Self {
+ Self {
+ group_id,
+ object_id,
+ }
+ }
+
+ pub fn group_id(&self) -> u64 {
+ self.group_id
+ }
+
+ pub fn object_id(&self) -> Option {
+ self.object_id
+ }
+}
diff --git a/moqt-core/src/modules/models/subscriptions.rs b/moqt-core/src/modules/models/subscriptions.rs
index b5129d2a..c2703eef 100644
--- a/moqt-core/src/modules/models/subscriptions.rs
+++ b/moqt-core/src/modules/models/subscriptions.rs
@@ -1,7 +1,7 @@
pub mod nodes;
-
+use super::range::{ObjectRange, ObjectStart};
use crate::{
- messages::control_messages::subscribe::{FilterType, GroupOrder},
+ messages::control_messages::{group_order::GroupOrder, subscribe::FilterType},
models::tracks::{ForwardingPreference, Track},
};
@@ -17,10 +17,8 @@ pub struct Subscription {
priority: u8,
group_order: GroupOrder,
filter_type: FilterType,
- start_group: Option,
- start_object: Option,
- end_group: Option,
- end_object: Option,
+ requested_object_range: ObjectRange,
+ actual_object_start: Option,
status: Status,
}
@@ -36,7 +34,6 @@ impl Subscription {
start_group: Option,
start_object: Option,
end_group: Option,
- end_object: Option,
forwarding_preference: Option,
) -> Self {
let track = Track::new(
@@ -46,15 +43,15 @@ impl Subscription {
forwarding_preference,
);
+ let requested_object_range = ObjectRange::new(start_group, start_object, end_group, None);
+
Self {
track,
priority,
group_order,
filter_type,
- start_group,
- start_object,
- end_group,
- end_object,
+ requested_object_range,
+ actual_object_start: None,
status: Status::Requesting,
}
}
@@ -80,12 +77,8 @@ impl Subscription {
self.filter_type
}
- pub fn get_absolute_start(&self) -> (Option, Option) {
- (self.start_group, self.start_object)
- }
-
- pub fn get_absolute_end(&self) -> (Option, Option) {
- (self.end_group, self.end_object)
+ pub fn get_requested_object_range(&self) -> ObjectRange {
+ self.requested_object_range.clone()
}
pub fn set_forwarding_preference(&mut self, forwarding_preference: ForwardingPreference) {
@@ -108,18 +101,38 @@ impl Subscription {
self.group_order
}
- pub fn is_end(&self, group_id: u64, object_id: u64) -> bool {
- if self.filter_type != FilterType::AbsoluteRange {
- return false;
- }
+ pub fn set_stream_id(&mut self, group_id: u64, subgroup_id: u64, stream_id: u64) {
+ self.track.set_stream_id(group_id, subgroup_id, stream_id);
+ }
+
+ pub fn get_all_group_ids(&self) -> Vec {
+ let mut group_ids = self.track.get_all_group_ids();
+ group_ids.sort_unstable();
+ group_ids
+ }
+
+ pub fn get_subgroup_ids_for_group(&self, group_id: u64) -> Vec {
+ let mut subgroup_ids = self.track.get_subgroup_ids_for_group(group_id);
+ subgroup_ids.sort_unstable();
+ subgroup_ids
+ }
+
+ pub fn get_stream_id_for_subgroup(&self, group_id: u64, subgroup_id: u64) -> Option {
+ self.track.get_stream_id_for_subgroup(group_id, subgroup_id)
+ }
+
+ pub fn set_actual_object_start(&mut self, actual_object_start: ObjectStart) {
+ self.actual_object_start = Some(actual_object_start);
+ }
- group_id == self.end_group.unwrap() && object_id == self.end_object.unwrap()
+ pub fn get_actual_object_start(&self) -> Option {
+ self.actual_object_start.clone()
}
}
#[cfg(test)]
pub(crate) mod test_helper_fn {
- use crate::messages::control_messages::subscribe::{FilterType, GroupOrder};
+ use crate::messages::control_messages::{group_order::GroupOrder, subscribe::FilterType};
#[derive(Debug, Clone)]
pub(crate) struct SubscriptionVariables {
@@ -132,7 +145,6 @@ pub(crate) mod test_helper_fn {
pub(crate) start_group: Option,
pub(crate) start_object: Option,
pub(crate) end_group: Option,
- pub(crate) end_object: Option,
}
pub(crate) fn common_subscription_variable() -> SubscriptionVariables {
@@ -145,7 +157,6 @@ pub(crate) mod test_helper_fn {
let start_group = Some(0);
let start_object = Some(0);
let end_group = None;
- let end_object = None;
SubscriptionVariables {
track_alias,
@@ -157,7 +168,6 @@ pub(crate) mod test_helper_fn {
start_group,
start_object,
end_group,
- end_object,
}
}
}
@@ -165,8 +175,9 @@ pub(crate) mod test_helper_fn {
#[cfg(test)]
mod success {
use crate::{
- messages::control_messages::subscribe::{FilterType, GroupOrder},
+ messages::control_messages::{group_order::GroupOrder, subscribe::FilterType},
models::{
+ range::ObjectStart,
subscriptions::{test_helper_fn, Subscription},
tracks::ForwardingPreference,
},
@@ -183,8 +194,7 @@ mod success {
let start_group = Some(1);
let start_object = Some(1);
let end_group = Some(1);
- let end_object = Some(1);
- let forwarding_preference = Some(ForwardingPreference::Track);
+ let forwarding_preference = Some(ForwardingPreference::Subgroup);
let subscription = Subscription::new(
track_alias,
@@ -196,7 +206,6 @@ mod success {
start_group,
start_object,
end_group,
- end_object,
forwarding_preference,
);
@@ -208,10 +217,15 @@ mod success {
assert_eq!(subscription.priority, priority);
assert_eq!(subscription.group_order, group_order);
assert_eq!(subscription.filter_type, filter_type);
- assert_eq!(subscription.start_group, start_group);
- assert_eq!(subscription.start_object, start_object);
- assert_eq!(subscription.end_group, end_group);
- assert_eq!(subscription.end_object, end_object);
+ assert_eq!(
+ subscription.requested_object_range.start_group(),
+ start_group
+ );
+ assert_eq!(
+ subscription.requested_object_range.start_object(),
+ start_object
+ );
+ assert_eq!(subscription.requested_object_range.end_group(), end_group);
}
#[test]
@@ -228,7 +242,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -253,7 +266,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -277,7 +289,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -301,7 +312,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -322,7 +332,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -346,7 +355,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -367,7 +375,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -378,7 +385,7 @@ mod success {
fn set_and_get_forwarding_preference() {
let variable = test_helper_fn::common_subscription_variable();
- let forwarding_preference = ForwardingPreference::Track;
+ let forwarding_preference = ForwardingPreference::Subgroup;
let mut subscription = Subscription::new(
variable.track_alias,
@@ -390,7 +397,6 @@ mod success {
variable.start_group,
variable.start_object,
variable.end_group,
- variable.end_object,
None,
);
@@ -400,4 +406,156 @@ mod success {
assert_eq!(result_forwarding_preference, forwarding_preference);
}
+
+ #[test]
+ fn get_stream_id_for_group() {
+ let variable = test_helper_fn::common_subscription_variable();
+
+ let mut subscription = Subscription::new(
+ variable.track_alias,
+ variable.track_namespace,
+ variable.track_name,
+ variable.subscriber_priority,
+ variable.group_order,
+ variable.filter_type,
+ variable.start_group,
+ variable.start_object,
+ variable.end_group,
+ None,
+ );
+
+ let group_id = 0;
+ let subgroup_ids = vec![0, 1, 2];
+ let stream_ids = vec![3, 4, 5];
+
+ subscription.set_stream_id(group_id, subgroup_ids[0], stream_ids[0]);
+ subscription.set_stream_id(group_id, subgroup_ids[1], stream_ids[1]);
+ subscription.set_stream_id(group_id, subgroup_ids[2], stream_ids[2]);
+
+ let result_subgroup_ids = subscription.get_subgroup_ids_for_group(group_id);
+
+ assert_eq!(result_subgroup_ids, subgroup_ids);
+
+ let result_stream_id = vec![
+ subscription
+ .get_stream_id_for_subgroup(group_id, result_subgroup_ids[0])
+ .unwrap(),
+ subscription
+ .get_stream_id_for_subgroup(group_id, result_subgroup_ids[1])
+ .unwrap(),
+ subscription
+ .get_stream_id_for_subgroup(group_id, result_subgroup_ids[2])
+ .unwrap(),
+ ];
+
+ assert_eq!(result_stream_id, stream_ids);
+ }
+
+ #[test]
+ fn get_requested_object_range() {
+ let variable = test_helper_fn::common_subscription_variable();
+
+ let subscription = Subscription::new(
+ variable.track_alias,
+ variable.track_namespace,
+ variable.track_name,
+ variable.subscriber_priority,
+ variable.group_order,
+ variable.filter_type,
+ variable.start_group,
+ variable.start_object,
+ variable.end_group,
+ None,
+ );
+
+ let result = subscription.get_requested_object_range();
+
+ assert_eq!(result.start_group(), variable.start_group);
+ assert_eq!(result.start_object(), variable.start_object);
+ assert_eq!(result.end_group(), variable.end_group);
+ }
+
+ #[test]
+ fn set_actual_object_start() {
+ let variable = test_helper_fn::common_subscription_variable();
+
+ let mut subscription = Subscription::new(
+ variable.track_alias,
+ variable.track_namespace,
+ variable.track_name,
+ variable.subscriber_priority,
+ variable.group_order,
+ variable.filter_type,
+ variable.start_group,
+ variable.start_object,
+ variable.end_group,
+ None,
+ );
+
+ let start_group = 1;
+ let start_object = 1;
+
+ subscription.set_actual_object_start(ObjectStart::new(start_group, start_object));
+
+ let result = subscription.get_actual_object_start().unwrap();
+
+ assert_eq!(result.group_id(), start_group);
+ assert_eq!(result.object_id(), start_object);
+ }
+
+ #[test]
+ fn get_actual_object_start() {
+ let variable = test_helper_fn::common_subscription_variable();
+
+ let start_group = 1;
+ let start_object = 1;
+
+ let mut subscription = Subscription::new(
+ variable.track_alias,
+ variable.track_namespace,
+ variable.track_name,
+ variable.subscriber_priority,
+ variable.group_order,
+ variable.filter_type,
+ variable.start_group,
+ variable.start_object,
+ variable.end_group,
+ None,
+ );
+
+ subscription.set_actual_object_start(ObjectStart::new(start_group, start_object));
+
+ let result = subscription.get_actual_object_start().unwrap();
+
+ assert_eq!(result.group_id(), start_group);
+ assert_eq!(result.object_id(), start_object);
+ }
+
+ #[test]
+ fn get_all_group_ids() {
+ let variable = test_helper_fn::common_subscription_variable();
+
+ let mut subscription = Subscription::new(
+ variable.track_alias,
+ variable.track_namespace,
+ variable.track_name,
+ variable.subscriber_priority,
+ variable.group_order,
+ variable.filter_type,
+ variable.start_group,
+ variable.start_object,
+ variable.end_group,
+ None,
+ );
+
+ let group_ids = vec![0, 1, 2];
+
+ subscription.set_stream_id(group_ids[0], 0, 0);
+ subscription.set_stream_id(group_ids[1], 0, 0);
+ subscription.set_stream_id(group_ids[2], 0, 0);
+
+ let result = subscription.get_all_group_ids();
+
+ assert_eq!(result, group_ids);
+ }
}
diff --git a/moqt-core/src/modules/models/subscriptions/nodes/consumers.rs b/moqt-core/src/modules/models/subscriptions/nodes/consumers.rs
index 82f5ed1d..4258db41 100644
--- a/moqt-core/src/modules/models/subscriptions/nodes/consumers.rs
+++ b/moqt-core/src/modules/models/subscriptions/nodes/consumers.rs
@@ -1,13 +1,13 @@
-use anyhow::{bail, Result};
-use std::collections::HashMap;
-
use crate::{
- messages::control_messages::subscribe::{FilterType, GroupOrder},
+ messages::control_messages::{group_order::GroupOrder, subscribe::FilterType},
models::{
+ range::{ObjectRange, ObjectStart},
subscriptions::{nodes::registry::SubscriptionNodeRegistry, Subscription},
tracks::ForwardingPreference,
},
};
+use anyhow::{bail, Result};
+use std::collections::HashMap;
type SubscribeId = u64;
type TrackNamespace = Vec;
@@ -47,7 +47,6 @@ impl SubscriptionNodeRegistry for Consumer {
start_group: Option,
start_object: Option,
end_group: Option,
- end_object: Option,
) -> Result<()> {
// Subscriber cannot define forwarding preference until it receives object message.
let subscription = Subscription::new(
@@ -60,7 +59,6 @@ impl SubscriptionNodeRegistry for Consumer {
start_group,
start_object,
end_group,
- end_object,
None,
);
@@ -74,36 +72,40 @@ impl SubscriptionNodeRegistry for Consumer {
Ok(self.subscriptions.get(&subscribe_id).cloned())
}
- fn get_subscription_by_full_track_name(
+ fn get_subscribe_id(
&self,
track_namespace: TrackNamespace,
track_name: String,
- ) -> Result