]>
code.octet-stream.net Git - m17rt/blob - m17app/src/soundmodem.rs
1 use std
::io
::{self, ErrorKind
, Read
, Write
};
3 use crate::tnc
::{Tnc
, TncError
};
5 use m17core
::tnc
::SoftTnc
;
7 use std
::path
::PathBuf
;
8 use std
::sync
::mpsc
::{channel
, sync_channel
, Receiver
, Sender
, SyncSender
, TryRecvError
};
9 use std
::sync
::{Arc
, Mutex
};
10 use std
::time
::{Duration
, Instant
};
12 pub struct Soundmodem
{
14 config
: SoundmodemConfig
,
17 pub struct SoundmodemConfig
{
18 // sound cards, PTT, etc.
19 input
: Box
<dyn InputSource
>,
22 impl Read
for Soundmodem
{
23 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
26 .map_err(|s
| io
::Error
::new(ErrorKind
::Other
, format
!("{:?}", s
)))
30 impl Write
for Soundmodem
{
31 fn write(&mut self, buf
: &[u8]) -> std
::io
::Result
<usize> {
34 .map_err(|s
| io
::Error
::new(ErrorKind
::Other
, format
!("{:?}", s
)))
37 fn flush(&mut self) -> std
::io
::Result
<()> {
42 impl Tnc
for Soundmodem
{
43 fn try_clone(&mut self) -> Result
<Self, TncError
> {
47 fn start(&mut self) -> Result
<(), TncError
> {
51 fn close(&mut self) -> Result
<(), TncError
> {
56 pub enum SoundmodemEvent
{
58 BasebandInput(Arc
<[i16]>),
61 pub trait InputSource
: Send
+ Sync
+ '
static {
62 fn start(&self, samples
: SyncSender
<SoundmodemEvent
>);
66 pub struct InputSoundcard
{
70 impl InputSource
for InputSoundcard
{
71 fn start(&self, samples
: SyncSender
<SoundmodemEvent
>) {
80 pub struct InputRrcFile
{
82 end_tx
: Mutex
<Option
<Sender
<()>>>,
85 impl InputSource
for InputRrcFile
{
86 fn start(&self, samples
: SyncSender
<SoundmodemEvent
>) {
87 let (end_tx
, end_rx
) = channel();
88 let path
= self.path
.clone();
89 std
::thread
::spawn(move || {
90 // TODO: error handling
91 let mut file
= File
::open(path
).unwrap
();
92 let mut baseband
= vec
![];
93 file
.read_to_end(&mut baseband
).unwrap
();
95 // assuming 48 kHz for now
96 const TICK
: Duration
= Duration
::from_millis(25);
97 const SAMPLES_PER_TICK
: usize = 1200;
99 let mut next_tick
= Instant
::now() + TICK
;
100 let mut buf
= [0i16; SAMPLES_PER_TICK
];
103 for sample
in baseband
105 .map(|pair
| i16::from_le_bytes([pair
[0], pair
[1]]))
109 if idx
== SAMPLES_PER_TICK
{
110 if let Err(e
) = samples
.try_send(SoundmodemEvent
::BasebandInput(buf
.into
())) {
111 debug
!("overflow feeding soundmodem: {e:?}");
113 next_tick
= next_tick
+ TICK
;
115 std
::thread
::sleep(next_tick
.duration_since(Instant
::now()));
117 if end_rx
.try_recv() != Err(TryRecvError
::Empty
) {
122 *self.end_tx
.lock().unwrap
() = Some(end_tx
);
126 let _
= self.end_tx
.lock().unwrap
().take();