API and example for printing a session's SDP
This is useful for debugging.
This commit is contained in:
parent
76d5d883fa
commit
d49e77a668
@ -78,9 +78,9 @@ $ cargo run --example client <CMD>
|
||||
|
||||
Where CMD:
|
||||
|
||||
* **info** - Get info about available streams and exit
|
||||
* **mp4** - Write RTSP streams to mp4 file, exit with Ctrl+C
|
||||
* **metadata** - Get realtime onvif metadata if available, exit with Ctrl+C
|
||||
* **info** - Gets info about available streams and exits.
|
||||
* **mp4** - Writes RTSP streams to mp4 file; exit with Ctrl+C.
|
||||
* **metadata** - Gets realtime onvif metadata if available; exit with Ctrl+C.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
|
43
examples/client/info.rs
Normal file
43
examples/client/info.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2022 Scott Lamb <slamb@slamb.org>
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
//! Gets info about available streams and exits.
|
||||
|
||||
use anyhow::Error;
|
||||
|
||||
#[derive(structopt::StructOpt)]
|
||||
pub struct Opts {
|
||||
#[structopt(flatten)]
|
||||
src: super::Source,
|
||||
|
||||
/// Prints the SDP (Session Description Protocol) session description.
|
||||
#[structopt(long)]
|
||||
print_sdp: bool,
|
||||
|
||||
/// Prints debug output for each decoded stream.
|
||||
#[structopt(long)]
|
||||
print_streams: bool,
|
||||
}
|
||||
|
||||
pub async fn run(opts: Opts) -> Result<(), Error> {
|
||||
let creds = super::creds(opts.src.username.clone(), opts.src.password.clone());
|
||||
let session = retina::client::Session::describe(
|
||||
opts.src.url.clone(),
|
||||
retina::client::SessionOptions::default()
|
||||
.creds(creds)
|
||||
.user_agent("Retina sdp example".to_owned()),
|
||||
)
|
||||
.await?;
|
||||
if opts.print_sdp {
|
||||
println!("SDP:\n{}\n\n", std::str::from_utf8(session.sdp())?);
|
||||
}
|
||||
if opts.print_streams {
|
||||
for (i, stream) in session.streams().iter().enumerate() {
|
||||
println!("stream {}:\n{:#?}\n\n", i, stream);
|
||||
}
|
||||
}
|
||||
if !opts.print_sdp && !opts.print_streams {
|
||||
eprintln!("You probably wanted at least one of --print-sdp or --print-streams?");
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -3,8 +3,9 @@
|
||||
|
||||
//! RTSP client examples.
|
||||
|
||||
mod metadata;
|
||||
mod info;
|
||||
mod mp4;
|
||||
mod onvif;
|
||||
|
||||
use anyhow::Error;
|
||||
use log::{error, info};
|
||||
@ -28,12 +29,12 @@ struct Source {
|
||||
|
||||
#[derive(StructOpt)]
|
||||
enum Cmd {
|
||||
/// Write available audio and video streams to mp4 file
|
||||
/// Gets info about available streams and exits.
|
||||
Info(info::Opts),
|
||||
/// Writes available audio and video streams to mp4 file; use Ctrl+C to stop.
|
||||
Mp4(mp4::Opts),
|
||||
/// Get realtime metadata of onvif stream, use Ctrl+C to stop
|
||||
Metadata(metadata::Opts),
|
||||
/// Get info about available streams and exit
|
||||
Info(metadata::Opts),
|
||||
/// Follows ONVIF metadata stream; use Ctrl+C to stop.
|
||||
Onvif(onvif::Opts),
|
||||
}
|
||||
|
||||
fn init_logging() -> mylog::Handle {
|
||||
@ -81,8 +82,8 @@ fn creds(
|
||||
async fn main_inner() -> Result<(), Error> {
|
||||
let cmd = Cmd::from_args();
|
||||
match cmd {
|
||||
Cmd::Info(opts) => info::run(opts).await,
|
||||
Cmd::Mp4(opts) => mp4::run(opts).await,
|
||||
Cmd::Metadata(opts) => metadata::run(opts, false).await,
|
||||
Cmd::Info(opts) => metadata::run(opts, true).await,
|
||||
Cmd::Onvif(opts) => onvif::run(opts).await,
|
||||
}
|
||||
}
|
||||
|
@ -14,20 +14,16 @@ pub struct Opts {
|
||||
src: super::Source,
|
||||
}
|
||||
|
||||
pub async fn run(opts: Opts, is_info: bool) -> Result<(), Error> {
|
||||
pub async fn run(opts: Opts) -> Result<(), Error> {
|
||||
let session_group = Arc::new(SessionGroup::default());
|
||||
let r = run_inner(opts, session_group.clone(), is_info).await;
|
||||
let r = run_inner(opts, session_group.clone()).await;
|
||||
if let Err(e) = session_group.await_teardown().await {
|
||||
error!("TEARDOWN failed: {}", e);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
async fn run_inner(
|
||||
opts: Opts,
|
||||
session_group: Arc<SessionGroup>,
|
||||
is_info: bool,
|
||||
) -> Result<(), Error> {
|
||||
async fn run_inner(opts: Opts, session_group: Arc<SessionGroup>) -> Result<(), Error> {
|
||||
let stop = tokio::signal::ctrl_c();
|
||||
|
||||
let creds = super::creds(opts.src.username, opts.src.password);
|
||||
@ -39,12 +35,6 @@ async fn run_inner(
|
||||
.session_group(session_group),
|
||||
)
|
||||
.await?;
|
||||
if is_info {
|
||||
for stream in session.streams() {
|
||||
println!("{:#?}", stream);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
let onvif_stream_i = session
|
||||
.streams()
|
||||
.iter()
|
@ -758,7 +758,9 @@ pub trait State {}
|
||||
|
||||
/// Initial state after a `DESCRIBE`; use via `Session<Described>`.
|
||||
#[doc(hidden)]
|
||||
pub struct Described(());
|
||||
pub struct Described {
|
||||
sdp: Bytes,
|
||||
}
|
||||
impl State for Described {}
|
||||
|
||||
enum KeepaliveState {
|
||||
@ -1127,6 +1129,8 @@ impl Session<Described> {
|
||||
description,
|
||||
})
|
||||
})?;
|
||||
let describe_status = response.status();
|
||||
let sdp = response.into_body();
|
||||
Ok(Session(
|
||||
Box::pin(SessionInner {
|
||||
conn: Some(conn),
|
||||
@ -1137,16 +1141,25 @@ impl Session<Described> {
|
||||
session: None,
|
||||
describe_ctx: msg_ctx,
|
||||
describe_cseq: cseq,
|
||||
describe_status: response.status(),
|
||||
describe_status,
|
||||
keepalive_state: KeepaliveState::Idle,
|
||||
keepalive_timer: None,
|
||||
maybe_playing: false,
|
||||
udp_next_poll_i: 0,
|
||||
}),
|
||||
Described(()),
|
||||
Described { sdp },
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns the raw SDP (Session Description Protocol) session description of this URL.
|
||||
///
|
||||
/// Retina interprets the SDP automatically, but the raw bytes may be useful for debugging.
|
||||
/// They're accessibled in the `Session<Described>` state. Currently, they're discarded on
|
||||
/// `play` to reduce memory usage.
|
||||
pub fn sdp(&self) -> &[u8] {
|
||||
&self.1.sdp
|
||||
}
|
||||
|
||||
/// Sends a `SETUP` request for a stream.
|
||||
///
|
||||
/// Note these can't reasonably be pipelined because subsequent requests
|
||||
|
Loading…
Reference in New Issue
Block a user