ignore unparseable SDP media

https://github.com/scottlamb/moonfire-nvr/issues/238
This commit is contained in:
Scott Lamb 2022-09-28 08:54:35 -07:00
parent d6c0e84db8
commit bc03c61ae3
5 changed files with 61 additions and 11 deletions

View File

@ -1,3 +1,8 @@
## `v0.4.2` (2022-09-28)
* ignore unparseable SDP media, improving compatibility with TP-Link cameras,
as described in [scottlamb/moonfire-nvr#238](https://github.com/scottlamb/moonfire-nvr/issues/238).
## `v0.4.1` (2022-08-09)
* Send keepalives at every half-session-timeout rather than a fixed 30-second

2
Cargo.lock generated
View File

@ -1780,7 +1780,7 @@ checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "retina"
version = "0.4.1"
version = "0.4.2"
dependencies = [
"base64",
"bitreader",

View File

@ -4,7 +4,7 @@ default-members = ["."]
[package]
name = "retina"
version = "0.4.1"
version = "0.4.2"
authors = ["Scott Lamb <slamb@slamb.org>"]
license = "MIT/Apache-2.0"
edition = "2021"

View File

@ -452,19 +452,30 @@ pub(crate) fn parse_describe(
}
let control = control.unwrap_or(request_url);
let streams = sdp
let streams: Box<[Stream]> = sdp
.medias
.iter()
.enumerate()
.map(|(i, m)| {
parse_media(&base_url, m).map_err(|e| {
format!(
"Unable to parse stream {}: {}\nraw SDP: {:#?}",
.filter_map(|(i, m)| {
parse_media(&base_url, m).map_or_else(
|e| {
warn!(
"Ignoring unparseable stream {}: {}\nraw SDP: {:#?}",
i, &e, raw_sdp
);
None
},
Some,
)
})
})
.collect::<Result<_, String>>()?;
.collect();
if streams.is_empty() {
return Err(format!(
"No parseable streams (and {} unparseable streams)",
sdp.medias.len()
));
}
Ok(Presentation {
streams,
@ -757,6 +768,23 @@ mod tests {
super::parse_describe(url, &response).unwrap();
}
/// Parses SDP taken from a TP-LINK TL-IPC44AW-COLOR 4.0 camera running firmware
/// FW: 1.0.10 Build 220330 Rel.35741n, which has a stream with a string where an RTP
/// payload description is expected.
/// https://github.com/scottlamb/moonfire-nvr/issues/238
#[test]
fn tplink_sdp() {
let url = Url::parse("rtsp://127.0.0.1/").unwrap();
let response =
rtsp_types::Response::builder(rtsp_types::Version::V1_0, rtsp_types::StatusCode::Ok)
.header(rtsp_types::headers::CONTENT_TYPE, "application/sdp")
.build(Bytes::from_static(include_bytes!(
"testdata/tplink_sdp.txt"
)));
let p = super::parse_describe(url, &response).unwrap();
assert_eq!(p.streams.len(), 2);
}
#[test]
fn dahua_h264_aac_onvif() {
// DESCRIBE.

17
src/client/testdata/tplink_sdp.txt vendored Normal file
View File

@ -0,0 +1,17 @@
v=0
o=- 14665860 31787219 1 IN IP4 192.168.2.29
s=Session streamed by "TP-LINK RTSP Server"
t=0 0
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:4096
a=range:npt=0-
a=control:track1
a=rtpmap:96 H265/90000
a=fmtp:96 profile-space=0;profile-id=1;tier-flag=0;level-id=150;interop-constraints=000000000000;sprop-vps=QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ;sprop-sps=QgEBAWAAAAMAAAMAAAMAAAMAlqABQCAFof4qtO6JLuaAgA27oADN/mAE;sprop-pps=RAHAcvAbJA==
m=audio 0 RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=control:track2
m=application/TP-LINK 0 RTP/AVP smart/1/90000
a=rtpmap:95 TP-LINK/90000
a=control:track3