1use crate::gamepad::GamepadManager;
2use crate::*;
3use alloc::boxed::Box;
4use core::cell::Cell;
5use core::fmt::Display;
6use core::marker::PhantomData;
7use core::net::{IpAddr, Ipv4Addr, SocketAddr};
8use std::io::{Read, Write};
9use std::net::{SocketAddrV4, TcpListener, TcpStream, UdpSocket};
10use std::path::PathBuf;
11use std::sync::mpsc;
12
13const UDP_PORT_MIN: u16 = 3110;
14const UDP_PORT_MAX: u16 = 3117;
15const TCP_PORT_MIN: u16 = 3210;
16const TCP_PORT_MAX: u16 = 3217;
17const AUDIO_BUF_SIZE: usize = SAMPLE_RATE as usize / 6;
18
19static NAMES: &[&str] = &[
20 "j0vial-dharm4",
21 "angry-6r4d13y",
22 "nic3-5ugar",
23 "quirky-5co06ie",
24 "r31ax3d-s0phie",
25 "sh4rp-7oni",
26 "boring-5ky",
27 "m4gica1-5i3nn4",
28 "b0ring-che57er",
29 "shy-a5tr0",
30];
31
32#[derive(Clone)]
33pub struct DeviceConfig {
34 pub root: PathBuf,
36
37 pub tcp_ip: IpAddr,
39
40 pub udp_ip: IpAddr,
42
43 pub peers: Vec<IpAddr>,
45
46 pub wav: Option<PathBuf>,
48
49 pub mute: bool,
51}
52
53impl Default for DeviceConfig {
54 fn default() -> Self {
55 let localhost = IpAddr::V4(Ipv4Addr::LOCALHOST);
56 Self {
57 root: PathBuf::new(),
58 tcp_ip: localhost,
59 udp_ip: localhost,
60 peers: vec![localhost],
61 wav: None,
62 mute: false,
63 }
64 }
65}
66
67pub struct DeviceImpl<'a> {
68 config: DeviceConfig,
69 start: std::time::Instant,
71 gamepad: GamepadManager,
73 audio: Option<AudioWriter>,
75 wifi_status: u8,
76 network: NetworkImpl<'a>,
77 serial: SerialImpl,
78 tcp_conn: Option<TcpStream>,
79}
80
81impl<'a> DeviceImpl<'a> {
82 pub fn new(config: DeviceConfig) -> Self {
83 let mut audio = None;
84 #[cfg(not(target_os = "android"))]
85 if !config.mute {
86 audio = start_audio(&config);
87 }
88 Self {
89 start: std::time::Instant::now(),
90 gamepad: GamepadManager::new(),
91 audio,
92 config,
93 wifi_status: 2,
94 network: NetworkImpl::new(),
95 serial: SerialImpl::new(),
96 tcp_conn: None,
97 }
98 }
99
100 pub fn update_input(&mut self, input: InputState) {
102 self.gamepad.update_input(input)
103 }
104
105 pub fn alloc_psram(&self, size: usize) -> Vec<u8> {
106 Vec::with_capacity(size)
107 }
108}
109
110impl<'a> Device for DeviceImpl<'a> {
111 type Dir = DirImpl;
112
113 fn now(&self) -> Instant {
114 let now = std::time::Instant::now();
115 let dur = now.duration_since(self.start);
116 Instant {
117 us: dur.as_micros() as u32,
118 }
119 }
120
121 fn delay(&self, d: Duration) {
122 let dur = core::time::Duration::from_micros(d.us as u64);
123 std::thread::sleep(dur);
124 }
125
126 fn read_input(&mut self) -> Option<InputState> {
127 self.gamepad.read_input()
128 }
129
130 fn get_name(&mut self) -> Option<&'static str> {
131 let addr = self.network.local_addr?;
132 let IpAddr::V4(ip) = addr.ip() else {
133 return None;
134 };
135 let port = addr.port();
136 if port == UDP_PORT_MIN {
137 return None;
138 }
139 let hash = (ip.to_bits() + u32::from(port)) % 10;
140 let name = NAMES[hash as usize];
141 Some(name)
142 }
143
144 fn log_debug<D: Display>(&mut self, src: &str, msg: D) {
145 println!("DEBUG({src}): {msg}");
146 }
147
148 fn log_error<D: Display>(&mut self, src: &str, msg: D) {
149 eprintln!("ERROR({src}): {msg}");
150 }
151
152 fn random(&mut self) -> u32 {
153 rand::random()
154 }
155
156 fn open_dir(&mut self, path: &[&str]) -> Result<Self::Dir, FSError> {
157 let path: PathBuf = path.iter().collect();
158 let path = self.config.root.join(path);
159 if !path.exists() {
160 return Err(FSError::NotFound);
161 }
162 if !path.is_dir() {
163 return Err(FSError::OpenedFileAsDir);
164 }
165 Ok(DirImpl { path })
166 }
167
168 fn has_headphones(&mut self) -> bool {
169 false
170 }
171
172 fn get_audio_buffer(&mut self) -> &mut [i16] {
173 match &mut self.audio {
174 Some(audio) => audio.get_write_buf(),
175 None => &mut [][..],
176 }
177 }
178
179 #[cfg(target_os = "android")]
180 fn get_battery_status(&mut self) -> Option<BatteryStatus> {
181 None
182 }
183
184 #[cfg(not(target_os = "android"))]
185 fn get_battery_status(&mut self) -> Option<BatteryStatus> {
186 Some(BatteryStatus {
187 voltage: 40_000,
188 connected: false,
189 full: false,
190 })
191 }
192}
193
194pub struct DirImpl {
195 path: PathBuf,
196}
197
198impl Dir for DirImpl {
199 type Read = File;
200 type Write = File;
201
202 fn open_file(&mut self, name: &str) -> Result<Self::Read, FSError> {
203 let path = self.path.join(name);
204 let file = std::fs::File::open(path)?;
205 Ok(File { file })
206 }
207
208 fn create_file(&mut self, name: &str) -> Result<Self::Write, FSError> {
209 let path = self.path.join(name);
210 if let Some(parent) = path.parent() {
211 _ = std::fs::create_dir_all(parent);
212 }
213 let file = std::fs::File::create(path)?;
214 Ok(File { file })
215 }
216
217 fn append_file(&mut self, name: &str) -> Result<Self::Write, FSError> {
218 let path = self.path.join(name);
219 let mut opts = std::fs::OpenOptions::new();
220 let file = opts.append(true).open(path)?;
221 Ok(File { file })
222 }
223
224 fn get_file_size(&mut self, name: &str) -> Result<u32, FSError> {
225 let path = self.path.join(name);
226 let meta = std::fs::metadata(path)?;
227 Ok(meta.len() as u32)
228 }
229
230 fn remove_file(&mut self, name: &str) -> Result<(), FSError> {
231 let path = self.path.join(name);
232 let res = std::fs::remove_file(path);
233 match res {
234 Ok(_) => Ok(()),
235 Err(err) => match err.kind() {
236 std::io::ErrorKind::NotFound => Ok(()),
237 _ => Err(err.into()),
238 },
239 }
240 }
241
242 fn create_dir(&mut self, name: &str) -> Result<(), FSError> {
243 let path = self.path.join(name);
244 std::fs::create_dir(path)?;
245 Ok(())
246 }
247
248 fn remove_dir(self) -> Result<(), FSError> {
249 let res = std::fs::remove_dir_all(&self.path);
250 match res {
251 Ok(_) => Ok(()),
252 Err(err) => match err.kind() {
253 std::io::ErrorKind::NotFound => Ok(()),
254 _ => Err(err.into()),
255 },
256 }
257 }
258
259 fn iter_dir<F>(&mut self, mut f: F) -> Result<(), FSError>
260 where
261 F: FnMut(EntryKind, &[u8]),
262 {
263 let entries = std::fs::read_dir(&self.path)?;
264 for entry in entries {
265 let entry = entry?;
266 let path = entry.path();
267 let kind = if path.is_dir() {
268 EntryKind::Dir
269 } else if path.is_file() {
270 EntryKind::File
271 } else {
272 continue;
273 };
274 let fname = entry.file_name();
275 let fname = fname.as_encoded_bytes();
276 f(kind, fname);
277 }
278 Ok(())
279 }
280}
281
282pub struct File {
283 file: std::fs::File,
284}
285
286impl embedded_io::ErrorType for File {
287 type Error = std::io::Error;
288}
289
290impl embedded_io::Read for File {
291 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
292 std::io::Read::read(&mut self.file, buf)
293 }
294}
295
296impl embedded_io::Seek for File {
297 fn seek(&mut self, pos: embedded_io::SeekFrom) -> Result<u64, Self::Error> {
298 let pos = match pos {
299 embedded_io::SeekFrom::Start(n) => std::io::SeekFrom::Start(n),
300 embedded_io::SeekFrom::End(n) => std::io::SeekFrom::End(n),
301 embedded_io::SeekFrom::Current(n) => std::io::SeekFrom::Current(n),
302 };
303 std::io::Seek::seek(&mut self.file, pos)
304 }
305}
306
307impl embedded_io::Write for File {
308 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
309 std::io::Write::write(&mut self.file, buf)
310 }
311
312 fn flush(&mut self) -> Result<(), Self::Error> {
313 std::io::Write::flush(&mut self.file)
314 }
315}
316
317pub struct NetworkImpl<'a> {
318 worker: Cell<Option<UdpWorker>>,
319 r_in: mpsc::Receiver<NetMessage>,
320 s_out: mpsc::Sender<NetMessage>,
321 s_stop: mpsc::Sender<()>,
322 local_addr: Option<SocketAddr>,
323 _life: &'a PhantomData<()>,
324}
325
326impl<'a> NetworkImpl<'a> {
327 fn new() -> Self {
328 let (s_in, r_in) = mpsc::channel();
329 let (s_out, r_out) = mpsc::channel();
330 let (s_stop, r_stop) = mpsc::channel();
331 let worker = Cell::new(Some(UdpWorker {
332 s_in,
333 r_out,
334 r_stop,
335 }));
336 Self {
337 worker,
338 r_in,
339 s_out,
340 s_stop,
341 local_addr: None,
342 _life: &PhantomData,
343 }
344 }
345}
346
347pub type Addr = SocketAddr;
348
349impl<'a> Network for DeviceImpl<'a> {
350 type Addr = SocketAddr;
351
352 fn net_local_addr(&self) -> SocketAddr {
353 self.network.local_addr.unwrap()
354 }
355
356 fn net_start(&mut self) -> NetworkResult<()> {
357 let worker = self.network.worker.replace(None);
358 let Some(worker) = worker else {
359 return Ok(());
360 };
361 let local_addr = worker.start(self.config.udp_ip)?;
362 self.network.local_addr = Some(local_addr);
363 Ok(())
364 }
365
366 fn net_stop(&mut self) -> NetworkResult<()> {
367 _ = self.network.s_stop.send(());
368 self.network = NetworkImpl::new();
369 Ok(())
370 }
371
372 fn net_advertise(&mut self) -> NetworkResult<()> {
373 let hello = b"HELLO".to_owned();
374 let hello: Box<[u8]> = Box::new(hello);
375 for ip in &self.config.peers {
376 for port in UDP_PORT_MIN..=UDP_PORT_MAX {
377 let addr = SocketAddr::new(*ip, port);
378 let res = self.network.s_out.send((addr, hello.clone()));
379 if res.is_err() {
380 return Err(NetworkError::NetThreadDeallocated);
381 }
382 }
383 }
384 Ok(())
385 }
386
387 fn net_recv(&mut self) -> NetworkResult<Option<(Self::Addr, Box<[u8]>)>> {
388 Ok(self.network.r_in.try_recv().ok())
389 }
390
391 fn net_send(&mut self, addr: Self::Addr, data: &[u8]) -> NetworkResult<()> {
392 if data.len() >= 200 {
393 return Err(NetworkError::OutMessageTooBig);
394 };
395 let msg = data.to_vec().into_boxed_slice();
396 let res = self.network.s_out.send((addr, msg));
397 if res.is_err() {
398 return Err(NetworkError::NetThreadDeallocated);
399 }
400 Ok(())
401 }
402
403 fn net_send_status(&mut self, _: Self::Addr) -> NetworkResult<firefly_types::spi::SendStatus> {
404 Ok(firefly_types::spi::SendStatus::Empty)
405 }
406}
407
408pub struct SerialImpl {
409 worker: Cell<Option<TcpWorker>>,
410 r_in: mpsc::Receiver<SerialMessage>,
411 s_out: mpsc::Sender<SerialMessage>,
412 s_stop: mpsc::Sender<()>,
413}
414
415impl SerialImpl {
416 fn new() -> Self {
417 let (s_in, r_in) = mpsc::channel();
418 let (s_out, r_out) = mpsc::channel();
419 let (s_stop, r_stop) = mpsc::channel();
420 let worker = TcpWorker {
421 s_in,
422 r_out,
423 r_stop,
424 };
425 let worker = Cell::new(Some(worker));
426 Self {
427 worker,
428 r_in,
429 s_out,
430 s_stop,
431 }
432 }
433}
434
435impl Serial for DeviceImpl<'_> {
436 fn serial_start(&mut self) -> NetworkResult<()> {
437 let worker = self.serial.worker.replace(None);
438 let Some(worker) = worker else {
439 return Ok(());
440 };
441 worker.start(self.config.tcp_ip)?;
442 Ok(())
443 }
444
445 fn serial_stop(&mut self) -> NetworkResult<()> {
446 _ = self.serial.s_stop.send(());
447 Ok(())
448 }
449
450 fn serial_recv(&mut self) -> NetworkResult<Option<Box<[u8]>>> {
451 Ok(self.serial.r_in.try_recv().ok())
452 }
453
454 fn serial_send(&mut self, data: &[u8]) -> NetworkResult<()> {
455 if data.len() >= 200 {
456 return Err(NetworkError::OutMessageTooBig);
457 };
458 let msg = data.to_vec().into_boxed_slice();
459 let res = self.serial.s_out.send(msg);
460 if res.is_err() {
461 return Err(NetworkError::NetThreadDeallocated);
462 }
463 Ok(())
464 }
465}
466
467impl Wifi for DeviceImpl<'_> {
468 fn wifi_scan(&mut self) -> NetworkResult<[String; 6]> {
469 let points = ["Default Network", "", "", "", "", ""];
470 let points = points.map(|s| s.to_string());
471 Ok(points)
472 }
473
474 fn wifi_connect(&mut self, ssid: &str, pass: &str) -> NetworkResult<()> {
475 if ssid != "Default Network" {
476 self.wifi_status = 2; } else if pass == "invalid" {
478 self.wifi_status = 1; } else {
480 self.wifi_status = 3; }
482 Ok(())
483 }
484
485 fn wifi_status(&mut self) -> NetworkResult<u8> {
486 if self.wifi_status == 3 {
487 self.wifi_status = 4; Ok(3)
489 } else {
490 Ok(self.wifi_status)
491 }
492 }
493
494 fn wifi_disconnect(&mut self) -> NetworkResult<()> {
495 self.wifi_status = 2;
496 Ok(())
497 }
498
499 fn tcp_connect(&mut self, ip: u32, port: u16) -> NetworkResult<()> {
500 if self.wifi_status != 4 {
501 return Err(NetworkError::Error("not connected to wifi"));
502 }
503 let ip = Ipv4Addr::new(
504 (ip >> 24) as u8,
505 (ip >> 16) as u8,
506 (ip >> 8) as u8,
507 ip as u8,
508 );
509 let addr = SocketAddrV4::new(ip, port);
510 let Ok(stream) = TcpStream::connect(addr) else {
511 return Err(NetworkError::CannotBind);
512 };
513 _ = stream.set_nonblocking(true);
514 self.tcp_conn = Some(stream);
515 Ok(())
516 }
517
518 fn tcp_status(&mut self) -> NetworkResult<u8> {
519 let Some(stream) = &mut self.tcp_conn else {
520 return Ok(1);
521 };
522 if stream.peer_addr().is_err() {
523 return Ok(1);
524 }
525 Ok(5)
526 }
527
528 fn tcp_send(&mut self, data: &[u8]) -> NetworkResult<()> {
529 let Some(stream) = &mut self.tcp_conn else {
530 return Err(NetworkError::NotInitialized);
531 };
532 let res = stream.write_all(data);
533 if let Err(err) = res {
534 let err = alloc::format!("{err}");
535 return Err(NetworkError::OwnedError(err));
536 }
537 Ok(())
538 }
539
540 fn tcp_recv(&mut self) -> NetworkResult<Box<[u8]>> {
541 let Some(stream) = &mut self.tcp_conn else {
542 return Err(NetworkError::NotInitialized);
543 };
544 let mut buf = vec![0; 80];
545 let n = match stream.read(&mut buf) {
546 Ok(n) => n,
547 Err(err) => {
548 if err.kind() == std::io::ErrorKind::WouldBlock {
549 0
550 } else {
551 return Err(NetworkError::Error("failed to read incoming TCP data"));
552 }
553 }
554 };
555 buf.truncate(n);
556 Ok(buf.into_boxed_slice())
557 }
558
559 fn tcp_close(&mut self) -> NetworkResult<()> {
560 let Some(stream) = self.tcp_conn.take() else {
561 return Ok(());
562 };
563 _ = stream.shutdown(std::net::Shutdown::Both);
564 Ok(())
565 }
566}
567
568type NetMessage = (SocketAddr, Box<[u8]>);
569type SerialMessage = Box<[u8]>;
570
571struct UdpWorker {
572 s_in: mpsc::Sender<NetMessage>,
573 r_out: mpsc::Receiver<NetMessage>,
574 r_stop: mpsc::Receiver<()>,
575}
576
577impl UdpWorker {
578 fn start(self, ip: IpAddr) -> Result<SocketAddr, NetworkError> {
579 let addrs: Vec<_> = (UDP_PORT_MIN..=UDP_PORT_MAX)
580 .map(|port| SocketAddr::new(ip, port))
581 .collect();
582 let socket = match UdpSocket::bind(&addrs[..]) {
583 Ok(socket) => socket,
584 Err(_) => return Err(NetworkError::CannotBind),
585 };
586 let timeout = std::time::Duration::from_millis(10);
587 socket.set_read_timeout(Some(timeout)).unwrap();
588 if let Ok(addr) = socket.local_addr() {
589 println!("listening on {addr}/udp");
590 } else {
591 println!("listening a UDP port");
592 }
593 let local_addr = socket.local_addr().unwrap();
594 std::thread::spawn(move || {
595 loop {
596 match self.r_stop.try_recv() {
597 Ok(_) | Err(mpsc::TryRecvError::Disconnected) => {
598 break;
599 }
600 Err(mpsc::TryRecvError::Empty) => {}
601 }
602 let mut buf = vec![0; 64];
603 if let Ok((size, addr)) = socket.recv_from(&mut buf) {
604 if size == 0 {
605 continue;
606 }
607 buf.truncate(size);
608 let buf = buf.into_boxed_slice();
609 _ = self.s_in.send((addr, buf));
610 }
611 if let Ok((addr, buf)) = self.r_out.try_recv() {
612 if addr == local_addr {
613 continue;
614 }
615 _ = socket.send_to(&buf, addr);
616 }
617 }
618 });
619 Ok(local_addr)
620 }
621}
622
623struct TcpWorker {
624 s_in: mpsc::Sender<SerialMessage>,
625 r_out: mpsc::Receiver<SerialMessage>,
626 r_stop: mpsc::Receiver<()>,
627}
628
629impl TcpWorker {
630 fn start(self, ip: IpAddr) -> Result<(), NetworkError> {
631 let addrs: Vec<_> = (TCP_PORT_MIN..=TCP_PORT_MAX)
632 .map(|port| SocketAddr::new(ip, port))
633 .collect();
634 let Ok(socket) = TcpListener::bind(&addrs[..]) else {
635 return Err(NetworkError::CannotBind);
636 };
637 socket.set_nonblocking(true).unwrap();
638 std::thread::spawn(move || {
639 let mut streams = RingBuf::new();
640 loop {
641 match self.r_stop.try_recv() {
642 Ok(_) | Err(mpsc::TryRecvError::Disconnected) => {
643 break;
644 }
645 Err(mpsc::TryRecvError::Empty) => {}
646 }
647
648 if let Ok((stream, _addr)) = socket.accept() {
649 stream.set_nonblocking(true).unwrap();
650 streams.push(stream);
651 };
652
653 for stream in streams.iter_mut() {
654 let mut buf = vec![0; 200];
655 let Ok(size) = stream.read(&mut buf) else {
656 continue;
657 };
658 if size == 0 {
659 continue;
660 }
661 buf.truncate(size);
662 let buf = buf.into_boxed_slice();
663 _ = self.s_in.send(buf);
664 }
665 if let Ok(buf) = self.r_out.try_recv() {
666 for stream in streams.iter_mut() {
667 _ = stream.write_all(&buf)
668 }
669 }
670 }
671 });
672 Ok(())
673 }
674}
675
676struct RingBuf {
681 data: [Option<TcpStream>; 4],
682 next: usize,
683}
684
685impl RingBuf {
686 fn new() -> Self {
687 Self {
688 data: [None, None, None, None],
689 next: 0,
690 }
691 }
692
693 fn push(&mut self, val: TcpStream) {
694 self.data[self.next] = Some(val);
695 self.next = (self.next + 1) % 4
696 }
697
698 fn iter_mut(&mut self) -> impl Iterator<Item = &mut TcpStream> {
699 self.data.iter_mut().filter_map(Option::as_mut)
700 }
701}
702
703#[cfg(not(target_os = "android"))]
704fn start_audio(config: &DeviceConfig) -> Option<AudioWriter> {
705 let wav = if let Some(filename) = &config.wav {
706 let spec = hound::WavSpec {
707 channels: 2,
708 sample_rate: SAMPLE_RATE,
709 bits_per_sample: 16,
710 sample_format: hound::SampleFormat::Int,
711 };
712 let writer = hound::WavWriter::create(filename, spec).unwrap();
713 Some(writer)
714 } else {
715 None
716 };
717
718 let (send, recv) = mpsc::sync_channel(AUDIO_BUF_SIZE);
719 let Ok(mut stream) = rodio::OutputStreamBuilder::open_default_stream() else {
720 eprintln!("WARNING: audio device is not available, sound will be disabled");
721 return None;
722 };
723 stream.log_on_drop(false);
724 let mixer = stream.mixer();
725 let source = AudioReader { wav, recv };
726 mixer.add(source);
727 let audio = AudioWriter {
728 buf: [0; AUDIO_BUF_SIZE],
729 pending_from: 0,
730 pending_to: 0,
731 send,
732 _stream: stream,
733 };
734 Some(audio)
735}
736
737struct AudioWriter {
738 buf: [i16; AUDIO_BUF_SIZE],
739 send: mpsc::SyncSender<i16>,
740 pending_from: usize,
741 pending_to: usize,
742 #[cfg(not(target_os = "android"))]
743 _stream: rodio::OutputStream,
744}
745
746impl AudioWriter {
747 fn consume(&mut self) {
748 while self.pending_from > self.pending_to {
749 let byte = self.buf[self.pending_from];
750 let res = self.send.try_send(byte);
751 if res.is_err() {
752 return;
753 }
754 if self.pending_from < self.buf.len() {
755 self.pending_from += 1;
756 } else {
757 self.pending_from = 0;
758 }
759 }
760 while self.pending_from < self.pending_to {
761 let byte = self.buf[self.pending_from];
762 let res = self.send.try_send(byte);
763 if res.is_err() {
764 return;
765 }
766 self.pending_from += 1;
767 }
768 }
769
770 fn get_write_buf(&mut self) -> &mut [i16] {
771 self.consume();
772 if self.pending_from == self.pending_to {
773 self.pending_from = 0;
774 self.pending_to = self.buf.len();
775 return &mut self.buf;
776 }
777 if self.pending_from < self.pending_to {
778 let start = self.pending_to;
779 self.pending_to = self.buf.len();
780 return &mut self.buf[start..self.pending_to];
781 }
782 &mut []
783 }
784}
785
786#[cfg(not(target_os = "android"))]
787struct AudioReader {
788 wav: Option<hound::WavWriter<std::io::BufWriter<std::fs::File>>>,
789 recv: mpsc::Receiver<i16>,
790}
791
792#[cfg(not(target_os = "android"))]
793impl rodio::Source for AudioReader {
794 fn current_span_len(&self) -> Option<usize> {
795 None
796 }
797
798 fn channels(&self) -> u16 {
799 2
800 }
801
802 fn sample_rate(&self) -> u32 {
803 SAMPLE_RATE
804 }
805
806 fn total_duration(&self) -> Option<core::time::Duration> {
807 None
808 }
809}
810
811#[cfg(not(target_os = "android"))]
812impl Iterator for AudioReader {
813 type Item = f32;
814
815 fn next(&mut self) -> Option<Self::Item> {
816 let s = self.recv.try_recv().unwrap_or_default();
817 if let Some(wav) = self.wav.as_mut() {
818 wav.write_sample(s).unwrap()
819 }
820 let s = f32::from(s) / f32::from(i16::MAX);
821 Some(s)
822 }
823}