]> code.octet-stream.net Git - m17rt/blob - m17codec2/src/tx.rs
b824268f600c40b40a5da22e50d7d82acde46ef4
[m17rt] / m17codec2 / src / tx.rs
1 use codec2::{Codec2, Codec2Mode};
2 use m17app::app::TxHandle;
3 use m17app::link_setup::LinkSetup;
4 use m17app::link_setup::M17Address;
5 use m17app::StreamFrame;
6 use std::path::PathBuf;
7 use std::time::Duration;
8 use std::time::Instant;
9
10 /// Transmits a wave file as an M17 stream
11 pub struct WavePlayer;
12
13 impl WavePlayer {
14 /// Plays a wave file (blocking).
15 ///
16 /// * `path`: wave file to transmit, must be 8 kHz mono and 16-bit LE
17 /// * `tx`: a `TxHandle` obtained from an `M17App`
18 /// * `source`: address of transmission source
19 /// * `destination`: address of transmission destination
20 /// * `channel_access_number`: from 0 to 15, usually 0
21 pub fn play(
22 path: PathBuf,
23 tx: TxHandle,
24 source: &M17Address,
25 destination: &M17Address,
26 channel_access_number: u8,
27 ) {
28 let mut reader = hound::WavReader::open(path).unwrap();
29 let mut samples = reader.samples::<i16>();
30
31 let mut codec = Codec2::new(Codec2Mode::MODE_3200);
32 let mut in_buf = [0i16; 160];
33 let mut out_buf = [0u8; 16];
34 let mut lsf_chunk: usize = 0;
35 const TICK: Duration = Duration::from_millis(40);
36 let mut next_tick = Instant::now() + TICK;
37 let mut frame_number = 0;
38
39 let mut setup = LinkSetup::new_voice(source, destination);
40 setup.set_channel_access_number(channel_access_number);
41 tx.transmit_stream_start(&setup);
42
43 loop {
44 let mut last_one = false;
45 for out in out_buf.chunks_mut(8) {
46 for i in in_buf.iter_mut() {
47 let sample = match samples.next() {
48 Some(Ok(sample)) => sample,
49 _ => {
50 last_one = true;
51 0
52 }
53 };
54 *i = sample;
55 }
56 codec.encode(out, &in_buf);
57 }
58 tx.transmit_stream_next(&StreamFrame {
59 lich_idx: lsf_chunk as u8,
60 lich_part: setup.lich_part(lsf_chunk as u8),
61 frame_number,
62 end_of_stream: last_one,
63 stream_data: out_buf,
64 });
65 frame_number += 1;
66 lsf_chunk = (lsf_chunk + 1) % 6;
67
68 if last_one {
69 break;
70 }
71
72 std::thread::sleep(next_tick.duration_since(Instant::now()));
73 next_tick += TICK;
74 }
75 }
76 }