remove StreamContextRef type

Turns out it's not a problem to keep around a StreamContext, so let's
avoid the complexity of another public type (and another internal type).
This commit is contained in:
Scott Lamb 2022-05-11 09:26:00 -07:00
parent 8caa1d9ae3
commit 1b6491370f
9 changed files with 113 additions and 147 deletions

View File

@ -32,7 +32,7 @@ fn h264_aac<F: FnMut(CodecItem) -> ()>(mut f: F) {
Depacketizer::new("video", "h264", 90_000, None, Some("packetization-mode=1;profile-level-id=42C01E;sprop-parameter-sets=Z0LAHtkDxWhAAAADAEAAAAwDxYuS,aMuMsg==")).unwrap(), Depacketizer::new("video", "h264", 90_000, None, Some("packetization-mode=1;profile-level-id=42C01E;sprop-parameter-sets=Z0LAHtkDxWhAAAADAEAAAAwDxYuS,aMuMsg==")).unwrap(),
]; ];
let conn_ctx = retina::ConnectionContext::dummy(); let conn_ctx = retina::ConnectionContext::dummy();
let stream_ctx = retina::StreamContextRef::dummy(); let stream_ctx = retina::StreamContext::dummy();
let pkt_ctx = retina::PacketContext::dummy(); let pkt_ctx = retina::PacketContext::dummy();
while !remaining.is_empty() { while !remaining.is_empty() {
assert!(remaining.len() > 4); assert!(remaining.len() > 4);
@ -50,7 +50,7 @@ fn h264_aac<F: FnMut(CodecItem) -> ()>(mut f: F) {
}; };
let pkt = match rtps[stream_id].rtp( let pkt = match rtps[stream_id].rtp(
&retina::client::SessionOptions::default(), &retina::client::SessionOptions::default(),
stream_ctx, &stream_ctx,
None, None,
&conn_ctx, &conn_ctx,
&pkt_ctx, &pkt_ctx,
@ -63,7 +63,7 @@ fn h264_aac<F: FnMut(CodecItem) -> ()>(mut f: F) {
}; };
depacketizers[stream_id].push(pkt).unwrap(); depacketizers[stream_id].push(pkt).unwrap();
while let Some(pkt) = depacketizers[stream_id] while let Some(pkt) = depacketizers[stream_id]
.pull(&conn_ctx, stream_ctx) .pull(&conn_ctx, &stream_ctx)
.unwrap() .unwrap()
{ {
f(pkt); f(pkt);

View File

@ -12,7 +12,7 @@ fuzz_target!(|data: &[u8]| {
let mut timestamp = retina::Timestamp::new(0, NonZeroU32::new(90_000).unwrap(), 0).unwrap(); let mut timestamp = retina::Timestamp::new(0, NonZeroU32::new(90_000).unwrap(), 0).unwrap();
let mut sequence_number: u16 = 0; let mut sequence_number: u16 = 0;
let conn_ctx = retina::ConnectionContext::dummy(); let conn_ctx = retina::ConnectionContext::dummy();
let stream_ctx = retina::StreamContextRef::dummy(); let stream_ctx = retina::StreamContext::dummy();
let pkt_ctx = retina::PacketContext::dummy(); let pkt_ctx = retina::PacketContext::dummy();
loop { loop {
let (hdr, rest) = match data.split_first() { let (hdr, rest) = match data.split_first() {
@ -50,7 +50,7 @@ fuzz_target!(|data: &[u8]| {
if depacketizer.push(pkt).is_err() { if depacketizer.push(pkt).is_err() {
return; return;
} }
while let Some(item) = depacketizer.pull(&conn_ctx, stream_ctx).transpose() { while let Some(item) = depacketizer.pull(&conn_ctx, &stream_ctx).transpose() {
if item.is_err() { if item.is_err() {
return; return;
} }

View File

@ -16,7 +16,7 @@ fuzz_target!(|data: &[u8]| {
return; return;
} }
let conn_ctx = retina::ConnectionContext::dummy(); let conn_ctx = retina::ConnectionContext::dummy();
let stream_ctx = retina::StreamContextRef::dummy(); let stream_ctx = retina::StreamContext::dummy();
let max_payload_size = u16::from_be_bytes([data[0], data[1]]); let max_payload_size = u16::from_be_bytes([data[0], data[1]]);
let mut p = match retina::codec::h264::Packetizer::new(max_payload_size, 0, 0, 0, 0) { let mut p = match retina::codec::h264::Packetizer::new(max_payload_size, 0, 0, 0, 0) {
Ok(p) => p, Ok(p) => p,
@ -43,7 +43,7 @@ fuzz_target!(|data: &[u8]| {
if d.push(pkt).is_err() { if d.push(pkt).is_err() {
return; return;
} }
match d.pull(&conn_ctx, stream_ctx) { match d.pull(&conn_ctx, &stream_ctx) {
Err(_) => return, Err(_) => return,
Ok(Some(retina::codec::CodecItem::VideoFrame(f))) => { Ok(Some(retina::codec::CodecItem::VideoFrame(f))) => {
assert!(mark); assert!(mark);
@ -69,6 +69,6 @@ fuzz_target!(|data: &[u8]| {
} }
}; };
assert_eq!(&data[2..], &frame.data()[..]); assert_eq!(&data[2..], &frame.data()[..]);
assert!(matches!(d.pull(&conn_ctx, stream_ctx), Ok(None))); assert!(matches!(d.pull(&conn_ctx, &stream_ctx), Ok(None)));
assert!(matches!(p.pull(), Ok(None))); assert!(matches!(p.pull(), Ok(None)));
}); });

View File

@ -25,7 +25,7 @@ use url::Url;
use crate::client::parse::SessionHeader; use crate::client::parse::SessionHeader;
use crate::codec::CodecItem; use crate::codec::CodecItem;
use crate::{ use crate::{
Error, ErrorInt, RtspMessageContext, StreamContextRef, StreamContextRefInner, TcpStreamContext, Error, ErrorInt, RtspMessageContext, StreamContext, StreamContextInner, TcpStreamContext,
UdpStreamContext, UdpStreamContext,
}; };
@ -771,33 +771,18 @@ impl Stream {
} }
} }
enum StreamTransport { struct UdpSockets {
Udp(UdpStreamTransport), // the ...Transport wrapper struct keeps ...Context and the sockets. rtp: UdpSocket,
Tcp(TcpStreamContext), // no sockets; ...Context suffices. rtcp: UdpSocket,
} }
impl std::fmt::Debug for StreamTransport { /// Placeholder `Debug` impl to allow `UdpSockets` to be a field within a `#[derive(Debug)]` struct.
impl std::fmt::Debug for UdpSockets {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.ctx(), f) f.debug_struct("UdpSockets").finish()
} }
} }
impl StreamTransport {
fn ctx(&self) -> StreamContextRef {
StreamContextRef(match self {
StreamTransport::Tcp(tcp) => StreamContextRefInner::Tcp(*tcp),
StreamTransport::Udp(udp) => StreamContextRefInner::Udp(&udp.ctx),
})
}
}
#[derive(Debug)]
struct UdpStreamTransport {
ctx: UdpStreamContext,
rtp_socket: UdpSocket,
rtcp_socket: UdpSocket,
}
impl Stream { impl Stream {
/// Returns codec-specified parameters for this stream, if available. /// Returns codec-specified parameters for this stream, if available.
/// ///
@ -834,11 +819,11 @@ impl Stream {
} }
/// Returns a context for this stream, if it has been set up. /// Returns a context for this stream, if it has been set up.
pub fn ctx(&self) -> Option<StreamContextRef> { pub fn ctx(&self) -> Option<&StreamContext> {
match &self.state { match &self.state {
StreamState::Uninit => None, StreamState::Uninit => None,
StreamState::Init(init) => Some(init.transport.ctx()), StreamState::Init(init) => Some(&init.ctx),
StreamState::Playing { transport, .. } => Some(transport.ctx()), StreamState::Playing { ctx, .. } => Some(ctx),
} }
} }
} }
@ -855,7 +840,8 @@ enum StreamState {
Playing { Playing {
timeline: Timeline, timeline: Timeline,
rtp_handler: rtp::InorderParser, rtp_handler: rtp::InorderParser,
transport: StreamTransport, ctx: StreamContext,
udp_sockets: Option<UdpSockets>,
}, },
} }
@ -877,7 +863,8 @@ struct StreamStateInit {
/// itself; by the time it returns, the stream will be in state `Playing`. /// itself; by the time it returns, the stream will be in state `Playing`.
initial_rtptime: Option<u32>, initial_rtptime: Option<u32>,
transport: StreamTransport, ctx: StreamContext,
udp_sockets: Option<UdpSockets>,
} }
/// Username and password authentication credentials. /// Username and password authentication credentials.
@ -1426,16 +1413,18 @@ impl Session<Described> {
), ),
); );
*inner.flags |= SessionFlag::UdpStreams as u8; *inner.flags |= SessionFlag::UdpStreams as u8;
Some(UdpStreamTransport { Some((
ctx: UdpStreamContext { UdpStreamContext {
local_ip, local_ip,
peer_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED), peer_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
local_rtp_port: pair.rtp_port, local_rtp_port: pair.rtp_port,
peer_rtp_port: 0, peer_rtp_port: 0,
}, },
rtp_socket: pair.rtp_socket, UdpSockets {
rtcp_socket: pair.rtcp_socket, rtp: pair.rtp_socket,
}) rtcp: pair.rtcp_socket,
},
))
} }
}; };
if let Some(ref s) = inner.session { if let Some(ref s) = inner.session {
@ -1481,7 +1470,8 @@ impl Session<Described> {
None => *inner.session = Some(response.session), None => *inner.session = Some(response.session),
}; };
let conn_ctx = conn.inner.ctx(); let conn_ctx = conn.inner.ctx();
let transport = match udp { let (stream_ctx, udp_sockets);
match udp {
None => { None => {
let channel_id = match response.channel_id { let channel_id = match response.channel_id {
Some(id) => id, Some(id) => id,
@ -1506,11 +1496,12 @@ impl Session<Described> {
description, description,
}) })
})?; })?;
StreamTransport::Tcp(TcpStreamContext { stream_ctx = StreamContext(StreamContextInner::Tcp(TcpStreamContext {
rtp_channel_id: channel_id, rtp_channel_id: channel_id,
}) }));
udp_sockets = None;
} }
Some(mut udp) => { Some((mut ctx, sockets)) => {
// TODO: RFC 2326 section 12.39 says "If the source address for // TODO: RFC 2326 section 12.39 says "If the source address for
// the stream is different than can be derived from the RTSP // the stream is different than can be derived from the RTSP
// endpoint address (the server in playback or the client in // endpoint address (the server in playback or the client in
@ -1531,27 +1522,31 @@ impl Session<Described> {
description: "Transport header is missing server_port parameter".to_owned(), description: "Transport header is missing server_port parameter".to_owned(),
}) })
})?; })?;
udp.ctx.peer_ip = source; ctx.peer_ip = source;
udp.ctx.peer_rtp_port = server_port; ctx.peer_rtp_port = server_port;
udp.rtp_socket sockets
.rtp
.connect(SocketAddr::new(source, server_port)) .connect(SocketAddr::new(source, server_port))
.await .await
.map_err(|e| wrap!(ErrorInt::ConnectError(e)))?; .map_err(|e| wrap!(ErrorInt::ConnectError(e)))?;
udp.rtcp_socket sockets
.rtcp
.connect(SocketAddr::new(source, server_port + 1)) .connect(SocketAddr::new(source, server_port + 1))
.await .await
.map_err(|e| wrap!(ErrorInt::ConnectError(e)))?; .map_err(|e| wrap!(ErrorInt::ConnectError(e)))?;
punch_firewall_hole(&udp.rtp_socket, &udp.rtcp_socket) punch_firewall_hole(&sockets)
.await .await
.map_err(|e| wrap!(ErrorInt::ConnectError(e)))?; .map_err(|e| wrap!(ErrorInt::ConnectError(e)))?;
StreamTransport::Udp(udp) stream_ctx = StreamContext(StreamContextInner::Udp(ctx));
udp_sockets = Some(sockets);
} }
}; };
stream.state = StreamState::Init(StreamStateInit { stream.state = StreamState::Init(StreamStateInit {
ssrc: response.ssrc, ssrc: response.ssrc,
initial_seq: None, initial_seq: None,
initial_rtptime: None, initial_rtptime: None,
transport, ctx: stream_ctx,
udp_sockets,
}); });
Ok(()) Ok(())
} }
@ -1631,7 +1626,8 @@ impl Session<Described> {
initial_rtptime, initial_rtptime,
initial_seq, initial_seq,
ssrc, ssrc,
transport, ctx,
udp_sockets,
.. ..
}) => { }) => {
let initial_rtptime = match policy.initial_timestamp { let initial_rtptime = match policy.initial_timestamp {
@ -1687,7 +1683,8 @@ impl Session<Described> {
}) })
})?, })?,
rtp_handler: rtp::InorderParser::new(ssrc, initial_seq), rtp_handler: rtp::InorderParser::new(ssrc, initial_seq),
transport, ctx,
udp_sockets,
}; };
} }
StreamState::Uninit => {} StreamState::Uninit => {}
@ -1800,10 +1797,7 @@ fn note_stale_live555_data(tool: Option<&Tool>, options: &SessionOptions) {
/// ///
/// Note this is insufficient for NAT traversal; the NAT firewall must be /// Note this is insufficient for NAT traversal; the NAT firewall must be
/// RTSP-aware to rewrite the Transport header's client_ports. /// RTSP-aware to rewrite the Transport header's client_ports.
async fn punch_firewall_hole( async fn punch_firewall_hole(sockets: &UdpSockets) -> Result<(), std::io::Error> {
rtp_socket: &UdpSocket,
rtcp_socket: &UdpSocket,
) -> Result<(), std::io::Error> {
#[rustfmt::skip] #[rustfmt::skip]
const DUMMY_RTP: [u8; 12] = [ const DUMMY_RTP: [u8; 12] = [
2 << 6, // version=2 + p=0 + x=0 + cc=0 2 << 6, // version=2 + p=0 + x=0 + cc=0
@ -1819,8 +1813,8 @@ async fn punch_firewall_hole(
0, 1, // length=1 (in 4-byte words minus 1) 0, 1, // length=1 (in 4-byte words minus 1)
0, 0, 0, 0, // ssrc=0 (bogus but we don't know the ssrc reliably yet) 0, 0, 0, 0, // ssrc=0 (bogus but we don't know the ssrc reliably yet)
]; ];
rtp_socket.send(&DUMMY_RTP[..]).await?; sockets.rtp.send(&DUMMY_RTP[..]).await?;
rtcp_socket.send(&DUMMY_RTCP[..]).await?; sockets.rtcp.send(&DUMMY_RTCP[..]).await?;
Ok(()) Ok(())
} }
@ -1988,8 +1982,9 @@ impl Session<Playing> {
StreamState::Playing { StreamState::Playing {
timeline, timeline,
rtp_handler, rtp_handler,
transport, ctx,
} => (timeline, rtp_handler, transport.ctx()), ..
} => (timeline, rtp_handler, ctx),
_ => unreachable!( _ => unreachable!(
"Session<Playing>'s {}->{:?} not in Playing state", "Session<Playing>'s {}->{:?} not in Playing state",
channel_id, m channel_id, m
@ -2043,12 +2038,14 @@ impl Session<Playing> {
debug_assert!(buf.filled().is_empty()); debug_assert!(buf.filled().is_empty());
let inner = self.0.as_mut().project(); let inner = self.0.as_mut().project();
let s = &mut inner.presentation.streams[i]; let s = &mut inner.presentation.streams[i];
let (timeline, rtp_handler, udp) = match &mut s.state { let (timeline, rtp_handler, stream_ctx, udp_sockets) = match &mut s.state {
StreamState::Playing { StreamState::Playing {
timeline, timeline,
rtp_handler, rtp_handler,
transport: StreamTransport::Udp(udp), ctx,
} => (timeline, rtp_handler, udp), udp_sockets: Some(udp_sockets),
..
} => (timeline, rtp_handler, ctx, udp_sockets),
_ => return Poll::Pending, _ => return Poll::Pending,
}; };
let conn_ctx = inner let conn_ctx = inner
@ -2057,10 +2054,9 @@ impl Session<Playing> {
.ok_or_else(|| wrap!(ErrorInt::FailedPrecondition("no connection".into())))? .ok_or_else(|| wrap!(ErrorInt::FailedPrecondition("no connection".into())))?
.inner .inner
.ctx(); .ctx();
let stream_ctx = StreamContextRef(StreamContextRefInner::Udp(&udp.ctx));
// Prioritize RTCP over RTP within a stream. // Prioritize RTCP over RTP within a stream.
while let Poll::Ready(r) = udp.rtcp_socket.poll_recv(cx, buf) { while let Poll::Ready(r) = udp_sockets.rtcp.poll_recv(cx, buf) {
let when = crate::WallTime::now(); let when = crate::WallTime::now();
match r { match r {
Ok(()) => { Ok(()) => {
@ -2100,9 +2096,8 @@ impl Session<Playing> {
} }
} }
} }
while let Poll::Ready(r) = udp.rtp_socket.poll_recv(cx, buf) { while let Poll::Ready(r) = udp_sockets.rtp.poll_recv(cx, buf) {
let when = crate::WallTime::now(); let when = crate::WallTime::now();
let stream_ctx = StreamContextRef(StreamContextRefInner::Udp(&udp.ctx));
match r { match r {
Ok(()) => { Ok(()) => {
let msg = Bytes::copy_from_slice(buf.filled()); let msg = Bytes::copy_from_slice(buf.filled());
@ -2358,7 +2353,7 @@ impl futures::Stream for Demuxed {
let inner = self.session.0.as_mut().project(); let inner = self.session.0.as_mut().project();
let stream = &mut inner.presentation.streams[stream_id]; let stream = &mut inner.presentation.streams[stream_id];
let stream_ctx = match stream.state { let stream_ctx = match stream.state {
StreamState::Playing { ref transport, .. } => transport.ctx(), StreamState::Playing { ref ctx, .. } => ctx,
_ => unreachable!(), _ => unreachable!(),
}; };
let depacketizer = match &mut stream.depacketizer { let depacketizer = match &mut stream.depacketizer {

View File

@ -669,9 +669,8 @@ mod tests {
use bytes::Bytes; use bytes::Bytes;
use url::Url; use url::Url;
use crate::client::StreamTransport;
use crate::TcpStreamContext;
use crate::{client::StreamStateInit, codec::Parameters}; use crate::{client::StreamStateInit, codec::Parameters};
use crate::{StreamContext, StreamContextInner, TcpStreamContext};
use super::super::StreamState; use super::super::StreamState;
use super::SessionHeader; use super::SessionHeader;
@ -690,7 +689,10 @@ mod tests {
ssrc, ssrc,
initial_seq: None, initial_seq: None,
initial_rtptime: None, initial_rtptime: None,
transport: StreamTransport::Tcp(TcpStreamContext { rtp_channel_id: 0 }), ctx: StreamContext(StreamContextInner::Tcp(TcpStreamContext {
rtp_channel_id: 0,
})),
udp_sockets: None,
}) })
} }

View File

@ -9,9 +9,7 @@ use log::debug;
use crate::client::PacketItem; use crate::client::PacketItem;
use crate::rtcp::ReceivedCompoundPacket; use crate::rtcp::ReceivedCompoundPacket;
use crate::rtp::{RawPacket, ReceivedPacket}; use crate::rtp::{RawPacket, ReceivedPacket};
use crate::{ use crate::{ConnectionContext, Error, ErrorInt, PacketContext, StreamContext, StreamContextInner};
ConnectionContext, Error, ErrorInt, PacketContext, StreamContextRef, StreamContextRefInner,
};
use super::{SessionOptions, Timeline}; use super::{SessionOptions, Timeline};
@ -69,7 +67,7 @@ impl InorderParser {
pub fn rtp( pub fn rtp(
&mut self, &mut self,
session_options: &SessionOptions, session_options: &SessionOptions,
stream_ctx: StreamContextRef, stream_ctx: &StreamContext,
tool: Option<&super::Tool>, tool: Option<&super::Tool>,
conn_ctx: &ConnectionContext, conn_ctx: &ConnectionContext,
pkt_ctx: &PacketContext, pkt_ctx: &PacketContext,
@ -107,7 +105,7 @@ impl InorderParser {
let ssrc = raw.ssrc(); let ssrc = raw.ssrc();
let loss = sequence_number.wrapping_sub(self.next_seq.unwrap_or(sequence_number)); let loss = sequence_number.wrapping_sub(self.next_seq.unwrap_or(sequence_number));
if matches!(self.ssrc, Some(s) if s != ssrc) { if matches!(self.ssrc, Some(s) if s != ssrc) {
if matches!(stream_ctx.0, StreamContextRefInner::Udp(_)) { if matches!(stream_ctx.0, StreamContextInner::Udp(_)) {
super::note_stale_live555_data(tool, session_options); super::note_stale_live555_data(tool, session_options);
} }
bail!(ErrorInt::RtpPacketError { bail!(ErrorInt::RtpPacketError {
@ -125,7 +123,7 @@ impl InorderParser {
}); });
} }
if loss > 0x80_00 { if loss > 0x80_00 {
if matches!(stream_ctx.0, StreamContextRefInner::Tcp { .. }) { if matches!(stream_ctx.0, StreamContextInner::Tcp { .. }) {
bail!(ErrorInt::RtpPacketError { bail!(ErrorInt::RtpPacketError {
conn_ctx: *conn_ctx, conn_ctx: *conn_ctx,
pkt_ctx: *pkt_ctx, pkt_ctx: *pkt_ctx,
@ -177,7 +175,7 @@ impl InorderParser {
pub fn rtcp( pub fn rtcp(
&mut self, &mut self,
session_options: &SessionOptions, session_options: &SessionOptions,
stream_ctx: StreamContextRef, stream_ctx: &StreamContext,
tool: Option<&super::Tool>, tool: Option<&super::Tool>,
pkt_ctx: &PacketContext, pkt_ctx: &PacketContext,
timeline: &mut Timeline, timeline: &mut Timeline,
@ -196,7 +194,7 @@ impl InorderParser {
let ssrc = sr.ssrc(); let ssrc = sr.ssrc();
if matches!(self.ssrc, Some(s) if s != ssrc) { if matches!(self.ssrc, Some(s) if s != ssrc) {
if matches!(stream_ctx.0, StreamContextRefInner::Tcp { .. }) { if matches!(stream_ctx.0, StreamContextInner::Tcp { .. }) {
super::note_stale_live555_data(tool, session_options); super::note_stale_live555_data(tool, session_options);
} }
return Err(format!( return Err(format!(
@ -231,7 +229,7 @@ mod tests {
fn geovision_pt50_packet() { fn geovision_pt50_packet() {
let mut timeline = Timeline::new(None, 90_000, None).unwrap(); let mut timeline = Timeline::new(None, 90_000, None).unwrap();
let mut parser = InorderParser::new(Some(0xd25614e), None); let mut parser = InorderParser::new(Some(0xd25614e), None);
let stream_ctx = StreamContextRef::dummy(); let stream_ctx = StreamContext::dummy();
// Normal packet. // Normal packet.
let (pkt, _payload_range) = crate::rtp::RawPacketBuilder { let (pkt, _payload_range) = crate::rtp::RawPacketBuilder {
@ -245,7 +243,7 @@ mod tests {
.unwrap(); .unwrap();
match parser.rtp( match parser.rtp(
&SessionOptions::default(), &SessionOptions::default(),
stream_ctx, &stream_ctx,
None, None,
&ConnectionContext::dummy(), &ConnectionContext::dummy(),
&PacketContext::dummy(), &PacketContext::dummy(),
@ -269,7 +267,7 @@ mod tests {
.unwrap(); .unwrap();
match parser.rtp( match parser.rtp(
&SessionOptions::default(), &SessionOptions::default(),
stream_ctx, &stream_ctx,
None, None,
&ConnectionContext::dummy(), &ConnectionContext::dummy(),
&PacketContext::dummy(), &PacketContext::dummy(),
@ -286,13 +284,12 @@ mod tests {
fn out_of_order() { fn out_of_order() {
let mut timeline = Timeline::new(None, 90_000, None).unwrap(); let mut timeline = Timeline::new(None, 90_000, None).unwrap();
let mut parser = InorderParser::new(Some(0xd25614e), None); let mut parser = InorderParser::new(Some(0xd25614e), None);
let udp = UdpStreamContext { let stream_ctx = StreamContext(StreamContextInner::Udp(UdpStreamContext {
local_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED), local_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
peer_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED), peer_ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
local_rtp_port: 0, local_rtp_port: 0,
peer_rtp_port: 0, peer_rtp_port: 0,
}; }));
let stream_ctx = StreamContextRef(StreamContextRefInner::Udp(&udp));
let session_options = SessionOptions::default(); let session_options = SessionOptions::default();
let (pkt, _payload_range) = crate::rtp::RawPacketBuilder { let (pkt, _payload_range) = crate::rtp::RawPacketBuilder {
sequence_number: 2, sequence_number: 2,
@ -305,7 +302,7 @@ mod tests {
.unwrap(); .unwrap();
match parser.rtp( match parser.rtp(
&session_options, &session_options,
stream_ctx, &stream_ctx,
None, None,
&ConnectionContext::dummy(), &ConnectionContext::dummy(),
&PacketContext::dummy(), &PacketContext::dummy(),
@ -330,7 +327,7 @@ mod tests {
.unwrap(); .unwrap();
match parser.rtp( match parser.rtp(
&session_options, &session_options,
stream_ctx, &stream_ctx,
None, None,
&ConnectionContext::dummy(), &ConnectionContext::dummy(),
&PacketContext::dummy(), &PacketContext::dummy(),
@ -353,7 +350,7 @@ mod tests {
.unwrap(); .unwrap();
match parser.rtp( match parser.rtp(
&session_options, &session_options,
stream_ctx, &stream_ctx,
None, None,
&ConnectionContext::dummy(), &ConnectionContext::dummy(),
&PacketContext::dummy(), &PacketContext::dummy(),

View File

@ -21,7 +21,7 @@ use std::{
num::{NonZeroU16, NonZeroU32}, num::{NonZeroU16, NonZeroU32},
}; };
use crate::{error::ErrorInt, rtp::ReceivedPacket, ConnectionContext, Error, StreamContextRef}; use crate::{error::ErrorInt, rtp::ReceivedPacket, ConnectionContext, Error, StreamContext};
use super::CodecItem; use super::CodecItem;
@ -652,7 +652,7 @@ impl Depacketizer {
pub(super) fn pull( pub(super) fn pull(
&mut self, &mut self,
conn_ctx: &ConnectionContext, conn_ctx: &ConnectionContext,
stream_ctx: StreamContextRef, stream_ctx: &StreamContext,
) -> Result<Option<super::CodecItem>, Error> { ) -> Result<Option<super::CodecItem>, Error> {
match std::mem::take(&mut self.state) { match std::mem::take(&mut self.state) {
s @ DepacketizerState::Idle { .. } | s @ DepacketizerState::Fragmented(..) => { s @ DepacketizerState::Idle { .. } | s @ DepacketizerState::Fragmented(..) => {
@ -770,13 +770,13 @@ impl Depacketizer {
fn error( fn error(
conn_ctx: ConnectionContext, conn_ctx: ConnectionContext,
stream_ctx: StreamContextRef, stream_ctx: &StreamContext,
agg: Aggregate, agg: Aggregate,
description: String, description: String,
) -> Error { ) -> Error {
Error(std::sync::Arc::new(ErrorInt::RtpPacketError { Error(std::sync::Arc::new(ErrorInt::RtpPacketError {
conn_ctx, conn_ctx,
stream_ctx: stream_ctx.to_owned(), stream_ctx: *stream_ctx,
pkt_ctx: *agg.pkt.ctx(), pkt_ctx: *agg.pkt.ctx(),
stream_id: agg.pkt.stream_id(), stream_id: agg.pkt.stream_id(),
ssrc: agg.pkt.ssrc(), ssrc: agg.pkt.ssrc(),
@ -842,7 +842,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -851,7 +851,7 @@ mod tests {
assert_eq!(a.timestamp, timestamp); assert_eq!(a.timestamp, timestamp);
assert_eq!(&a.data[..], b"asdf"); assert_eq!(&a.data[..], b"asdf");
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
@ -880,7 +880,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -889,7 +889,7 @@ mod tests {
assert_eq!(a.timestamp, timestamp); assert_eq!(a.timestamp, timestamp);
assert_eq!(&a.data[..], b"foo"); assert_eq!(&a.data[..], b"foo");
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -898,7 +898,7 @@ mod tests {
assert_eq!(a.timestamp, timestamp.try_add(1_024).unwrap()); assert_eq!(a.timestamp, timestamp.try_add(1_024).unwrap());
assert_eq!(&a.data[..], b"bar"); assert_eq!(&a.data[..], b"bar");
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -907,7 +907,7 @@ mod tests {
assert_eq!(a.timestamp, timestamp.try_add(2_048).unwrap()); assert_eq!(a.timestamp, timestamp.try_add(2_048).unwrap());
assert_eq!(&a.data[..], b"baz"); assert_eq!(&a.data[..], b"baz");
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
@ -935,7 +935,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
d.push( d.push(
@ -961,7 +961,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
d.push( d.push(
@ -987,7 +987,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -996,7 +996,7 @@ mod tests {
assert_eq!(a.timestamp, timestamp); assert_eq!(a.timestamp, timestamp);
assert_eq!(&a.data[..], b"foobarbaz"); assert_eq!(&a.data[..], b"foobarbaz");
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
} }
@ -1038,7 +1038,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
d.push( d.push(
@ -1063,7 +1063,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
@ -1091,7 +1091,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -1100,7 +1100,7 @@ mod tests {
assert_eq!(a.loss, 1); assert_eq!(a.loss, 1);
assert_eq!(&a.data[..], b"asdf"); assert_eq!(&a.data[..], b"asdf");
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
} }
@ -1142,7 +1142,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
// Fragment 2/3 is lost // Fragment 2/3 is lost
@ -1169,7 +1169,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
@ -1197,7 +1197,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -1206,7 +1206,7 @@ mod tests {
assert_eq!(a.loss, 1); assert_eq!(a.loss, 1);
assert_eq!(&a.data[..], b"asdf"); assert_eq!(&a.data[..], b"asdf");
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
} }
@ -1248,7 +1248,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
// Fragment 2/3 is lost // Fragment 2/3 is lost
@ -1275,7 +1275,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
@ -1303,7 +1303,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let a = match d let a = match d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
{ {
Some(CodecItem::AudioFrame(a)) => a, Some(CodecItem::AudioFrame(a)) => a,
@ -1312,7 +1312,7 @@ mod tests {
assert_eq!(a.loss, 1); assert_eq!(a.loss, 1);
assert_eq!(&a.data[..], b"asdf"); assert_eq!(&a.data[..], b"asdf");
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
} }
@ -1357,7 +1357,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert!(d assert!(d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap() .unwrap()
.is_none()); .is_none());
@ -1385,7 +1385,7 @@ mod tests {
) )
.unwrap(); .unwrap();
let e = d let e = d
.pull(&ConnectionContext::dummy(), StreamContextRef::dummy()) .pull(&ConnectionContext::dummy(), &StreamContext::dummy())
.unwrap_err(); .unwrap_err();
let e_str = e.to_string(); let e_str = e.to_string();
assert!( assert!(

View File

@ -12,7 +12,7 @@ use std::num::{NonZeroU16, NonZeroU32};
use crate::rtp::ReceivedPacket; use crate::rtp::ReceivedPacket;
use crate::ConnectionContext; use crate::ConnectionContext;
use crate::Error; use crate::Error;
use crate::StreamContextRef; use crate::StreamContext;
use bytes::Bytes; use bytes::Bytes;
pub(crate) mod aac; pub(crate) mod aac;
@ -555,7 +555,7 @@ impl Depacketizer {
pub fn pull( pub fn pull(
&mut self, &mut self,
conn_ctx: &ConnectionContext, conn_ctx: &ConnectionContext,
stream_ctx: StreamContextRef, stream_ctx: &StreamContext,
) -> Result<Option<CodecItem>, Error> { ) -> Result<Option<CodecItem>, Error> {
match &mut self.0 { match &mut self.0 {
DepacketizerInner::Aac(d) => d.pull(conn_ctx, stream_ctx), DepacketizerInner::Aac(d) => d.pull(conn_ctx, stream_ctx),

View File

@ -367,34 +367,6 @@ enum StreamContextInner {
Dummy, Dummy,
} }
/// Context for an active stream (RTP+RTCP session), either TCP or UDP. Reference version.
#[derive(Copy, Clone, Debug)]
pub struct StreamContextRef<'a>(StreamContextRefInner<'a>);
impl StreamContextRef<'_> {
#[doc(hidden)]
pub fn dummy() -> Self {
StreamContextRef(StreamContextRefInner::Dummy)
}
}
#[derive(Copy, Clone, Debug)]
enum StreamContextRefInner<'a> {
Tcp(TcpStreamContext), // this one is by value because TcpStreamContext is small.
Udp(&'a UdpStreamContext),
Dummy,
}
impl StreamContextRef<'_> {
fn to_owned(self) -> StreamContext {
StreamContext(match self.0 {
StreamContextRefInner::Tcp(tcp) => StreamContextInner::Tcp(tcp),
StreamContextRefInner::Udp(udp) => StreamContextInner::Udp(*udp),
StreamContextRefInner::Dummy => StreamContextInner::Dummy,
})
}
}
/// Context for a UDP stream (aka UDP-based RTP transport). Unstable/internal. Exposed for benchmarks. /// Context for a UDP stream (aka UDP-based RTP transport). Unstable/internal. Exposed for benchmarks.
/// ///
/// This stores only the RTP addresses; the RTCP addresses are assumed to use /// This stores only the RTP addresses; the RTCP addresses are assumed to use