Skip to main content

firefly_hal/
hosted.rs

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    /// The full path to the VFS.
35    pub root: PathBuf,
36
37    /// The TCP IP address where to listen for serial events.
38    pub tcp_ip: IpAddr,
39
40    /// The UDP IP address where to listen for netplay events.
41    pub udp_ip: IpAddr,
42
43    /// The UDP IP addresses where to send netplay advertisements.
44    pub peers: Vec<IpAddr>,
45
46    /// If provided, the path where to save the audio output (as a WAV file).
47    pub wav: Option<PathBuf>,
48
49    /// Don't play any audio.
50    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    /// The time at which the device instance was created.
70    start: std::time::Instant,
71    /// The shared logic for reading the gamepad input.
72    gamepad: GamepadManager,
73    /// The audio buffer
74    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    /// Called by the GUI to set input from UI and keyboard.
101    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; // disconnected
477        } else if pass == "invalid" {
478            self.wifi_status = 1; // error
479        } else {
480            self.wifi_status = 3; // initializing
481        }
482        Ok(())
483    }
484
485    fn wifi_status(&mut self) -> NetworkResult<u8> {
486        if self.wifi_status == 3 {
487            self.wifi_status = 4; // connected
488            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
676/// A collection that holds 4 latest TCP connections.
677///
678/// If there are already 4 TCP connections and a new one comes in,
679/// the oldest one is dropped.
680struct 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}