pub mod sys;
use std::{
fs::{
File,
OpenOptions,
},
io::Read,
os::{
fd::{
AsFd,
BorrowedFd,
},
unix::io::{
AsRawFd,
RawFd,
},
},
};
use self::sys::*;
use crate::error::{
Error,
Result,
};
#[derive(Debug)]
pub struct DmxDevice {
file: File,
}
impl AsRawFd for DmxDevice {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl AsFd for DmxDevice {
fn as_fd(&self) -> BorrowedFd<'_> {
self.file.as_fd()
}
}
impl Read for DmxDevice {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
(&self.file).read(buf)
}
}
impl DmxDevice {
pub fn open(adapter: u32, device: u32) -> Result<Self> {
let path = format!("/dev/dvb/adapter{}/demux{}", adapter, device);
let file = OpenOptions::new().read(true).write(true).open(&path)?;
let dmx = DmxDevice { file };
Ok(dmx)
}
pub fn open_ts_tap(adapter: u32, device: u32, pid: u16) -> Result<Self> {
let dmx = Self::open(adapter, device)?;
dmx.set_ts_tap(pid)?;
Ok(dmx)
}
pub fn set_pes_filter(&self, filter: &DmxPesFilterParams) -> Result<()> {
nix::ioctl_write_ptr!(
#[inline]
ioctl_call,
b'o',
44,
DmxPesFilterParams
);
unsafe { ioctl_call(self.as_raw_fd(), filter) }?;
Ok(())
}
pub fn set_ts_tap(&self, pid: u16) -> Result<()> {
if pid > 0x2000 {
return Err(Error::InvalidData(format!(
"transport-stream PID must be in range 0..=8191 or 8192 for all PIDs, got {pid}"
)));
}
let filter = DmxPesFilterParams {
pid,
input: DMX_IN_FRONTEND,
output: DMX_OUT_TS_TAP,
pes_type: DMX_PES_OTHER,
flags: DmxFilterFlags::IMMEDIATE_START.bits(),
};
self.set_pes_filter(&filter)
}
pub fn set_buffer_size(&self, buffer_size: u64) -> Result<()> {
nix::ioctl_write_int_bad!(
#[inline]
ioctl_call,
nix::request_code_none!(b'o', 45)
);
unsafe { ioctl_call(self.as_raw_fd(), buffer_size as _) }?;
Ok(())
}
pub fn start(&self) -> Result<()> {
nix::ioctl_none!(
#[inline]
ioctl_call,
b'o',
41
);
unsafe { ioctl_call(self.as_raw_fd()) }?;
Ok(())
}
pub fn stop(&self) -> Result<()> {
nix::ioctl_none!(
#[inline]
ioctl_call,
b'o',
42
);
unsafe { ioctl_call(self.as_raw_fd()) }?;
Ok(())
}
}