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