blob: e4b96d12dc10c34f8ee54c623dbff696af143cbb [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_MEDIA_AUDIO_AUDIO_CORE_STREAM_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_STREAM_H_
#include <fuchsia/media/cpp/fidl.h>
#include <lib/fit/result.h>
#include <lib/media/cpp/timeline_function.h>
#include <lib/zx/time.h>
#include <optional>
#include "src/media/audio/audio_core/format.h"
#include "src/media/audio/audio_core/packet.h"
namespace media::audio {
class BaseStream {
public:
BaseStream(Format format) : format_(format) {}
virtual ~BaseStream() = default;
// A snapshot of a |TimelineFunction| with an associated |generation|. If |generation| is equal
// between two subsequent calls to |ReferenceClockToFractionalFrames|, then the
// |timeline_function| is guaranteed to be unchanged.
struct TimelineFunctionSnapshot {
TimelineFunction timeline_function;
uint32_t generation;
};
virtual TimelineFunctionSnapshot ReferenceClockToFractionalFrames() const = 0;
const Format& format() const { return format_; }
virtual void SetMinLeadTime(zx::duration min_lead_time) { min_lead_time_.store(min_lead_time); }
zx::duration GetMinLeadTime() const { return min_lead_time_.load(); }
private:
Format format_;
std::atomic<zx::duration> min_lead_time_{zx::duration(0)};
};
// A read-only stream of audio data.
class ReadableStream : public BaseStream {
public:
ReadableStream(Format format) : BaseStream(format) {}
virtual ~ReadableStream() = default;
class Buffer {
public:
using DestructorT = fit::callback<void(bool fully_consumed)>;
Buffer(int64_t start, uint32_t length, void* payload, bool is_continuous,
DestructorT dtor = nullptr)
: dtor_(std::move(dtor)),
payload_(payload),
start_(start),
length_(length),
is_continuous_(is_continuous) {}
Buffer(FractionalFrames<int64_t> start, FractionalFrames<uint32_t> length, void* payload,
bool is_continuous, DestructorT dtor = nullptr)
: dtor_(std::move(dtor)),
payload_(payload),
start_(start),
length_(length),
is_continuous_(is_continuous) {}
~Buffer() {
if (dtor_) {
dtor_(is_fully_consumed_);
}
}
Buffer(Buffer&& rhs) = default;
Buffer& operator=(Buffer&& rhs) = default;
Buffer(const Buffer& rhs) = delete;
Buffer& operator=(const Buffer& rhs) = delete;
FractionalFrames<int64_t> start() const { return start_; }
FractionalFrames<int64_t> end() const { return start_ + length_; }
FractionalFrames<uint32_t> length() const { return length_; }
void* payload() const { return payload_; }
// Indicates this packet is continuous with a packet previously returned from an immediately
// preceding |ReadLock| call.
//
// Buffers may become discontinuous if, for example, and AudioRenderer is flushed and new
// packets are provided; these new packets will not be assumed to be continuous with the
// preceeding ones. Each |ReadableStream| implementation is reponsible for reporting any
// discontinuity so that stream processors (ex: the mixer) may clear any intermediate state
// based on the continuity of the stream.
bool is_continuous() const { return is_continuous_; }
// Call this to indicate whether the buffer was fully consumed.
// By default, we assume this is true.
void set_is_fully_consumed(bool fully_consumed) { is_fully_consumed_ = fully_consumed; }
private:
DestructorT dtor_;
void* payload_;
FractionalFrames<int64_t> start_;
FractionalFrames<uint32_t> length_;
bool is_continuous_;
bool is_fully_consumed_ = true;
};
// ReadLock acquires a read lock on the stream and returns a buffer representing the requested
// time range. Returns nullopt if no data is available for that time range. The buffer will remain
// locked until it is destructed.
//
// For each stream, it is not legal to hold more than one lock at a time.
//
// TODO(50669): Some implementations (e.g., PacketQueue) disregard the requested time range and
// can return data from any time range. Specify if this is allowed and fix implementations if not.
virtual std::optional<Buffer> ReadLock(zx::time now, int64_t frame, uint32_t frame_count) = 0;
// Trims the stream by releasing any frames before |trim_threshold|.
virtual void Trim(zx::time trim_threshold) = 0;
// Hooks to add logging or metrics for [Partial] Underflow events.
virtual void ReportUnderflow(FractionalFrames<int64_t> frac_source_start,
FractionalFrames<int64_t> frac_source_mix_point,
zx::duration underflow_duration) {}
virtual void ReportPartialUnderflow(FractionalFrames<int64_t> frac_source_offset,
int64_t dest_mix_offset) {}
};
// A write-only stream of audio data.
class WritableStream : public BaseStream {
public:
WritableStream(Format format) : BaseStream(format) {}
virtual ~WritableStream() = default;
class Buffer {
public:
using DestructorT = fit::callback<void()>;
Buffer(int64_t start, uint32_t length, void* payload, DestructorT dtor = nullptr)
: dtor_(std::move(dtor)), payload_(payload), start_(start), length_(length) {}
~Buffer() {
if (dtor_) {
dtor_();
}
}
Buffer(Buffer&& rhs) = default;
Buffer& operator=(Buffer&& rhs) = default;
Buffer(const Buffer& rhs) = delete;
Buffer& operator=(const Buffer& rhs) = delete;
FractionalFrames<int64_t> start() const { return start_; }
FractionalFrames<int64_t> end() const { return start_ + length_; }
FractionalFrames<uint32_t> length() const { return length_; }
void* payload() const { return payload_; }
private:
DestructorT dtor_;
void* payload_;
FractionalFrames<int64_t> start_;
FractionalFrames<uint32_t> length_;
};
// WriteLock acquires a write lock on the stream and returns a buffer representing the requested
// time range. Returns nullopt if no data is available for that time range. The buffer will remain
// locked until it is destructed.
//
// For each stream, it is not legal to hold more than one lock at a time.
virtual std::optional<Buffer> WriteLock(zx::time now, int64_t frame, uint32_t frame_count) = 0;
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_STREAM_H_