Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for RTSP attributes (a=contorl, a=range) #174

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 93 additions & 2 deletions src/attribute_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,8 @@ pub enum SdpAttribute {
Simulcast(SdpAttributeSimulcast),
Ssrc(SdpAttributeSsrc),
SsrcGroup(String),
Control(String), // RFC7826 - D.1.1
Range(String), // RFC7826 - D.1.6
}

impl SdpAttribute {
Expand Down Expand Up @@ -1172,7 +1174,9 @@ impl SdpAttribute {
| SdpAttribute::Recvonly
| SdpAttribute::Sendonly
| SdpAttribute::Sendrecv
| SdpAttribute::Setup(..) => true,
| SdpAttribute::Setup(..)
| SdpAttribute::Control(..)
| SdpAttribute::Range(..) => true,
}
}

Expand Down Expand Up @@ -1218,7 +1222,9 @@ impl SdpAttribute {
| SdpAttribute::Setup(..)
| SdpAttribute::Simulcast(..)
| SdpAttribute::Ssrc(..)
| SdpAttribute::SsrcGroup(..) => true,
| SdpAttribute::SsrcGroup(..)
| SdpAttribute::Control(..)
| SdpAttribute::Range(..) => true,
}
}
}
Expand Down Expand Up @@ -1286,6 +1292,8 @@ impl FromStr for SdpAttribute {
"setup" => parse_setup(val),
"simulcast" => parse_simulcast(val),
"ssrc" => parse_ssrc(val),
"control" => parse_control(val),
"range" => parse_range(val),
_ => Err(SdpParserInternalError::Unsupported(format!(
"Unknown attribute type {}",
name
Expand Down Expand Up @@ -1339,6 +1347,8 @@ impl fmt::Display for SdpAttribute {
SdpAttribute::Simulcast(ref a) => attr_to_string(a.to_string()),
SdpAttribute::Ssrc(ref a) => attr_to_string(a.to_string()),
SdpAttribute::SsrcGroup(ref a) => attr_to_string(a.to_string()),
SdpAttribute::Control(ref a) => attr_to_string(a.to_string()),
SdpAttribute::Range(ref a) => attr_to_string(a.to_string()),
}
.fmt(f)
}
Expand Down Expand Up @@ -1400,6 +1410,8 @@ pub enum SdpAttributeType {
Simulcast,
Ssrc,
SsrcGroup,
Control, // RTC7826
Range, // RTC7826
}

impl<'a> From<&'a SdpAttribute> for SdpAttributeType {
Expand Down Expand Up @@ -1445,6 +1457,8 @@ impl<'a> From<&'a SdpAttribute> for SdpAttributeType {
SdpAttribute::Simulcast { .. } => SdpAttributeType::Simulcast,
SdpAttribute::Ssrc { .. } => SdpAttributeType::Ssrc,
SdpAttribute::SsrcGroup { .. } => SdpAttributeType::SsrcGroup,
SdpAttribute::Control { .. } => SdpAttributeType::Control,
SdpAttribute::Range { .. } => SdpAttributeType::Range,
}
}
}
Expand Down Expand Up @@ -1492,6 +1506,8 @@ impl fmt::Display for SdpAttributeType {
SdpAttributeType::Simulcast => "simulcast",
SdpAttributeType::Ssrc => "ssrc",
SdpAttributeType::SsrcGroup => "ssrc-group",
SdpAttributeType::Control => "control",
SdpAttributeType::Range => "range",
}
.fmt(f)
}
Expand Down Expand Up @@ -3117,6 +3133,34 @@ fn parse_ssrc(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
Ok(SdpAttribute::Ssrc(ssrc))
}

///////////////////////////////////////////////////////////////////////////
// a=control, RFC7826 - D.1.1
//-------------------------------------------------------------------------
// control-attribute = "a=control:" *SP RTSP-REQ-Ref CRLF
fn parse_control(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
if to_parse.is_empty() {
return Err(SdpParserInternalError::Generic(
"Control attribute is missing value".to_string(),
));
}

Ok(SdpAttribute::Control(to_parse.to_string()))
}

///////////////////////////////////////////////////////////////////////////
// a=range, RFC7826 - D.1.6
//-------------------------------------------------------------------------
// a-range-def = "a=range:" ranges-spec CRLF
fn parse_range(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
if to_parse.is_empty() {
return Err(SdpParserInternalError::Generic(
"Range attribute is missing value".to_string(),
));
}

Ok(SdpAttribute::Range(to_parse.to_string()))
}

pub fn parse_attribute(value: &str) -> Result<SdpType, SdpParserInternalError> {
Ok(SdpType::Attribute(value.trim().parse()?))
}
Expand Down Expand Up @@ -4192,4 +4236,51 @@ mod tests {
fn test_parse_unknown_attribute() {
assert!(parse_attribute("unknown").is_err())
}

#[test]
fn test_parse_control_attribute() {
let check_parse = make_check_parse!(String, SdpAttribute::Control);
let check_parse_and_serialize =
make_check_parse_and_serialize!(check_parse, SdpAttribute::Control);

check_parse_and_serialize("control:rtsp://example.com/foo");
check_parse_and_serialize("control:*");
check_parse_and_serialize("control:streamid=0");

// any number of spaces are allowed before RTSP-REQ-Ref
let uri = check_parse("control: rtsp://live.example.com/concert/audio");
assert_eq!(uri, "rtsp://live.example.com/concert/audio");

let uri = check_parse("control: *");
assert_eq!(uri, "*");

let uri = check_parse("control: trackId=4");
assert_eq!(uri, "trackId=4");

assert!(parse_attribute("control:").is_err());
assert!(parse_attribute("control: ").is_err());
}

#[test]
fn test_parse_range_attribute() {
let check_parse = make_check_parse!(String, SdpAttribute::Range);
let check_parse_and_serialize =
make_check_parse_and_serialize!(check_parse, SdpAttribute::Range);

check_parse_and_serialize("range:npt=00:00:00-00:10:34.10");
check_parse_and_serialize("range:npt=0-");
check_parse_and_serialize("range:npt=0-34.4368");
check_parse_and_serialize("range:clock=19971113T211503Z-19971113T220300Z");

let range_spec = check_parse("range:npt=now-");
assert_eq!(range_spec, "npt=now-");

let range_spec = check_parse("range:smpte-25=10:07:00-10:07:33:05.01");
assert_eq!(range_spec, "smpte-25=10:07:00-10:07:33:05.01");

let range_spec = check_parse("range:clock=19961108T143720.25Z-19961108T144725.25Z");
assert_eq!(range_spec, "clock=19961108T143720.25Z-19961108T144725.25Z");

assert!(parse_attribute("range:").is_err());
}
}