upgrade to Retina v0.3.9

This alone improves interop and diagnostics, as noted in Retina's
release notes. We also now give the camera name to the session group
(for improved logging of TEARDOWN operations) and expose the RTSP
server's "tool" attribute in debug logs and the config UI's "Test"
button.

Fixes #209
Fixes #213
This commit is contained in:
Scott Lamb 2022-04-12 14:57:16 -07:00
parent 3bc410b417
commit 5e7d558f99
7 changed files with 32 additions and 8 deletions

View File

@ -6,6 +6,10 @@ changes, see Git history.
Each release is tagged in Git and on the Docker repository Each release is tagged in Git and on the Docker repository
[`scottlamb/moonfire-nvr`](https://hub.docker.com/r/scottlamb/moonfire-nvr). [`scottlamb/moonfire-nvr`](https://hub.docker.com/r/scottlamb/moonfire-nvr).
## unreleased
* upgrade to Retina 0.3.9, improving camera interop and diagnostics
## `v0.7.3` (2022-03-22) ## `v0.7.3` (2022-03-22)
* security fix: check the `Origin` header on live stream WebSocket requests * security fix: check the `Origin` header on live stream WebSocket requests

4
server/Cargo.lock generated
View File

@ -1640,9 +1640,9 @@ dependencies = [
[[package]] [[package]]
name = "retina" name = "retina"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3629d5f6a30d1a0ee184bd2a3e62eba8ffbb121250a8c72ed984575c9ffb0601" checksum = "df90aca400866f8b1327902f7c9e93ab17f195c36b7e06b804e8acd3a79bbe41"
dependencies = [ dependencies = [
"base64", "base64",
"bitreader", "bitreader",

View File

@ -46,7 +46,7 @@ parking_lot = "0.12.0"
password-hash = "0.3.2" password-hash = "0.3.2"
protobuf = "3.0.0-alpha.1" protobuf = "3.0.0-alpha.1"
reffers = "0.7.0" reffers = "0.7.0"
retina = "0.3.7" retina = "0.3.9"
ring = "0.16.2" ring = "0.16.2"
rusqlite = "0.27.0" rusqlite = "0.27.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View File

@ -214,7 +214,7 @@ fn press_test_inner(
.enable_io() .enable_io()
.build()?; .build()?;
let _guard = rt.enter(); let _guard = rt.enter();
let (extra_data, _stream) = stream::OPENER.open( let (extra_data, stream) = stream::OPENER.open(
&rt, &rt,
"test stream".to_owned(), "test stream".to_owned(),
url, url,
@ -227,8 +227,10 @@ fn press_test_inner(
.transport(transport), .transport(transport),
)?; )?;
Ok(format!( Ok(format!(
"{}x{} video stream", "{}x{} video stream served by tool {:?}",
extra_data.width, extra_data.height extra_data.width,
extra_data.height,
stream.tool(),
)) ))
} }

View File

@ -13,6 +13,7 @@ use fnv::FnvHashMap;
use hyper::service::{make_service_fn, service_fn}; use hyper::service::{make_service_fn, service_fn};
use log::error; use log::error;
use log::{info, warn}; use log::{info, warn};
use retina::client::SessionGroup;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
@ -324,7 +325,9 @@ async fn inner(
let syncer = syncers.get(&sample_file_dir_id).unwrap(); let syncer = syncers.get(&sample_file_dir_id).unwrap();
let session_group = session_groups_by_camera let session_group = session_groups_by_camera
.entry(camera.id) .entry(camera.id)
.or_default() .or_insert_with(|| {
Arc::new(SessionGroup::default().named(camera.short_name.clone()))
})
.clone(); .clone();
let mut streamer = streamer::Streamer::new( let mut streamer = streamer::Streamer::new(
&env, &env,

View File

@ -45,6 +45,7 @@ pub struct VideoFrame {
} }
pub trait Stream: Send { pub trait Stream: Send {
fn tool(&self) -> Option<&retina::client::Tool>;
fn next(&mut self) -> Result<VideoFrame, Error>; fn next(&mut self) -> Result<VideoFrame, Error>;
} }
@ -63,7 +64,7 @@ impl Opener for RealOpener {
let options = options.user_agent(format!("Moonfire NVR {}", env!("CARGO_PKG_VERSION"))); let options = options.user_agent(format!("Moonfire NVR {}", env!("CARGO_PKG_VERSION")));
let (session, video_params, first_frame) = rt.block_on(tokio::time::timeout( let (session, video_params, first_frame) = rt.block_on(tokio::time::timeout(
RETINA_TIMEOUT, RETINA_TIMEOUT,
RetinaStream::play(url, options), RetinaStream::play(&label, url, options),
))??; ))??;
let extra_data = h264::parse_extra_data(video_params.extra_data())?; let extra_data = h264::parse_extra_data(video_params.extra_data())?;
let stream = Box::new(RetinaStream { let stream = Box::new(RetinaStream {
@ -91,6 +92,7 @@ struct RetinaStream<'a> {
impl<'a> RetinaStream<'a> { impl<'a> RetinaStream<'a> {
/// Plays to first frame. No timeout; that's the caller's responsibility. /// Plays to first frame. No timeout; that's the caller's responsibility.
async fn play( async fn play(
label: &str,
url: Url, url: Url,
options: retina::client::SessionOptions, options: retina::client::SessionOptions,
) -> Result< ) -> Result<
@ -102,6 +104,7 @@ impl<'a> RetinaStream<'a> {
Error, Error,
> { > {
let mut session = retina::client::Session::describe(url, options).await?; let mut session = retina::client::Session::describe(url, options).await?;
log::debug!("connected to {:?}, tool {:?}", label, session.tool());
let (video_i, mut video_params) = session let (video_i, mut video_params) = session
.streams() .streams()
.iter() .iter()
@ -177,6 +180,10 @@ impl<'a> RetinaStream<'a> {
} }
impl<'a> Stream for RetinaStream<'a> { impl<'a> Stream for RetinaStream<'a> {
fn tool(&self) -> Option<&retina::client::Tool> {
Pin::into_inner(self.session.as_ref()).tool()
}
fn next(&mut self) -> Result<VideoFrame, Error> { fn next(&mut self) -> Result<VideoFrame, Error> {
let frame = self.first_frame.take().map(Ok).unwrap_or_else(|| { let frame = self.first_frame.take().map(Ok).unwrap_or_else(|| {
self.rt self.rt
@ -247,6 +254,10 @@ pub mod testutil {
} }
impl Stream for Mp4Stream { impl Stream for Mp4Stream {
fn tool(&self) -> Option<&retina::client::Tool> {
None
}
fn next(&mut self) -> Result<VideoFrame, Error> { fn next(&mut self) -> Result<VideoFrame, Error> {
let sample = self let sample = self
.reader .reader

View File

@ -313,6 +313,10 @@ mod tests {
} }
impl Stream for ProxyingStream { impl Stream for ProxyingStream {
fn tool(&self) -> Option<&retina::client::Tool> {
self.inner.tool()
}
fn next(&mut self) -> Result<stream::VideoFrame, Error> { fn next(&mut self) -> Result<stream::VideoFrame, Error> {
if self.pkts_left == 0 { if self.pkts_left == 0 {
bail!("end of stream"); bail!("end of stream");