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