blob: 07e58349bf719c7888036a261a9815d38bff07fe [file] [log] [blame]
// Copyright 2016 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.
#pragma once
#include <atomic>
#include <media/cpp/fidl.h>
#include "lib/fidl/cpp/binding.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/synchronization/thread_checker.h"
#include "lib/media/timeline/timeline_rate.h"
#include "lib/media/transport/shared_buffer_set.h"
namespace media {
// Base class that implements MediaPacketConsumer.
class MediaPacketConsumerBase : public MediaPacketConsumer {
private:
class SuppliedPacketCounter;
public:
MediaPacketConsumerBase();
~MediaPacketConsumerBase() override;
// Wraps a supplied MediaPacket and calls the associated callback when
// destroyed. Also works with SuppliedPacketCounter to keep track of the
// number of outstanding packets and to deliver demand updates.
class SuppliedPacket {
public:
~SuppliedPacket();
const MediaPacket& packet() { return packet_; }
void* payload() { return payload_; }
uint64_t payload_size() { return packet_.payload_size; }
uint64_t label() { return label_; }
private:
SuppliedPacket(uint64_t label,
MediaPacket packet,
void* payload,
SupplyPacketCallback callback,
std::shared_ptr<SuppliedPacketCounter> counter);
uint64_t label_;
MediaPacket packet_;
void* payload_;
SupplyPacketCallback callback_;
std::shared_ptr<SuppliedPacketCounter> counter_;
FXL_DECLARE_THREAD_CHECKER(thread_checker_);
// So the constructor can be private.
friend class MediaPacketConsumerBase;
};
// Binds to this MediaPacketConsumer.
void Bind(fidl::InterfaceRequest<MediaPacketConsumer> request);
// Binds to this MediaPacketConsumer.
void Bind(fidl::InterfaceHandle<MediaPacketConsumer>* handle);
// Determines if the consumer is bound to a channel.
bool is_bound();
// Sets the PTS rate to apply to all incoming packets. If the PTS rate is
// set to TimelineRate::Zero (the default), PTS rates on incoming packets
// are not adjusted.
void SetPtsRate(TimelineRate pts_rate) { pts_rate_ = pts_rate; }
// Indicates that revised media type is to be accepted.
void AcceptRevisedMediaType() { accept_revised_media_type_ = true; }
const MediaPacketDemand& current_demand() { return demand_; }
// Sets the demand, which is communicated back to the producer at the first
// opportunity (in response to PullDemandUpdate or SupplyPacket).
void SetDemand(uint32_t min_packets_outstanding,
int64_t min_pts = kNoTimestamp);
// Shuts down the consumer.
void Reset();
// Shuts down the consumer and calls OnFailure().
void Fail();
protected:
// Called when a packet is supplied.
virtual void OnPacketSupplied(
std::unique_ptr<SuppliedPacket> supplied_packet) = 0;
// Called upon the return of a supplied packet after the value returned by
// supplied_packets_outstanding() has been updated and before the callback is
// called. This is often a good time to call SetDemand. The default
// implementation does nothing.
virtual void OnPacketReturning();
// Called when the consumer is asked to flush. The default implementation
// just runs the callback.
virtual void OnFlushRequested(bool hold_frame, FlushCallback callback);
// Called when the binding is unbound. The default implementation does
// nothing. Subclasses may delete themselves in overrides of |OnUnbind|.
virtual void OnUnbind();
// Called when a fatal error occurs. The default implementation does nothing.
virtual void OnFailure();
uint32_t supplied_packets_outstanding() {
return counter_->packets_outstanding();
}
private:
// MediaPacketConsumer implementation.
void PullDemandUpdate(PullDemandUpdateCallback callback) final;
void AddPayloadBuffer(uint32_t payload_buffer_id,
zx::vmo payload_buffer) final;
void RemovePayloadBuffer(uint32_t payload_buffer_id) final;
void SupplyPacket(MediaPacket packet, SupplyPacketCallback callback) final;
void SupplyPacketNoReply(MediaPacket packet) final;
void Flush(bool hold_frame, FlushCallback callback) final;
// Counts oustanding supplied packets and uses their callbacks to deliver
// demand updates. This class is referenced using shared_ptrs so that no
// SuppliedPackets outlive it.
// TODO(dalesat): Get rid of this separate class by insisting that the
// MediaPacketConsumerBase outlive its SuppliedPackets.
class SuppliedPacketCounter {
public:
SuppliedPacketCounter(MediaPacketConsumerBase* owner);
~SuppliedPacketCounter();
async_t* async() { return async_; }
// Prevents any subsequent calls to the owner.
void Detach() {
FXL_DCHECK_CREATION_THREAD_IS_CURRENT(thread_checker_);
owner_ = nullptr;
}
// Records the arrival of a packet.
void OnPacketArrival() {
FXL_DCHECK_CREATION_THREAD_IS_CURRENT(thread_checker_);
++packets_outstanding_;
}
// Records the departure of a packet and returns the current demand update,
// if any.
MediaPacketDemandPtr OnPacketDeparture(uint64_t label) {
FXL_DCHECK_CREATION_THREAD_IS_CURRENT(thread_checker_);
--packets_outstanding_;
return (owner_ == nullptr) ? nullptr
: owner_->GetDemandForPacketDeparture(label);
}
// Returns number of packets currently outstanding.
uint32_t packets_outstanding() { return packets_outstanding_; }
SharedBufferSet& buffer_set() { return buffer_set_; }
private:
MediaPacketConsumerBase* owner_;
// We keep the buffer set here, because it needs to outlive SuppliedPackets.
async_t* async_;
SharedBufferSet buffer_set_;
std::atomic_uint32_t packets_outstanding_;
FXL_DECLARE_THREAD_CHECKER(thread_checker_);
};
// Completes a pending PullDemandUpdate if there is one and if there's an
// update to send.
void MaybeCompletePullDemandUpdate();
// Returns the demand update, if any, to be included in a SupplyPacket
// callback.
MediaPacketDemandPtr GetDemandForPacketDeparture(uint64_t label);
// Sets the PTS rate of the packet to pts_rate_ unless pts_rate_ is zero.
// Does nothing if pts_rate_ is zero.
void SetPacketPtsRate(MediaPacket* packet);
fidl::Binding<MediaPacketConsumer> binding_;
bool accept_revised_media_type_ = false;
MediaPacketDemand demand_;
bool demand_update_required_ = false;
bool returning_packet_ = false;
PullDemandUpdateCallback get_demand_update_callback_;
std::shared_ptr<SuppliedPacketCounter> counter_;
TimelineRate pts_rate_ = TimelineRate::Zero; // Zero means do not adjust.
uint64_t prev_packet_label_ = 0;
bool flush_pending_ = false;
bool is_reset_ = true;
FXL_DECLARE_THREAD_CHECKER(thread_checker_);
};
} // namespace media