pub struct RingBuffer {
    pub buffer: Option<Buffer>,
    pub format: Option<Format>,
    pub producer_bytes: Option<u64>,
    pub consumer_bytes: Option<u64>,
    pub reference_clock: Option<Clock>,
    pub reference_clock_domain: Option<u32>,
    /* private fields */
}
Expand description

A ring buffer of audio data.

Each ring buffer has a producer (who writes to the buffer) and a consumer (who reads from the buffer). Additionally, each ring buffer is associated with a reference clock that keeps time for the buffer.

§PCM Data

A ring buffer of PCM audio is a window into a potentially-infinite sequence of frames. Each frame is assigned a “frame number” where the first frame in the infinite sequence is numbered 0. Frame X can be found at ring buffer offset (X % RingBufferFrames) * BytesPerFrame, where RingBufferFrames is the size of the ring buffer in frames and BytesPerFrame is the size of a single frame.

§Concurrency Protocol

Each ring buffer has a single producer and a single consumer which are synchronized by time. At each point in time T according to the ring buffer’s reference clock, we define two functions:

  • SafeWritePos(T) is the lowest (oldest) frame number the producer is allowed to write. The producer can write to this frame or to any higher-numbered frame.

  • SafeReadPos(T) is the highest (youngest) frame number the consumer is allowed to read. The consumer can read this frame or any lower-numbered frame.

To prevent conflicts, we define these to be offset by one:

SafeWritePos(T) = SafeReadPos(T) + 1

To avoid races, there must be a single producer, but there may be multiple consumers. Additionally, since the producer and consumer(s) are synchronized by time, we require explicit fences to ensure cache coherency: the producer must insert an appropriate fence after each write (to flush CPU caches and prevent compiler reordering of stores) and the consumer(s) must insert an appropriate fence before each read (to invalidate CPU caches and prevent compiler reordering of loads).

Since the buffer has finite size, the producer/consumer cannot write/read infinitely in the future/past. We allocate P frames to the producer and C frames to the consumer(s), where P + C <= RingBufferFrames and P and C are both chosen by whoever creates the ring buffer.

§Deciding on P and C

In practice, producers/consumers typically write/read batches of frames on regular periods. For example, a producer might wake every Dp milliseconds to write Dp*FrameRate frames, where FrameRate is the PCM stream’s frame rate. If a producer wakes at time T, it will spend up to the next Dp period writing those frames. This means the lowest frame number it can safely write to is SafeWritePos(T+Dp), which is equivalent to SafeWritePos(T) + Dp*FrameRate. The producer writes Dp*FrameRate frames from the position onwards. This entire region, from SafeWritePos(T) through 2*Dp*FrameRate must be allocated to the producer at time T. Making a similar argument for consumers, we arrive at the following constraints:

P >= 2*Dp*FrameRate
C >= 2*Dc*FrameRate
RingBufferFrames >= P + C

Hence, in practice, P and C can be derived from the batch sizes used by the producer and consumer, where the maximum batch sizes are limited by the ring buffer size.

§Defining SafeWritePos

The definition of SafeWritePos (and, implicitly, SafeReadPos) must be provided out-of-band.

§Non-PCM Data

Non-PCM data is handled similarly to PCM data, except positions are expressed as “byte offsets” instead of “frame numbers”, where the infinite sequence starts at byte offset 0.

Fields§

§buffer: Option<Buffer>

The actual ring buffer. The sum of producer_bytes and consumer_bytes must be <= buffer.size.

Required.

§format: Option<Format>

Encoding of audio data in the buffer. Required.

§producer_bytes: Option<u64>

The number of bytes allocated to the producer.

For PCM encodings, P = producer_bytes / BytesPerFrame(format), where P must be integral.

For non-PCM encodings, there are no constraints, however individual encodings may impose stricter requirements.

Required.

§consumer_bytes: Option<u64>

The number of bytes allocated to the consumer.

For PCM encodings, C = consumer_bytes / BytesPerFrame(format), where C must be integral.

For non-PCM encodings, there are no constraints, however individual encodings may impose stricter requirements.

Required.

§reference_clock: Option<Clock>

Reference clock for the ring buffer.

Required.

§reference_clock_domain: Option<u32>

Domain of reference_clock. See fuchsia.hardware.audio.ClockDomain. TODO(https://fxbug.dev/42066209): If fuchsia.hardware.audio doesn’t need to import fuchsia.audio, we can use that type directly below.

Optional. If not specified, defaults to CLOCK_DOMAIN_EXTERNAL.

Trait Implementations§

source§

impl Debug for RingBuffer

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Decode<RingBuffer> for RingBuffer

source§

fn new_empty() -> Self

Creates a valid instance of Self. The specific value does not matter, since it will be overwritten by decode.
source§

unsafe fn decode( &mut self, decoder: &mut Decoder<'_>, offset: usize, depth: Depth ) -> Result<()>

Decodes an object of type T from the decoder’s buffers into self. Read more
source§

impl Default for RingBuffer

source§

fn default() -> RingBuffer

Returns the “default value” for a type. Read more
source§

impl Encode<RingBuffer> for &mut RingBuffer

source§

unsafe fn encode( self, encoder: &mut Encoder<'_>, offset: usize, depth: Depth ) -> Result<()>

Encodes the object into the encoder’s buffers. Any handles stored in the object are swapped for Handle::INVALID. Read more
source§

impl PartialEq for RingBuffer

source§

fn eq(&self, other: &RingBuffer) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl ResourceTypeMarker for RingBuffer

§

type Borrowed<'a> = &'a mut RingBuffer

The Rust type to use for encoding. This is a particular Encode<Self> type cheaply obtainable from &mut Self::Owned. There are three cases: Read more
source§

fn take_or_borrow<'a>( value: &'a mut <Self as TypeMarker>::Owned ) -> Self::Borrowed<'a>

Cheaply converts from &mut Self::Owned to Self::Borrowed. For HandleBased types this is “take” (it returns an owned handle and replaces value with Handle::invalid), and for all other types it is “borrow” (just converts from one reference to another).
source§

impl TypeMarker for RingBuffer

§

type Owned = RingBuffer

The owned Rust type which this FIDL type decodes into.
source§

fn inline_align(_context: Context) -> usize

Returns the minimum required alignment of the inline portion of the encoded object. It must be a (nonzero) power of two.
source§

fn inline_size(_context: Context) -> usize

Returns the size of the inline portion of the encoded object, including padding for alignment. Must be a multiple of inline_align.
§

fn encode_is_copy() -> bool

Returns true if the memory layout of 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

Returns true if the memory layout of 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 Standalone for RingBuffer

source§

impl StructuralPartialEq for RingBuffer

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Encode<Ambiguous1> for T

§

unsafe fn encode( self, _encoder: &mut Encoder<'_>, _offset: usize, _depth: Depth ) -> Result<(), Error>

Encodes the object into the encoder’s buffers. Any handles stored in the object are swapped for Handle::INVALID. Read more
§

impl<T> Encode<Ambiguous2> for T

§

unsafe fn encode( self, _encoder: &mut Encoder<'_>, _offset: usize, _depth: Depth ) -> Result<(), Error>

Encodes the object into the encoder’s buffers. Any handles stored in the object are swapped for Handle::INVALID. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more