зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1553011 - update import of Rust SDP parser - r=drno
update import of Rust SDP parser Differential Revision: https://phabricator.services.mozilla.com/D31943 --HG-- rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/10.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/10.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/11.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/11.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/12.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/12.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/13.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/13.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/14.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/14.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/15.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/15.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/16.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/16.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/17.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/17.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/18.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/18.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/19.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/19.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/2.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/2.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/20.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/20.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/21.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/21.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/22.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/22.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/23.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/23.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/24.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/24.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/25.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/25.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/26.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/26.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/27.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/27.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/28.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/28.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/29.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/29.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/3.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/3.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/30.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/30.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/31.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/31.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/32.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/32.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/33.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/33.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/34.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/34.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/34.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/35.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/34.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/36.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/37.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/37.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/38.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/38.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/39.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/39.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/4.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/4.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/39.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/40.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/41.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/41.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/5.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/5.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/6.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/6.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/7.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/7.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/8.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/8.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/9.sdp => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/9.sdp rename : media/webrtc/signaling/src/sdp/rsdparsa/src/bin/sdps/extract.sh => media/webrtc/signaling/src/sdp/rsdparsa/examples/sdps/extract.sh extra : moz-landing-system : lando
This commit is contained in:
Родитель
48132a691b
Коммит
5ba5af588b
|
@ -60,6 +60,9 @@ enum class RustSdpProtocolValue {
|
|||
kRustDtlsSctp,
|
||||
kRustUdpDtlsSctp,
|
||||
kRustTcpDtlsSctp,
|
||||
kRustRtpAvp,
|
||||
kRustRtpAvpf,
|
||||
kRustRtpSavp,
|
||||
};
|
||||
|
||||
enum class RustSdpFormatType { kRustIntegers, kRustStrings };
|
||||
|
|
|
@ -77,8 +77,13 @@ SdpMediaSection::Protocol RsdparsaSdpMediaSection::GetProtocol() const {
|
|||
return kUdpDtlsSctp;
|
||||
case RustSdpProtocolValue::kRustTcpDtlsSctp:
|
||||
return kTcpDtlsSctp;
|
||||
case RustSdpProtocolValue::kRustRtpAvp:
|
||||
return kRtpAvp;
|
||||
case RustSdpProtocolValue::kRustRtpAvpf:
|
||||
return kRtpAvpf;
|
||||
case RustSdpProtocolValue::kRustRtpSavp:
|
||||
return kRtpSavp;
|
||||
}
|
||||
|
||||
MOZ_CRASH("invalid media protocol");
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,11 @@ cache: cargo
|
|||
sudo: true
|
||||
os:
|
||||
- linux
|
||||
# Taken out temporarily because it's to slow
|
||||
# - osx
|
||||
- osx
|
||||
|
||||
env:
|
||||
- FEATURES=""
|
||||
- FEATURES="serialize"
|
||||
rust:
|
||||
- nightly
|
||||
- beta
|
||||
|
@ -17,13 +19,12 @@ matrix:
|
|||
allow_failures:
|
||||
- rust: nightly
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcurl4-openssl-dev
|
||||
- zlib1g-dev
|
||||
- libiberty-dev
|
||||
- libelf-dev
|
||||
- libdw-dev
|
||||
- cmake
|
||||
|
@ -34,34 +35,46 @@ addons:
|
|||
before_script:
|
||||
- export PATH=$PATH:~/.cargo/bin
|
||||
- |
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
|
||||
cargo install --force clippy;
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
||||
rustup component add rustfmt-preview
|
||||
rustup component add clippy
|
||||
fi
|
||||
|
||||
script:
|
||||
- cargo build --verbose --all
|
||||
- echo FEATURES="$FEATURES"
|
||||
- |
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "nightly" &&
|
||||
-f ~/.cargo/bin/cargo-clippy ]]; then
|
||||
cargo clippy;
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
||||
cargo fmt --all -- --check
|
||||
fi
|
||||
- cargo test --verbose --all
|
||||
- cargo build --verbose --all --features="$FEATURES"
|
||||
- |
|
||||
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:
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then
|
||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
||||
tar xzf master.tar.gz &&
|
||||
cd kcov-master &&
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" && "$FEATURES" == "serialize" ]]; then
|
||||
wget https://github.com/SimonKagstrom/kcov/archive/v34.tar.gz &&
|
||||
tar xzf v34.tar.gz &&
|
||||
cd kcov-34 &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake .. &&
|
||||
make &&
|
||||
sudo make install &&
|
||||
cd ../.. &&
|
||||
rm -rf kcov-master &&
|
||||
rm -rf kcov-34 &&
|
||||
kcov --version &&
|
||||
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 &&
|
||||
(cd target/debug/ && ls -al) &&
|
||||
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 &&
|
||||
bash <(curl -s https://codecov.io/bash) &&
|
||||
echo "Uploaded code coverage"
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
[package]
|
||||
name = "rsdparsa"
|
||||
name = "webrtc-sdp"
|
||||
version = "0.1.0"
|
||||
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]
|
||||
default = []
|
||||
|
@ -9,10 +19,9 @@ default = []
|
|||
serialize = ["serde", "serde_derive"]
|
||||
|
||||
[dependencies]
|
||||
# clippy = {version = "*", optional = true}
|
||||
log = "0.4"
|
||||
log = {version = "0.4.6"}
|
||||
serde = {version = "1.0" , optional = true}
|
||||
serde_derive = {version = "1.0" , optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
# serde_json = {version = "1.0"}
|
||||
serde_json = {version = "1.0"}
|
||||
|
|
|
@ -1,13 +1,61 @@
|
|||
# rsdparsa
|
||||
# webrtc-sdp
|
||||
|
||||
[![Crates.io](https://img.shields.io/crates/v/webrtc-sdp.svg)](https://crates.io/crates/webrtc-sdp)
|
||||
[![Build Status](https://travis-ci.org/nils-ohlmeier/rsdparsa.svg?branch=master)](https://travis-ci.org/nils-ohlmeier/rsdparsa)
|
||||
[![Codecov coverage status](https://codecov.io/gh/nils-ohlmeier/rsdparsa/branch/master/graph/badge.svg)](https://codecov.io/gh/nils-ohlmeier/rsdparsa)
|
||||
[![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](#License)
|
||||
[![dependency status](https://deps.rs/repo/github/nils-ohlmeier/rsdparsa/status.svg)](https://deps.rs/repo/github/nils-ohlmeier/rsdparsa)
|
||||
|
||||
A SDP parser written in Rust specifically aimed for WebRTC
|
||||
A SDP parser written in Rust specifically aimed to handle WebRTC SDP offers and answers.
|
||||
|
||||
Requires minimum Rust 1.17
|
||||
## Dependecies
|
||||
|
||||
* 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
|
||||
|
||||
Licensed under [MPL](https://www.mozilla.org/MPL/2.0/).
|
||||
Licensed under [MPL-2.0](https://www.mozilla.org/MPL/2.0/)
|
||||
|
|
|
@ -1,35 +1,31 @@
|
|||
use std::error::Error;
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::env;
|
||||
extern crate rsdparsa;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
extern crate webrtc_sdp;
|
||||
|
||||
fn main() {
|
||||
let filename = match env::args().nth(1) {
|
||||
None => {
|
||||
println!("Missing file name argument!");
|
||||
return;
|
||||
},
|
||||
}
|
||||
Some(x) => x,
|
||||
};
|
||||
let path = Path::new(filename.as_str());
|
||||
let display = path.display();
|
||||
|
||||
let mut file = match File::open(&path) {
|
||||
Err(why) => panic!("Failed to open {}: {}",
|
||||
display,
|
||||
why.description()),
|
||||
Ok(file) => file
|
||||
Err(why) => panic!("Failed to open {}: {}", display, why.description()),
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
let mut s = String::new();
|
||||
match file.read_to_string(&mut s) {
|
||||
Err(why) => panic!("couldn't read {}: {}",
|
||||
display,
|
||||
why.description()),
|
||||
Ok(s) => s
|
||||
Err(why) => panic!("couldn't read {}: {}", display, why.description()),
|
||||
Ok(s) => s,
|
||||
};
|
||||
|
||||
rsdparsa::parse_sdp(&s, true).is_ok();
|
||||
webrtc_sdp::parse_sdp(&s, true).is_ok();
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,14 +1,13 @@
|
|||
use std::num::ParseIntError;
|
||||
use std::num::ParseFloatError;
|
||||
use std::net::AddrParseError;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
use std::error;
|
||||
use std::error::Error;
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::ser::{Serializer, Serialize, SerializeStruct};
|
||||
use std::fmt;
|
||||
use std::net::AddrParseError;
|
||||
use std::num::ParseFloatError;
|
||||
use std::num::ParseIntError;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum SdpParserInternalError {
|
||||
Generic(String),
|
||||
Unsupported(String),
|
||||
|
@ -42,8 +41,8 @@ impl fmt::Display for SdpParserInternalError {
|
|||
impl error::Error for SdpParserInternalError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
SdpParserInternalError::Generic(ref message) |
|
||||
SdpParserInternalError::Unsupported(ref message) => message,
|
||||
SdpParserInternalError::Generic(ref message)
|
||||
| SdpParserInternalError::Unsupported(ref message) => message,
|
||||
SdpParserInternalError::Integer(ref error) => error.description(),
|
||||
SdpParserInternalError::Float(ref error) => error.description(),
|
||||
SdpParserInternalError::Address(ref error) => error.description(),
|
||||
|
@ -62,51 +61,63 @@ impl error::Error for SdpParserInternalError {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_internal_error_generic() {
|
||||
let generic = SdpParserInternalError::Generic("generic message".to_string());
|
||||
assert_eq!(format!("{}", generic),
|
||||
"Generic parsing error: generic message");
|
||||
assert_eq!(
|
||||
format!("{}", generic),
|
||||
"Generic parsing error: generic message"
|
||||
);
|
||||
assert_eq!(generic.description(), "generic message");
|
||||
assert!(generic.cause().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_internal_error_unsupported() {
|
||||
let unsupported = SdpParserInternalError::Unsupported("unsupported internal message"
|
||||
.to_string());
|
||||
assert_eq!(format!("{}", unsupported),
|
||||
"Unsupported parsing error: unsupported internal message");
|
||||
let unsupported =
|
||||
SdpParserInternalError::Unsupported("unsupported internal message".to_string());
|
||||
assert_eq!(
|
||||
format!("{}", unsupported),
|
||||
"Unsupported parsing error: unsupported internal message"
|
||||
);
|
||||
assert_eq!(unsupported.description(), "unsupported internal message");
|
||||
assert!(unsupported.cause().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_internal_error_integer() {
|
||||
let v = "12a";
|
||||
let integer = v.parse::<u64>();
|
||||
assert!(integer.is_err());
|
||||
let int_err = SdpParserInternalError::Integer(integer.err().unwrap());
|
||||
assert_eq!(format!("{}", int_err),
|
||||
"Integer parsing error: invalid digit found in string");
|
||||
assert_eq!(
|
||||
format!("{}", int_err),
|
||||
"Integer parsing error: invalid digit found in string"
|
||||
);
|
||||
assert_eq!(int_err.description(), "invalid digit found in string");
|
||||
assert!(!int_err.cause().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_internal_error_address() {
|
||||
let v = "127.0.0.a";
|
||||
use std::str::FromStr;
|
||||
use std::net::IpAddr;
|
||||
use std::str::FromStr;
|
||||
let addr = IpAddr::from_str(v);
|
||||
assert!(addr.is_err());
|
||||
let addr_err = SdpParserInternalError::Address(addr.err().unwrap());
|
||||
assert_eq!(format!("{}", addr_err),
|
||||
"IP address parsing error: invalid IP address syntax");
|
||||
assert_eq!(
|
||||
format!("{}", addr_err),
|
||||
"IP address parsing error: invalid IP address syntax"
|
||||
);
|
||||
assert_eq!(addr_err.description(), "invalid IP address syntax");
|
||||
assert!(!addr_err.cause().is_none());
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum SdpParserError {
|
||||
Line {
|
||||
error: SdpParserInternalError,
|
||||
|
@ -118,37 +129,57 @@ pub enum SdpParserError {
|
|||
line: String,
|
||||
line_number: usize,
|
||||
},
|
||||
Sequence { message: String, line_number: usize },
|
||||
Sequence {
|
||||
message: String,
|
||||
line_number: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl Serialize for SdpParserError {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
let mut state = serializer.serialize_struct("error", match self {
|
||||
&SdpParserError::Sequence{..} => 3,
|
||||
_ => 4
|
||||
})?;
|
||||
match self {
|
||||
&SdpParserError::Line {ref error, ref line, ..} => {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct(
|
||||
"error",
|
||||
match *self {
|
||||
SdpParserError::Sequence { .. } => 3,
|
||||
_ => 4,
|
||||
},
|
||||
)?;
|
||||
match *self {
|
||||
SdpParserError::Line {
|
||||
ref error,
|
||||
ref line,
|
||||
..
|
||||
} => {
|
||||
state.serialize_field("type", "Line")?;
|
||||
state.serialize_field("message", &format!("{}", error))?;
|
||||
state.serialize_field("line", &line)?
|
||||
},
|
||||
&SdpParserError::Unsupported {ref error, ref line, ..} => {
|
||||
}
|
||||
SdpParserError::Unsupported {
|
||||
ref error,
|
||||
ref line,
|
||||
..
|
||||
} => {
|
||||
state.serialize_field("type", "Unsupported")?;
|
||||
state.serialize_field("message", &format!("{}", error))?;
|
||||
state.serialize_field("line", &line)?
|
||||
},
|
||||
&SdpParserError::Sequence {ref message, ..} => {
|
||||
}
|
||||
SdpParserError::Sequence { ref message, .. } => {
|
||||
state.serialize_field("type", "Sequence")?;
|
||||
state.serialize_field("message", &message)?;
|
||||
}
|
||||
};
|
||||
state.serialize_field("line_number", &match self {
|
||||
&SdpParserError::Line {line_number, ..} => line_number,
|
||||
&SdpParserError::Unsupported {line_number, ..} => line_number,
|
||||
&SdpParserError::Sequence {line_number, ..} => line_number,
|
||||
})?;
|
||||
state.serialize_field(
|
||||
"line_number",
|
||||
&match *self {
|
||||
SdpParserError::Line { line_number, .. } => line_number,
|
||||
SdpParserError::Unsupported { line_number, .. } => line_number,
|
||||
SdpParserError::Sequence { line_number, .. } => line_number,
|
||||
},
|
||||
)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
@ -160,24 +191,24 @@ impl fmt::Display for SdpParserError {
|
|||
ref error,
|
||||
ref line,
|
||||
ref line_number,
|
||||
} => {
|
||||
write!(f,
|
||||
"Line error: {} in line({}): {}",
|
||||
error.description(),
|
||||
line_number,
|
||||
line)
|
||||
}
|
||||
} => write!(
|
||||
f,
|
||||
"Line error: {} in line({}): {}",
|
||||
error.description(),
|
||||
line_number,
|
||||
line
|
||||
),
|
||||
SdpParserError::Unsupported {
|
||||
ref error,
|
||||
ref line,
|
||||
ref line_number,
|
||||
} => {
|
||||
write!(f,
|
||||
"Unsupported: {} in line({}): {}",
|
||||
error.description(),
|
||||
line_number,
|
||||
line)
|
||||
}
|
||||
} => write!(
|
||||
f,
|
||||
"Unsupported: {} in line({}): {}",
|
||||
error.description(),
|
||||
line_number,
|
||||
line
|
||||
),
|
||||
SdpParserError::Sequence {
|
||||
ref message,
|
||||
ref line_number,
|
||||
|
@ -186,20 +217,19 @@ impl fmt::Display for SdpParserError {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl error::Error for SdpParserError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
SdpParserError::Line { ref error, .. } |
|
||||
SdpParserError::Unsupported { ref error, .. } => error.description(),
|
||||
SdpParserError::Line { ref error, .. }
|
||||
| SdpParserError::Unsupported { ref error, .. } => error.description(),
|
||||
SdpParserError::Sequence { ref message, .. } => message,
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
SdpParserError::Line { ref error, .. } |
|
||||
SdpParserError::Unsupported { ref error, .. } => Some(error),
|
||||
SdpParserError::Line { ref error, .. }
|
||||
| SdpParserError::Unsupported { ref error, .. } => Some(error),
|
||||
// Can't tell much more about our internal errors
|
||||
_ => None,
|
||||
}
|
||||
|
@ -225,39 +255,48 @@ impl From<ParseFloatError> for SdpParserInternalError {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_error_line() {
|
||||
let line1 = SdpParserError::Line {
|
||||
error: SdpParserInternalError::Generic("test message".to_string()),
|
||||
line: "test line".to_string(),
|
||||
line_number: 13,
|
||||
};
|
||||
assert_eq!(format!("{}", line1),
|
||||
"Line error: test message in line(13): test line");
|
||||
assert_eq!(
|
||||
format!("{}", line1),
|
||||
"Line error: test message in line(13): test line"
|
||||
);
|
||||
assert_eq!(line1.description(), "test message");
|
||||
assert!(line1.cause().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_error_unsupported() {
|
||||
let unsupported1 = SdpParserError::Unsupported {
|
||||
error: SdpParserInternalError::Generic("unsupported value".to_string()),
|
||||
line: "unsupported line".to_string(),
|
||||
line_number: 21,
|
||||
};
|
||||
assert_eq!(format!("{}", unsupported1),
|
||||
"Unsupported: unsupported value in line(21): unsupported line");
|
||||
assert_eq!(
|
||||
format!("{}", unsupported1),
|
||||
"Unsupported: unsupported value in line(21): unsupported line"
|
||||
);
|
||||
assert_eq!(unsupported1.description(), "unsupported value");
|
||||
assert!(unsupported1.cause().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)] // see issue #102
|
||||
fn test_sdp_parser_error_sequence() {
|
||||
let sequence1 = SdpParserError::Sequence {
|
||||
message: "sequence message".to_string(),
|
||||
line_number: 42,
|
||||
};
|
||||
assert_eq!(format!("{}", sequence1),
|
||||
"Sequence error in line(42): sequence message");
|
||||
assert_eq!(
|
||||
format!("{}", sequence1),
|
||||
"Sequence error in line(42): sequence message"
|
||||
);
|
||||
assert_eq!(sequence1.description(), "sequence message");
|
||||
assert!(sequence1.cause().is_none());
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,10 +1,10 @@
|
|||
use std::fmt;
|
||||
use {SdpType, SdpLine, SdpBandwidth, SdpConnection};
|
||||
use attribute_type::{SdpAttribute, SdpAttributeType, SdpAttributeRtpmap, SdpAttributeSctpmap};
|
||||
use attribute_type::{
|
||||
maybe_print_param, SdpAttribute, SdpAttributeRtpmap, SdpAttributeSctpmap, SdpAttributeType,
|
||||
};
|
||||
use error::{SdpParserError, SdpParserInternalError};
|
||||
use {SdpBandwidth, SdpConnection, SdpLine, SdpType};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
pub struct SdpMediaLine {
|
||||
pub media: SdpMediaValue,
|
||||
pub port: u32,
|
||||
|
@ -13,73 +13,91 @@ pub struct SdpMediaLine {
|
|||
pub formats: SdpFormatList,
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||
impl ToString for SdpMediaLine {
|
||||
fn to_string(&self) -> String {
|
||||
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 {
|
||||
Audio,
|
||||
Video,
|
||||
Application,
|
||||
}
|
||||
|
||||
impl fmt::Display for SdpMediaValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let printable = match *self {
|
||||
SdpMediaValue::Audio => "Audio",
|
||||
SdpMediaValue::Video => "Video",
|
||||
SdpMediaValue::Application => "Application",
|
||||
};
|
||||
write!(f, "{}", printable)
|
||||
impl ToString for SdpMediaValue {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
SdpMediaValue::Audio => "audio",
|
||||
SdpMediaValue::Video => "video",
|
||||
SdpMediaValue::Application => "application",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
pub enum SdpProtocolValue {
|
||||
RtpAvp,
|
||||
RtpAvpf,
|
||||
RtpSavp,
|
||||
RtpSavpf,
|
||||
UdpTlsRtpSavp,
|
||||
TcpDtlsRtpSavp,
|
||||
UdpTlsRtpSavpf,
|
||||
TcpTlsRtpSavpf,
|
||||
TcpDtlsRtpSavpf,
|
||||
UdpTlsRtpSavp,
|
||||
UdpTlsRtpSavpf,
|
||||
DtlsSctp,
|
||||
UdpDtlsSctp,
|
||||
TcpDtlsSctp,
|
||||
TcpTlsRtpSavpf, /* not standardized - to be removed */
|
||||
}
|
||||
|
||||
impl fmt::Display for SdpProtocolValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let printable = match *self {
|
||||
SdpProtocolValue::RtpSavpf => "Rtp/Savpf",
|
||||
SdpProtocolValue::UdpTlsRtpSavp => "Udp/Tls/Rtp/Savp",
|
||||
SdpProtocolValue::TcpDtlsRtpSavp => "Tcp/Dtls/Rtp/Savp",
|
||||
SdpProtocolValue::UdpTlsRtpSavpf => "Udp/Tls/Rtp/Savpf",
|
||||
SdpProtocolValue::TcpTlsRtpSavpf => "Tcp/Tls/Rtp/Savpf",
|
||||
SdpProtocolValue::TcpDtlsRtpSavpf => "Tcp/Dtls/Rtp/Savpf",
|
||||
SdpProtocolValue::DtlsSctp => "Dtls/Sctp",
|
||||
SdpProtocolValue::UdpDtlsSctp => "Udp/Dtls/Sctp",
|
||||
SdpProtocolValue::TcpDtlsSctp => "Tcp/Dtls/Sctp",
|
||||
};
|
||||
write!(f, "{}", printable)
|
||||
impl ToString for SdpProtocolValue {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
SdpProtocolValue::RtpAvp => "RTP/AVP",
|
||||
SdpProtocolValue::RtpAvpf => "RTP/AVPF",
|
||||
SdpProtocolValue::RtpSavp => "RTP/SAVP",
|
||||
SdpProtocolValue::RtpSavpf => "RTP/SAVPF",
|
||||
SdpProtocolValue::TcpDtlsRtpSavp => "TCP/DTLS/RTP/SAVP",
|
||||
SdpProtocolValue::TcpDtlsRtpSavpf => "TCP/DTLS/RTP/SAVPF",
|
||||
SdpProtocolValue::UdpTlsRtpSavp => "UDP/TLS/RTP/SAVP",
|
||||
SdpProtocolValue::UdpTlsRtpSavpf => "UDP/TLS/RTP/SAVPF",
|
||||
SdpProtocolValue::DtlsSctp => "DTLS/SCTP",
|
||||
SdpProtocolValue::UdpDtlsSctp => "UDP/DTLS/SCTP",
|
||||
SdpProtocolValue::TcpDtlsSctp => "TCP/DTLS/SCTP",
|
||||
SdpProtocolValue::TcpTlsRtpSavpf => "TCP/TLS/RTP/SAVPF",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
pub enum SdpFormatList {
|
||||
Integers(Vec<u32>),
|
||||
Strings(Vec<String>),
|
||||
}
|
||||
|
||||
impl fmt::Display for SdpFormatList {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl ToString for SdpFormatList {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
SdpFormatList::Integers(ref x) => write!(f, "{:?}", x),
|
||||
SdpFormatList::Strings(ref x) => write!(f, "{:?}", x),
|
||||
SdpFormatList::Integers(ref x) => maybe_vector_to_string!("{}", x, " "),
|
||||
SdpFormatList::Strings(ref x) => x.join(" "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="serialize", derive(Serialize))]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize))]
|
||||
pub struct SdpMedia {
|
||||
media: SdpMediaLine,
|
||||
connection: Option<SdpConnection>,
|
||||
|
@ -128,109 +146,136 @@ impl SdpMedia {
|
|||
&self.bandwidth
|
||||
}
|
||||
|
||||
pub fn add_bandwidth(&mut self, bw: &SdpBandwidth) {
|
||||
self.bandwidth.push(bw.clone())
|
||||
pub fn add_bandwidth(&mut self, bw: SdpBandwidth) {
|
||||
self.bandwidth.push(bw)
|
||||
}
|
||||
|
||||
pub fn get_attributes(&self) -> &Vec<SdpAttribute> {
|
||||
&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() {
|
||||
return Err(SdpParserInternalError::Generic(format!("{} not allowed at media level",
|
||||
attr)));
|
||||
return Err(SdpParserInternalError::Generic(format!(
|
||||
"{} not allowed at media level",
|
||||
attr.to_string()
|
||||
)));
|
||||
}
|
||||
Ok(self.attribute.push(attr.clone()))
|
||||
self.attribute.push(attr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_attribute(&self, t: SdpAttributeType) -> Option<&SdpAttribute> {
|
||||
self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next()
|
||||
self.attribute
|
||||
.iter()
|
||||
.find(|a| SdpAttributeType::from(*a) == t)
|
||||
}
|
||||
|
||||
pub fn remove_attribute(&mut self, t: SdpAttributeType) {
|
||||
self.attribute.retain(|a| SdpAttributeType::from(a) != t);
|
||||
}
|
||||
|
||||
pub fn set_attribute(&mut self, attr: &SdpAttribute) -> Result<(), SdpParserInternalError> {
|
||||
self.remove_attribute(SdpAttributeType::from(attr));
|
||||
pub fn set_attribute(&mut self, attr: SdpAttribute) -> Result<(), SdpParserInternalError> {
|
||||
self.remove_attribute(SdpAttributeType::from(&attr));
|
||||
self.add_attribute(attr)
|
||||
}
|
||||
|
||||
pub fn remove_codecs(&mut self) {
|
||||
match self.media.formats{
|
||||
match self.media.formats {
|
||||
SdpFormatList::Integers(_) => self.media.formats = SdpFormatList::Integers(Vec::new()),
|
||||
SdpFormatList::Strings(_) => self.media.formats = SdpFormatList::Strings(Vec::new()),
|
||||
}
|
||||
|
||||
self.attribute.retain({|x|
|
||||
match x {
|
||||
&SdpAttribute::Rtpmap(_) |
|
||||
&SdpAttribute::Fmtp(_) |
|
||||
&SdpAttribute::Rtcpfb(_) |
|
||||
&SdpAttribute::Sctpmap(_) => false,
|
||||
_ => true
|
||||
self.attribute.retain({
|
||||
|x| match *x {
|
||||
SdpAttribute::Rtpmap(_)
|
||||
| SdpAttribute::Fmtp(_)
|
||||
| SdpAttribute::Rtcpfb(_)
|
||||
| SdpAttribute::Sctpmap(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn add_codec(&mut self, rtpmap: SdpAttributeRtpmap) -> Result<(),SdpParserInternalError> {
|
||||
match self.media.formats {
|
||||
SdpFormatList::Integers(ref mut x) => x.push(rtpmap.payload_type as u32),
|
||||
SdpFormatList::Strings(ref mut x) => x.push(rtpmap.payload_type.to_string()),
|
||||
}
|
||||
pub fn add_codec(&mut self, rtpmap: SdpAttributeRtpmap) -> Result<(), SdpParserInternalError> {
|
||||
match self.media.formats {
|
||||
SdpFormatList::Integers(ref mut x) => x.push(u32::from(rtpmap.payload_type)),
|
||||
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(())
|
||||
}
|
||||
|
||||
pub fn get_attributes_of_type(&self, t: SdpAttributeType) -> Vec<&SdpAttribute> {
|
||||
self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).collect()
|
||||
self.attribute
|
||||
.iter()
|
||||
.filter(|a| SdpAttributeType::from(*a) == t)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_connection(&self) -> &Option<SdpConnection> {
|
||||
&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() {
|
||||
return Err(SdpParserInternalError::Generic("connection type already exists at this media level"
|
||||
.to_string(),
|
||||
));
|
||||
return Err(SdpParserInternalError::Generic(
|
||||
"connection type already exists at this media level".to_string(),
|
||||
));
|
||||
}
|
||||
Ok(self.connection = Some(c.clone()))
|
||||
self.connection = Some(c);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_datachannel(&mut self, name: String, port: u16, streams: u16, msg_size:u32)
|
||||
-> Result<(),SdpParserInternalError> {
|
||||
// Only one allowed, for now. This may change as the specs (and deployments) evolve.
|
||||
pub fn add_datachannel(
|
||||
&mut self,
|
||||
name: String,
|
||||
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 {
|
||||
SdpProtocolValue::UdpDtlsSctp |
|
||||
SdpProtocolValue::TcpDtlsSctp => {
|
||||
SdpProtocolValue::UdpDtlsSctp | SdpProtocolValue::TcpDtlsSctp => {
|
||||
// new data channel format according to draft 21
|
||||
self.media.formats = SdpFormatList::Strings(vec![name]);
|
||||
self.set_attribute(&SdpAttribute::SctpPort(port as u64))?;
|
||||
self.set_attribute(SdpAttribute::SctpPort(u64::from(port)))?;
|
||||
}
|
||||
_ => {
|
||||
// old data channels format according to draft 05
|
||||
self.media.formats = SdpFormatList::Integers(vec![port as u32]);
|
||||
self.set_attribute(&SdpAttribute::Sctpmap(SdpAttributeSctpmap {
|
||||
self.media.formats = SdpFormatList::Integers(vec![u32::from(port)]);
|
||||
self.set_attribute(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
|
||||
port,
|
||||
channels: streams as u32,
|
||||
channels: u32::from(streams),
|
||||
}))?;
|
||||
}
|
||||
}
|
||||
|
||||
if msg_size > 0 {
|
||||
self.set_attribute(&SdpAttribute::MaxMessageSize(msg_size as u64))?;
|
||||
self.set_attribute(SdpAttribute::MaxMessageSize(u64::from(msg_size)))?;
|
||||
}
|
||||
|
||||
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_attr(feature="serialize", derive(Serialize))]
|
||||
pub fn create_dummy_media_section() -> SdpMedia {
|
||||
let media_line = SdpMediaLine {
|
||||
media: SdpMediaValue::Audio,
|
||||
|
@ -244,14 +289,16 @@ pub fn create_dummy_media_section() -> SdpMedia {
|
|||
|
||||
fn parse_media_token(value: &str) -> Result<SdpMediaValue, SdpParserInternalError> {
|
||||
Ok(match value.to_lowercase().as_ref() {
|
||||
"audio" => SdpMediaValue::Audio,
|
||||
"video" => SdpMediaValue::Video,
|
||||
"application" => SdpMediaValue::Application,
|
||||
_ => {
|
||||
return Err(SdpParserInternalError::Unsupported(format!("unsupported media value: {}",
|
||||
value)))
|
||||
}
|
||||
})
|
||||
"audio" => SdpMediaValue::Audio,
|
||||
"video" => SdpMediaValue::Video,
|
||||
"application" => SdpMediaValue::Application,
|
||||
_ => {
|
||||
return Err(SdpParserInternalError::Unsupported(format!(
|
||||
"unsupported media value: {}",
|
||||
value
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -270,44 +317,66 @@ fn test_parse_media_token() {
|
|||
assert!(parse_media_token("foobar").is_err());
|
||||
}
|
||||
|
||||
|
||||
fn parse_protocol_token(value: &str) -> Result<SdpProtocolValue, SdpParserInternalError> {
|
||||
Ok(match value.to_uppercase().as_ref() {
|
||||
"RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
|
||||
"UDP/TLS/RTP/SAVP" => SdpProtocolValue::UdpTlsRtpSavp,
|
||||
"TCP/DTLS/RTP/SAVP" => SdpProtocolValue::TcpDtlsRtpSavp,
|
||||
"TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
|
||||
"TCP/DTLS/RTP/SAVPF" => SdpProtocolValue::TcpDtlsRtpSavpf,
|
||||
"DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
|
||||
"UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
|
||||
"TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
|
||||
_ => {
|
||||
return Err(SdpParserInternalError::Unsupported(format!("unsupported protocol value: {}",
|
||||
value)))
|
||||
}
|
||||
})
|
||||
"RTP/AVP" => SdpProtocolValue::RtpAvp,
|
||||
"RTP/AVPF" => SdpProtocolValue::RtpAvpf,
|
||||
"RTP/SAVP" => SdpProtocolValue::RtpSavp,
|
||||
"RTP/SAVPF" => SdpProtocolValue::RtpSavpf,
|
||||
"TCP/DTLS/RTP/SAVP" => SdpProtocolValue::TcpDtlsRtpSavp,
|
||||
"TCP/DTLS/RTP/SAVPF" => SdpProtocolValue::TcpDtlsRtpSavpf,
|
||||
"UDP/TLS/RTP/SAVP" => SdpProtocolValue::UdpTlsRtpSavp,
|
||||
"UDP/TLS/RTP/SAVPF" => SdpProtocolValue::UdpTlsRtpSavpf,
|
||||
"DTLS/SCTP" => SdpProtocolValue::DtlsSctp,
|
||||
"UDP/DTLS/SCTP" => SdpProtocolValue::UdpDtlsSctp,
|
||||
"TCP/DTLS/SCTP" => SdpProtocolValue::TcpDtlsSctp,
|
||||
/* to be removed */
|
||||
"TCP/TLS/RTP/SAVPF" => SdpProtocolValue::TcpTlsRtpSavpf,
|
||||
_ => {
|
||||
return Err(SdpParserInternalError::Unsupported(format!(
|
||||
"unsupported protocol value: {}",
|
||||
value
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_protocol_token() {
|
||||
fn test_parse_protocol_rtp_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");
|
||||
assert!(rtps.is_ok());
|
||||
assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf);
|
||||
let udps = parse_protocol_token("udp/tls/rtp/savp");
|
||||
assert!(udps.is_ok());
|
||||
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");
|
||||
assert!(udps.is_ok());
|
||||
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");
|
||||
assert!(tcps.is_ok());
|
||||
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpTlsRtpSavpf);
|
||||
let tcps = parse_protocol_token("TCP/DtlS/rTp/sAVpf");
|
||||
assert!(tcps.is_ok());
|
||||
assert_eq!(tcps.unwrap(), SdpProtocolValue::TcpDtlsRtpSavpf);
|
||||
|
||||
assert!(parse_protocol_token("").is_err());
|
||||
assert!(parse_protocol_token("foobar").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_protocol_sctp_token() {
|
||||
let dtls = parse_protocol_token("dtLs/ScTP");
|
||||
assert!(dtls.is_ok());
|
||||
assert_eq!(dtls.unwrap(), SdpProtocolValue::DtlsSctp);
|
||||
|
@ -317,25 +386,29 @@ fn test_parse_protocol_token() {
|
|||
let tsctp = parse_protocol_token("tcp/dtls/SCTP");
|
||||
assert!(tsctp.is_ok());
|
||||
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> {
|
||||
let mv: Vec<&str> = value.split_whitespace().collect();
|
||||
if mv.len() < 4 {
|
||||
return Err(SdpParserInternalError::Generic("media attribute must have at least four tokens"
|
||||
.to_string()));
|
||||
return Err(SdpParserInternalError::Generic(
|
||||
"media attribute must have at least four tokens".to_string(),
|
||||
));
|
||||
}
|
||||
let media = parse_media_token(mv[0])?;
|
||||
let mut ptokens = mv[1].split('/');
|
||||
let port = match ptokens.next() {
|
||||
None => return Err(SdpParserInternalError::Generic("missing port token".to_string())),
|
||||
None => {
|
||||
return Err(SdpParserInternalError::Generic(
|
||||
"missing port token".to_string(),
|
||||
));
|
||||
}
|
||||
Some(p) => p.parse::<u32>()?,
|
||||
};
|
||||
if port > 65535 {
|
||||
return Err(SdpParserInternalError::Generic("media port token is too big".to_string()));
|
||||
return Err(SdpParserInternalError::Generic(
|
||||
"media port token is too big".to_string(),
|
||||
));
|
||||
}
|
||||
let port_count = match ptokens.next() {
|
||||
None => 0,
|
||||
|
@ -377,20 +450,41 @@ pub fn parse_media(value: &str) -> Result<SdpType, SdpParserInternalError> {
|
|||
proto,
|
||||
formats,
|
||||
};
|
||||
trace!("media: {}, {}, {}, {}", m.media, m.port, m.proto, m.formats);
|
||||
trace!(
|
||||
"media: {}, {}, {}, {}",
|
||||
m.media.to_string(),
|
||||
m.port.to_string(),
|
||||
m.proto.to_string(),
|
||||
m.formats.to_string()
|
||||
);
|
||||
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]
|
||||
fn test_media_works() {
|
||||
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109").is_ok());
|
||||
assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF 126").is_ok());
|
||||
assert!(parse_media("application 9 DTLS/SCTP 5000").is_ok());
|
||||
assert!(parse_media("application 9 UDP/DTLS/SCTP webrtc-datachannel").is_ok());
|
||||
check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109");
|
||||
check_parse_and_serialize("video 9 UDP/TLS/RTP/SAVPF 126");
|
||||
check_parse_and_serialize("application 9 DTLS/SCTP 5000");
|
||||
check_parse_and_serialize("application 9 UDP/DTLS/SCTP webrtc-datachannel");
|
||||
|
||||
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8").is_ok());
|
||||
assert!(parse_media("audio 0 UDP/TLS/RTP/SAVPF 8").is_ok());
|
||||
assert!(parse_media("audio 9/2 UDP/TLS/RTP/SAVPF 8").is_ok());
|
||||
check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8");
|
||||
check_parse_and_serialize("audio 0 UDP/TLS/RTP/SAVPF 8");
|
||||
check_parse_and_serialize("audio 9/2 UDP/TLS/RTP/SAVPF 8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -423,84 +517,68 @@ fn test_media_invalid_payload() {
|
|||
assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
|
||||
}
|
||||
|
||||
pub fn parse_media_vector(lines: &[SdpLine]) -> Result<Vec<SdpMedia>, SdpParserError> {
|
||||
pub fn parse_media_vector(lines: &mut Vec<SdpLine>) -> Result<Vec<SdpMedia>, SdpParserError> {
|
||||
let mut media_sections: Vec<SdpMedia> = Vec::new();
|
||||
let mut sdp_media = match lines[0].sdp_type {
|
||||
SdpType::Media(ref v) => SdpMedia::new(v.clone()),
|
||||
|
||||
let media_line = lines.remove(0);
|
||||
let mut sdp_media = match media_line.sdp_type {
|
||||
SdpType::Media(v) => SdpMedia::new(v),
|
||||
_ => {
|
||||
return Err(SdpParserError::Sequence {
|
||||
message: "first line in media section needs to be a media line"
|
||||
.to_string(),
|
||||
line_number: lines[0].line_number,
|
||||
})
|
||||
message: "first line in media section needs to be a media line".to_string(),
|
||||
line_number: media_line.line_number,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
for line in lines.iter().skip(1) {
|
||||
while !lines.is_empty() {
|
||||
let line = lines.remove(0);
|
||||
let _line_number = line.line_number;
|
||||
match line.sdp_type {
|
||||
SdpType::Connection(ref c) => {
|
||||
SdpType::Connection(c) => {
|
||||
sdp_media
|
||||
.set_connection(c)
|
||||
.map_err(|e: SdpParserInternalError| {
|
||||
SdpParserError::Sequence {
|
||||
message: format!("{}", e),
|
||||
line_number: line.line_number,
|
||||
}
|
||||
})?
|
||||
.map_err(|e: SdpParserInternalError| SdpParserError::Sequence {
|
||||
message: format!("{}", e),
|
||||
line_number: _line_number,
|
||||
})?
|
||||
}
|
||||
SdpType::Bandwidth(ref b) => sdp_media.add_bandwidth(b),
|
||||
SdpType::Attribute(ref a) => {
|
||||
SdpType::Bandwidth(b) => sdp_media.add_bandwidth(b),
|
||||
SdpType::Attribute(a) => {
|
||||
match a {
|
||||
&SdpAttribute::DtlsMessage(_) => {
|
||||
SdpAttribute::DtlsMessage(_) => {
|
||||
// Ignore this attribute on media level
|
||||
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)
|
||||
}
|
||||
}.map_err(|e: SdpParserInternalError| {
|
||||
SdpParserError::Sequence {
|
||||
message: format!("{}", e),
|
||||
line_number: line.line_number,
|
||||
}
|
||||
})?
|
||||
SdpAttribute::Rtpmap(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),
|
||||
}
|
||||
.map_err(|e: SdpParserInternalError| SdpParserError::Sequence {
|
||||
message: format!("{}", e),
|
||||
line_number: _line_number,
|
||||
})?
|
||||
}
|
||||
SdpType::Media(ref v) => {
|
||||
SdpType::Media(v) => {
|
||||
media_sections.push(sdp_media);
|
||||
sdp_media = SdpMedia::new(v.clone());
|
||||
sdp_media = SdpMedia::new(v);
|
||||
}
|
||||
|
||||
SdpType::Email(_) |
|
||||
SdpType::Phone(_) |
|
||||
SdpType::Origin(_) |
|
||||
SdpType::Repeat(_) |
|
||||
SdpType::Session(_) |
|
||||
SdpType::Timing(_) |
|
||||
SdpType::Uri(_) |
|
||||
SdpType::Version(_) |
|
||||
SdpType::Zone(_) => {
|
||||
SdpType::Origin(_) | SdpType::Session(_) | SdpType::Timing(_) | SdpType::Version(_) => {
|
||||
return Err(SdpParserError::Sequence {
|
||||
message: "invalid type in media section".to_string(),
|
||||
line_number: line.line_number,
|
||||
})
|
||||
message: "invalid type in media section".to_string(),
|
||||
line_number: line.line_number,
|
||||
});
|
||||
}
|
||||
|
||||
// the line parsers throw unsupported errors for these already
|
||||
SdpType::Information(_) |
|
||||
SdpType::Key(_) => (),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -514,10 +592,10 @@ fn test_media_vector_first_line_failure() {
|
|||
let mut sdp_lines: Vec<SdpLine> = Vec::new();
|
||||
let line = SdpLine {
|
||||
line_number: 0,
|
||||
sdp_type: SdpType::Session("hello".to_string())
|
||||
sdp_type: SdpType::Session("hello".to_string()),
|
||||
};
|
||||
sdp_lines.push(line);
|
||||
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -532,26 +610,27 @@ fn test_media_vector_multiple_connections() {
|
|||
};
|
||||
let media = SdpLine {
|
||||
line_number: 0,
|
||||
sdp_type: SdpType::Media(media_line)
|
||||
sdp_type: SdpType::Media(media_line),
|
||||
};
|
||||
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 c = SdpConnection {
|
||||
addr,
|
||||
ttl: None,
|
||||
amount: None };
|
||||
amount: None,
|
||||
};
|
||||
let c1 = SdpLine {
|
||||
line_number: 1,
|
||||
sdp_type: SdpType::Connection(c.clone())
|
||||
sdp_type: SdpType::Connection(c.clone()),
|
||||
};
|
||||
sdp_lines.push(c1);
|
||||
let c2 = SdpLine {
|
||||
line_number: 2,
|
||||
sdp_type: SdpType::Connection(c)
|
||||
sdp_type: SdpType::Connection(c),
|
||||
};
|
||||
sdp_lines.push(c2);
|
||||
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -566,17 +645,17 @@ fn test_media_vector_invalid_types() {
|
|||
};
|
||||
let media = SdpLine {
|
||||
line_number: 0,
|
||||
sdp_type: SdpType::Media(media_line)
|
||||
sdp_type: SdpType::Media(media_line),
|
||||
};
|
||||
sdp_lines.push(media);
|
||||
use {SdpTiming};
|
||||
use SdpTiming;
|
||||
let t = SdpTiming { start: 0, stop: 0 };
|
||||
let tline = SdpLine {
|
||||
line_number: 1,
|
||||
sdp_type: SdpType::Timing(t)
|
||||
sdp_type: SdpType::Timing(t),
|
||||
};
|
||||
sdp_lines.push(tline);
|
||||
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -591,14 +670,14 @@ fn test_media_vector_invalid_media_level_attribute() {
|
|||
};
|
||||
let media = SdpLine {
|
||||
line_number: 0,
|
||||
sdp_type: SdpType::Media(media_line)
|
||||
sdp_type: SdpType::Media(media_line),
|
||||
};
|
||||
sdp_lines.push(media);
|
||||
let a = SdpAttribute::IceLite;
|
||||
let aline = SdpLine {
|
||||
line_number: 1,
|
||||
sdp_type: SdpType::Attribute(a)
|
||||
sdp_type: SdpType::Attribute(a),
|
||||
};
|
||||
sdp_lines.push(aline);
|
||||
assert!(parse_media_vector(&sdp_lines).is_err());
|
||||
assert!(parse_media_vector(&mut sdp_lines).is_err());
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
use std::str::FromStr;
|
||||
use std::fmt;
|
||||
use std::net::IpAddr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use error::SdpParserInternalError;
|
||||
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum SdpAddrType {
|
||||
IP4 = 4,
|
||||
IP6 = 6,
|
||||
}
|
||||
|
||||
impl SdpAddrType {
|
||||
pub fn same_protocol(&self, addr: &IpAddr) -> bool {
|
||||
(addr.is_ipv6() && *self == SdpAddrType::IP6) ||
|
||||
(addr.is_ipv4() && *self == SdpAddrType::IP4)
|
||||
pub fn same_protocol(self, addr: &IpAddr) -> bool {
|
||||
(addr.is_ipv6() && self == SdpAddrType::IP6) || (addr.is_ipv4() && self == SdpAddrType::IP4)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +28,9 @@ impl fmt::Display for SdpAddrType {
|
|||
|
||||
pub fn parse_nettype(value: &str) -> Result<(), SdpParserInternalError> {
|
||||
if value.to_uppercase() != "IN" {
|
||||
return Err(SdpParserInternalError::Generic("nettype needs to be IN".to_string()));
|
||||
return Err(SdpParserInternalError::Generic(
|
||||
"nettype needs to be IN".to_string(),
|
||||
));
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
@ -45,13 +46,14 @@ fn test_parse_nettype() {
|
|||
|
||||
pub fn parse_addrtype(value: &str) -> Result<SdpAddrType, SdpParserInternalError> {
|
||||
Ok(match value.to_uppercase().as_ref() {
|
||||
"IP4" => SdpAddrType::IP4,
|
||||
"IP6" => SdpAddrType::IP6,
|
||||
_ => {
|
||||
return Err(SdpParserInternalError::Generic("address type needs to be IP4 or IP6"
|
||||
.to_string()))
|
||||
}
|
||||
})
|
||||
"IP4" => SdpAddrType::IP4,
|
||||
"IP6" => SdpAddrType::IP6,
|
||||
_ => {
|
||||
return Err(SdpParserInternalError::Generic(
|
||||
"address type needs to be IP4 or IP6".to_string(),
|
||||
));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
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,14 +1,21 @@
|
|||
extern crate rsdparsa;
|
||||
extern crate webrtc_sdp;
|
||||
|
||||
#[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]
|
||||
fn parse_minimal_sdp() {
|
||||
let sdp = "v=0\r\n
|
||||
o=- 0 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\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";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=- 0 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\r\n\
|
||||
t=0 0\r\n\
|
||||
c=IN IP4 0.0.0.0\r\n\
|
||||
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -20,14 +27,20 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
|||
assert_eq!(sdp.media.len(), 1);
|
||||
|
||||
let msection = &(sdp.media[0]);
|
||||
assert_eq!(*msection.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Audio);
|
||||
assert_eq!(
|
||||
*msection.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Audio
|
||||
);
|
||||
assert_eq!(msection.get_port(), 0);
|
||||
assert_eq!(*msection.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||
assert_eq!(
|
||||
*msection.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
||||
);
|
||||
assert!(msection.get_attributes().is_empty());
|
||||
assert!(msection.get_bandwidth().is_empty());
|
||||
assert!(msection.get_connection().is_none());
|
||||
|
||||
check_parse_and_serialize(sdp_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -40,7 +53,7 @@ s=-\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";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, false);
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp, false);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -51,17 +64,17 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
|||
|
||||
#[test]
|
||||
fn parse_minimal_sdp_with_most_session_types() {
|
||||
let sdp = "v=0\r\n
|
||||
o=- 0 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\r\n
|
||||
t=0 0\r\n
|
||||
b=AS:1\r\n
|
||||
b=CT:123\r\n
|
||||
b=TIAS:12345\r\n
|
||||
c=IN IP4 0.0.0.0\r\n
|
||||
a=ice-options:trickle\r\n
|
||||
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, false);
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=- 0 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\r\n\
|
||||
t=0 0\r\n\
|
||||
b=AS:1\r\n\
|
||||
b=CT:123\r\n\
|
||||
b=TIAS:12345\r\n\
|
||||
c=IN IP4 0.0.0.0\r\n\
|
||||
a=ice-options:trickle\r\n\
|
||||
m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, false);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -69,21 +82,23 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n";
|
|||
assert_eq!(sdp.version, 0);
|
||||
assert_eq!(sdp.session, "-");
|
||||
assert!(sdp.get_connection().is_some());
|
||||
|
||||
check_parse_and_serialize(sdp_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_minimal_sdp_with_most_media_types() {
|
||||
let sdp = "v=0\r\n
|
||||
o=- 0 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\r\n
|
||||
t=0 0\r\n
|
||||
m=video 0 UDP/TLS/RTP/SAVPF 0\r\n
|
||||
b=AS:1\r\n
|
||||
b=CT:123\r\n
|
||||
b=TIAS:12345\r\n
|
||||
c=IN IP4 0.0.0.0\r\n
|
||||
a=sendrecv\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, false);
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=- 0 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\r\n\
|
||||
t=0 0\r\n\
|
||||
m=video 0 UDP/TLS/RTP/SAVPF 0\r\n\
|
||||
b=AS:1\r\n\
|
||||
b=CT:123\r\n\
|
||||
b=TIAS:12345\r\n\
|
||||
c=IN IP4 0.0.0.0\r\n\
|
||||
a=sendrecv\r\n";
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, false);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -94,44 +109,52 @@ a=sendrecv\r\n";
|
|||
assert_eq!(sdp.media.len(), 1);
|
||||
|
||||
let msection = &(sdp.media[0]);
|
||||
assert_eq!(*msection.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Video);
|
||||
assert_eq!(
|
||||
*msection.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Video
|
||||
);
|
||||
assert_eq!(msection.get_port(), 0);
|
||||
assert_eq!(*msection.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||
assert_eq!(
|
||||
*msection.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
||||
);
|
||||
assert!(!msection.get_bandwidth().is_empty());
|
||||
assert!(!msection.get_connection().is_none());
|
||||
assert!(!msection.get_attributes().is_empty());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sendrecv)
|
||||
.is_some());
|
||||
|
||||
check_parse_and_serialize(sdp_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_firefox_audio_offer() {
|
||||
let sdp = "v=0\r\n
|
||||
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\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=group:BUNDLE sdparta_0\r\n
|
||||
a=ice-options:trickle\r\n
|
||||
a=msid-semantic:WMS *\r\n
|
||||
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8\r\n
|
||||
c=IN IP4 0.0.0.0\r\n
|
||||
a=sendrecv\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=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n
|
||||
a=ice-ufrag:58b99ead\r\n
|
||||
a=mid:sdparta_0\r\n
|
||||
a=msid:{5a990edd-0568-ac40-8d97-310fc33f3411} {218cfa1c-617d-2249-9997-60929ce4c405}\r\n
|
||||
a=rtcp-mux\r\n
|
||||
a=rtpmap:109 opus/48000/2\r\n
|
||||
a=rtpmap:9 G722/8000/1\r\n
|
||||
a=rtpmap:0 PCMU/8000\r\n
|
||||
a=rtpmap:8 PCMA/8000\r\n
|
||||
a=setup:actpass\r\n
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\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=group:BUNDLE sdparta_0\r\n\
|
||||
a=ice-options:trickle\r\n\
|
||||
a=msid-semantic:WMS *\r\n\
|
||||
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8\r\n\
|
||||
c=IN IP4 0.0.0.0\r\n\
|
||||
a=sendrecv\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=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n\
|
||||
a=ice-ufrag:58b99ead\r\n\
|
||||
a=mid:sdparta_0\r\n\
|
||||
a=msid:{5a990edd-0568-ac40-8d97-310fc33f3411} {218cfa1c-617d-2249-9997-60929ce4c405}\r\n\
|
||||
a=rtcp-mux\r\n\
|
||||
a=rtpmap:109 opus/48000/2\r\n\
|
||||
a=rtpmap:9 G722/8000/1\r\n\
|
||||
a=rtpmap:0 PCMU/8000\r\n\
|
||||
a=rtpmap:8 PCMA/8000\r\n\
|
||||
a=setup:actpass\r\n\
|
||||
a=ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -140,66 +163,94 @@ a=ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}\r\n";
|
|||
assert_eq!(sdp.media.len(), 1);
|
||||
|
||||
let msection = &(sdp.media[0]);
|
||||
assert_eq!(*msection.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Audio);
|
||||
assert_eq!(
|
||||
*msection.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Audio
|
||||
);
|
||||
assert_eq!(msection.get_port(), 9);
|
||||
assert_eq!(*msection.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||
assert_eq!(
|
||||
*msection.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
||||
);
|
||||
assert!(msection.get_connection().is_some());
|
||||
assert!(msection.get_bandwidth().is_empty());
|
||||
assert!(!msection.get_attributes().is_empty());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sendrecv)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Extmap)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Fmtp)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IcePwd)
|
||||
.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]
|
||||
fn parse_firefox_video_offer() {
|
||||
let sdp = "v=0\r\n
|
||||
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\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=group:BUNDLE sdparta_2\r\n
|
||||
a=ice-options:trickle\r\n
|
||||
a=msid-semantic:WMS *\r\n
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 126 120 97\r\n
|
||||
c=IN IP4 0.0.0.0\r\n
|
||||
a=recvonly\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:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\n
|
||||
a=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n
|
||||
a=ice-ufrag:58b99ead\r\n
|
||||
a=mid:sdparta_2\r\n
|
||||
a=rtcp-fb:126 nack\r\n
|
||||
a=rtcp-fb:126 nack pli\r\n
|
||||
a=rtcp-fb:126 ccm fir\r\n
|
||||
a=rtcp-fb:126 goog-remb\r\n
|
||||
a=rtcp-fb:120 nack\r\n
|
||||
a=rtcp-fb:120 nack pli\r\n
|
||||
a=rtcp-fb:120 ccm fir\r\n
|
||||
a=rtcp-fb:120 goog-remb\r\n
|
||||
a=rtcp-fb:97 nack\r\n
|
||||
a=rtcp-fb:97 nack pli\r\n
|
||||
a=rtcp-fb:97 ccm fir\r\n
|
||||
a=rtcp-fb:97 goog-remb\r\n
|
||||
a=rtcp-mux\r\n
|
||||
a=rtpmap:126 H264/90000\r\n
|
||||
a=rtpmap:120 VP8/90000\r\n
|
||||
a=rtpmap:97 H264/90000\r\n
|
||||
a=setup:actpass\r\n
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\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=group:BUNDLE sdparta_2\r\n\
|
||||
a=ice-options:trickle\r\n\
|
||||
a=msid-semantic:WMS *\r\n\
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 126 120 97\r\n\
|
||||
c=IN IP4 0.0.0.0\r\n\
|
||||
a=recvonly\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:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\n\
|
||||
a=ice-pwd:e3baa26dd2fa5030d881d385f1e36cce\r\n\
|
||||
a=ice-ufrag:58b99ead\r\n\
|
||||
a=mid:sdparta_2\r\n\
|
||||
a=rtcp-fb:126 nack\r\n\
|
||||
a=rtcp-fb:126 nack pli\r\n\
|
||||
a=rtcp-fb:126 ccm fir\r\n\
|
||||
a=rtcp-fb:126 goog-remb\r\n\
|
||||
a=rtcp-fb:120 nack\r\n\
|
||||
a=rtcp-fb:120 nack pli\r\n\
|
||||
a=rtcp-fb:120 ccm fir\r\n\
|
||||
a=rtcp-fb:120 goog-remb\r\n\
|
||||
a=rtcp-fb:97 nack\r\n\
|
||||
a=rtcp-fb:97 nack pli\r\n\
|
||||
a=rtcp-fb:97 ccm fir\r\n\
|
||||
a=rtcp-fb:97 goog-remb\r\n\
|
||||
a=rtcp-mux\r\n\
|
||||
a=rtpmap:126 H264/90000\r\n\
|
||||
a=rtpmap:120 VP8/90000\r\n\
|
||||
a=rtpmap:97 H264/90000\r\n\
|
||||
a=setup:actpass\r\n\
|
||||
a=ssrc:2709871439 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -208,51 +259,80 @@ a=ssrc:2709871439 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}";
|
|||
assert_eq!(sdp.media.len(), 1);
|
||||
|
||||
let msection = &(sdp.media[0]);
|
||||
assert_eq!(*msection.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Video);
|
||||
assert_eq!(
|
||||
*msection.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Video
|
||||
);
|
||||
assert_eq!(msection.get_port(), 9);
|
||||
assert_eq!(*msection.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||
assert_eq!(
|
||||
*msection.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
||||
);
|
||||
assert!(msection.get_connection().is_some());
|
||||
assert!(msection.get_bandwidth().is_empty());
|
||||
assert!(!msection.get_attributes().is_empty());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Recvonly).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Recvonly)
|
||||
.is_some());
|
||||
assert!(!msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Extmap)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Fmtp)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IcePwd)
|
||||
.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::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]
|
||||
fn parse_firefox_datachannel_offer() {
|
||||
let sdp = "v=0\r\n
|
||||
o=mozilla...THIS_IS_SDPARTA-52.0a2 3327975756663609975 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\r\n
|
||||
t=0 0\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=ice-options:trickle\r\n
|
||||
a=msid-semantic:WMS *\r\n
|
||||
m=application 49760 DTLS/SCTP 5000\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=sendrecv\r\n
|
||||
a=end-of-candidates\r\n
|
||||
a=ice-pwd:24f485c580129b36447b65df77429a82\r\n
|
||||
a=ice-ufrag:4cba30fe\r\n
|
||||
a=mid:sdparta_0\r\n
|
||||
a=sctpmap:5000 webrtc-datachannel 256\r\n
|
||||
a=setup:active\r\n
|
||||
a=ssrc:3376683177 cname:{62f78ee0-620f-a043-86ca-b69f189f1aea}\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=mozilla...THIS_IS_SDPARTA-52.0a2 3327975756663609975 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\r\n\
|
||||
t=0 0\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=ice-options:trickle\r\n\
|
||||
a=msid-semantic:WMS *\r\n\
|
||||
m=application 49760 DTLS/SCTP 5000\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=sendrecv\r\n\
|
||||
a=end-of-candidates\r\n\
|
||||
a=ice-pwd:24f485c580129b36447b65df77429a82\r\n\
|
||||
a=ice-ufrag:4cba30fe\r\n\
|
||||
a=mid:sdparta_0\r\n\
|
||||
a=sctpmap:5000 webrtc-datachannel 256\r\n\
|
||||
a=setup:active\r\n\
|
||||
a=ssrc:3376683177 cname:{62f78ee0-620f-a043-86ca-b69f189f1aea}\r\n";
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp_str, true);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -261,27 +341,59 @@ a=ssrc:3376683177 cname:{62f78ee0-620f-a043-86ca-b69f189f1aea}\r\n";
|
|||
assert_eq!(sdp.media.len(), 1);
|
||||
|
||||
let msection = &(sdp.media[0]);
|
||||
assert_eq!(*msection.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Application);
|
||||
assert_eq!(
|
||||
*msection.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Application
|
||||
);
|
||||
assert_eq!(msection.get_port(), 49760);
|
||||
assert_eq!(*msection.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::DtlsSctp);
|
||||
assert_eq!(
|
||||
*msection.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::DtlsSctp
|
||||
);
|
||||
assert!(msection.get_connection().is_some());
|
||||
assert!(msection.get_bandwidth().is_empty());
|
||||
assert!(!msection.get_attributes().is_empty());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::EndOfCandidates).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some());
|
||||
assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sctpmap).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some());
|
||||
assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Sendrecv)
|
||||
.is_some());
|
||||
assert!(!msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::Extmap)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IcePwd)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.get_attribute(webrtc_sdp::attribute_type::SdpAttributeType::IceUfrag)
|
||||
.is_some());
|
||||
assert!(msection
|
||||
.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]
|
||||
|
@ -373,7 +485,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 mslabel:HWpbmTmXleVSnlssQd80bPuw9cxQFroDkkBP\r\n
|
||||
a=ssrc:2673335628 label:b6ec5178-c611-403f-bbec-3833ed547c09\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp, true);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -382,21 +494,29 @@ a=ssrc:2673335628 label:b6ec5178-c611-403f-bbec-3833ed547c09\r\n";
|
|||
assert_eq!(sdp.media.len(), 2);
|
||||
|
||||
let msection1 = &(sdp.media[0]);
|
||||
assert_eq!(*msection1.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Audio);
|
||||
assert_eq!(
|
||||
*msection1.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Audio
|
||||
);
|
||||
assert_eq!(msection1.get_port(), 9);
|
||||
assert_eq!(*msection1.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||
assert_eq!(
|
||||
*msection1.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
||||
);
|
||||
assert!(!msection1.get_attributes().is_empty());
|
||||
assert!(msection1.get_connection().is_some());
|
||||
assert!(msection1.get_bandwidth().is_empty());
|
||||
|
||||
let msection2 = &(sdp.media[1]);
|
||||
assert_eq!(*msection2.get_type(),
|
||||
rsdparsa::media_type::SdpMediaValue::Video);
|
||||
assert_eq!(
|
||||
*msection2.get_type(),
|
||||
webrtc_sdp::media_type::SdpMediaValue::Video
|
||||
);
|
||||
assert_eq!(msection2.get_port(), 9);
|
||||
assert_eq!(*msection2.get_proto(),
|
||||
rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf);
|
||||
assert_eq!(
|
||||
*msection2.get_proto(),
|
||||
webrtc_sdp::media_type::SdpProtocolValue::UdpTlsRtpSavpf
|
||||
);
|
||||
assert!(!msection2.get_attributes().is_empty());
|
||||
assert!(msection2.get_connection().is_some());
|
||||
assert!(msection2.get_bandwidth().is_empty());
|
||||
|
@ -452,7 +572,7 @@ a=setup:actpass\r\n
|
|||
a=simulcast: send rid=foo;bar\r\n
|
||||
a=ssrc:2988475468 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n
|
||||
a=ssrc:1649784806 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_res = webrtc_sdp::parse_sdp(sdp, true);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
@ -463,35 +583,35 @@ a=ssrc:1649784806 cname:{77067f00-2e8d-8b4c-8992-cfe338f56851}\r\n";
|
|||
|
||||
#[test]
|
||||
fn parse_firefox_simulcast_answer() {
|
||||
let sdp = "v=0\r\n
|
||||
o=mozilla...THIS_IS_SDPARTA-55.0a1 7548296603161351381 0 IN IP4 0.0.0.0\r\n
|
||||
s=-\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=ice-options:trickle\r\n
|
||||
a=msid-semantic:WMS *\r\n
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 120\r\n
|
||||
c=IN IP4 0.0.0.0\r\n
|
||||
a=recvonly\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=fmtp:120 max-fs=12288;max-fr=60\r\n
|
||||
a=ice-pwd:c886e2caf2ae397446312930cd1afe51\r\n
|
||||
a=ice-ufrag:f57396c0\r\n
|
||||
a=mid:sdparta_0\r\n
|
||||
a=rtcp-fb:120 nack\r\n
|
||||
a=rtcp-fb:120 nack pli\r\n
|
||||
a=rtcp-fb:120 ccm fir\r\n
|
||||
a=rtcp-fb:120 goog-remb\r\n
|
||||
a=rtcp-mux\r\n
|
||||
a=rtpmap:120 VP8/90000\r\n
|
||||
a=setup:active\r\n
|
||||
a=ssrc:2564157021 cname:{cae1cd32-7433-5b48-8dc8-8e3f8b2f96cd}\r\n
|
||||
a=simulcast: recv rid=foo;bar\r\n
|
||||
a=rid:foo recv\r\n
|
||||
a=rid:bar recv\r\n
|
||||
a=extmap:3/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n";
|
||||
let sdp_res = rsdparsa::parse_sdp(sdp, true);
|
||||
let sdp_str = "v=0\r\n\
|
||||
o=mozilla...THIS_IS_SDPARTA-55.0a1 7548296603161351381 0 IN IP4 0.0.0.0\r\n\
|
||||
s=-\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=ice-options:trickle\r\n\
|
||||
a=msid-semantic:WMS *\r\n\
|
||||
m=video 9 UDP/TLS/RTP/SAVPF 120\r\n\
|
||||
c=IN IP4 0.0.0.0\r\n
|
||||
a=recvonly\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=fmtp:120 max-fs=12288;max-fr=60\r\n\
|
||||
a=ice-pwd:c886e2caf2ae397446312930cd1afe51\r\n\
|
||||
a=ice-ufrag:f57396c0\r\n\
|
||||
a=mid:sdparta_0\r\n\
|
||||
a=rtcp-fb:120 nack\r\n\
|
||||
a=rtcp-fb:120 nack pli\r\n\
|
||||
a=rtcp-fb:120 ccm fir\r\n\
|
||||
a=rtcp-fb:120 goog-remb\r\n\
|
||||
a=rtcp-mux\r\n\
|
||||
a=rtpmap:120 VP8/90000\r\n\
|
||||
a=setup:active\r\n\
|
||||
a=ssrc:2564157021 cname:{cae1cd32-7433-5b48-8dc8-8e3f8b2f96cd}\r\n\
|
||||
a=simulcast: recv rid=foo;bar\r\n\
|
||||
a=rid:foo recv\r\n\
|
||||
a=rid:bar recv\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);
|
||||
assert!(sdp_res.is_ok());
|
||||
let sdp_opt = sdp_res.ok();
|
||||
assert!(sdp_opt.is_some());
|
||||
|
|
|
@ -7,5 +7,5 @@ authors = ["Paul Ellenbogen <pe5@cs.princeton.edu>",
|
|||
[dependencies]
|
||||
libc = "^0.2.0"
|
||||
log = "0.4"
|
||||
rsdparsa = {version = "0.1.0", path = "../rsdparsa"}
|
||||
rsdparsa = {package = "webrtc-sdp", version = "0.1.0", path = "../rsdparsa"}
|
||||
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| {
|
||||
if let SdpAttribute::Candidate(ref attr) = *x {
|
||||
// The serialized attribute starts with "candidate:...", this needs to be removed
|
||||
Some(attr.to_string()[10..].to_string())
|
||||
Some(attr.to_string())
|
||||
} else {
|
||||
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);
|
||||
match parser_result {
|
||||
Ok(parsed) => {
|
||||
Ok(mut parsed) => {
|
||||
*error = match parsed.warnings.len(){
|
||||
0 => ptr::null(),
|
||||
_ => Box::into_raw(Box::new(parsed.warnings[0].clone())),
|
||||
_ => Box::into_raw(Box::new(parsed.warnings.remove(0))),
|
||||
};
|
||||
*session = Rc::into_raw(Rc::new(parsed));
|
||||
NS_OK
|
||||
|
|
|
@ -56,6 +56,9 @@ pub enum RustSdpProtocolValue {
|
|||
DtlsSctp,
|
||||
UdpDtlsSctp,
|
||||
TcpDtlsSctp,
|
||||
RtpAvp,
|
||||
RtpAvpf,
|
||||
RtpSavp,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue {
|
||||
|
@ -70,6 +73,9 @@ impl<'a> From<&'a SdpProtocolValue> for RustSdpProtocolValue {
|
|||
SdpProtocolValue::DtlsSctp => RustSdpProtocolValue::DtlsSctp,
|
||||
SdpProtocolValue::UdpDtlsSctp => RustSdpProtocolValue::UdpDtlsSctp,
|
||||
SdpProtocolValue::TcpDtlsSctp => RustSdpProtocolValue::TcpDtlsSctp,
|
||||
SdpProtocolValue::RtpAvp => RustSdpProtocolValue::RtpAvp,
|
||||
SdpProtocolValue::RtpAvpf => RustSdpProtocolValue::RtpAvpf,
|
||||
SdpProtocolValue::RtpSavp => RustSdpProtocolValue::RtpSavp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче