alsa/direct/
ffi.rs

1//! Some definitions from the kernel headers
2
3#![allow(non_camel_case_types)]
4
5use cfg_if::cfg_if;
6
7// const SNDRV_PCM_MMAP_OFFSET_DATA: c_uint = 0x00000000;
8pub const SNDRV_PCM_MMAP_OFFSET_STATUS: libc::c_uint = 0x80000000;
9pub const SNDRV_PCM_MMAP_OFFSET_CONTROL: libc::c_uint = 0x81000000;
10
11pub const SNDRV_PCM_SYNC_PTR_HWSYNC: libc::c_uint = 1;
12pub const SNDRV_PCM_SYNC_PTR_APPL: libc::c_uint = 2;
13pub const SNDRV_PCM_SYNC_PTR_AVAIL_MIN: libc::c_uint = 4;
14
15// #[repr(C)]
16#[allow(non_camel_case_types)]
17pub type snd_pcm_state_t = libc::c_int;
18
19// #[repr(C)]
20#[allow(non_camel_case_types)]
21pub type snd_pcm_uframes_t = libc::c_ulong;
22
23// I think?! Not sure how this will work with X32 ABI?!
24#[allow(non_camel_case_types)]
25pub type __kernel_off_t = libc::c_long;
26
27#[repr(C)]
28#[derive(Copy, Clone)]
29pub struct snd_pcm_mmap_status {
30    pub state: snd_pcm_state_t,    /* RO: state - SNDRV_PCM_STATE_XXXX */
31    pub pad1: libc::c_int,         /* Needed for 64 bit alignment */
32    pub hw_ptr: snd_pcm_uframes_t, /* RO: hw ptr (0...boundary-1) */
33    pub tstamp: libc::timespec,    /* Timestamp */
34    pub suspended_state: snd_pcm_state_t, /* RO: suspended stream state */
35    pub audio_tstamp: libc::timespec, /* from sample counter or wall clock */
36}
37
38#[repr(C)]
39#[derive(Debug, Copy, Clone)]
40pub struct snd_pcm_mmap_control {
41    pub appl_ptr: snd_pcm_uframes_t,  /* RW: appl ptr (0...boundary-1) */
42    pub avail_min: snd_pcm_uframes_t, /* RW: min available frames for wakeup */
43}
44
45#[repr(C)]
46#[derive(Debug)]
47pub struct snd_pcm_channel_info {
48    pub channel: libc::c_uint,
49    pub offset: __kernel_off_t, /* mmap offset */
50    pub first: libc::c_uint,    /* offset to first sample in bits */
51    pub step: libc::c_uint,     /* samples distance in bits */
52}
53
54#[repr(C)]
55#[derive(Copy, Clone)]
56pub union snd_pcm_mmap_status_r {
57    pub status: snd_pcm_mmap_status,
58    pub reserved: [libc::c_uchar; 64],
59}
60
61#[repr(C)]
62#[derive(Copy, Clone)]
63pub union snd_pcm_mmap_control_r {
64    pub control: snd_pcm_mmap_control,
65    pub reserved: [libc::c_uchar; 64],
66}
67
68#[repr(C)]
69#[derive(Copy, Clone)]
70pub struct snd_pcm_sync_ptr {
71    pub flags: libc::c_uint,
72    pub s: snd_pcm_mmap_status_r,
73    pub c: snd_pcm_mmap_control_r,
74}
75
76cfg_if! {
77    if #[cfg(any(target_os = "linux", target_os = "android"))] {
78        // See <https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/linux.rs>
79
80        cfg_if! {
81            if #[cfg(any(target_os = "android", target_env = "musl"))] {
82                pub(super) type ioctl_num_type = libc::c_int;
83            } else {
84                pub(super) type ioctl_num_type = libc::c_ulong;
85            }
86        }
87
88        // The READ dir is consistent across arches
89        pub(super) const READ: ioctl_num_type = 2;
90
91        // But WRITE is not, as well as having a different number of bits for the SIZEBITS
92        cfg_if!{
93            if #[cfg(any(
94                target_arch = "mips",
95                target_arch = "mips32r6",
96                target_arch = "mips64",
97                target_arch = "mips64r6",
98                target_arch = "powerpc",
99                target_arch = "powerpc64",
100                target_arch = "sparc64"
101            ))] {
102                pub(super) const WRITE: ioctl_num_type = 4;
103                const SIZEBITS: ioctl_num_type = 13;
104            } else {
105                pub(super) const WRITE: ioctl_num_type = 1;
106                const SIZEBITS: ioctl_num_type = 14;
107            }
108        }
109
110        const NRSHIFT: ioctl_num_type = 0;
111        const NRBITS: ioctl_num_type = 8;
112        const TYPEBITS: ioctl_num_type = 8;
113        const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS;
114        const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS;
115        const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS;
116
117        /// Replication of the [`nix::ioc!`](https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/linux.rs#L78-L96)
118        pub(super) const fn make_request(
119            dir: ioctl_num_type,
120            typ: u8,
121            nr: u8,
122            size: usize,
123        ) -> ioctl_num_type {
124            dir << DIRSHIFT
125                | (typ as ioctl_num_type) << TYPESHIFT
126                | (nr as ioctl_num_type) << NRSHIFT
127                | (size as ioctl_num_type) << SIZESHIFT
128        }
129    } else if #[cfg(any(
130        target_os = "dragonfly",
131        target_os = "freebsd",
132        target_os = "netbsd",
133        target_os = "openbsd",
134        target_os = "solaris",
135        target_os = "illumos"
136    ))] {
137        // See <https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/bsd.rs>
138
139        cfg_if! {
140            if #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] {
141                pub(super) type ioctl_num_type = libc::c_ulong;
142            } else {
143                pub(super) type ioctl_num_type = libc::c_int;
144            }
145        }
146
147        #[allow(overflowing_literals)]
148        pub(super) const READ: ioctl_num_type = 0x4000_0000;
149        #[allow(overflowing_literals)]
150        pub(super) const WRITE: ioctl_num_type = 0x8000_0000;
151
152        const IOCPARM_MASK: ioctl_num_type = 0x1fff;
153
154        /// Replication of [`nix::ioc!`](https://github.com/nix-rust/nix/blob/197f55b3ccbce3273bf6ce119d1a8541b5df5d66/src/sys/ioctl/bsd.rs#L31-L42)
155        pub(super) const fn make_request(
156            dir: ioctl_num_type,
157            typ: u8,
158            nr: u8,
159            size: usize,
160        ) -> ioctl_num_type {
161            dir | ((size as ioctl_num_type) & IOCPARM_MASK) << 16
162                | (typ as ioctl_num_type) << 8
163                | nr as ioctl_num_type
164        }
165    } else {
166        compile_error!("unknown target platform");
167    }
168}
169
170pub(crate) unsafe fn sndrv_pcm_ioctl_channel_info(
171    fd: libc::c_int,
172    data: *mut snd_pcm_channel_info,
173) -> Result<(), crate::Error> {
174    const REQUEST: ioctl_num_type = make_request(
175        READ,
176        b'A',
177        0x32,
178        std::mem::size_of::<snd_pcm_channel_info>(),
179    );
180
181    unsafe {
182        if libc::ioctl(fd, REQUEST, data) == -1 {
183            Err(crate::Error::last("SNDRV_PCM_IOCTL_CHANNEL_INFO"))
184        } else {
185            Ok(())
186        }
187    }
188}
189
190pub(crate) unsafe fn sndrv_pcm_ioctl_sync_ptr(
191    fd: libc::c_int,
192    data: *mut snd_pcm_sync_ptr,
193) -> Result<(), crate::Error> {
194    const REQUEST: ioctl_num_type = make_request(
195        READ | WRITE,
196        b'A',
197        0x23,
198        std::mem::size_of::<snd_pcm_sync_ptr>(),
199    );
200
201    unsafe {
202        if libc::ioctl(fd, REQUEST, data) == -1 {
203            Err(crate::Error::last("SNDRV_PCM_IOCTL_SYNC_PTR"))
204        } else {
205            Ok(())
206        }
207    }
208}
209
210pub fn pagesize() -> usize {
211    unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
212}