libspa/buffer/
mod.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4pub mod meta;
5
6use std::{convert::TryFrom, fmt::Debug, os::fd::RawFd};
7
8#[derive(Copy, Clone, PartialEq, Eq)]
9pub struct DataType(spa_sys::spa_data_type);
10
11#[allow(non_upper_case_globals)]
12impl DataType {
13    pub const Invalid: Self = Self(spa_sys::SPA_DATA_Invalid);
14    /// Pointer to memory, the data field in struct [`Data`] is set.
15    pub const MemPtr: Self = Self(spa_sys::SPA_DATA_MemPtr);
16    /// Generic fd, `mmap` to get to memory
17    pub const MemFd: Self = Self(spa_sys::SPA_DATA_MemFd);
18    /// Fd to `dmabuf` memory
19    pub const DmaBuf: Self = Self(spa_sys::SPA_DATA_DmaBuf);
20    /// Memory is identified with an id
21    pub const MemId: Self = Self(spa_sys::SPA_DATA_MemId);
22
23    pub fn from_raw(raw: spa_sys::spa_data_type) -> Self {
24        Self(raw)
25    }
26
27    pub fn as_raw(&self) -> spa_sys::spa_data_type {
28        self.0
29    }
30}
31
32impl std::fmt::Debug for DataType {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        let name = format!(
35            "DataType::{}",
36            match *self {
37                Self::Invalid => "Invalid",
38                Self::MemPtr => "MemPtr",
39                Self::MemFd => "MemFd",
40                Self::DmaBuf => "DmaBuf",
41                Self::MemId => "MemId",
42                _ => "Unknown",
43            }
44        );
45        f.write_str(&name)
46    }
47}
48
49bitflags::bitflags! {
50    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
51    pub struct DataFlags: u32 {
52        /// Data is readable
53        const READABLE = 1<<0;
54        /// Data is writable
55        const WRITABLE = 1<<1;
56        /// Data pointer can be changed
57        const DYNAMIC = 1<<2;
58        const READWRITE = Self::READABLE.bits() | Self::WRITABLE.bits();
59    }
60}
61
62#[repr(transparent)]
63pub struct Data(spa_sys::spa_data);
64
65impl Data {
66    pub fn as_raw(&self) -> &spa_sys::spa_data {
67        &self.0
68    }
69
70    pub fn type_(&self) -> DataType {
71        DataType::from_raw(self.0.type_)
72    }
73
74    pub fn flags(&self) -> DataFlags {
75        DataFlags::from_bits_retain(self.0.flags)
76    }
77
78    pub fn fd(&self) -> RawFd {
79        // We don't have a reliable way of checking if the fd is invalid or uninitialized, so we just return it as a RawFd.
80        // The client side will need to use unsafe if they want to manipulate the file descriptor.
81        self.0.fd as RawFd
82    }
83
84    pub fn data(&mut self) -> Option<&mut [u8]> {
85        // FIXME: For safety, perhaps only return a non-mut slice when DataFlags::WRITABLE is not set?
86        if self.0.data.is_null() {
87            None
88        } else {
89            unsafe {
90                Some(std::slice::from_raw_parts_mut(
91                    self.0.data as *mut u8,
92                    usize::try_from(self.0.maxsize).unwrap(),
93                ))
94            }
95        }
96    }
97
98    pub fn chunk(&self) -> &Chunk {
99        assert_ne!(self.0.chunk, std::ptr::null_mut());
100        unsafe {
101            let chunk: *const spa_sys::spa_chunk = self.0.chunk;
102            &*(chunk as *const Chunk)
103        }
104    }
105
106    pub fn chunk_mut(&mut self) -> &mut Chunk {
107        assert_ne!(self.0.chunk, std::ptr::null_mut());
108        unsafe {
109            let chunk: *mut spa_sys::spa_chunk = self.0.chunk;
110            &mut *(chunk as *mut Chunk)
111        }
112    }
113}
114
115impl Debug for Data {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.debug_struct("Data")
118            .field("type", &self.type_())
119            .field("flags", &self.flags())
120            .field("fd", &self.fd())
121            .field("data", &self.0.data) // Only print the pointer here, as we don't want to print a (potentially very big) slice.
122            .field("chunk", &self.chunk())
123            .finish()
124    }
125}
126
127bitflags::bitflags! {
128    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
129    pub struct ChunkFlags: i32 {
130        /// Chunk data is corrupted in some way
131        const CORRUPTED = 1<<0;
132    }
133}
134
135#[repr(transparent)]
136pub struct Chunk(spa_sys::spa_chunk);
137
138impl Chunk {
139    pub fn as_raw(&self) -> &spa_sys::spa_chunk {
140        &self.0
141    }
142
143    pub fn size(&self) -> u32 {
144        self.0.size
145    }
146
147    pub fn size_mut(&mut self) -> &mut u32 {
148        &mut self.0.size
149    }
150
151    pub fn offset(&self) -> u32 {
152        self.0.offset
153    }
154
155    pub fn offset_mut(&mut self) -> &mut u32 {
156        &mut self.0.offset
157    }
158
159    pub fn stride(&self) -> i32 {
160        self.0.stride
161    }
162
163    pub fn stride_mut(&mut self) -> &mut i32 {
164        &mut self.0.stride
165    }
166
167    pub fn flags(&self) -> ChunkFlags {
168        ChunkFlags::from_bits_retain(self.0.flags)
169    }
170}
171
172impl Debug for Chunk {
173    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174        f.debug_struct("Chunk")
175            .field("offset", &self.offset())
176            .field("size", &self.size())
177            .field("stride", &self.stride())
178            .field("flags", &self.flags())
179            .finish()
180    }
181}