Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions audio-device/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,20 @@ unix = ["libc"]
wasapi = [
"windows",
"events-driver",
"windows?/Win32_System_Threading",
"windows?/Win32_Foundation",
"windows?/Win32_System_Com_StructuredStorage",
"windows?/Win32_Security",
"windows?/Win32_System_WindowsProgramming",
"windows?/Win32_System_Com",
"windows?/Win32_Media_Audio",
"windows?/Win32_Media_KernelStreaming",
"windows?/Win32_Media_Multimedia",
"windows/Win32_System_Threading",
"windows/Win32_Foundation",
"windows/Win32_System_Com_StructuredStorage",
"windows/Win32_Security",
"windows/Win32_System_Com",
"windows/Win32_Media_Audio",
"windows/Win32_Media_KernelStreaming",
"windows/Win32_Media_Multimedia",
]
sync = []

[dependencies]
tracing = "0.1.36"
audio-core = { version = "0.2.1", path = "../audio-core" }
thiserror = { version = "2.0.17", default-features = false }
rand = "0.9.2"
ste = { version = "0.1.0-alpha.11", path = "../ste" }

pulse-sys = { package = "audio-device-pulse-sys", version = "0.1.0-alpha.1", path = "../audio-device-pulse-sys", optional = true }
Expand All @@ -62,6 +59,7 @@ alsa-sys = { package = "audio-device-alsa-sys", version = "0.1.0-alpha.1", path
libc = { version = "0.2.125", optional = true }

[dev-dependencies]
rand = "0.9.2"
audio = { version = "0.2.1", path = "../audio" }
audio-generator = { version = "0.1.0-alpha.2", path = "../audio-generator" }
anyhow = "1.0.57"
Expand Down
3 changes: 2 additions & 1 deletion audio-device/examples/alsa-list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use audio_device::alsa;
use std::ffi::CString;

use audio_device::alsa;

fn main() -> anyhow::Result<()> {
let thread = ste::spawn();

Expand Down
2 changes: 1 addition & 1 deletion audio-device/examples/pulse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn generate_audio() -> anyhow::Result<()> {

context.set_callback(|c| {
println!("state changed: {}", c.state()?);
Err(pulse::Error::User("hello".into()))
Err(pulse::Error::user("hello"))
})?;

context.connect()?;
Expand Down
1 change: 1 addition & 0 deletions audio-device/src/alsa/access_mask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::ptr::NonNull;

use alsa_sys as alsa;

use crate::alsa::error::errno;
use crate::alsa::{Access, Result};

/// Access mask used in combination with hardware parameters.
Expand Down
10 changes: 5 additions & 5 deletions audio-device/src/alsa/async_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use core::marker;
use core::ffi::c_void;

use crate::alsa::{Error, Pcm, Result};
use crate::alsa::error::ErrorKind;
use crate::libc as c;
use crate::unix::{Errno, PollFlags};
use crate::unix::AsyncPoll;
use crate::unix::{PollFlags, AsyncPoll};

/// An interleaved type-checked async PCM writer.
///
Expand Down Expand Up @@ -40,10 +40,10 @@ impl<'a, T> AsyncWriter<'a, T> {
B: audio_core::Buf<Sample = T> + audio_core::ReadBuf + audio_core::ExactSizeBuf + audio_core::InterleavedBuf,
{
if buf.channels() != self.channels {
return Err(Error::ChannelsMismatch {
return Err(Error::from(ErrorKind::ChannelsMismatch {
actual: buf.channels(),
expected: self.channels,
});
}));
}

while buf.has_remaining() {
Expand All @@ -58,7 +58,7 @@ impl<'a, T> AsyncWriter<'a, T> {

let written = match result {
Ok(written) => written as usize,
Err(Error::Sys(Errno::EWOULDBLOCK)) => {
Err(e) if e.would_block() => {
loop {
let guard = self.poll_handle.returned_events().await;
self.pollfd.revents = guard.events();
Expand Down
41 changes: 41 additions & 0 deletions audio-device/src/alsa/c_string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use core::ffi::{CStr, c_char};
use core::ops;

/// A string allocated through libc.
#[repr(transparent)]
pub struct CString {
ptr: *mut c_char,
}

// Safety: string is allocated with the libc allocator and can be freely shared
// across threads.
unsafe impl Send for CString {}
unsafe impl Sync for CString {}

impl CString {
/// Construct a new string that was allocated through libc.
///
/// This differs from [std::ffi::CString] in that it requires the underlying
/// string to have been allocated using libc allocators, and will free the
/// underlying string using those as well.
pub unsafe fn from_raw(ptr: *mut c_char) -> Self {
Self { ptr }
}
}

impl Drop for CString {
fn drop(&mut self) {
unsafe {
libc::free(self.ptr.cast());
}
}
}

impl ops::Deref for CString {
type Target = CStr;

#[inline]
fn deref(&self) -> &Self::Target {
unsafe { CStr::from_ptr(self.ptr) }
}
}
1 change: 1 addition & 0 deletions audio-device/src/alsa/card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use core::mem;

use alsa_sys as alsa;

use crate::alsa::error::errno;
use crate::alsa::{CString, Result};

/// Construct an iterator over sounds cards.
Expand Down
5 changes: 3 additions & 2 deletions audio-device/src/alsa/configurator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use core::ffi::{c_uint, c_ulong};
use core::marker;
use core::time::Duration;

use crate::alsa::error::ErrorKind;
use crate::alsa::{Access, Direction, Error, Format, Pcm, Result, Sample};

/// Default access to configure.
Expand Down Expand Up @@ -118,10 +119,10 @@ where
/// ```
pub fn format(self, format: Format) -> Result<Self> {
if !T::test(format) {
return Err(Error::FormatMismatch {
return Err(Error::from(ErrorKind::FormatMismatch {
ty: T::describe(),
format,
});
}));
}

Ok(Self { format, ..self })
Expand Down
1 change: 1 addition & 0 deletions audio-device/src/alsa/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::ptr::NonNull;

use alsa_sys as alsa;

use crate::alsa::error::errno;
use crate::alsa::{ControlElementInterface, Result};

/// A control associated with a device.
Expand Down
1 change: 1 addition & 0 deletions audio-device/src/alsa/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::fmt;
use alsa_sys as alsa;

use crate::alsa::Result;
use crate::alsa::error::errno;

macro_rules! decl_enum {
(
Expand Down
146 changes: 146 additions & 0 deletions audio-device/src/alsa/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use core::error::Error as CoreError;
use core::ffi::{c_int, c_uint};
use core::fmt;

use crate::alsa::Format;
use crate::unix::Errno;

/// ALSA-specific result alias.
pub type Result<T, E = Error> = ::core::result::Result<T, E>;

macro_rules! __errno {
($expr:expr) => {{
let result = $expr;

if result < 0 {
Err($crate::unix::Errno::new(-result as i32))
} else {
Ok(result)
}
}};
}

pub(crate) use __errno as errno;

/// ALSA-specific errors.
pub struct Error {
kind: ErrorKind,
}

impl Error {
#[cfg(feature = "alsa")]
pub(crate) fn would_block(&self) -> bool {
matches!(self.kind, ErrorKind::Errno(errno) if errno == Errno::EWOULDBLOCK)
}
}

impl From<ErrorKind> for Error {
#[inline]
fn from(kind: ErrorKind) -> Self {
Self { kind }
}
}

impl From<Errno> for Error {
#[inline]
fn from(errno: Errno) -> Self {
Self {
kind: ErrorKind::Errno(errno),
}
}
}

impl fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.kind.fmt(f)
}
}

impl fmt::Debug for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.kind.fmt(f)
}
}

impl CoreError for Error {
#[inline]
fn source(&self) -> Option<&(dyn CoreError + 'static)> {
match self.kind {
#[cfg(feature = "unix")]
ErrorKind::Errno(ref error) => Some(error),
_ => None,
}
}
}

#[derive(Debug)]
pub(crate) enum ErrorKind {
/// System error.
Errno(Errno),
/// Error raised when there's a format mismatch between an underlying stream
/// and the type attempting to be used with it.
FormatMismatch {
/// A description of the type expected.
ty: &'static str,
/// The format that mismatched.
format: Format,
},
/// Error raised when there's a channel count mismatch between an underlying
/// stream and the type attempting to be used with it.
ChannelsMismatch {
/// The actual number of channels.
actual: usize,
/// The expected number of channels.
expected: usize,
},
/// Underlying function call returned an illegal format identifier.
BadFormat(c_int),
/// Underlying function call returned an illegal access identifier.
BadAccess(c_uint),
/// Underlying function call returned an illegal timestamp identifier.
BadTimestamp(c_uint),
/// Underlying function call returned an illegal timestamp type identifier.
BadTimestampType(c_uint),
/// Underlying PCM was not set up for polling.
MissingPollFds,
}

impl fmt::Display for ErrorKind {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Errno(errno) => {
write!(f, "system error: {errno}")
}
Self::FormatMismatch { ty, format } => {
write!(
f,
"type `{ty}` is not appropriate to use with format `{format}`"
)
}
Self::ChannelsMismatch { actual, expected } => {
write!(
f,
"mismatch in number of channels in buffer; actual = {actual}, expected = {expected}"
)
}
Self::BadFormat(format) => {
write!(f, "bad format identifier ({format})")
}
Self::BadAccess(access) => {
write!(f, "bad access identifier ({access})")
}
Self::BadTimestamp(timestamp) => {
write!(f, "bad timestamp mode identifier ({timestamp})")
}
Self::BadTimestampType(ty) => {
write!(f, "bad timestamp type identifier ({ty})")
}
Self::MissingPollFds => {
write!(f, "pcm device is not pollable")
}
}
}
}
1 change: 1 addition & 0 deletions audio-device/src/alsa/format_mask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::ptr::NonNull;

use alsa_sys as alsa;

use crate::alsa::error::errno;
use crate::alsa::{Format, Result};

/// Format mask used in combination with hardware parameters.
Expand Down
Loading
Loading