dvb_stream/
t2mi_stream.rs1use std::collections::VecDeque;
14use std::pin::Pin;
15use std::task::{Context, Poll};
16
17use dvb_t2mi::pump::{T2miEvent, T2miPump};
18use futures_core::Stream;
19use tokio::io::AsyncRead;
20use tokio::io::ReadBuf;
21
22use crate::ResyncStats;
23use crate::resync::{TS_PACKET_SIZE, TS_SYNC_BYTE, resync};
24
25const READ_BUF_SIZE: usize = TS_PACKET_SIZE * 7;
27
28pub struct T2miEventStream<R> {
40 reader: R,
41 pump: T2miPump,
42 queue: VecDeque<T2miEvent>,
43 buf: Vec<u8>,
44 filled: usize,
46 eof: bool,
48 synced: bool,
50 resync_stats: ResyncStats,
52}
53
54impl<R: AsyncRead + Unpin> T2miEventStream<R> {
55 #[must_use]
59 pub fn new(reader: R, pid: u16) -> Self {
60 Self::with_pump(reader, T2miPump::new(pid))
61 }
62
63 #[must_use]
65 pub fn with_pump(reader: R, pump: T2miPump) -> Self {
66 Self {
67 reader,
68 pump,
69 queue: VecDeque::new(),
70 buf: vec![0u8; READ_BUF_SIZE],
71 filled: 0,
72 eof: false,
73 synced: false,
74 resync_stats: ResyncStats::default(),
75 }
76 }
77
78 #[must_use]
80 pub fn stats(&self) -> dvb_t2mi::pump::Stats {
81 self.pump.stats()
82 }
83
84 #[must_use]
86 pub fn resync_stats(&self) -> ResyncStats {
87 self.resync_stats
88 }
89
90 fn feed_buf(&mut self, data: &[u8]) {
92 let start = if self.synced {
93 0
94 } else {
95 match resync(data) {
96 Some(off) => {
97 self.synced = true;
98 self.resync_stats.resyncs += 1;
99 self.resync_stats.bytes_discarded += off as u64;
100 off
101 }
102 None => {
103 self.resync_stats.bytes_discarded += data.len() as u64;
104 return;
105 }
106 }
107 };
108
109 let aligned = &data[start..];
111 let n_packets = aligned.len() / TS_PACKET_SIZE;
112 for i in 0..n_packets {
113 let pkt_start = i * TS_PACKET_SIZE;
114 let pkt = &aligned[pkt_start..pkt_start + TS_PACKET_SIZE];
115 if pkt[0] != TS_SYNC_BYTE {
116 self.resync_stats.desyncs += 1;
118 let discarded = aligned.len() - pkt_start;
119 self.resync_stats.bytes_discarded += discarded as u64;
120 self.synced = false;
121 self.filled = 0;
122 return;
123 }
124 for event in self.pump.feed_ts(pkt) {
125 self.queue.push_back(event);
126 }
127 }
128
129 self.filled = 0;
130 }
131}
132
133impl<R: AsyncRead + Unpin> Stream for T2miEventStream<R> {
134 type Item = T2miEvent;
135
136 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
137 let this = self.get_mut();
138
139 loop {
140 if let Some(event) = this.queue.pop_front() {
141 return Poll::Ready(Some(event));
142 }
143
144 if this.eof {
145 return Poll::Ready(None);
146 }
147
148 let buf_len = this.buf.len();
149 let read_from = this.filled;
150 let mut read_buf = ReadBuf::new(&mut this.buf[read_from..buf_len]);
151
152 match Pin::new(&mut this.reader).poll_read(cx, &mut read_buf) {
153 Poll::Pending => return Poll::Pending,
154 Poll::Ready(Err(_)) => {
155 this.eof = true;
156 return Poll::Ready(None);
157 }
158 Poll::Ready(Ok(())) => {
159 let n = read_buf.filled().len();
160 if n == 0 {
161 this.eof = true;
162 return Poll::Ready(None);
163 }
164 let total = read_from + n;
165 let data: Vec<u8> = this.buf[..total].to_vec();
166 this.feed_buf(&data);
167 }
168 }
169 }
170 }
171}
172
173#[cfg(feature = "udp")]
175impl T2miEventStream<crate::section_stream::UdpReader> {
176 pub async fn bind_multicast(
185 bind_addr: std::net::SocketAddrV4,
186 multicast_addr: std::net::Ipv4Addr,
187 pid: u16,
188 ) -> std::io::Result<Self> {
189 use tokio::net::UdpSocket;
190 let socket = UdpSocket::bind(bind_addr).await?;
191 socket.join_multicast_v4(multicast_addr, *bind_addr.ip())?;
192 Ok(Self::new(crate::section_stream::UdpReader { socket }, pid))
193 }
194}