forked from mirrors/gecko-dev
Backed out changeset 09e682ea9d23 (bug 1553011) for spidermonkey bustages. CLOSED TREE
--HG-- rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/10.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/10.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/11.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/11.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/12.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/12.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/13.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/13.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/14.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/14.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/15.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/15.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/16.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/16.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/17.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/17.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/18.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/18.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/19.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/19.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/2.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/2.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/20.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/20.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/21.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/21.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/22.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/22.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/23.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/23.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/24.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/24.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/25.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/25.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/26.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/26.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/27.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/27.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/28.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/28.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/29.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/29.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/3.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/3.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/30.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/30.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/31.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/31.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/32.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/32.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/33.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/33.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/36.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/34.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/37.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/37.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/38.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/38.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/40.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/39.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/4.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/4.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/41.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/41.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/5.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/5.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/6.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/6.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/7.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/7.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/8.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/8.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/9.sdp => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/9.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/extract.sh => media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/extract.sh
This commit is contained in:
parent
5e31eadf72
commit
da33717f34
58 changed files with 1988 additions and 3295 deletions
|
|
@ -60,9 +60,6 @@ enum class RustSdpProtocolValue {
|
||||||
kRustDtlsSctp,
|
kRustDtlsSctp,
|
||||||
kRustUdpDtlsSctp,
|
kRustUdpDtlsSctp,
|
||||||
kRustTcpDtlsSctp,
|
kRustTcpDtlsSctp,
|
||||||
kRustRtpAvp,
|
|
||||||
kRustRtpAvpf,
|
|
||||||
kRustRtpSavp,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class RustSdpFormatType { kRustIntegers, kRustStrings };
|
enum class RustSdpFormatType { kRustIntegers, kRustStrings };
|
||||||
|
|
|
||||||
|
|
@ -77,13 +77,8 @@ SdpMediaSection::Protocol RsdparsaSdpMediaSection::GetProtocol() const {
|
||||||
return kUdpDtlsSctp;
|
return kUdpDtlsSctp;
|
||||||
case RustSdpProtocolValue::kRustTcpDtlsSctp:
|
case RustSdpProtocolValue::kRustTcpDtlsSctp:
|
||||||
return kTcpDtlsSctp;
|
return kTcpDtlsSctp;
|
||||||
case RustSdpProtocolValue::kRustRtpAvp:
|
|
||||||
return kRtpAvp;
|
|
||||||
case RustSdpProtocolValue::kRustRtpAvpf:
|
|
||||||
return kRtpAvpf;
|
|
||||||
case RustSdpProtocolValue::kRustRtpSavp:
|
|
||||||
return kRtpSavp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_CRASH("invalid media protocol");
|
MOZ_CRASH("invalid media protocol");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,9 @@ cache: cargo
|
||||||
sudo: true
|
sudo: true
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
# Taken out temporarily because it's to slow
|
||||||
|
# - osx
|
||||||
|
|
||||||
env:
|
|
||||||
- FEATURES=""
|
|
||||||
- FEATURES="serialize"
|
|
||||||
rust:
|
rust:
|
||||||
- nightly
|
- nightly
|
||||||
- beta
|
- beta
|
||||||
|
|
@ -19,12 +17,13 @@ matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- rust: nightly
|
- rust: nightly
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- libcurl4-openssl-dev
|
- libcurl4-openssl-dev
|
||||||
- zlib1g-dev
|
|
||||||
- libiberty-dev
|
|
||||||
- libelf-dev
|
- libelf-dev
|
||||||
- libdw-dev
|
- libdw-dev
|
||||||
- cmake
|
- cmake
|
||||||
|
|
@ -35,46 +34,34 @@ addons:
|
||||||
before_script:
|
before_script:
|
||||||
- export PATH=$PATH:~/.cargo/bin
|
- export PATH=$PATH:~/.cargo/bin
|
||||||
- |
|
- |
|
||||||
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||||
rustup component add rustfmt-preview
|
cargo install --force clippy;
|
||||||
rustup component add clippy
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- echo FEATURES="$FEATURES"
|
- cargo build --verbose --all
|
||||||
- |
|
- |
|
||||||
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
if [[ "$TRAVIS_RUST_VERSION" == "nightly" &&
|
||||||
cargo fmt --all -- --check
|
-f ~/.cargo/bin/cargo-clippy ]]; then
|
||||||
|
cargo clippy;
|
||||||
fi
|
fi
|
||||||
- cargo build --verbose --all --features="$FEATURES"
|
- cargo test --verbose --all
|
||||||
- |
|
|
||||||
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
|
||||||
cargo clippy --all-targets --all-features -- -D warnings;
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [[ "$TRAVIS_RUST_VERSION" == "1.17.0" ]]; then
|
|
||||||
cargo test --all-features --verbose --all
|
|
||||||
else
|
|
||||||
cargo test --all-targets --all-features --verbose --all
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- |
|
- |
|
||||||
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" && "$FEATURES" == "serialize" ]]; then
|
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
||||||
wget https://github.com/SimonKagstrom/kcov/archive/v34.tar.gz &&
|
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
||||||
tar xzf v34.tar.gz &&
|
tar xzf master.tar.gz &&
|
||||||
cd kcov-34 &&
|
cd kcov-master &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake .. &&
|
cmake .. &&
|
||||||
make &&
|
make &&
|
||||||
sudo make install &&
|
sudo make install &&
|
||||||
cd ../.. &&
|
cd ../.. &&
|
||||||
rm -rf kcov-34 &&
|
rm -rf kcov-master &&
|
||||||
kcov --version &&
|
kcov --version &&
|
||||||
(cd target/debug/ && ls -al) &&
|
for file in target/debug/rsdparsa-*[^\.d]; do echo "$file"; mkdir -p "target/cov/$(basename $file)"; kcov --verify --exclude-pattern=/.cargo,/usr/lib "target/cov/$(basename $file)" "$file"; done &&
|
||||||
for file in target/debug/webrtc_sdp-*[^\.d]; do echo "$file"; mkdir -p "target/cov/$(basename $file)"; kcov --verify --exclude-pattern=/.cargo,/usr/lib "target/cov/$(basename $file)" "$file"; done &&
|
|
||||||
for file in target/debug/unit_tests-*[^\.d]; do echo "$file"; mkdir -p "target/cov/$(basename $file)"; kcov --verify --exclude-pattern=/.cargo,/usr/lib "target/cov/$(basename $file)" "$file"; done &&
|
for file in target/debug/unit_tests-*[^\.d]; do echo "$file"; mkdir -p "target/cov/$(basename $file)"; kcov --verify --exclude-pattern=/.cargo,/usr/lib "target/cov/$(basename $file)" "$file"; done &&
|
||||||
bash <(curl -s https://codecov.io/bash) &&
|
bash <(curl -s https://codecov.io/bash) &&
|
||||||
echo "Uploaded code coverage"
|
echo "Uploaded code coverage"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "webrtc-sdp"
|
name = "rsdparsa"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Nils Ohlmeier <github@ohlmeier.org>"]
|
authors = ["Nils Ohlmeier <github@ohlmeier.org>"]
|
||||||
description = "This create parses strings in the format of the Session Description Protocol according to RFC4566. It specifically supports the subset of features required to support WebRTC according to the JSEP draft."
|
|
||||||
homepage = "https://github.com/nils-ohlmeier/rsdparsa"
|
|
||||||
readme = "README.md"
|
|
||||||
keywords = ["webrtc", "sdp", "jsep"]
|
|
||||||
categories = ["parsing", "network-programming"]
|
|
||||||
license = "MPL-2.0"
|
|
||||||
|
|
||||||
[badges]
|
|
||||||
travis-ci = { repository = "nils-ohlmeier/rsdparsa", branch = "master" }
|
|
||||||
codecov = { repository = "nils-ohlmeier/rsdparsa", branch = "master", service = "github" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
@ -19,9 +9,10 @@ default = []
|
||||||
serialize = ["serde", "serde_derive"]
|
serialize = ["serde", "serde_derive"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = {version = "0.4.6"}
|
# clippy = {version = "*", optional = true}
|
||||||
|
log = "0.4"
|
||||||
serde = {version = "1.0" , optional = true}
|
serde = {version = "1.0" , optional = true}
|
||||||
serde_derive = {version = "1.0" , optional = true}
|
serde_derive = {version = "1.0" , optional = true}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = {version = "1.0"}
|
# serde_json = {version = "1.0"}
|
||||||
|
|
|
||||||
|
|
@ -1,61 +1,13 @@
|
||||||
# webrtc-sdp
|
# rsdparsa
|
||||||
|
|
||||||
[](https://crates.io/crates/webrtc-sdp)
|
|
||||||
[](https://travis-ci.org/nils-ohlmeier/rsdparsa)
|
[](https://travis-ci.org/nils-ohlmeier/rsdparsa)
|
||||||
[](https://codecov.io/gh/nils-ohlmeier/rsdparsa)
|
[](https://codecov.io/gh/nils-ohlmeier/rsdparsa)
|
||||||
[](#License)
|
[](#License)
|
||||||
[](https://deps.rs/repo/github/nils-ohlmeier/rsdparsa)
|
|
||||||
|
|
||||||
A SDP parser written in Rust specifically aimed to handle WebRTC SDP offers and answers.
|
A SDP parser written in Rust specifically aimed for WebRTC
|
||||||
|
|
||||||
## Dependecies
|
Requires minimum Rust 1.17
|
||||||
|
|
||||||
* Rust >= 1.17.0
|
|
||||||
* log module
|
|
||||||
* serde module
|
|
||||||
* serde-derive module
|
|
||||||
|
|
||||||
Cargo installs the missing modules automatically when building webrtc-sdp for the first time.
|
|
||||||
|
|
||||||
## The webrtc-sdp API
|
|
||||||
|
|
||||||
The main function is:
|
|
||||||
```
|
|
||||||
fn parse_sdp(sdp: &str, fail_on_warning: bool) -> Result<SdpSession, SdpParserError>
|
|
||||||
```
|
|
||||||
The `sdp` parameter is the string which will get parsed. The `fail_on_warning` parameter determines how to treat warnings encountered during parsing. Any problems encountered during are stored until the whole string has been parsed. Any problem during parsing falls into two catgeories:
|
|
||||||
|
|
||||||
* Fatal error preventing further parsing or processing of the SDP
|
|
||||||
* Warning which don't block further processing of the SDP
|
|
||||||
|
|
||||||
Warnings will be for example unknown parameters in attributes. Setting `fail_on_warning` to `true` makes most sense during development, when you want to be aware of all potential problems. In production `fail_on_warning` is expected to be `false`.
|
|
||||||
|
|
||||||
`parse_sdp()` returns either an `SdpSession` struct ([code](https://github.com/nils-ohlmeier/rsdparsa/blob/master/src/lib.rs#L137)) which contains all the parsed information. Or in case a fatal error was encountered (or if `fail_on_warning` was set to `true` and any warnings were encountered) an `SdpParserError` ([code](https://github.com/nils-ohlmeier/rsdparsa/blob/master/src/error.rs#L117)) will be returned as a `Result`.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
The [file parser](https://github.com/nils-ohlmeier/rsdparsa/blob/master/src/bin/file_parser.rs) in the webrtc-sdp package gives you an easy example of how to invoke the webrtc-sdp parser.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
As the Travis CI runs are checking for code formating and clippy warnings please run the following commands locally, before submitting a Pull Request.
|
|
||||||
|
|
||||||
If you haven't clippy and Rust format installed already you add them like this:
|
|
||||||
```
|
|
||||||
rustup component add rustfmt-preview
|
|
||||||
rustup component add clippy
|
|
||||||
```
|
|
||||||
|
|
||||||
Check with clippy for warnings in the code:
|
|
||||||
```
|
|
||||||
cargo clippy --all-targets --all-features
|
|
||||||
```
|
|
||||||
|
|
||||||
And format all of the code according to Rust code style convention:
|
|
||||||
```
|
|
||||||
cargo fmt --all
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Licensed under [MPL-2.0](https://www.mozilla.org/MPL/2.0/)
|
Licensed under [MPL](https://www.mozilla.org/MPL/2.0/).
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,31 +1,35 @@
|
||||||
use std::env;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
extern crate webrtc_sdp;
|
use std::env;
|
||||||
|
extern crate rsdparsa;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let filename = match env::args().nth(1) {
|
let filename = match env::args().nth(1) {
|
||||||
None => {
|
None => {
|
||||||
println!("Missing file name argument!");
|
println!("Missing file name argument!");
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
let path = Path::new(filename.as_str());
|
let path = Path::new(filename.as_str());
|
||||||
let display = path.display();
|
let display = path.display();
|
||||||
|
|
||||||
let mut file = match File::open(&path) {
|
let mut file = match File::open(&path) {
|
||||||
Err(why) => panic!("Failed to open {}: {}", display, why.description()),
|
Err(why) => panic!("Failed to open {}: {}",
|
||||||
Ok(file) => file,
|
display,
|
||||||
|
why.description()),
|
||||||
|
Ok(file) => file
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
match file.read_to_string(&mut s) {
|
match file.read_to_string(&mut s) {
|
||||||
Err(why) => panic!("couldn't read {}: {}", display, why.description()),
|
Err(why) => panic!("couldn't read {}: {}",
|
||||||
Ok(s) => s,
|
display,
|
||||||
|
why.description()),
|
||||||
|
Ok(s) => s
|
||||||
};
|
};
|
||||||
|
|
||||||
webrtc_sdp::parse_sdp(&s, true).is_ok();
|
rsdparsa::parse_sdp(&s, true).is_ok();
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
#[cfg(feature = "serialize")]
|
use std::num::ParseIntError;
|
||||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
use std::num::ParseFloatError;
|
||||||
|
use std::net::AddrParseError;
|
||||||
|
use std::fmt;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
#[cfg(feature = "serialize")]
|
||||||
use std::net::AddrParseError;
|
use serde::ser::{Serializer, Serialize, SerializeStruct};
|
||||||
use std::num::ParseFloatError;
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum SdpParserInternalError {
|
pub enum SdpParserInternalError {
|
||||||
Generic(String),
|
Generic(String),
|
||||||
Unsupported(String),
|
Unsupported(String),
|
||||||
|
|
@ -41,8 +42,8 @@ impl fmt::Display for SdpParserInternalError {
|
||||||
impl error::Error for SdpParserInternalError {
|
impl error::Error for SdpParserInternalError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
SdpParserInternalError::Generic(ref message)
|
SdpParserInternalError::Generic(ref message) |
|
||||||
| SdpParserInternalError::Unsupported(ref message) => message,
|
SdpParserInternalError::Unsupported(ref message) => message,
|
||||||
SdpParserInternalError::Integer(ref error) => error.description(),
|
SdpParserInternalError::Integer(ref error) => error.description(),
|
||||||
SdpParserInternalError::Float(ref error) => error.description(),
|
SdpParserInternalError::Float(ref error) => error.description(),
|
||||||
SdpParserInternalError::Address(ref error) => error.description(),
|
SdpParserInternalError::Address(ref error) => error.description(),
|
||||||
|
|
@ -61,63 +62,51 @@ impl error::Error for SdpParserInternalError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_internal_error_generic() {
|
fn test_sdp_parser_internal_error_generic() {
|
||||||
let generic = SdpParserInternalError::Generic("generic message".to_string());
|
let generic = SdpParserInternalError::Generic("generic message".to_string());
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", generic),
|
||||||
format!("{}", generic),
|
"Generic parsing error: generic message");
|
||||||
"Generic parsing error: generic message"
|
|
||||||
);
|
|
||||||
assert_eq!(generic.description(), "generic message");
|
assert_eq!(generic.description(), "generic message");
|
||||||
assert!(generic.cause().is_none());
|
assert!(generic.cause().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_internal_error_unsupported() {
|
fn test_sdp_parser_internal_error_unsupported() {
|
||||||
let unsupported =
|
let unsupported = SdpParserInternalError::Unsupported("unsupported internal message"
|
||||||
SdpParserInternalError::Unsupported("unsupported internal message".to_string());
|
.to_string());
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", unsupported),
|
||||||
format!("{}", unsupported),
|
"Unsupported parsing error: unsupported internal message");
|
||||||
"Unsupported parsing error: unsupported internal message"
|
|
||||||
);
|
|
||||||
assert_eq!(unsupported.description(), "unsupported internal message");
|
assert_eq!(unsupported.description(), "unsupported internal message");
|
||||||
assert!(unsupported.cause().is_none());
|
assert!(unsupported.cause().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_internal_error_integer() {
|
fn test_sdp_parser_internal_error_integer() {
|
||||||
let v = "12a";
|
let v = "12a";
|
||||||
let integer = v.parse::<u64>();
|
let integer = v.parse::<u64>();
|
||||||
assert!(integer.is_err());
|
assert!(integer.is_err());
|
||||||
let int_err = SdpParserInternalError::Integer(integer.err().unwrap());
|
let int_err = SdpParserInternalError::Integer(integer.err().unwrap());
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", int_err),
|
||||||
format!("{}", int_err),
|
"Integer parsing error: invalid digit found in string");
|
||||||
"Integer parsing error: invalid digit found in string"
|
|
||||||
);
|
|
||||||
assert_eq!(int_err.description(), "invalid digit found in string");
|
assert_eq!(int_err.description(), "invalid digit found in string");
|
||||||
assert!(!int_err.cause().is_none());
|
assert!(!int_err.cause().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_internal_error_address() {
|
fn test_sdp_parser_internal_error_address() {
|
||||||
let v = "127.0.0.a";
|
let v = "127.0.0.a";
|
||||||
use std::net::IpAddr;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::net::IpAddr;
|
||||||
let addr = IpAddr::from_str(v);
|
let addr = IpAddr::from_str(v);
|
||||||
assert!(addr.is_err());
|
assert!(addr.is_err());
|
||||||
let addr_err = SdpParserInternalError::Address(addr.err().unwrap());
|
let addr_err = SdpParserInternalError::Address(addr.err().unwrap());
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", addr_err),
|
||||||
format!("{}", addr_err),
|
"IP address parsing error: invalid IP address syntax");
|
||||||
"IP address parsing error: invalid IP address syntax"
|
|
||||||
);
|
|
||||||
assert_eq!(addr_err.description(), "invalid IP address syntax");
|
assert_eq!(addr_err.description(), "invalid IP address syntax");
|
||||||
assert!(!addr_err.cause().is_none());
|
assert!(!addr_err.cause().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SdpParserError {
|
pub enum SdpParserError {
|
||||||
Line {
|
Line {
|
||||||
error: SdpParserInternalError,
|
error: SdpParserInternalError,
|
||||||
|
|
@ -129,57 +118,37 @@ pub enum SdpParserError {
|
||||||
line: String,
|
line: String,
|
||||||
line_number: usize,
|
line_number: usize,
|
||||||
},
|
},
|
||||||
Sequence {
|
Sequence { message: String, line_number: usize },
|
||||||
message: String,
|
|
||||||
line_number: usize,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
impl Serialize for SdpParserError {
|
impl Serialize for SdpParserError {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||||
where
|
let mut state = serializer.serialize_struct("error", match self {
|
||||||
S: Serializer,
|
&SdpParserError::Sequence{..} => 3,
|
||||||
{
|
_ => 4
|
||||||
let mut state = serializer.serialize_struct(
|
})?;
|
||||||
"error",
|
match self {
|
||||||
match *self {
|
&SdpParserError::Line {ref error, ref line, ..} => {
|
||||||
SdpParserError::Sequence { .. } => 3,
|
|
||||||
_ => 4,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
match *self {
|
|
||||||
SdpParserError::Line {
|
|
||||||
ref error,
|
|
||||||
ref line,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
state.serialize_field("type", "Line")?;
|
state.serialize_field("type", "Line")?;
|
||||||
state.serialize_field("message", &format!("{}", error))?;
|
state.serialize_field("message", &format!("{}", error))?;
|
||||||
state.serialize_field("line", &line)?
|
state.serialize_field("line", &line)?
|
||||||
}
|
},
|
||||||
SdpParserError::Unsupported {
|
&SdpParserError::Unsupported {ref error, ref line, ..} => {
|
||||||
ref error,
|
|
||||||
ref line,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
state.serialize_field("type", "Unsupported")?;
|
state.serialize_field("type", "Unsupported")?;
|
||||||
state.serialize_field("message", &format!("{}", error))?;
|
state.serialize_field("message", &format!("{}", error))?;
|
||||||
state.serialize_field("line", &line)?
|
state.serialize_field("line", &line)?
|
||||||
}
|
},
|
||||||
SdpParserError::Sequence { ref message, .. } => {
|
&SdpParserError::Sequence {ref message, ..} => {
|
||||||
state.serialize_field("type", "Sequence")?;
|
state.serialize_field("type", "Sequence")?;
|
||||||
state.serialize_field("message", &message)?;
|
state.serialize_field("message", &message)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
state.serialize_field(
|
state.serialize_field("line_number", &match self {
|
||||||
"line_number",
|
&SdpParserError::Line {line_number, ..} => line_number,
|
||||||
&match *self {
|
&SdpParserError::Unsupported {line_number, ..} => line_number,
|
||||||
SdpParserError::Line { line_number, .. } => line_number,
|
&SdpParserError::Sequence {line_number, ..} => line_number,
|
||||||
SdpParserError::Unsupported { line_number, .. } => line_number,
|
})?;
|
||||||
SdpParserError::Sequence { line_number, .. } => line_number,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,24 +160,24 @@ impl fmt::Display for SdpParserError {
|
||||||
ref error,
|
ref error,
|
||||||
ref line,
|
ref line,
|
||||||
ref line_number,
|
ref line_number,
|
||||||
} => write!(
|
} => {
|
||||||
f,
|
write!(f,
|
||||||
"Line error: {} in line({}): {}",
|
"Line error: {} in line({}): {}",
|
||||||
error.description(),
|
error.description(),
|
||||||
line_number,
|
line_number,
|
||||||
line
|
line)
|
||||||
),
|
}
|
||||||
SdpParserError::Unsupported {
|
SdpParserError::Unsupported {
|
||||||
ref error,
|
ref error,
|
||||||
ref line,
|
ref line,
|
||||||
ref line_number,
|
ref line_number,
|
||||||
} => write!(
|
} => {
|
||||||
f,
|
write!(f,
|
||||||
"Unsupported: {} in line({}): {}",
|
"Unsupported: {} in line({}): {}",
|
||||||
error.description(),
|
error.description(),
|
||||||
line_number,
|
line_number,
|
||||||
line
|
line)
|
||||||
),
|
}
|
||||||
SdpParserError::Sequence {
|
SdpParserError::Sequence {
|
||||||
ref message,
|
ref message,
|
||||||
ref line_number,
|
ref line_number,
|
||||||
|
|
@ -217,19 +186,20 @@ impl fmt::Display for SdpParserError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl error::Error for SdpParserError {
|
impl error::Error for SdpParserError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
SdpParserError::Line { ref error, .. }
|
SdpParserError::Line { ref error, .. } |
|
||||||
| SdpParserError::Unsupported { ref error, .. } => error.description(),
|
SdpParserError::Unsupported { ref error, .. } => error.description(),
|
||||||
SdpParserError::Sequence { ref message, .. } => message,
|
SdpParserError::Sequence { ref message, .. } => message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self) -> Option<&error::Error> {
|
fn cause(&self) -> Option<&error::Error> {
|
||||||
match *self {
|
match *self {
|
||||||
SdpParserError::Line { ref error, .. }
|
SdpParserError::Line { ref error, .. } |
|
||||||
| SdpParserError::Unsupported { ref error, .. } => Some(error),
|
SdpParserError::Unsupported { ref error, .. } => Some(error),
|
||||||
// Can't tell much more about our internal errors
|
// Can't tell much more about our internal errors
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
@ -255,48 +225,39 @@ impl From<ParseFloatError> for SdpParserInternalError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_error_line() {
|
fn test_sdp_parser_error_line() {
|
||||||
let line1 = SdpParserError::Line {
|
let line1 = SdpParserError::Line {
|
||||||
error: SdpParserInternalError::Generic("test message".to_string()),
|
error: SdpParserInternalError::Generic("test message".to_string()),
|
||||||
line: "test line".to_string(),
|
line: "test line".to_string(),
|
||||||
line_number: 13,
|
line_number: 13,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", line1),
|
||||||
format!("{}", line1),
|
"Line error: test message in line(13): test line");
|
||||||
"Line error: test message in line(13): test line"
|
|
||||||
);
|
|
||||||
assert_eq!(line1.description(), "test message");
|
assert_eq!(line1.description(), "test message");
|
||||||
assert!(line1.cause().is_some());
|
assert!(line1.cause().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_error_unsupported() {
|
fn test_sdp_parser_error_unsupported() {
|
||||||
let unsupported1 = SdpParserError::Unsupported {
|
let unsupported1 = SdpParserError::Unsupported {
|
||||||
error: SdpParserInternalError::Generic("unsupported value".to_string()),
|
error: SdpParserInternalError::Generic("unsupported value".to_string()),
|
||||||
line: "unsupported line".to_string(),
|
line: "unsupported line".to_string(),
|
||||||
line_number: 21,
|
line_number: 21,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", unsupported1),
|
||||||
format!("{}", unsupported1),
|
"Unsupported: unsupported value in line(21): unsupported line");
|
||||||
"Unsupported: unsupported value in line(21): unsupported line"
|
|
||||||
);
|
|
||||||
assert_eq!(unsupported1.description(), "unsupported value");
|
assert_eq!(unsupported1.description(), "unsupported value");
|
||||||
assert!(unsupported1.cause().is_some());
|
assert!(unsupported1.cause().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)] // see issue #102
|
|
||||||
fn test_sdp_parser_error_sequence() {
|
fn test_sdp_parser_error_sequence() {
|
||||||
let sequence1 = SdpParserError::Sequence {
|
let sequence1 = SdpParserError::Sequence {
|
||||||
message: "sequence message".to_string(),
|
message: "sequence message".to_string(),
|
||||||
line_number: 42,
|
line_number: 42,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", sequence1),
|
||||||
format!("{}", sequence1),
|
"Sequence error in line(42): sequence message");
|
||||||
"Sequence error in line(42): sequence message"
|
|
||||||
);
|
|
||||||
assert_eq!(sequence1.description(), "sequence message");
|
assert_eq!(sequence1.description(), "sequence message");
|
||||||
assert!(sequence1.cause().is_none());
|
assert!(sequence1.cause().is_none());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,10 @@
|
||||||
use attribute_type::{
|
use std::fmt;
|
||||||
maybe_print_param, SdpAttribute, SdpAttributeRtpmap, SdpAttributeSctpmap, SdpAttributeType,
|
use {SdpType, SdpLine, SdpBandwidth, SdpConnection};
|
||||||
};
|
use attribute_type::{SdpAttribute, SdpAttributeType, SdpAttributeRtpmap, SdpAttributeSctpmap};
|
||||||
use error::{SdpParserError, SdpParserInternalError};
|
use error::{SdpParserError, SdpParserInternalError};
|
||||||
use {SdpBandwidth, SdpConnection, SdpLine, SdpType};
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||||
pub struct SdpMediaLine {
|
pub struct SdpMediaLine {
|
||||||
pub media: SdpMediaValue,
|
pub media: SdpMediaValue,
|
||||||
pub port: u32,
|
pub port: u32,
|
||||||
|
|
@ -13,91 +13,73 @@ pub struct SdpMediaLine {
|
||||||
pub formats: SdpFormatList,
|
pub formats: SdpFormatList,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SdpMediaLine {
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
fn to_string(&self) -> String {
|
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||||
format!(
|
|
||||||
"{media_line} {port}{port_count} {protocol} {formats}",
|
|
||||||
media_line = self.media.to_string(),
|
|
||||||
port_count = maybe_print_param("/", self.port_count, 0),
|
|
||||||
port = self.port.to_string(),
|
|
||||||
protocol = self.proto.to_string(),
|
|
||||||
formats = self.formats.to_string()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
|
||||||
pub enum SdpMediaValue {
|
pub enum SdpMediaValue {
|
||||||
Audio,
|
Audio,
|
||||||
Video,
|
Video,
|
||||||
Application,
|
Application,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SdpMediaValue {
|
impl fmt::Display for SdpMediaValue {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
let printable = match *self {
|
||||||
SdpMediaValue::Audio => "audio",
|
SdpMediaValue::Audio => "Audio",
|
||||||
SdpMediaValue::Video => "video",
|
SdpMediaValue::Video => "Video",
|
||||||
SdpMediaValue::Application => "application",
|
SdpMediaValue::Application => "Application",
|
||||||
}
|
};
|
||||||
.to_string()
|
write!(f, "{}", printable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||||
pub enum SdpProtocolValue {
|
pub enum SdpProtocolValue {
|
||||||
RtpAvp,
|
|
||||||
RtpAvpf,
|
|
||||||
RtpSavp,
|
|
||||||
RtpSavpf,
|
RtpSavpf,
|
||||||
TcpDtlsRtpSavp,
|
|
||||||
TcpDtlsRtpSavpf,
|
|
||||||
UdpTlsRtpSavp,
|
UdpTlsRtpSavp,
|
||||||
|
TcpDtlsRtpSavp,
|
||||||
UdpTlsRtpSavpf,
|
UdpTlsRtpSavpf,
|
||||||
|
TcpTlsRtpSavpf,
|
||||||
|
TcpDtlsRtpSavpf,
|
||||||
DtlsSctp,
|
DtlsSctp,
|
||||||
UdpDtlsSctp,
|
UdpDtlsSctp,
|
||||||
TcpDtlsSctp,
|
TcpDtlsSctp,
|
||||||
TcpTlsRtpSavpf, /* not standardized - to be removed */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SdpProtocolValue {
|
impl fmt::Display for SdpProtocolValue {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
let printable = match *self {
|
||||||
SdpProtocolValue::RtpAvp => "RTP/AVP",
|
SdpProtocolValue::RtpSavpf => "Rtp/Savpf",
|
||||||
SdpProtocolValue::RtpAvpf => "RTP/AVPF",
|
SdpProtocolValue::UdpTlsRtpSavp => "Udp/Tls/Rtp/Savp",
|
||||||
SdpProtocolValue::RtpSavp => "RTP/SAVP",
|
SdpProtocolValue::TcpDtlsRtpSavp => "Tcp/Dtls/Rtp/Savp",
|
||||||
SdpProtocolValue::RtpSavpf => "RTP/SAVPF",
|
SdpProtocolValue::UdpTlsRtpSavpf => "Udp/Tls/Rtp/Savpf",
|
||||||
SdpProtocolValue::TcpDtlsRtpSavp => "TCP/DTLS/RTP/SAVP",
|
SdpProtocolValue::TcpTlsRtpSavpf => "Tcp/Tls/Rtp/Savpf",
|
||||||
SdpProtocolValue::TcpDtlsRtpSavpf => "TCP/DTLS/RTP/SAVPF",
|
SdpProtocolValue::TcpDtlsRtpSavpf => "Tcp/Dtls/Rtp/Savpf",
|
||||||
SdpProtocolValue::UdpTlsRtpSavp => "UDP/TLS/RTP/SAVP",
|
SdpProtocolValue::DtlsSctp => "Dtls/Sctp",
|
||||||
SdpProtocolValue::UdpTlsRtpSavpf => "UDP/TLS/RTP/SAVPF",
|
SdpProtocolValue::UdpDtlsSctp => "Udp/Dtls/Sctp",
|
||||||
SdpProtocolValue::DtlsSctp => "DTLS/SCTP",
|
SdpProtocolValue::TcpDtlsSctp => "Tcp/Dtls/Sctp",
|
||||||
SdpProtocolValue::UdpDtlsSctp => "UDP/DTLS/SCTP",
|
};
|
||||||
SdpProtocolValue::TcpDtlsSctp => "TCP/DTLS/SCTP",
|
write!(f, "{}", printable)
|
||||||
SdpProtocolValue::TcpTlsRtpSavpf => "TCP/TLS/RTP/SAVPF",
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||||
pub enum SdpFormatList {
|
pub enum SdpFormatList {
|
||||||
Integers(Vec<u32>),
|
Integers(Vec<u32>),
|
||||||
Strings(Vec<String>),
|
Strings(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SdpFormatList {
|
impl fmt::Display for SdpFormatList {
|
||||||
fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
SdpFormatList::Integers(ref x) => maybe_vector_to_string!("{}", x, " "),
|
SdpFormatList::Integers(ref x) => write!(f, "{:?}", x),
|
||||||
SdpFormatList::Strings(ref x) => x.join(" "),
|
SdpFormatList::Strings(ref x) => write!(f, "{:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||||
pub struct SdpMedia {
|
pub struct SdpMedia {
|
||||||
media: SdpMediaLine,
|
media: SdpMediaLine,
|
||||||
connection: Option<SdpConnection>,
|
connection: Option<SdpConnection>,
|
||||||
|
|
@ -146,136 +128,109 @@ impl SdpMedia {
|
||||||
&self.bandwidth
|
&self.bandwidth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_bandwidth(&mut self, bw: SdpBandwidth) {
|
pub fn add_bandwidth(&mut self, bw: &SdpBandwidth) {
|
||||||
self.bandwidth.push(bw)
|
self.bandwidth.push(bw.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_attributes(&self) -> &Vec<SdpAttribute> {
|
pub fn get_attributes(&self) -> &Vec<SdpAttribute> {
|
||||||
&self.attribute
|
&self.attribute
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError> {
|
pub fn add_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserInternalError> {
|
||||||
if !attr.allowed_at_media_level() {
|
if !attr.allowed_at_media_level() {
|
||||||
return Err(SdpParserInternalError::Generic(format!(
|
return Err(SdpParserInternalError::Generic(format!("{} not allowed at media level",
|
||||||
"{} not allowed at media level",
|
attr)));
|
||||||
attr.to_string()
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
self.attribute.push(attr);
|
Ok(self.attribute.push(attr.clone()))
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
|
pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
|
||||||
self.attribute
|
self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next()
|
||||||
.iter()
|
|
||||||
.find(|a| SdpAttributeType::from(*a) == t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_attribute(&mut self, t: SdpAttributeType) {
|
pub fn remove_attribute(&mut self, t: SdpAttributeType) {
|
||||||
self.attribute.retain(|a| SdpAttributeType::from(a) != t);
|
self.attribute.retain(|a| SdpAttributeType::from(a) != t);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError> {
|
pub fn set_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserInternalError> {
|
||||||
self.remove_attribute(SdpAttributeType::from(&attr));
|
self.remove_attribute(SdpAttributeType::from(attr));
|
||||||
self.add_attribute(attr)
|
self.add_attribute(attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_codecs(&mut self) {
|
pub fn remove_codecs(&mut self) {
|
||||||
match self.media.formats {
|
match self.media.formats{
|
||||||
SdpFormatList::Integers(_) => self.media.formats = SdpFormatList::Integers(Vec::new()),
|
SdpFormatList::Integers(_) => self.media.formats = SdpFormatList::Integers(Vec::new()),
|
||||||
SdpFormatList::Strings(_) => self.media.formats = SdpFormatList::Strings(Vec::new()),
|
SdpFormatList::Strings(_) => self.media.formats = SdpFormatList::Strings(Vec::new()),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.attribute.retain({
|
self.attribute.retain({|x|
|
||||||
|x| match *x {
|
match x {
|
||||||
SdpAttribute::Rtpmap(_)
|
&SdpAttribute::Rtpmap(_) |
|
||||||
| SdpAttribute::Fmtp(_)
|
&SdpAttribute::Fmtp(_) |
|
||||||
| SdpAttribute::Rtcpfb(_)
|
&SdpAttribute::Rtcpfb(_) |
|
||||||
| SdpAttribute::Sctpmap(_) => false,
|
&SdpAttribute::Sctpmap(_) => false,
|
||||||
_ => true,
|
_ => true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_codec(&mut self, rtpmap: SdpAttributeRtpmap) -> Result<(), SdpParserInternalError> {
|
pub fn add_codec(&mut self, rtpmap: SdpAttributeRtpmap) -> Result<(),SdpParserInternalError> {
|
||||||
match self.media.formats {
|
match self.media.formats {
|
||||||
SdpFormatList::Integers(ref mut x) => x.push(u32::from(rtpmap.payload_type)),
|
SdpFormatList::Integers(ref mut x) => x.push(rtpmap.payload_type as u32),
|
||||||
SdpFormatList::Strings(ref mut x) => x.push(rtpmap.payload_type.to_string()),
|
SdpFormatList::Strings(ref mut x) => x.push(rtpmap.payload_type.to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.add_attribute(SdpAttribute::Rtpmap(rtpmap))?;
|
self.add_attribute(&SdpAttribute::Rtpmap(rtpmap))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute> {
|
pub fn get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute> {
|
||||||
self.attribute
|
self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).collect()
|
||||||
.iter()
|
|
||||||
.filter(|a| SdpAttributeType::from(*a) == t)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_connection(&self) -> &Option<SdpConnection> {
|
pub fn get_connection(&self) -> &Option<SdpConnection> {
|
||||||
&self.connection
|
&self.connection
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_connection(&mut self, c: SdpConnection) -> Result<(), SdpParserInternalError> {
|
pub fn set_connection(&mut self, c: &SdpConnection) -> Result<(), SdpParserInternalError> {
|
||||||
if self.connection.is_some() {
|
if self.connection.is_some() {
|
||||||
return Err(SdpParserInternalError::Generic(
|
return Err(SdpParserInternalError::Generic("connection type already exists at this media level"
|
||||||
"connection type already exists at this media level".to_string(),
|
.to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.connection = Some(c);
|
Ok(self.connection = Some(c.clone()))
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_datachannel(
|
pub fn add_datachannel(&mut self, name: String, port: u16, streams: u16, msg_size:u32)
|
||||||
&mut self,
|
-> Result<(),SdpParserInternalError> {
|
||||||
name: String,
|
// Only one allowed, for now. This may change as the specs (and deployments) evolve.
|
||||||
port: u16,
|
|
||||||
streams: u16,
|
|
||||||
msg_size: u32,
|
|
||||||
) -> Result<(), SdpParserInternalError> {
|
|
||||||
// Only one allowed, for now. This may change as the specs (and deployments) evolve.
|
|
||||||
match self.media.proto {
|
match self.media.proto {
|
||||||
SdpProtocolValue::UdpDtlsSctp | SdpProtocolValue::TcpDtlsSctp => {
|
SdpProtocolValue::UdpDtlsSctp |
|
||||||
|
SdpProtocolValue::TcpDtlsSctp => {
|
||||||
// new data channel format according to draft 21
|
// new data channel format according to draft 21
|
||||||
self.media.formats = SdpFormatList::Strings(vec![name]);
|
self.media.formats = SdpFormatList::Strings(vec![name]);
|
||||||
self.set_attribute(SdpAttribute::SctpPort(u64::from(port)))?;
|
self.set_attribute(&SdpAttribute::SctpPort(port as u64))?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// old data channels format according to draft 05
|
// old data channels format according to draft 05
|
||||||
self.media.formats = SdpFormatList::Integers(vec![u32::from(port)]);
|
self.media.formats = SdpFormatList::Integers(vec![port as u32]);
|
||||||
self.set_attribute(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
|
self.set_attribute(&SdpAttribute::Sctpmap(SdpAttributeSctpmap {
|
||||||
port,
|
port,
|
||||||
channels: u32::from(streams),
|
channels: streams as u32,
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg_size > 0 {
|
if msg_size > 0 {
|
||||||
self.set_attribute(SdpAttribute::MaxMessageSize(u64::from(msg_size)))?;
|
self.set_attribute(&SdpAttribute::MaxMessageSize(msg_size as u64))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SdpMedia {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
format!(
|
|
||||||
"m={media_line}\r\n\
|
|
||||||
{bandwidth}\
|
|
||||||
{connection}\
|
|
||||||
{attributes}",
|
|
||||||
media_line = self.media.to_string(),
|
|
||||||
connection = option_to_string!("c={}\r\n", self.connection),
|
|
||||||
bandwidth = maybe_vector_to_string!("b={}\r\n", self.bandwidth, "\r\nb="),
|
|
||||||
attributes = maybe_vector_to_string!("a={}\r\n", self.attribute, "\r\na=")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||||
pub fn create_dummy_media_section() -> SdpMedia {
|
pub fn create_dummy_media_section() -> SdpMedia {
|
||||||
let media_line = SdpMediaLine {
|
let media_line = SdpMediaLine {
|
||||||
media: SdpMediaValue::Audio,
|
media: SdpMediaValue::Audio,
|
||||||
|
|
@ -289,16 +244,14 @@ pub fn create_dummy_media_section() -> SdpMedia {
|
||||||
|
|
||||||
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserInternalError> {
|
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserInternalError> {
|
||||||
Ok(match value.to_lowercase().as_ref() {
|
Ok(match value.to_lowercase().as_ref() {
|
||||||
"audio" => SdpMediaValue::Audio,
|
"audio" => SdpMediaValue::Audio,
|
||||||
"video" => SdpMediaValue::Video,
|
"video" => SdpMediaValue::Video,
|
||||||
"application" => SdpMediaValue::Application,
|
"application" => SdpMediaValue::Application,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(SdpParserInternalError::Unsupported(format!(
|
return Err(SdpParserInternalError::Unsupported(format!("unsupported media value: {}",
|
||||||
"unsupported media value: {}",
|
value)))
|
||||||
value
|
}
|
||||||
)));
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -317,66 +270,44 @@ fn test_parse_media_token() {
|
||||||
assert!(parse_media_token("foobar").is_err());
|
assert!(parse_media_token("foobar").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserInternalError> {
|
fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserInternalError> {
|
||||||
Ok(match value.to_uppercase().as_ref() {
|
Ok(match value.to_uppercase().as_ref() {
|
||||||
"RTP/AVP" => SdpProtocolValue::RtpAvp,
|
"RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
|
||||||
"RTP/AVPF" => SdpProtocolValue::RtpAvpf,
|
"UDP/TLS/RTP/SAVP" => SdpProtocolValue::UdpTlsRtpSavp,
|
||||||
"RTP/SAVP" => SdpProtocolValue::RtpSavp,
|
"TCP/DTLS/RTP/SAVP" => SdpProtocolValue::TcpDtlsRtpSavp,
|
||||||
"RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
|
"TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
|
||||||
"TCP/DTLS/RTP/SAVP" => SdpProtocolValue::TcpDtlsRtpSavp,
|
"TCP/DTLS/RTP/SAVPF" => SdpProtocolValue::TcpDtlsRtpSavpf,
|
||||||
"TCP/DTLS/RTP/SAVPF" => SdpProtocolValue::TcpDtlsRtpSavpf,
|
"DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
|
||||||
"UDP/TLS/RTP/SAVP" => SdpProtocolValue::UdpTlsRtpSavp,
|
"UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
|
||||||
"UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
|
"TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
|
||||||
"DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
|
_ => {
|
||||||
"UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
|
return Err(SdpParserInternalError::Unsupported(format!("unsupported protocol value: {}",
|
||||||
"TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
|
value)))
|
||||||
/* to be removed */
|
}
|
||||||
"TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
|
})
|
||||||
_ => {
|
|
||||||
return Err(SdpParserInternalError::Unsupported(format!(
|
|
||||||
"unsupported protocol value: {}",
|
|
||||||
value
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_protocol_rtp_token() {
|
fn test_parse_protocol_token() {
|
||||||
let rtps = parse_protocol_token("rtp/avp");
|
|
||||||
assert!(rtps.is_ok());
|
|
||||||
assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpAvp);
|
|
||||||
let rtps = parse_protocol_token("rtp/avpf");
|
|
||||||
assert!(rtps.is_ok());
|
|
||||||
assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpAvpf);
|
|
||||||
let rtps = parse_protocol_token("rtp/savp");
|
|
||||||
assert!(rtps.is_ok());
|
|
||||||
assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavp);
|
|
||||||
let rtps = parse_protocol_token("rtp/savpf");
|
let rtps = parse_protocol_token("rtp/savpf");
|
||||||
assert!(rtps.is_ok());
|
assert!(rtps.is_ok());
|
||||||
assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
|
assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
|
||||||
let udps = parse_protocol_token("udp/tls/rtp/savp");
|
let udps = parse_protocol_token("udp/tls/rtp/savp");
|
||||||
assert!(udps.is_ok());
|
assert!(udps.is_ok());
|
||||||
assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavp);
|
assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavp);
|
||||||
|
let tcps = parse_protocol_token("tcp/dtls/rtp/savp");
|
||||||
|
assert!(tcps.is_ok());
|
||||||
|
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpDtlsRtpSavp);
|
||||||
let udps = parse_protocol_token("udp/tls/rtp/savpf");
|
let udps = parse_protocol_token("udp/tls/rtp/savpf");
|
||||||
assert!(udps.is_ok());
|
assert!(udps.is_ok());
|
||||||
assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavpf);
|
assert_eq!(udps.unwrap(), SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
let tcps = parse_protocol_token("TCP/dtls/rtp/savp");
|
|
||||||
assert!(tcps.is_ok());
|
|
||||||
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpDtlsRtpSavp);
|
|
||||||
let tcps = parse_protocol_token("TCP/dtls/rtp/savpf");
|
|
||||||
assert!(tcps.is_ok());
|
|
||||||
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpDtlsRtpSavpf);
|
|
||||||
let tcps = parse_protocol_token("TCP/tls/rtp/savpf");
|
let tcps = parse_protocol_token("TCP/tls/rtp/savpf");
|
||||||
assert!(tcps.is_ok());
|
assert!(tcps.is_ok());
|
||||||
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
|
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
|
||||||
|
let tcps = parse_protocol_token("TCP/DtlS/rTp/sAVpf");
|
||||||
assert!(parse_protocol_token("").is_err());
|
assert!(tcps.is_ok());
|
||||||
assert!(parse_protocol_token("foobar").is_err());
|
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpDtlsRtpSavpf);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_protocol_sctp_token() {
|
|
||||||
let dtls = parse_protocol_token("dtLs/ScTP");
|
let dtls = parse_protocol_token("dtLs/ScTP");
|
||||||
assert!(dtls.is_ok());
|
assert!(dtls.is_ok());
|
||||||
assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
|
assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
|
||||||
|
|
@ -386,29 +317,25 @@ fn test_parse_protocol_sctp_token() {
|
||||||
let tsctp = parse_protocol_token("tcp/dtls/SCTP");
|
let tsctp = parse_protocol_token("tcp/dtls/SCTP");
|
||||||
assert!(tsctp.is_ok());
|
assert!(tsctp.is_ok());
|
||||||
assert_eq!(tsctp.unwrap(), SdpProtocolValue::TcpDtlsSctp);
|
assert_eq!(tsctp.unwrap(), SdpProtocolValue::TcpDtlsSctp);
|
||||||
|
|
||||||
|
assert!(parse_protocol_token("").is_err());
|
||||||
|
assert!(parse_protocol_token("foobar").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_media(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
pub fn parse_media(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
let mv: Vec<&str> = value.split_whitespace().collect();
|
let mv: Vec<&str> = value.split_whitespace().collect();
|
||||||
if mv.len() < 4 {
|
if mv.len() < 4 {
|
||||||
return Err(SdpParserInternalError::Generic(
|
return Err(SdpParserInternalError::Generic("media attribute must have at least four tokens"
|
||||||
"media attribute must have at least four tokens".to_string(),
|
.to_string()));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let media = parse_media_token(mv[0])?;
|
let media = parse_media_token(mv[0])?;
|
||||||
let mut ptokens = mv[1].split('/');
|
let mut ptokens = mv[1].split('/');
|
||||||
let port = match ptokens.next() {
|
let port = match ptokens.next() {
|
||||||
None => {
|
None => return Err(SdpParserInternalError::Generic("missing port token".to_string())),
|
||||||
return Err(SdpParserInternalError::Generic(
|
|
||||||
"missing port token".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Some(p) => p.parse::<u32>()?,
|
Some(p) => p.parse::<u32>()?,
|
||||||
};
|
};
|
||||||
if port > 65535 {
|
if port > 65535 {
|
||||||
return Err(SdpParserInternalError::Generic(
|
return Err(SdpParserInternalError::Generic("media port token is too big".to_string()));
|
||||||
"media port token is too big".to_string(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let port_count = match ptokens.next() {
|
let port_count = match ptokens.next() {
|
||||||
None => 0,
|
None => 0,
|
||||||
|
|
@ -450,41 +377,20 @@ pub fn parse_media(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
proto,
|
proto,
|
||||||
formats,
|
formats,
|
||||||
};
|
};
|
||||||
trace!(
|
trace!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
|
||||||
"media: {}, {}, {}, {}",
|
|
||||||
m.media.to_string(),
|
|
||||||
m.port.to_string(),
|
|
||||||
m.proto.to_string(),
|
|
||||||
m.formats.to_string()
|
|
||||||
);
|
|
||||||
Ok(SdpType::Media(m))
|
Ok(SdpType::Media(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn check_parse(media_line_str: &str) -> SdpMediaLine {
|
|
||||||
if let Ok(SdpType::Media(media_line)) = parse_media(media_line_str) {
|
|
||||||
media_line
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn check_parse_and_serialize(media_line_str: &str) {
|
|
||||||
let parsed = check_parse(media_line_str);
|
|
||||||
assert_eq!(parsed.to_string(), media_line_str.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_media_works() {
|
fn test_media_works() {
|
||||||
check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109");
|
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
|
||||||
check_parse_and_serialize("video 9 UDP/TLS/RTP/SAVPF 126");
|
assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
|
||||||
check_parse_and_serialize("application 9 DTLS/SCTP 5000");
|
assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
|
||||||
check_parse_and_serialize("application 9 UDP/DTLS/SCTP webrtc-datachannel");
|
assert!(parse_media("application 9 UDP/DTLS/SCTP webrtc-datachannel").is_ok());
|
||||||
|
|
||||||
check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8");
|
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8").is_ok());
|
||||||
check_parse_and_serialize("audio 0 UDP/TLS/RTP/SAVPF 8");
|
assert!(parse_media("audio 0 UDP/TLS/RTP/SAVPF 8").is_ok());
|
||||||
check_parse_and_serialize("audio 9/2 UDP/TLS/RTP/SAVPF 8");
|
assert!(parse_media("audio 9/2 UDP/TLS/RTP/SAVPF 8").is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -517,68 +423,84 @@ fn test_media_invalid_payload() {
|
||||||
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
|
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_media_vector(lines: &mut Vec<SdpLine>) -> Result<Vec<SdpMedia>, SdpParserError> {
|
pub fn parse_media_vector(lines: &[SdpLine]) -> Result<Vec<SdpMedia>, SdpParserError> {
|
||||||
let mut media_sections: Vec<SdpMedia> = Vec::new();
|
let mut media_sections: Vec<SdpMedia> = Vec::new();
|
||||||
|
let mut sdp_media = match lines[0].sdp_type {
|
||||||
let media_line = lines.remove(0);
|
SdpType::Media(ref v) => SdpMedia::new(v.clone()),
|
||||||
let mut sdp_media = match media_line.sdp_type {
|
|
||||||
SdpType::Media(v) => SdpMedia::new(v),
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(SdpParserError::Sequence {
|
return Err(SdpParserError::Sequence {
|
||||||
message: "first line in media section needs to be a media line".to_string(),
|
message: "first line in media section needs to be a media line"
|
||||||
line_number: media_line.line_number,
|
.to_string(),
|
||||||
});
|
line_number: lines[0].line_number,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
while !lines.is_empty() {
|
for line in lines.iter().skip(1) {
|
||||||
let line = lines.remove(0);
|
|
||||||
let _line_number = line.line_number;
|
|
||||||
match line.sdp_type {
|
match line.sdp_type {
|
||||||
SdpType::Connection(c) => {
|
SdpType::Connection(ref c) => {
|
||||||
sdp_media
|
sdp_media
|
||||||
.set_connection(c)
|
.set_connection(c)
|
||||||
.map_err(|e: SdpParserInternalError| SdpParserError::Sequence {
|
.map_err(|e: SdpParserInternalError| {
|
||||||
message: format!("{}", e),
|
SdpParserError::Sequence {
|
||||||
line_number: _line_number,
|
message: format!("{}", e),
|
||||||
})?
|
line_number: line.line_number,
|
||||||
|
}
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
SdpType::Bandwidth(b) => sdp_media.add_bandwidth(b),
|
SdpType::Bandwidth(ref b) => sdp_media.add_bandwidth(b),
|
||||||
SdpType::Attribute(a) => {
|
SdpType::Attribute(ref a) => {
|
||||||
match a {
|
match a {
|
||||||
SdpAttribute::DtlsMessage(_) => {
|
&SdpAttribute::DtlsMessage(_) => {
|
||||||
// Ignore this attribute on media level
|
// Ignore this attribute on media level
|
||||||
Ok(())
|
Ok(())
|
||||||
|
},
|
||||||
|
&SdpAttribute::Rtpmap(ref rtpmap) => {
|
||||||
|
sdp_media.add_attribute(&SdpAttribute::Rtpmap(
|
||||||
|
SdpAttributeRtpmap {
|
||||||
|
payload_type: rtpmap.payload_type,
|
||||||
|
codec_name: rtpmap.codec_name.clone(),
|
||||||
|
frequency: rtpmap.frequency,
|
||||||
|
channels: match sdp_media.media.media {
|
||||||
|
SdpMediaValue::Video => Some(0),
|
||||||
|
_ => rtpmap.channels
|
||||||
|
},
|
||||||
|
}
|
||||||
|
))
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
sdp_media.add_attribute(a)
|
||||||
}
|
}
|
||||||
SdpAttribute::Rtpmap(rtpmap) => {
|
}.map_err(|e: SdpParserInternalError| {
|
||||||
sdp_media.add_attribute(SdpAttribute::Rtpmap(SdpAttributeRtpmap {
|
SdpParserError::Sequence {
|
||||||
payload_type: rtpmap.payload_type,
|
message: format!("{}", e),
|
||||||
codec_name: rtpmap.codec_name.clone(),
|
line_number: line.line_number,
|
||||||
frequency: rtpmap.frequency,
|
}
|
||||||
channels: match sdp_media.media.media {
|
})?
|
||||||
SdpMediaValue::Video => Some(0),
|
|
||||||
_ => rtpmap.channels,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => sdp_media.add_attribute(a),
|
|
||||||
}
|
|
||||||
.map_err(|e: SdpParserInternalError| SdpParserError::Sequence {
|
|
||||||
message: format!("{}", e),
|
|
||||||
line_number: _line_number,
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
SdpType::Media(v) => {
|
SdpType::Media(ref v) => {
|
||||||
media_sections.push(sdp_media);
|
media_sections.push(sdp_media);
|
||||||
sdp_media = SdpMedia::new(v);
|
sdp_media = SdpMedia::new(v.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
SdpType::Origin(_) | SdpType::Session(_) | SdpType::Timing(_) | SdpType::Version(_) => {
|
SdpType::Email(_) |
|
||||||
|
SdpType::Phone(_) |
|
||||||
|
SdpType::Origin(_) |
|
||||||
|
SdpType::Repeat(_) |
|
||||||
|
SdpType::Session(_) |
|
||||||
|
SdpType::Timing(_) |
|
||||||
|
SdpType::Uri(_) |
|
||||||
|
SdpType::Version(_) |
|
||||||
|
SdpType::Zone(_) => {
|
||||||
return Err(SdpParserError::Sequence {
|
return Err(SdpParserError::Sequence {
|
||||||
message: "invalid type in media section".to_string(),
|
message: "invalid type in media section".to_string(),
|
||||||
line_number: line.line_number,
|
line_number: line.line_number,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the line parsers throw unsupported errors for these already
|
||||||
|
SdpType::Information(_) |
|
||||||
|
SdpType::Key(_) => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -592,10 +514,10 @@ fn test_media_vector_first_line_failure() {
|
||||||
let mut sdp_lines: Vec<SdpLine> = Vec::new();
|
let mut sdp_lines: Vec<SdpLine> = Vec::new();
|
||||||
let line = SdpLine {
|
let line = SdpLine {
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
sdp_type: SdpType::Session("hello".to_string()),
|
sdp_type: SdpType::Session("hello".to_string())
|
||||||
};
|
};
|
||||||
sdp_lines.push(line);
|
sdp_lines.push(line);
|
||||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -610,27 +532,26 @@ fn test_media_vector_multiple_connections() {
|
||||||
};
|
};
|
||||||
let media = SdpLine {
|
let media = SdpLine {
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
sdp_type: SdpType::Media(media_line),
|
sdp_type: SdpType::Media(media_line)
|
||||||
};
|
};
|
||||||
sdp_lines.push(media);
|
sdp_lines.push(media);
|
||||||
use network::parse_unicast_addr;
|
use network::{parse_unicast_addr};
|
||||||
let addr = parse_unicast_addr("127.0.0.1").unwrap();
|
let addr = parse_unicast_addr("127.0.0.1").unwrap();
|
||||||
let c = SdpConnection {
|
let c = SdpConnection {
|
||||||
addr,
|
addr,
|
||||||
ttl: None,
|
ttl: None,
|
||||||
amount: None,
|
amount: None };
|
||||||
};
|
|
||||||
let c1 = SdpLine {
|
let c1 = SdpLine {
|
||||||
line_number: 1,
|
line_number: 1,
|
||||||
sdp_type: SdpType::Connection(c.clone()),
|
sdp_type: SdpType::Connection(c.clone())
|
||||||
};
|
};
|
||||||
sdp_lines.push(c1);
|
sdp_lines.push(c1);
|
||||||
let c2 = SdpLine {
|
let c2 = SdpLine {
|
||||||
line_number: 2,
|
line_number: 2,
|
||||||
sdp_type: SdpType::Connection(c),
|
sdp_type: SdpType::Connection(c)
|
||||||
};
|
};
|
||||||
sdp_lines.push(c2);
|
sdp_lines.push(c2);
|
||||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -645,17 +566,17 @@ fn test_media_vector_invalid_types() {
|
||||||
};
|
};
|
||||||
let media = SdpLine {
|
let media = SdpLine {
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
sdp_type: SdpType::Media(media_line),
|
sdp_type: SdpType::Media(media_line)
|
||||||
};
|
};
|
||||||
sdp_lines.push(media);
|
sdp_lines.push(media);
|
||||||
use SdpTiming;
|
use {SdpTiming};
|
||||||
let t = SdpTiming { start: 0, stop: 0 };
|
let t = SdpTiming { start: 0, stop: 0 };
|
||||||
let tline = SdpLine {
|
let tline = SdpLine {
|
||||||
line_number: 1,
|
line_number: 1,
|
||||||
sdp_type: SdpType::Timing(t),
|
sdp_type: SdpType::Timing(t)
|
||||||
};
|
};
|
||||||
sdp_lines.push(tline);
|
sdp_lines.push(tline);
|
||||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -670,14 +591,14 @@ fn test_media_vector_invalid_media_level_attribute() {
|
||||||
};
|
};
|
||||||
let media = SdpLine {
|
let media = SdpLine {
|
||||||
line_number: 0,
|
line_number: 0,
|
||||||
sdp_type: SdpType::Media(media_line),
|
sdp_type: SdpType::Media(media_line)
|
||||||
};
|
};
|
||||||
sdp_lines.push(media);
|
sdp_lines.push(media);
|
||||||
let a = SdpAttribute::IceLite;
|
let a = SdpAttribute::IceLite;
|
||||||
let aline = SdpLine {
|
let aline = SdpLine {
|
||||||
line_number: 1,
|
line_number: 1,
|
||||||
sdp_type: SdpType::Attribute(a),
|
sdp_type: SdpType::Attribute(a)
|
||||||
};
|
};
|
||||||
sdp_lines.push(aline);
|
sdp_lines.push(aline);
|
||||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
|
use std::str::FromStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use error::SdpParserInternalError;
|
use error::SdpParserInternalError;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
pub enum SdpAddrType {
|
pub enum SdpAddrType {
|
||||||
IP4 = 4,
|
IP4 = 4,
|
||||||
IP6 = 6,
|
IP6 = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SdpAddrType {
|
impl SdpAddrType {
|
||||||
pub fn same_protocol(self, addr: &IpAddr) -> bool {
|
pub fn same_protocol(&self, addr: &IpAddr) -> bool {
|
||||||
(addr.is_ipv6() && self == SdpAddrType::IP6) || (addr.is_ipv4() && self == SdpAddrType::IP4)
|
(addr.is_ipv6() && *self == SdpAddrType::IP6) ||
|
||||||
|
(addr.is_ipv4() && *self == SdpAddrType::IP4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,9 +29,7 @@ impl fmt::Display for SdpAddrType {
|
||||||
|
|
||||||
pub fn parse_nettype(value: &str) -> Result<(), SdpParserInternalError> {
|
pub fn parse_nettype(value: &str) -> Result<(), SdpParserInternalError> {
|
||||||
if value.to_uppercase() != "IN" {
|
if value.to_uppercase() != "IN" {
|
||||||
return Err(SdpParserInternalError::Generic(
|
return Err(SdpParserInternalError::Generic("nettype needs to be IN".to_string()));
|
||||||
"nettype needs to be IN".to_string(),
|
|
||||||
));
|
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -46,14 +45,13 @@ fn test_parse_nettype() {
|
||||||
|
|
||||||
pub fn parse_addrtype(value: &str) -> Result<SdpAddrType, SdpParserInternalError> {
|
pub fn parse_addrtype(value: &str) -> Result<SdpAddrType, SdpParserInternalError> {
|
||||||
Ok(match value.to_uppercase().as_ref() {
|
Ok(match value.to_uppercase().as_ref() {
|
||||||
"IP4" => SdpAddrType::IP4,
|
"IP4" => SdpAddrType::IP4,
|
||||||
"IP6" => SdpAddrType::IP6,
|
"IP6" => SdpAddrType::IP6,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(SdpParserInternalError::Generic(
|
return Err(SdpParserInternalError::Generic("address type needs to be IP4 or IP6"
|
||||||
"address type needs to be IP4 or IP6".to_string(),
|
.to_string()))
|
||||||
));
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
use error::SdpParserInternalError;
|
||||||
|
use SdpType;
|
||||||
|
|
||||||
|
pub fn parse_repeat(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
// TODO implement this if it's ever needed
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type repeat: {} ", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_repeat_works() {
|
||||||
|
// FIXME use a proper r value here
|
||||||
|
assert!(parse_repeat("0 0").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_zone(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
// TODO implement this if it's ever needed
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type zone: {}", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zone_works() {
|
||||||
|
// FIXME use a proper z value here
|
||||||
|
assert!(parse_zone("0 0").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_key(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
// TODO implement this if it's ever needed
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type key: {}", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_keys_works() {
|
||||||
|
// FIXME use a proper k value here
|
||||||
|
assert!(parse_key("12345").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_information(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type information: {}", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_information_works() {
|
||||||
|
assert!(parse_information("foobar").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_uri(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
// TODO check if this is really a URI
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type uri: {}", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uri_works() {
|
||||||
|
assert!(parse_uri("http://www.mozilla.org").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_email(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
// TODO check if this is really an email address
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type email: {}", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_email_works() {
|
||||||
|
assert!(parse_email("nils@mozilla.com").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_phone(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
||||||
|
// TODO check if this is really a phone number
|
||||||
|
Err(SdpParserInternalError::Unsupported(format!("unsupported type phone: {}", value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_phone_works() {
|
||||||
|
assert!(parse_phone("+123456789").is_err());
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,14 @@
|
||||||
extern crate webrtc_sdp;
|
extern crate rsdparsa;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn check_parse_and_serialize(sdp_str: &str) {
|
|
||||||
let sdp = webrtc_sdp::parse_sdp(sdp_str, true);
|
|
||||||
assert!(sdp.is_ok());
|
|
||||||
assert_eq!(sdp.unwrap().to_string(), sdp_str.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_minimal_sdp() {
|
fn parse_minimal_sdp() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=- 0 0 IN IP4 0.0.0.0\r\n\
|
o=- 0 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
c=IN IP4 0.0.0.0\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n\
|
t=0 0\r\n
|
||||||
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -27,20 +20,14 @@ fn parse_minimal_sdp() {
|
||||||
assert_eq!(sdp.media.len(), 1);
|
assert_eq!(sdp.media.len(), 1);
|
||||||
|
|
||||||
let msection = &(sdp.media[0]);
|
let msection = &(sdp.media[0]);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_type(),
|
||||||
*msection.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Audio);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Audio
|
|
||||||
);
|
|
||||||
assert_eq!(msection.get_port(), 0);
|
assert_eq!(msection.get_port(), 0);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_proto(),
|
||||||
*msection.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
|
||||||
);
|
|
||||||
assert!(msection.get_attributes().is_empty());
|
assert!(msection.get_attributes().is_empty());
|
||||||
assert!(msection.get_bandwidth().is_empty());
|
assert!(msection.get_bandwidth().is_empty());
|
||||||
assert!(msection.get_connection().is_none());
|
assert!(msection.get_connection().is_none());
|
||||||
|
|
||||||
check_parse_and_serialize(sdp_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -53,7 +40,7 @@ s=-\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n
|
c=IN IP4 0.0.0.0\r\n
|
||||||
t=0 0\r\n
|
t=0 0\r\n
|
||||||
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp, false);
|
let sdp_res = rsdparsa::parse_sdp(sdp, false);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -64,17 +51,17 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_minimal_sdp_with_most_session_types() {
|
fn parse_minimal_sdp_with_most_session_types() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=- 0 0 IN IP4 0.0.0.0\r\n\
|
o=- 0 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
t=0 0\r\n
|
||||||
b=AS:1\r\n\
|
b=AS:1\r\n
|
||||||
b=CT:123\r\n\
|
b=CT:123\r\n
|
||||||
b=TIAS:12345\r\n\
|
b=TIAS:12345\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n\
|
c=IN IP4 0.0.0.0\r\n
|
||||||
a=ice-options:trickle\r\n\
|
a=ice-options:trickle\r\n
|
||||||
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, false);
|
let sdp_res = rsdparsa::parse_sdp(sdp, false);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -82,23 +69,21 @@ fn parse_minimal_sdp_with_most_session_types() {
|
||||||
assert_eq!(sdp.version, 0);
|
assert_eq!(sdp.version, 0);
|
||||||
assert_eq!(sdp.session, "-");
|
assert_eq!(sdp.session, "-");
|
||||||
assert!(sdp.get_connection().is_some());
|
assert!(sdp.get_connection().is_some());
|
||||||
|
|
||||||
check_parse_and_serialize(sdp_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_minimal_sdp_with_most_media_types() {
|
fn parse_minimal_sdp_with_most_media_types() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=- 0 0 IN IP4 0.0.0.0\r\n\
|
o=- 0 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
t=0 0\r\n
|
||||||
m=video 0 UDP/TLS/RTP/SAVPF 0\r\n\
|
m=video 0 UDP/TLS/RTP/SAVPF 0\r\n
|
||||||
b=AS:1\r\n\
|
b=AS:1\r\n
|
||||||
b=CT:123\r\n\
|
b=CT:123\r\n
|
||||||
b=TIAS:12345\r\n\
|
b=TIAS:12345\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n\
|
c=IN IP4 0.0.0.0\r\n
|
||||||
a=sendrecv\r\n";
|
a=sendrecv\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, false);
|
let sdp_res = rsdparsa::parse_sdp(sdp, false);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -109,52 +94,44 @@ fn parse_minimal_sdp_with_most_media_types() {
|
||||||
assert_eq!(sdp.media.len(), 1);
|
assert_eq!(sdp.media.len(), 1);
|
||||||
|
|
||||||
let msection = &(sdp.media[0]);
|
let msection = &(sdp.media[0]);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_type(),
|
||||||
*msection.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Video);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Video
|
|
||||||
);
|
|
||||||
assert_eq!(msection.get_port(), 0);
|
assert_eq!(msection.get_port(), 0);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_proto(),
|
||||||
*msection.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
|
||||||
);
|
|
||||||
assert!(!msection.get_bandwidth().is_empty());
|
assert!(!msection.get_bandwidth().is_empty());
|
||||||
assert!(!msection.get_connection().is_none());
|
assert!(!msection.get_connection().is_none());
|
||||||
assert!(!msection.get_attributes().is_empty());
|
assert!(!msection.get_attributes().is_empty());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sendrecv)
|
|
||||||
.is_some());
|
|
||||||
|
|
||||||
check_parse_and_serialize(sdp_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_firefox_audio_offer() {
|
fn parse_firefox_audio_offer() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n\
|
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
t=0 0\r\n
|
||||||
a=fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:BF:2F:E3:91:CB:57:A9:9D:4A:A2:0B:40\r\n\
|
a=fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:BF:2F:E3:91:CB:57:A9:9D:4A:A2:0B:40\r\n
|
||||||
a=group:BUNDLE sdparta_0\r\n\
|
a=group:BUNDLE sdparta_0\r\n
|
||||||
a=ice-options:trickle\r\n\
|
a=ice-options:trickle\r\n
|
||||||
a=msid-semantic:WMS *\r\n\
|
a=msid-semantic:WMS *\r\n
|
||||||
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8\r\n\
|
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n\
|
c=IN IP4 0.0.0.0\r\n
|
||||||
a=sendrecv\r\n\
|
a=sendrecv\r\n
|
||||||
a=extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n\
|
a=extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n
|
||||||
a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\n\
|
a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\n
|
||||||
a=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n\
|
a=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n
|
||||||
a=ice-ufrag:58b99ead\r\n\
|
a=ice-ufrag:58b99ead\r\n
|
||||||
a=mid:sdparta_0\r\n\
|
a=mid:sdparta_0\r\n
|
||||||
a=msid:{5a990edd-0568-ac40-8d97-310fc33f3411} {218cfa1c-617d-2249-9997-60929ce4c405}\r\n\
|
a=msid:{5a990edd-0568-ac40-8d97-310fc33f3411} {218cfa1c-617d-2249-9997-60929ce4c405}\r\n
|
||||||
a=rtcp-mux\r\n\
|
a=rtcp-mux\r\n
|
||||||
a=rtpmap:109 opus/48000/2\r\n\
|
a=rtpmap:109 opus/48000/2\r\n
|
||||||
a=rtpmap:9 G722/8000/1\r\n\
|
a=rtpmap:9 G722/8000/1\r\n
|
||||||
a=rtpmap:0 PCMU/8000\r\n\
|
a=rtpmap:0 PCMU/8000\r\n
|
||||||
a=rtpmap:8 PCMA/8000\r\n\
|
a=rtpmap:8 PCMA/8000\r\n
|
||||||
a=setup:actpass\r\n\
|
a=setup:actpass\r\n
|
||||||
a=ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}\r\n";
|
a=ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -163,94 +140,66 @@ a=ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}\r\n";
|
||||||
assert_eq!(sdp.media.len(), 1);
|
assert_eq!(sdp.media.len(), 1);
|
||||||
|
|
||||||
let msection = &(sdp.media[0]);
|
let msection = &(sdp.media[0]);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_type(),
|
||||||
*msection.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Audio);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Audio
|
|
||||||
);
|
|
||||||
assert_eq!(msection.get_port(), 9);
|
assert_eq!(msection.get_port(), 9);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_proto(),
|
||||||
*msection.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
|
||||||
);
|
|
||||||
assert!(msection.get_connection().is_some());
|
assert!(msection.get_connection().is_some());
|
||||||
assert!(msection.get_bandwidth().is_empty());
|
assert!(msection.get_bandwidth().is_empty());
|
||||||
assert!(!msection.get_attributes().is_empty());
|
assert!(!msection.get_attributes().is_empty());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sendrecv)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Extmap)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Fmtp)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IcePwd)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IceUfrag)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Mid)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Mid)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Msid)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::RtcpMux)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Rtpmap)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Setup)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Ssrc)
|
|
||||||
.is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_firefox_video_offer() {
|
fn parse_firefox_video_offer() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n\
|
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
t=0 0\r\n
|
||||||
a=fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:BF:2F:E3:91:CB:57:A9:9D:4A:A2:0B:40\r\n\
|
a=fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:BF:2F:E3:91:CB:57:A9:9D:4A:A2:0B:40\r\n
|
||||||
a=group:BUNDLE sdparta_2\r\n\
|
a=group:BUNDLE sdparta_2\r\n
|
||||||
a=ice-options:trickle\r\n\
|
a=ice-options:trickle\r\n
|
||||||
a=msid-semantic:WMS *\r\n\
|
a=msid-semantic:WMS *\r\n
|
||||||
m=video 9 UDP/TLS/RTP/SAVPF 126 120 97\r\n\
|
m=video 9 UDP/TLS/RTP/SAVPF 126 120 97\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n\
|
c=IN IP4 0.0.0.0\r\n
|
||||||
a=recvonly\r\n\
|
a=recvonly\r\n
|
||||||
a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1\r\n\
|
a=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1\r\n
|
||||||
a=fmtp:120 max-fs=12288;max-fr=60\r\n\
|
a=fmtp:120 max-fs=12288;max-fr=60\r\n
|
||||||
a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\n\
|
a=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\n
|
||||||
a=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n\
|
a=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n
|
||||||
a=ice-ufrag:58b99ead\r\n\
|
a=ice-ufrag:58b99ead\r\n
|
||||||
a=mid:sdparta_2\r\n\
|
a=mid:sdparta_2\r\n
|
||||||
a=rtcp-fb:126 nack\r\n\
|
a=rtcp-fb:126 nack\r\n
|
||||||
a=rtcp-fb:126 nack pli\r\n\
|
a=rtcp-fb:126 nack pli\r\n
|
||||||
a=rtcp-fb:126 ccm fir\r\n\
|
a=rtcp-fb:126 ccm fir\r\n
|
||||||
a=rtcp-fb:126 goog-remb\r\n\
|
a=rtcp-fb:126 goog-remb\r\n
|
||||||
a=rtcp-fb:120 nack\r\n\
|
a=rtcp-fb:120 nack\r\n
|
||||||
a=rtcp-fb:120 nack pli\r\n\
|
a=rtcp-fb:120 nack pli\r\n
|
||||||
a=rtcp-fb:120 ccm fir\r\n\
|
a=rtcp-fb:120 ccm fir\r\n
|
||||||
a=rtcp-fb:120 goog-remb\r\n\
|
a=rtcp-fb:120 goog-remb\r\n
|
||||||
a=rtcp-fb:97 nack\r\n\
|
a=rtcp-fb:97 nack\r\n
|
||||||
a=rtcp-fb:97 nack pli\r\n\
|
a=rtcp-fb:97 nack pli\r\n
|
||||||
a=rtcp-fb:97 ccm fir\r\n\
|
a=rtcp-fb:97 ccm fir\r\n
|
||||||
a=rtcp-fb:97 goog-remb\r\n\
|
a=rtcp-fb:97 goog-remb\r\n
|
||||||
a=rtcp-mux\r\n\
|
a=rtcp-mux\r\n
|
||||||
a=rtpmap:126 H264/90000\r\n\
|
a=rtpmap:126 H264/90000\r\n
|
||||||
a=rtpmap:120 VP8/90000\r\n\
|
a=rtpmap:120 VP8/90000\r\n
|
||||||
a=rtpmap:97 H264/90000\r\n\
|
a=rtpmap:97 H264/90000\r\n
|
||||||
a=setup:actpass\r\n\
|
a=setup:actpass\r\n
|
||||||
a=ssrc:2709871439 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}";
|
a=ssrc:2709871439 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -259,80 +208,51 @@ a=ssrc:2709871439 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}";
|
||||||
assert_eq!(sdp.media.len(), 1);
|
assert_eq!(sdp.media.len(), 1);
|
||||||
|
|
||||||
let msection = &(sdp.media[0]);
|
let msection = &(sdp.media[0]);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_type(),
|
||||||
*msection.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Video);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Video
|
|
||||||
);
|
|
||||||
assert_eq!(msection.get_port(), 9);
|
assert_eq!(msection.get_port(), 9);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_proto(),
|
||||||
*msection.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
|
||||||
);
|
|
||||||
assert!(msection.get_connection().is_some());
|
assert!(msection.get_connection().is_some());
|
||||||
assert!(msection.get_bandwidth().is_empty());
|
assert!(msection.get_bandwidth().is_empty());
|
||||||
assert!(!msection.get_attributes().is_empty());
|
assert!(!msection.get_attributes().is_empty());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Recvonly).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Recvonly)
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some());
|
||||||
assert!(!msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Extmap)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Fmtp)
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IcePwd)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IceUfrag)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Mid)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Mid)
|
|
||||||
.is_some());
|
|
||||||
assert!(!msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Msid)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Rtcpfb)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::RtcpMux)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Rtpmap)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Setup)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Ssrc)
|
|
||||||
.is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_firefox_datachannel_offer() {
|
fn parse_firefox_datachannel_offer() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=mozilla...THIS_IS_SDPARTA-52.0a2 3327975756663609975 0 IN IP4 0.0.0.0\r\n\
|
o=mozilla...THIS_IS_SDPARTA-52.0a2 3327975756663609975 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
t=0 0\r\n
|
||||||
a=sendrecv\r\n\
|
a=sendrecv\r\n
|
||||||
a=fingerprint:sha-256 AC:72:CB:D6:1E:A3:A3:B0:E7:97:77:25:03:4B:5B:FF:19:6C:02:C6:93:7D:EB:5C:81:6F:36:D9:02:32:F8:23\r\n\
|
a=fingerprint:sha-256 AC:72:CB:D6:1E:A3:A3:B0:E7:97:77:25:03:4B:5B:FF:19:6C:02:C6:93:7D:EB:5C:81:6F:36:D9:02:32:F8:23\r\n
|
||||||
a=ice-options:trickle\r\n\
|
a=ice-options:trickle\r\n
|
||||||
a=msid-semantic:WMS *\r\n\
|
a=msid-semantic:WMS *\r\n
|
||||||
m=application 49760 DTLS/SCTP 5000\r\n\
|
m=application 49760 DTLS/SCTP 5000\r\n
|
||||||
c=IN IP4 172.16.156.106\r\n\
|
c=IN IP4 172.16.156.106\r\n
|
||||||
a=candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ host\r\n\
|
a=candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ host\r\n
|
||||||
a=sendrecv\r\n\
|
a=sendrecv\r\n
|
||||||
a=end-of-candidates\r\n\
|
a=end-of-candidates\r\n
|
||||||
a=ice-pwd:24f485c580129b36447b65df77429a82\r\n\
|
a=ice-pwd:24f485c580129b36447b65df77429a82\r\n
|
||||||
a=ice-ufrag:4cba30fe\r\n\
|
a=ice-ufrag:4cba30fe\r\n
|
||||||
a=mid:sdparta_0\r\n\
|
a=mid:sdparta_0\r\n
|
||||||
a=sctpmap:5000 webrtc-datachannel 256\r\n\
|
a=sctpmap:5000 webrtc-datachannel 256\r\n
|
||||||
a=setup:active\r\n\
|
a=setup:active\r\n
|
||||||
a=ssrc:3376683177 cname:{62f78ee0-620f-a043-86ca-b69f189f1aea}\r\n";
|
a=ssrc:3376683177 cname:{62f78ee0-620f-a043-86ca-b69f189f1aea}\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -341,59 +261,27 @@ fn parse_firefox_datachannel_offer() {
|
||||||
assert_eq!(sdp.media.len(), 1);
|
assert_eq!(sdp.media.len(), 1);
|
||||||
|
|
||||||
let msection = &(sdp.media[0]);
|
let msection = &(sdp.media[0]);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_type(),
|
||||||
*msection.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Application);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Application
|
|
||||||
);
|
|
||||||
assert_eq!(msection.get_port(), 49760);
|
assert_eq!(msection.get_port(), 49760);
|
||||||
assert_eq!(
|
assert_eq!(*msection.get_proto(),
|
||||||
*msection.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::DtlsSctp);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::DtlsSctp
|
|
||||||
);
|
|
||||||
assert!(msection.get_connection().is_some());
|
assert!(msection.get_connection().is_some());
|
||||||
assert!(msection.get_bandwidth().is_empty());
|
assert!(msection.get_bandwidth().is_empty());
|
||||||
assert!(!msection.get_attributes().is_empty());
|
assert!(!msection.get_attributes().is_empty());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sendrecv)
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
|
||||||
assert!(!msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Extmap)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::EndOfCandidates).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||||
assert!(msection
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IcePwd)
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some());
|
||||||
.is_some());
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
|
||||||
assert!(msection
|
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IceUfrag)
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sctpmap).is_some());
|
||||||
.is_some());
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
|
||||||
assert!(msection
|
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::EndOfCandidates)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Mid)
|
|
||||||
.is_some());
|
|
||||||
assert!(!msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Msid)
|
|
||||||
.is_some());
|
|
||||||
assert!(!msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Rtcpfb)
|
|
||||||
.is_some());
|
|
||||||
assert!(!msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::RtcpMux)
|
|
||||||
.is_some());
|
|
||||||
assert!(!msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Rtpmap)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sctpmap)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Setup)
|
|
||||||
.is_some());
|
|
||||||
assert!(msection
|
|
||||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Ssrc)
|
|
||||||
.is_some());
|
|
||||||
|
|
||||||
check_parse_and_serialize(sdp_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -485,7 +373,7 @@ a=ssrc:2673335628 cname:qPTZ+BI+42mgbOi+\r\n
|
||||||
a=ssrc:2673335628 msid:HWpbmTmXleVSnlssQd80bPuw9cxQFroDkkBP b6ec5178-c611-403f-bbec-3833ed547c09\r\n
|
a=ssrc:2673335628 msid:HWpbmTmXleVSnlssQd80bPuw9cxQFroDkkBP b6ec5178-c611-403f-bbec-3833ed547c09\r\n
|
||||||
a=ssrc:2673335628 mslabel:HWpbmTmXleVSnlssQd80bPuw9cxQFroDkkBP\r\n
|
a=ssrc:2673335628 mslabel:HWpbmTmXleVSnlssQd80bPuw9cxQFroDkkBP\r\n
|
||||||
a=ssrc:2673335628 label:b6ec5178-c611-403f-bbec-3833ed547c09\r\n";
|
a=ssrc:2673335628 label:b6ec5178-c611-403f-bbec-3833ed547c09\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -494,29 +382,21 @@ a=ssrc:2673335628 label:b6ec5178-c611-403f-bbec-3833ed547c09\r\n";
|
||||||
assert_eq!(sdp.media.len(), 2);
|
assert_eq!(sdp.media.len(), 2);
|
||||||
|
|
||||||
let msection1 = &(sdp.media[0]);
|
let msection1 = &(sdp.media[0]);
|
||||||
assert_eq!(
|
assert_eq!(*msection1.get_type(),
|
||||||
*msection1.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Audio);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Audio
|
|
||||||
);
|
|
||||||
assert_eq!(msection1.get_port(), 9);
|
assert_eq!(msection1.get_port(), 9);
|
||||||
assert_eq!(
|
assert_eq!(*msection1.get_proto(),
|
||||||
*msection1.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
|
||||||
);
|
|
||||||
assert!(!msection1.get_attributes().is_empty());
|
assert!(!msection1.get_attributes().is_empty());
|
||||||
assert!(msection1.get_connection().is_some());
|
assert!(msection1.get_connection().is_some());
|
||||||
assert!(msection1.get_bandwidth().is_empty());
|
assert!(msection1.get_bandwidth().is_empty());
|
||||||
|
|
||||||
let msection2 = &(sdp.media[1]);
|
let msection2 = &(sdp.media[1]);
|
||||||
assert_eq!(
|
assert_eq!(*msection2.get_type(),
|
||||||
*msection2.get_type(),
|
rsdparsa::media_type::SdpMediaValue::Video);
|
||||||
webrtc_sdp::media_type::SdpMediaValue::Video
|
|
||||||
);
|
|
||||||
assert_eq!(msection2.get_port(), 9);
|
assert_eq!(msection2.get_port(), 9);
|
||||||
assert_eq!(
|
assert_eq!(*msection2.get_proto(),
|
||||||
*msection2.get_proto(),
|
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
|
||||||
);
|
|
||||||
assert!(!msection2.get_attributes().is_empty());
|
assert!(!msection2.get_attributes().is_empty());
|
||||||
assert!(msection2.get_connection().is_some());
|
assert!(msection2.get_connection().is_some());
|
||||||
assert!(msection2.get_bandwidth().is_empty());
|
assert!(msection2.get_bandwidth().is_empty());
|
||||||
|
|
@ -572,7 +452,7 @@ a=setup:actpass\r\n
|
||||||
a=simulcast: send rid=foo;bar\r\n
|
a=simulcast: send rid=foo;bar\r\n
|
||||||
a=ssrc:2988475468 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n
|
a=ssrc:2988475468 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n
|
||||||
a=ssrc:1649784806 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n";
|
a=ssrc:1649784806 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
@ -583,35 +463,35 @@ a=ssrc:1649784806 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_firefox_simulcast_answer() {
|
fn parse_firefox_simulcast_answer() {
|
||||||
let sdp_str = "v=0\r\n\
|
let sdp = "v=0\r\n
|
||||||
o=mozilla...THIS_IS_SDPARTA-55.0a1 7548296603161351381 0 IN IP4 0.0.0.0\r\n\
|
o=mozilla...THIS_IS_SDPARTA-55.0a1 7548296603161351381 0 IN IP4 0.0.0.0\r\n
|
||||||
s=-\r\n\
|
s=-\r\n
|
||||||
t=0 0\r\n\
|
t=0 0\r\n
|
||||||
a=fingerprint:sha-256 B1:47:49:4F:7D:83:03:BE:E9:FC:73:A3:FB:33:38:40:0B:3B:6A:56:78:EB:EE:D5:6D:2D:D5:3A:B6:13:97:E7\r\n\
|
a=fingerprint:sha-256 B1:47:49:4F:7D:83:03:BE:E9:FC:73:A3:FB:33:38:40:0B:3B:6A:56:78:EB:EE:D5:6D:2D:D5:3A:B6:13:97:E7\r\n
|
||||||
a=ice-options:trickle\r\n\
|
a=ice-options:trickle\r\n
|
||||||
a=msid-semantic:WMS *\r\n\
|
a=msid-semantic:WMS *\r\n
|
||||||
m=video 9 UDP/TLS/RTP/SAVPF 120\r\n\
|
m=video 9 UDP/TLS/RTP/SAVPF 120\r\n
|
||||||
c=IN IP4 0.0.0.0\r\n
|
c=IN IP4 0.0.0.0\r\n
|
||||||
a=recvonly\r\n\
|
a=recvonly\r\n
|
||||||
a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n\
|
a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n
|
||||||
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n\
|
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n
|
||||||
a=fmtp:120 max-fs=12288;max-fr=60\r\n\
|
a=fmtp:120 max-fs=12288;max-fr=60\r\n
|
||||||
a=ice-pwd:c886e2caf2ae397446312930cd1afe51\r\n\
|
a=ice-pwd:c886e2caf2ae397446312930cd1afe51\r\n
|
||||||
a=ice-ufrag:f57396c0\r\n\
|
a=ice-ufrag:f57396c0\r\n
|
||||||
a=mid:sdparta_0\r\n\
|
a=mid:sdparta_0\r\n
|
||||||
a=rtcp-fb:120 nack\r\n\
|
a=rtcp-fb:120 nack\r\n
|
||||||
a=rtcp-fb:120 nack pli\r\n\
|
a=rtcp-fb:120 nack pli\r\n
|
||||||
a=rtcp-fb:120 ccm fir\r\n\
|
a=rtcp-fb:120 ccm fir\r\n
|
||||||
a=rtcp-fb:120 goog-remb\r\n\
|
a=rtcp-fb:120 goog-remb\r\n
|
||||||
a=rtcp-mux\r\n\
|
a=rtcp-mux\r\n
|
||||||
a=rtpmap:120 VP8/90000\r\n\
|
a=rtpmap:120 VP8/90000\r\n
|
||||||
a=setup:active\r\n\
|
a=setup:active\r\n
|
||||||
a=ssrc:2564157021 cname:{cae1cd32-7433-5b48-8dc8-8e3f8b2f96cd}\r\n\
|
a=ssrc:2564157021 cname:{cae1cd32-7433-5b48-8dc8-8e3f8b2f96cd}\r\n
|
||||||
a=simulcast: recv rid=foo;bar\r\n\
|
a=simulcast: recv rid=foo;bar\r\n
|
||||||
a=rid:foo recv\r\n\
|
a=rid:foo recv\r\n
|
||||||
a=rid:bar recv\r\n\
|
a=rid:bar recv\r\n
|
||||||
a=extmap:3/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n";
|
a=extmap:3/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n";
|
||||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||||
assert!(sdp_res.is_ok());
|
assert!(sdp_res.is_ok());
|
||||||
let sdp_opt = sdp_res.ok();
|
let sdp_opt = sdp_res.ok();
|
||||||
assert!(sdp_opt.is_some());
|
assert!(sdp_opt.is_some());
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,5 @@ authors = ["Paul Ellenbogen <pe5@cs.princeton.edu>",
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "^0.2.0"
|
libc = "^0.2.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rsdparsa = {package = "webrtc-sdp", version = "0.1.0", path = "../rsdparsa"}
|
rsdparsa = {version = "0.1.0", path = "../rsdparsa"}
|
||||||
nserror = { path = "../../../../../../xpcom/rust/nserror" }
|
nserror = { path = "../../../../../../xpcom/rust/nserror" }
|
||||||
|
|
|
||||||
|
|
@ -1076,7 +1076,7 @@ pub unsafe extern "C" fn sdp_get_candidates(attributes: *const Vec<SdpAttribute>
|
||||||
let attr_strings: Vec<String> = (*attributes).iter().filter_map( |x| {
|
let attr_strings: Vec<String> = (*attributes).iter().filter_map( |x| {
|
||||||
if let SdpAttribute::Candidate(ref attr) = *x {
|
if let SdpAttribute::Candidate(ref attr) = *x {
|
||||||
// The serialized attribute starts with "candidate:...", this needs to be removed
|
// The serialized attribute starts with "candidate:...", this needs to be removed
|
||||||
Some(attr.to_string())
|
Some(attr.to_string()[10..].to_string())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,10 @@ pub unsafe extern "C" fn parse_sdp(sdp: StringView,
|
||||||
|
|
||||||
let parser_result = rsdparsa::parse_sdp(&sdp_str, fail_on_warning);
|
let parser_result = rsdparsa::parse_sdp(&sdp_str, fail_on_warning);
|
||||||
match parser_result {
|
match parser_result {
|
||||||
Ok(mut parsed) => {
|
Ok(parsed) => {
|
||||||
*error = match parsed.warnings.len(){
|
*error = match parsed.warnings.len(){
|
||||||
0 => ptr::null(),
|
0 => ptr::null(),
|
||||||
_ => Box::into_raw(Box::new(parsed.warnings.remove(0))),
|
_ => Box::into_raw(Box::new(parsed.warnings[0].clone())),
|
||||||
};
|
};
|
||||||
*session = Rc::into_raw(Rc::new(parsed));
|
*session = Rc::into_raw(Rc::new(parsed));
|
||||||
NS_OK
|
NS_OK
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,6 @@ pub enum RustSdpProtocolValue {
|
||||||
DtlsSctp,
|
DtlsSctp,
|
||||||
UdpDtlsSctp,
|
UdpDtlsSctp,
|
||||||
TcpDtlsSctp,
|
TcpDtlsSctp,
|
||||||
RtpAvp,
|
|
||||||
RtpAvpf,
|
|
||||||
RtpSavp,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue {
|
impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue {
|
||||||
|
|
@ -73,9 +70,6 @@ impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue {
|
||||||
SdpProtocolValue::DtlsSctp => RustSdpProtocolValue::DtlsSctp,
|
SdpProtocolValue::DtlsSctp => RustSdpProtocolValue::DtlsSctp,
|
||||||
SdpProtocolValue::UdpDtlsSctp => RustSdpProtocolValue::UdpDtlsSctp,
|
SdpProtocolValue::UdpDtlsSctp => RustSdpProtocolValue::UdpDtlsSctp,
|
||||||
SdpProtocolValue::TcpDtlsSctp => RustSdpProtocolValue::TcpDtlsSctp,
|
SdpProtocolValue::TcpDtlsSctp => RustSdpProtocolValue::TcpDtlsSctp,
|
||||||
SdpProtocolValue::RtpAvp => RustSdpProtocolValue::RtpAvp,
|
|
||||||
SdpProtocolValue::RtpAvpf => RustSdpProtocolValue::RtpAvpf,
|
|
||||||
SdpProtocolValue::RtpSavp => RustSdpProtocolValue::RtpSavp,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue