pub struct RingBufferProperties {
pub external_delay: Option<i64>,
pub fifo_depth: Option<u32>,
pub needs_cache_flush_or_invalidate: Option<bool>,
pub turn_on_delay: Option<i64>,
pub driver_transfer_bytes: Option<u32>,
/* private fields */
}
Expand description
Properties of the ring buffer. These values don’t change once the ring buffer is created.
Fields§
§external_delay: Option<i64>
The driver’s best estimate (for the chosen format) of the delay external to the hardware it
abstracts. External delay must be taken into account when precisely synchronizing
presentation across multiple entities (e.g. devices).
If not included external_delay
is unknown.
§Deprecation
Not needed anymore since the functionality is available via WatchDelayInfo
below.
fifo_depth: Option<u32>
Size (in bytes) of the temporary buffer used by the driver when consuming or generating ring
buffer contents. Required.
The ring buffer contents must be produced and consumed at the rate specified with the
CreateRingBuffer
command, however some amount of buffering is required when the data is
written into and read from the ring buffer. For playback the data is consumed by the driver
by reading ahead up to fifo_depth
bytes. For capture the data is produced by the driver
holding up to fifo_depth
bytes at the time before committing it to main system
memory. Hence fifo_depth
must be taken into account by the client when determining either
the minimum lead time requirement (for playback) or the maximum capture delay (for capture).
To convert fifo_depth
to the corresponding number of audio frames, use the frame size
returned by CreateRingBuffer
in the StreamConfig
protocol, note that the fifo_depth
is not necessarily a multiple size of an audio frame.
The ring buffer data may be directly consumed/generated by hardware, in this case
fifo_depth
maps directly to the size of a hardware FIFO block, since the hardware FIFO
block determines the amount of data read ahead or held back.
The ring buffer data may instead be consumed/generated by audio driver software that is
conceptually situated between the ring buffer and the audio hardware. In this case, for
playback the fifo_depth
read ahead amount is set large enough such that the driver
guarantees no undetected underruns, this assuming the client is generating the data as
determined by the CreateRingBuffer
and Start
commands. For capture, the
fifo_depth
held back amount is set large enough such that the driver guarantees no
undetected underruns when generating the data as determined by the CreateRingBuffer
and
Start
commands. The driver must set fifo_depth
big enough such that the potential
delays added by any software interfacing with the audio hardware do not occur under most
scenarios, and must detect and report underruns. How an underrun is reported is not defined
in this API.
§Deprecation
Not needed anymore since the functionality is available via driver_transfer_bytes
below.
needs_cache_flush_or_invalidate: Option<bool>
When set to true, indicates that the ring buffer runs in a different cache coherency domain, and thus clients must ensure that their data writes are flushed all the way to main memory (during playback), or that their view of the ring buffer must be invalidated before any reads (during capture). This is because there may be hardware external to the CPUs that reads/writes main memory, bypassing the CPUs.
When set to false, indicates that the ring buffer runs in the same cache coherency domain as the CPUs, hence the driver is not required to flush/invalidate the ring buffer. Note that in this case, the driver and client still must synchronize their data access, for instance by inserting the appropriate acquire fences before reading and releasing fences after writing.
Required.
turn_on_delay: Option<i64>
The driver’s best estimate of the time needed for the hardware to emit (during playback) or
accept (during capture) frames, after a channel is activated by SetActiveChannels
.
The driver estimates that after SetActiveChannels(channel)->(set_time)
enables a channel,
its data will resume flowing at approximately set_time
+ turn_on_delay
.
Hardware can take time to become fully operational (e.g. due to a power state change, or
communication delays between a Bluetooth driver’s multiple hardware entities). The client
must take this delay into account, if it is unacceptable to drop the actual audio frames
and instead play/capture silence during this interval.
If not included, turn_on_delay
is unknown.
Optional.
driver_transfer_bytes: Option<u32>
Size (in bytes) of the temporary buffer used by the driver/HW when consuming or generating the ring buffer contents.
The ring buffer contents must be produced and consumed at the rate specified with the
CreateRingBuffer
command, using data transfers between a temporary buffer and the ring
buffer. For playback, audio frames are consumed by the driver in transfers as large as
driver_transfer_bytes
. For capture, audio frames are produced by the driver in transfers
as large as driver_transfer_bytes
. In both cases, this many frames must accumulate before
they are read from or committed to the ring buffer.
These data transfers mean that there is always a section of the ring buffer that is unsafe
for the client to be writing/reading. This unsafe buffer region is defined on one side by
the current position ‘P’, and on the other side by the ‘safe pointer’ location ‘S’. Once the
ring buffer starts, these two pointers begin moving. ‘P’ begins moving from position 0 at
the start_time
from Start
. The region between these pointers must not be read or
written by the client at that time. The diagrams below note these pointers as ‘P’ and ‘S’.
During playback, client must write data BEFORE hardware transfers occur. During capture, client can read captured data only AFTER hardware transfers occur. For this reason, during playback ‘S’ is always ahead of ‘P’, whereas during capture ‘S’ is always behind ‘P’.
§Playback
Before they start the ring buffer, clients may safely write any ring buffer location. It is
recommended that they write at least driver_transfer_bytes
of initial audio, since they
must always stay at least that far ahead of where the driver/HW is reading, and upon Start
the hardware might immediately consume that much data from the ring buffer. Otherwise, the
client relies on the zeroed-out contents of the VMO to be the initial audio read by the
driver/HW.
Ring Buffer
+-------------------------+-------------------------------------------------------------+
|<--- safe to write --->|
| (to pre-populate the ring buffer before starting the hardware) |
+-------------------------+-------------------------------------------------------------+
0=P S 0
Once the ring buffer is started, it is not safe for the client to write data to the ring buffer between ‘P’ and ‘S’, because this represents data already in use (potentially already consumed). The client may safely write the rest of the ring buffer (between ‘S’ and ‘0/P’).
Ring Buffer
+-------------------------+-------------------------------------------------------------+
|<--- unsafe to write --->|<--- safe to write --->|
|< driver_transfer_bytes >| (empty unless prewritten by the client) |
+-------------------------+-------------------------------------------------------------+
0=P S 0
As time passes, the driver/HW reads the data in chunks of driver_transfer_bytes
or less,
at the rate specified in CreateRingBuffer
. The Position/Safe pointers move to the right at
the same rate, but do so smoothly. As a result, the “unsafe for client writes” area moves
gradually through the ring buffer, while maintaining a constant size equal to
driver_transfer_bytes
. Thus, after some period we now have:
Ring Buffer
+------------+-------------------------+------------------------------------------------+
|<-- safe -->|<--- unsafe to write --->|<-- safe to write -->|
| to write |< driver_transfer_bytes >| (not yet consumed by the hardware) |
+------------+-------------------------+------------------------------------------------+
0 P S 0
Later, ‘S’ wraps around the ring buffer before ‘P’ does. Note that the region from 0 to ‘S’,
plus the region from ‘P’ to the end of the ring buffer, adds up to driver_transfer_bytes
:
Ring Buffer
+---------------+------------------------------------------------------------+----------+
|<--- unsafe -->|<--- safe to write --->|<-unsafe->|
|< driver_transf| |er_bytes >|
+---------------+------------------------------------------------------------+----------+
0 S P 0
In steady state, any area outside of the pointers ‘P’ and ‘S’ is safe to write:
Ring Buffer
+--------------------------------+-------------------------+----------------------------+
[<-- safe to write -->|<--- unsafe to write --->|<-- safe to write -->|
| (prior data already consumed) |< driver_transfer_bytes >| |
+--------------------------------+-------------------------+----------------------------+
0 P S 0
§Recording
While recording, it is only safe for the client to read that part of the ring buffer that is not simultaneously being written by the driver/HW. Before capture begins, it may read the entire ring buffer, but the driver has not yet written anything for the client to read. This is the ring buffer at the moment that the client starts the ring buffer:
Ring Buffer
+---------------------------------------------------------------------------------------+
[<--- empty (not yet written by the hardware) -->|
+---------------------------------------------------------------------------------------+
0=S=P 0
Once capture begins, the driver/HW acquires frames, eventually making its first data
transfer to the ring buffer starting at ‘0’. These transfers are of unknown size but may be
as large as driver_transfer_bytes
; they occur at the rate specified in CreateRingBuffer
.
Before the driver/HW has written at least driver_transfer_bytes
into the ring buffer, the
client cannot yet safely read any of the newly captured frames:
Ring Buffer
+--------------+------------------------------------------------------------------------+
[<-- unsafe -->|<-- safe to read -->|
|< driver_transfer_bytes >| (but empty, not yet written by the hardware) |
+--------------+------------------------------------------------------------------------+
0=S P 0
Once the driver/HW has written at least driver_transfer_bytes
of data into the ring
buffer, ‘S’ begins to smoothly move forward at the same rate as ‘P’ (as determined by the
ring buffer’s rate and sample format). The client can safely read frames in the region
between ‘0’ and ‘S’. It is unsafe for the client to read data between ‘S’ and ‘P’, because
this is where the driver/HW is simultaneously writing. This region gradually progresses
across the ring buffer, maintaining a constant size of driver_transfer_bytes
.
After some time we have:
Ring Buffer
+----------------+-------------------------+--------------------------------------------+
[< safe to read >|<--- unsafe to read --->|<-- safe to read -->|
| captured audio |< driver_transfer_bytes >| (not yet written by the hardware) |
+----------------+-------------------------+--------------------------------------------+
0 S P 0
Later, ‘P’ wraps around the ring buffer before ‘S’ does. Note that the region from 0 to ‘P’,
plus the region from ‘S’ to the end of the ring buffer, adds up to driver_transfer_bytes
:
Ring Buffer
+-----------+------------------------------------------------------------+--------------+
|<--unsafe->|<--- safe to read --->|<---unsafe--->|
|< driver_tr| (captured audio) |ansfer_bytes >|
+-----------+------------------------------------------------------------+--------------+
0 P S 0
In steady state, i.e. once the process has wrapped around the ring buffer, any area outside of pointers ‘S’ and ‘P’ is safe to read:
Ring Buffer
+--------------------------------+-------------------------+----------------------------+
[<-- safe to read -->|<--- unsafe --->|<-- safe to read -->|
| |< driver_transfer_bytes >| |
+--------------------------------+-------------------------+----------------------------+
0 S P 0
§Hardware versus software
The ring buffer data may be directly consumed/generated by hardware, i.e.
driver_transfer_bytes
can be mapped directly to the size of a hardware FIFO block, since a
hardware FIFO block determines the upper limit amount of data read ahead or held back.
Note that if the FIFO buffer is not used in the traditional “high water” way (such as a
“ping pong” design where only half the FIFO size is used at any time – even during the very
first transfers at Start
time), then driver_transfer_bytes
may be set to a smaller value
but must be at least equal to the largest amount of data ever stored in the FIFO buffer.
Even if the transfer size never exceeds half the size of the FIFO, if the full size of the
FIFO is used (for instance, upon Start
when filling an initially empty hardware FIFO),
then driver_transfer_bytes
must be set to the entire size of the FIFO buffer.
The ring buffer data may instead be consumed/generated by audio driver software that is
conceptually situated between the ring buffer and the audio hardware. In this case, for
playback, the driver_transfer_bytes
read ahead amount must be large enough such that the
driver guarantees no undetected underruns, based on the client requirement to generate data
based on the CreateRingBuffer
rate and the start_time
from Start
. For capture,
driver_transfer_bytes
must be large enough for the driver to guarantee no underruns when
generating the data as determined by the CreateRingBuffer
and Start
commands.
driver_transfer_bytes
must not include the impact of delays caused by hardware or software
processing abstracted by the driver. Those delays are communicated by internal_delay
and
external_delay
fields in DelayInfo
; they are orthogonal to this value.
Required.
Trait Implementations§
Source§impl Clone for RingBufferProperties
impl Clone for RingBufferProperties
Source§fn clone(&self) -> RingBufferProperties
fn clone(&self) -> RingBufferProperties
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl Debug for RingBufferProperties
impl Debug for RingBufferProperties
Source§impl<D: ResourceDialect> Decode<RingBufferProperties, D> for RingBufferProperties
impl<D: ResourceDialect> Decode<RingBufferProperties, D> for RingBufferProperties
Source§impl Default for RingBufferProperties
impl Default for RingBufferProperties
Source§fn default() -> RingBufferProperties
fn default() -> RingBufferProperties
Source§impl<D: ResourceDialect> Encode<RingBufferProperties, D> for &RingBufferProperties
impl<D: ResourceDialect> Encode<RingBufferProperties, D> for &RingBufferProperties
Source§impl PartialEq for RingBufferProperties
impl PartialEq for RingBufferProperties
Source§impl TypeMarker for RingBufferProperties
impl TypeMarker for RingBufferProperties
Source§type Owned = RingBufferProperties
type Owned = RingBufferProperties
Source§fn inline_align(_context: Context) -> usize
fn inline_align(_context: Context) -> usize
Source§fn inline_size(_context: Context) -> usize
fn inline_size(_context: Context) -> usize
inline_align
.§fn encode_is_copy() -> bool
fn encode_is_copy() -> bool
Self::Owned
matches the FIDL wire
format and encoding requires no validation. When true, we can optimize
encoding arrays and vectors of Self::Owned
to a single memcpy. Read more§fn decode_is_copy() -> bool
fn decode_is_copy() -> bool
Self::Owned
matches the FIDL wire
format and decoding requires no validation. When true, we can optimize
decoding arrays and vectors of Self::Owned
to a single memcpy.Source§impl ValueTypeMarker for RingBufferProperties
impl ValueTypeMarker for RingBufferProperties
Source§type Borrowed<'a> = &'a RingBufferProperties
type Borrowed<'a> = &'a RingBufferProperties
Encode<Self>
type cheaply obtainable from &Self::Owned
. There are three cases: Read moreimpl Persistable for RingBufferProperties
impl StructuralPartialEq for RingBufferProperties
Auto Trait Implementations§
impl Freeze for RingBufferProperties
impl RefUnwindSafe for RingBufferProperties
impl Send for RingBufferProperties
impl Sync for RingBufferProperties
impl Unpin for RingBufferProperties
impl UnwindSafe for RingBufferProperties
Blanket Implementations§
§impl<T> Body for Twhere
T: Persistable,
impl<T> Body for Twhere
T: Persistable,
§type MarkerAtTopLevel = T
type MarkerAtTopLevel = T
§type MarkerInResultUnion = T
type MarkerInResultUnion = T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)