documentation improvements

This commit is contained in:
Scott Lamb 2021-11-30 11:35:53 -08:00
parent a63497eb09
commit 4b9a726a84
5 changed files with 101 additions and 25 deletions

View File

@ -3,6 +3,7 @@
* [#42](https://github.com/scottlamb/retina/issues/42): support servers that
don't send out-of-band H.264 parameters or send invalid parameters; wait for
in-band parameters in this case. The in-band parameters must be valid.
* documentation improvements.
## `v0.3.4` (2021-10-26)

View File

@ -1,6 +1,8 @@
// Copyright (C) 2021 Scott Lamb <slamb@slamb.org>
// SPDX-License-Identifier: MIT OR Apache-2.0
//! RTSP client: connect to a server via [`Session`].
use std::convert::TryFrom;
use std::mem::MaybeUninit;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
@ -31,6 +33,8 @@ pub mod rtp;
mod teardown;
mod timeline;
// TODO: this is pub but can't be fed back into the crate in any way; strange.
#[doc(hidden)]
/// Duration between keepalive RTSP requests during [Playing] state.
pub const KEEPALIVE_DURATION: std::time::Duration = std::time::Duration::from_secs(30);
@ -50,7 +54,7 @@ struct StaleSession {
expires: tokio::time::Instant,
}
/// A grouping of sessions, currently used only to track stale sessions.
/// A group of sessions, currently used only to track stale sessions.
///
/// Sessions are associated with a group via [`SessionOptions::session_group`].
///
@ -80,7 +84,7 @@ struct StaleSession {
/// no bound on when the server could see the request and extend the session.
/// Retina ignores this possibility.
///
/// A SessionGroup can be of any granularity, but a typical use is to ensure
/// A `SessionGroup` can be of any granularity, but a typical use is to ensure
/// there are no stale sessions before starting a fresh session. Groups should
/// be sized to match that idea. If connecting to a live555 server affected by
/// the stale TCP session bug, it might be wise to have one group per server, so
@ -344,11 +348,15 @@ pub struct SessionOptions {
teardown: TeardownPolicy,
}
/// The RTP packet transport to request.
///
/// Defaults to `Transport::Tcp`.
#[derive(Copy, Clone, Debug)]
pub enum Transport {
/// Sends RTP packets over the RTSP TCP connection via interleaved data.
Tcp,
/// UDP (experimental).
/// Sends RTP packets over UDP (experimental).
///
/// This support is currently only suitable for a LAN for a couple reasons:
/// * There's no reorder buffer, so out-of-order packets are all dropped.
@ -435,6 +443,7 @@ pub struct PlayOptions {
}
impl PlayOptions {
/// Sets the policy for handling the `rtptime` parameter normally seem in the `RTP-Info` header.
pub fn initial_timestamp(self, initial_timestamp: InitialTimestampPolicy) -> Self {
Self {
initial_timestamp,
@ -442,9 +451,11 @@ impl PlayOptions {
}
}
/// If the `RTP-Time` specifies `seq=0`, ignore it. Some cameras set this value then start
/// the stream with something dramatically different. (Eg the Hikvision DS-2CD2032-I on its
/// metadata stream; the other streams are fine.)
/// If the `RTP-Time` specifies `seq=0`, ignore it.
///
/// Some cameras set this value then start the stream with something
/// dramatically different. (Eg the Hikvision DS-2CD2032-I on its metadata
/// stream; the other streams are fine.)
pub fn ignore_zero_seq(self, ignore_zero_seq: bool) -> Self {
Self {
ignore_zero_seq,
@ -466,6 +477,9 @@ impl PlayOptions {
}
}
// TODO: this is `pub` yet not actually accessible from outside the crate, a combination which
// makes little sense.
#[doc(hidden)]
#[derive(Debug)]
pub struct Presentation {
pub streams: Vec<Stream>,
@ -478,6 +492,7 @@ pub struct Presentation {
}
/// Information about a stream offered within a presentation.
///
/// Currently if multiple formats are offered, this only describes the first.
#[derive(Debug)]
pub struct Stream {
@ -499,6 +514,7 @@ pub struct Stream {
pub encoding_name: String,
/// RTP payload type.
///
/// See the [registry](https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1).
/// It's common to use one of the dynamically assigned values, 96127.
pub rtp_payload_type: u8,
@ -512,6 +528,7 @@ pub struct Stream {
depacketizer: Result<crate::codec::Depacketizer, String>,
/// The specified control URL.
///
/// This is needed with multiple streams to send `SETUP` requests and
/// interpret the `PLAY` response's `RTP-Info` header.
/// [RFC 2326 section C.3](https://datatracker.ietf.org/doc/html/rfc2326#appendix-C.3)
@ -579,7 +596,8 @@ struct StreamStateInit {
initial_rtptime: Option<u32>,
}
#[derive(Clone)]
/// Username and password authentication credentials.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Credentials {
pub username: String,
pub password: String,
@ -639,10 +657,18 @@ enum ResponseMode {
/// An RTSP session.
///
/// When a `Session` is dropped, Retina may issue a `TEARDOWN` in the
/// background, depending on the [`SessionOptions::teardown`] parameter. Clients
/// may need to wait for the `TEARDOWN` to complete; see
/// [`SessionOptions::session_group`] and [`SessionGroup::await_teardown`].
/// The expected lifecycle is as follows:
///
/// 1. Create a session via [`Session::describe`].
/// 2. Examine the session's available streams via [`Session::streams`] and set
/// up one or more via [`Session::setup`].
/// 3. Start playing via [`Session::play`].
/// 4. Get packets via the [`futures::stream::Stream`] impl on `Session<Playing>`,
/// or frames via the [`futures::stream::Stream`] impl returned by [`Session<Playing>::demuxed`].
/// 5. Drop the session. Retina may issue a `TEARDOWN` in the background, depending on the
/// `[SessionOptions::teardown`] parameter.
/// 6. Possibly wait for `TEARDOWN` to complete; see
/// [`SessionOptions::session_group`] and [`SessionGroup::await_teardown`].
pub struct Session<S: State>(Pin<Box<SessionInner>>, S);
#[pin_project(PinnedDrop)]
@ -900,6 +926,13 @@ impl RtspConnection {
}
}
impl<S: State> Session<S> {
/// Returns the available streams as described the server.
pub fn streams(&self) -> &[Stream] {
&self.0.presentation.streams
}
}
impl Session<Described> {
/// Creates a new session from a `DESCRIBE` request on the given URL.
///
@ -969,10 +1002,6 @@ impl Session<Described> {
))
}
pub fn streams(&self) -> &[Stream] {
&self.0.presentation.streams
}
/// Sends a `SETUP` request for a stream.
///
/// Note these can't reasonably be pipelined because subsequent requests
@ -1344,6 +1373,7 @@ async fn punch_firewall_hole(
Ok(())
}
/// An item yielded by [`Session<Playing>`]'s [`futures::stream::Stream`] impl.
#[derive(Debug)]
pub enum PacketItem {
RtpPacket(rtp::Packet),
@ -1381,7 +1411,7 @@ impl Session<Playing> {
}
/// Sends a `TEARDOWN`, ending the session.
#[deprecated(since = "0.3.1", note = "Use SessionGroup::await_teardown instead")]
#[deprecated(since = "0.3.1", note = "Use `SessionGroup::await_teardown` instead")]
pub async fn teardown(mut self) -> Result<(), Error> {
let inner = self.0.as_mut().project();
let mut req = rtsp_types::Request::builder(Method::Teardown, rtsp_types::Version::V1_0)
@ -1407,10 +1437,6 @@ impl Session<Playing> {
Ok(())
}
pub fn streams(&self) -> &[Stream] {
&self.0.presentation.streams
}
fn handle_keepalive_timer(
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
@ -1847,7 +1873,7 @@ pub struct Demuxed {
}
impl Demuxed {
#[deprecated(since = "0.3.1", note = "Use SessionGroup::await_teardown instead")]
#[deprecated(since = "0.3.1", note = "Use `SessionGroup::await_teardown` instead")]
pub async fn teardown(self) -> Result<(), Error> {
#[allow(deprecated)]
self.session.teardown().await

View File

@ -25,7 +25,7 @@ pub struct Packet {
/// In the case of the first packet on the stream, this may also report loss
/// packets since the `RTP-Info` header's `seq` value. However, currently
/// that header is not required to be present and may be ignored (see
/// [`retina::client::PlayPolicy::ignore_zero_seq()`].)
/// [`super::PlayOptions::ignore_zero_seq()`].)
pub loss: u16,
pub mark: bool,

View File

@ -24,6 +24,7 @@ pub mod h264;
pub(crate) mod onvif;
pub(crate) mod simple_audio;
/// An item yielded from [`crate::client::Demuxed`]'s [`futures::stream::Stream`] impl.
#[derive(Debug)]
pub enum CodecItem {
VideoFrame(VideoFrame),
@ -32,6 +33,17 @@ pub enum CodecItem {
SenderReport(crate::client::rtp::SenderReport),
}
/// Parameters which describe a stream.
///
/// Parameters are often, but not always, available immediately
/// after `DESCRIBE` via [`crate::client::Stream::parameters`]. They should
/// always be available after the first frame.
///
/// Video streams' parameters may change mid-stream; if so, the frame which
/// changed them will have `VideoFrame::new_parameters` set, and subsequent
/// calls to [`crate::client::Stream::parameters`] will return the new value.
///
/// Currently audio and message streams' parameters never change mid-stream.
#[derive(Clone, Debug)]
pub enum Parameters {
Video(VideoParameters),
@ -39,6 +51,15 @@ pub enum Parameters {
Message(MessageParameters),
}
/// Parameters which describe a video stream.
///
/// A video stream's parameters are often, but not always, available immediately
/// after `DESCRIBE` via [`crate::client::Stream::parameters`]. They should
/// always be available after the first frame. They may change mid-stream.
///
/// Video streams' parameters may change mid-stream; if so, the frame which
/// changed them will have `VideoFrame::new_parameters` set, and subsequent
/// calls to [`crate::client::Stream::parameters`] will return the new value.
#[derive(Clone)]
pub struct VideoParameters {
pixel_dimensions: (u32, u32),
@ -107,6 +128,7 @@ impl std::fmt::Debug for VideoParameters {
}
}
/// Parameters which describe an audio stream.
#[derive(Clone)]
pub struct AudioParameters {
rfc6381_codec: Option<String>,
@ -198,9 +220,11 @@ impl Buf for AudioFrame {
}
}
/// Parameters which describe a message stream, for `application` media types.
#[derive(Clone, Debug)]
pub struct MessageParameters(onvif::CompressionType);
/// A single message, for `application` media types.
pub struct MessageFrame {
pub ctx: crate::PacketContext,
pub timestamp: crate::Timestamp,

View File

@ -1,6 +1,11 @@
// Copyright (C) 2021 Scott Lamb <slamb@slamb.org>
// SPDX-License-Identifier: MIT OR Apache-2.0
//! High-level RTSP library.
//!
//! Currently this is useful for clients; it will be extended to support
//! servers and proxies.
use bytes::Bytes;
use log::trace;
//use failure::{bail, format_err, Error};
@ -40,9 +45,13 @@ mod tokio;
use error::ErrorInt;
// TODO: these are `pub`, yet the crate doesn't expose a direct way to set or get
// headers, a combination which makes little sense.
#[doc(hidden)]
pub static X_ACCEPT_DYNAMIC_RATE: Lazy<rtsp_types::HeaderName> = Lazy::new(|| {
rtsp_types::HeaderName::from_static_str("x-Accept-Dynamic-Rate").expect("is ascii")
});
#[doc(hidden)]
pub static X_DYNAMIC_RATE: Lazy<rtsp_types::HeaderName> =
Lazy::new(|| rtsp_types::HeaderName::from_static_str("x-Dynamic-Rate").expect("is ascii"));
@ -54,6 +63,7 @@ struct ReceivedMessage {
}
/// A monotonically increasing timestamp within an RTP stream.
///
/// The [Display] and [Debug] implementations display:
/// * the bottom 32 bits, as seen in RTP packet headers. This advances at a
/// codec-specified clock rate.
@ -148,11 +158,26 @@ impl Debug for Timestamp {
}
}
/// The Unix epoch as an [`NtpTimestamp`].
pub const UNIX_EPOCH: NtpTimestamp = NtpTimestamp((2_208_988_800) << 32);
/// A wallclock time represented using the format of the Network Time Protocol.
/// This isn't necessarily gathered from a real NTP server. Reported NTP
/// timestamps are allowed to jump backwards and/or be complete nonsense.
///
/// NTP timestamps are in a fixed-point representation of seconds since
/// 0h UTC on 1 January 1900. The top 32 bits represent the integer part
/// (wrapping around every 68 years) and the bottom 32 bits represent the
/// fractional part.
///
/// This is a simple wrapper around a `u64` in that format, with a `Display`
/// impl that writes the timestamp as a human-readable string. Currently this
/// assumes the time is within 68 years of 1970; the string will be incorrect
/// after `2038-01-19T03:14:07Z`.
///
/// An `NtpTimestamp` isn't necessarily gathered from a real NTP server.
/// Reported NTP timestamps are allowed to jump backwards and/or be complete
/// nonsense.
///
/// The NTP timestamp of the Unix epoch is available via the constant [`UNIX_EPOCH`].
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct NtpTimestamp(pub u64);
@ -288,7 +313,7 @@ impl Display for RtspMessageContext {
/// Context for an RTP or RTCP packet, received either via RTSP interleaved data or UDP.
///
/// Should be paired with an [`RtspConnectionContext`] of the RTSP connection that started
/// Should be paired with an [`ConnectionContext`] of the RTSP connection that started
/// the session. In the interleaved data case, it's assumed the packet was received over
/// that same connection.
#[derive(Copy, Clone, Debug)]