class ReadableStream
Defined at line 91 of file ../../src/media/audio/audio_core/stream.h
A read-only stream of audio data.
ReadableStreams should be created and held as shared_ptr
<
>s.
Public Methods
std::optional<Buffer> ReadLock (ReadLockContext & ctx, Fixed dest_frame, int64_t frame_count)
ReadableStream is implemented by audio pipeline stages that consume zero or more source
streams and produce a destination stream. ReadLock acquires a read lock on the destination
stream. The parameters `dest_frame` and `frame_count` represent a range of frames on the
destination stream's frame timeline.
THE RETURNED BUFFER
If no data is available for the requested frame range, ReadLock returns std::nullopt.
Otherwise, ReadLock returns a buffer representing all or part of the requested range.
If `start()` on the returned buffer is greater than `dest_frame`, then the stream
has no data for those initial frames and it may be treated as silence. Conversely, if `end()`
on the returned buffer is less than `dest_frame + frame_count`, this indicates the full
frame range is not available on a single contiguous buffer. Clients should call `ReadLock`
again, with `dest_frame` set to the `end()` of the previous buffer, to query if the stream
has more frames.
The buffer must contain an integral number of frames and must satisfy the following
conditions:
- buffer.start() > dest_frame - Fixed(1)
- buffer.end()
<
= dest_frame + Fixed(frame_count)
- buffer.length()
<
= frame_count
The buffer's `start()` is the position of the left edge of the first frame in the buffer.
For example, given `ReadLock(Fixed(10), 5)`, if the stream's frames happen to be aligned
on positions 9.1, 10.1, 11.1, etc., then ReadLock should return a buffer with `start() = 9.1`
and `length() = 5`.
The stream will remain locked until the buffer is destructed.
THE PASSAGE OF TIME
Each ReadableStream maintains a current frame position (aka time). This position must always
move forward. Position advances to X after a call to `Trim(X)`. Position is also advanced by
ReadLock, which calls Trim as follows:
- If ReadLock returns std::nullopt, we advance time to
`Trim(dest_frame + frame_count)`.
- When a buffer is unlocked, we advance time to
`Trim(buffer.start + buffer.frames_consumed)`.
Put differently, time advances when ReadLock is called, when a buffer is consumed, and on
explicit calls to Trim. Time does not go backwards: each call to ReadLock must have
`dest_frame >= NextAvailableFrame()`.
RESET
Changing a stream's ref_time_to_frac_presentation_frame TimelineFunction discards all history
recorded by prior calls to ReadLock and Trim. This allows time to go backwards as a one-time
event after a Play or Pause command seeks backwards in a stream. Note that when time advances
normally past X, then is reset to X or earlier (by Play), all internal caches are discarded
and there's no requirement for a source to reproduce the same audio that was played at X the
first time.
Defined at line 37 of file ../../src/media/audio/audio_core/stream.cc
void Trim (Fixed dest_frame)
Trims the stream by releasing any frames before the given frame. This is a declaration
that the caller will not attempt to ReadLock any frame before dest_frame. If the stream has
allocated buffers for frames before dest_frame, it can free those buffers now.
Must not be called while the stream is locked.
Defined at line 122 of file ../../src/media/audio/audio_core/stream.cc
std::optional<Fixed> NextAvailableFrame ()
Reports the next frame that can be requested from ReadLock. This is the highest frame passed
to Trim. Returns std::nullopt if Trim has not been called or if the stream has been reset since
the last Trim.
Defined at line 259 of file ../../src/media/audio/audio_core/stream.h
Protected Methods
void ReadableStream (std::string name, Format format)
`name` should uniquely identify the stream. Used for debugging.
Defined at line 32 of file ../../src/media/audio/audio_core/stream.cc
std::optional<Buffer> ReadLockImpl (ReadLockContext & ctx, Fixed dest_frame, int64_t frame_count)
Child classes must provide stream-specific implementations of ReadLockImpl and TrimImpl.
These are called by ReadLock and Trim, respectively.
ReadLock and Trim add some default behavior, including logging, tracing, caching of
partially-consumed buffers, and validation of pre and post conditions.
void ReadUnlock ()
Child classes may override this to be notified when the most-recently locked buffer is
unlocked.
Defined at line 278 of file ../../src/media/audio/audio_core/stream.h
void TrimImpl (Fixed dest_frame)
std::optional<Buffer> MakeCachedBuffer (Fixed start_frame, int64_t frame_count, void * payload, StreamUsageMask usage_mask, float total_applied_gain_db)
ReadLockImpl should use this to create a cached buffer. If the buffer is not fully
consumed after one ReadLock, the next ReadLock call will return the same buffer
without asking ReadLockImpl to recreate the same data. ReadableStream will hold
onto this buffer until the buffer is fully consumed or trimmed away.
This is useful for pipeline stages that compute buffers dynamically, such as mixers
and effects. The std::optional return type is for convenience (so that `MakeCachedBuffer(...)`
can be returned directly from ReadLockImpl) -- the returned value is never std::nullopt.
REQUIRED:
- The buffer's `start()` must obey the buffer constraints described by ReadLock,
however the buffer's `length()` can be arbitrarily large. This is useful for pipeline
stages that generate data in fixed-sized blocks: they may cache the entire block for
future ReadLock calls.
- The payload must remain valid until the buffer is fully consumed, i.e. until the
stream is Trim'd past the end of the buffer.
Defined at line 177 of file ../../src/media/audio/audio_core/stream.cc
std::optional<Buffer> MakeUncachedBuffer (Fixed start_frame, int64_t frame_count, void * payload, StreamUsageMask usage_mask, float total_applied_gain_db)
ReadLockImpl should use this to create an uncached buffer. If the buffer is not fully
consumed after one ReadLock, the next ReadLock call will ask ReadLockImpl to recreate
the buffer.
This is useful for streams that don't need caching or that want precise control over
buffer lifetimes. Examples include ring buffers and packet queues. The std::optional
return type is for convenience -- the returned value is never std::nullopt.
REQUIRED:
- The buffer's `start()` and `length()` must obey the buffer constraints described
by ReadLock (above).
- The payload must remain valid until the buffer is unlocked.
Defined at line 189 of file ../../src/media/audio/audio_core/stream.cc
std::optional<Buffer> ForwardBuffer (std::optional<Buffer> && buffer, std::optional<Fixed> start_frame)
ReadLockImpl should use this when forwarding a Buffer from an upstream source.
This may be used by no-op pipeline stages. It is necessary to call ForwardBuffer,
rather than simply returning a buffer from an upstream source, so that this stream
will be Trim'd when the buffer is unlocked:
// Good: calls this->Trim() and src->Trim() when unlocked
return ForwardBuffer(src->ReadLock(ctx, dest_frame, frame_count));
// Bad: calls src->Trim() when unlocked, but not this->Trim()
return src->ReadLock(ctx, dest_frame, frame_count);
If `start_frame` is specified, the returned buffer's starting frame is set to the
given value. The buffer's length is unchanged. This is useful when doing SampleAndHold
on a source stream. For example:
auto buffer = src->ReadLock(ctx, frame, frame_count);
auto start_frame = buffer->start().Ceiling();
return ForwardBufferWithModifiedStart(std::move(buffer), start_frame);
If start_frame is not specified, the buffer is forwarded unchanged.
Defined at line 208 of file ../../src/media/audio/audio_core/stream.cc