audio_device/alsa/
async_writer.rs

1use crate::alsa::{Error, Pcm, Result};
2use crate::libc as c;
3use crate::unix::errno;
4use crate::unix::poll;
5use crate::unix::AsyncPoll;
6use audio_core as core;
7use std::marker;
8
9/// An interleaved type-checked async PCM writer.
10///
11/// See [Pcm::async_writer].
12pub struct AsyncWriter<'a, T> {
13    pcm: &'a mut Pcm,
14    poll_handle: AsyncPoll,
15    pollfd: c::pollfd,
16    channels: usize,
17    _marker: marker::PhantomData<T>,
18}
19
20impl<'a, T> AsyncWriter<'a, T> {
21    /// Construct a new writer surrounding the given PCM.
22    ///
23    /// # Safety
24    ///
25    /// This constructor assumes that the caller has checked that type `T` is
26    /// appropriate for writing to the given PCM.
27    pub(super) unsafe fn new(pcm: &'a mut Pcm, pollfd: c::pollfd, channels: usize) -> Result<Self> {
28        Ok(Self {
29            pcm,
30            poll_handle: AsyncPoll::new(pollfd)?,
31            pollfd,
32            channels,
33            _marker: marker::PhantomData,
34        })
35    }
36
37    /// Write an interleaved buffer.
38    pub async fn write_interleaved<B>(&mut self, mut buf: B) -> Result<()>
39    where
40        B: core::ReadBuf + core::ExactSizeBuf + core::AsInterleaved<T>,
41    {
42        if buf.channels() != self.channels {
43            return Err(Error::ChannelsMismatch {
44                actual: buf.channels(),
45                expected: self.channels,
46            });
47        }
48
49        while buf.has_remaining() {
50            self.pcm.tag.ensure_on_thread();
51            let frames = buf.frames() as usize;
52
53            unsafe {
54                let result = {
55                    let ptr = buf.as_interleaved().as_ptr() as *const c::c_void;
56                    self.pcm.write_interleaved_unchecked(ptr, frames as u64)
57                };
58
59                let written = match result {
60                    Ok(written) => written as usize,
61                    Err(Error::Sys(errno::EWOULDBLOCK)) => {
62                        loop {
63                            let guard = self.poll_handle.returned_events().await;
64                            self.pollfd.revents = guard.events();
65
66                            let mut fds = [self.pollfd];
67                            let flags = self.pcm.poll_descriptors_revents(&mut fds)?;
68
69                            if flags == poll::PollFlags::POLLOUT {
70                                break;
71                            }
72
73                            drop(guard);
74                        }
75
76                        continue;
77                    }
78                    Err(e) => return Err(e),
79                };
80
81                buf.advance(written);
82            }
83        }
84
85        Ok(())
86    }
87}
88
89// Safety: [Pcm] is tagged with the thread its created it and is ensured not to
90// leave it.
91unsafe impl<T> Send for AsyncWriter<'_, T> {}