blob: 2045dd99478789127386aef8d7a65cae4d2760ff [file] [log] [blame]
// Copyright 2018 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_PLAYBACK_MEDIAPLAYER_FIDL_BUFFER_SET_H_
#define SRC_MEDIA_PLAYBACK_MEDIAPLAYER_FIDL_BUFFER_SET_H_
#include <fuchsia/mediacodec/cpp/fidl.h>
#include <lib/fit/thread_checker.h>
#include <lib/syslog/cpp/macros.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include "src/lib/fxl/synchronization/thread_annotations.h"
#include "src/media/playback/mediaplayer/graph/payloads/payload_allocator.h"
#include "src/media/playback/mediaplayer/graph/payloads/payload_buffer.h"
namespace media_player {
// A set of buffers associated with a specific StreamBufferSettings and
// buffer lifetime ordinal.
//
// This class is thread-safe.
class BufferSet : public fbl::RefCounted<BufferSet> {
public:
// Creates a buffer set with the specified settings and lifetime ordinal.
// |single_vmo| indicates whether the buffers should be allocated from a
// single VMO (true) or a VMO per buffer.
static fbl::RefPtr<BufferSet> Create(const fuchsia::media::StreamBufferSettings& settings,
uint64_t lifetime_ordinal, bool single_vmo);
BufferSet(const fuchsia::media::StreamBufferSettings& settings, uint64_t lifetime_ordinal,
bool single_vmo);
~BufferSet();
// Sets the buffer count.
void SetBufferCount(uint32_t buffer_count);
// Gets the partial settings for this buffer set. The |buffer_lifetime_ordinal| of settings is set
// to the |lifetime_ordinal| value passed into the constructor.
fuchsia::media::StreamBufferPartialSettings PartialSettings(
fuchsia::sysmem::BufferCollectionTokenPtr token) const;
// Sets the value passed into the constructor as |single_vmo|.
bool single_vmo() const {
std::lock_guard<std::mutex> locker(mutex_);
return single_vmo_;
}
// Returns the buffer lifetime ordinal passed to the constructor.
uint64_t lifetime_ordinal() const {
std::lock_guard<std::mutex> locker(mutex_);
return lifetime_ordinal_;
}
uint32_t packet_count_for_server() {
std::lock_guard<std::mutex> locker(mutex_);
return packet_count_for_server_;
}
uint32_t packet_count_for_client() {
std::lock_guard<std::mutex> locker(mutex_);
return packet_count_for_client_;
}
// Returns the size in bytes of the buffers in this set.
uint32_t buffer_size() const {
std::lock_guard<std::mutex> locker(mutex_);
return buffer_size_;
}
// Returns the number of buffers in the set.
uint32_t buffer_count() const {
std::lock_guard<std::mutex> locker(mutex_);
return buffers_.size();
}
// Allocates a buffer.
fbl::RefPtr<PayloadBuffer> AllocateBuffer(uint64_t size, const PayloadVmos& payload_vmos);
// Adds a reference to the payload buffer on behalf of the outboard processor.
// |payload_buffer| cannot be null. This version is used when the client
// has a reference to the |PayloadBuffer| already.
void AddRefBufferForProcessor(uint32_t buffer_index, fbl::RefPtr<PayloadBuffer> payload_buffer);
// Takes a reference to the payload buffer previously added using
// |AddRefBufferForProcessor| or |AllocateAllBuffersForProcessor| and returns a
// reference to the |PayloadBuffer|.
fbl::RefPtr<PayloadBuffer> TakeBufferFromProcessor(uint32_t buffer_index);
// Gets a new reference to a buffer already owned by the outboard processor.
fbl::RefPtr<PayloadBuffer> GetProcessorOwnedBuffer(uint32_t buffer_index);
// Allocates all buffers for the outboard processor. All buffers must be free
// when this method is called.
void AllocateAllBuffersForProcessor(const PayloadVmos& payload_vmos);
// Releases all buffers currently owned by the output processor.
void ReleaseAllProcessorOwnedBuffers();
// Returns true if there's a free buffer, otherwise calls |callback| on an
// arbirary thread when one becomes free. The pending action can be cancelled
// by calling |CancelPendingFreeBufferCallback|.
bool HasFreeBuffer(fit::closure callback);
// Indicates that this |BufferSet| has been parked in favor of a new one.
// After decommissioning and When all its buffers have been recycled, the
// buffer set will be deleted.
void Decommission();
private:
// The current state of a buffer in the set.
struct BufferInfo {
// Indicates whether the buffer is free. |processor_ref_| must be false if
// this field is true.
bool free_ = true;
// This field is non-null for buffers that are currently owned by the
// outboard processor.
fbl::RefPtr<PayloadBuffer> processor_ref_;
};
// Creates a |PayloadBuffer| for the indicated |buffer_index|.
fbl::RefPtr<PayloadBuffer> CreateBuffer(uint32_t buffer_index,
const std::vector<fbl::RefPtr<PayloadVmo>>& payload_vmos)
FXL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable std::mutex mutex_;
uint64_t lifetime_ordinal_ FXL_GUARDED_BY(mutex_);
bool single_vmo_ FXL_GUARDED_BY(mutex_);
uint64_t buffer_constraints_version_ordinal_ FXL_GUARDED_BY(mutex_);
bool single_buffer_mode_ FXL_GUARDED_BY(mutex_);
uint32_t packet_count_for_server_ FXL_GUARDED_BY(mutex_);
uint32_t packet_count_for_client_ FXL_GUARDED_BY(mutex_);
uint32_t buffer_size_ FXL_GUARDED_BY(mutex_);
std::vector<BufferInfo> buffers_ FXL_GUARDED_BY(mutex_);
// |suggest_next_to_allocate_| suggests the next buffer to allocate. When
// allocating a buffer, a sequential search for a free buffer starts at this
// index, and this index is left referring to the buffer after the allocated
// buffer (with wraparound). Given the normally FIFO behavior of the caller,
// only one increment is typically required per allocation. This approach
// tends to allocate the buffers in a round-robin fashion.
uint32_t suggest_next_to_allocate_ FXL_GUARDED_BY(mutex_) = 0;
uint32_t free_buffer_count_ FXL_GUARDED_BY(mutex_) = 0;
fit::closure free_buffer_callback_ FXL_GUARDED_BY(mutex_);
// Disallow copy and assign.
BufferSet(const BufferSet&) = delete;
BufferSet& operator=(const BufferSet&) = delete;
};
// Manages a sequence of buffer sets.
//
// This class is not thread-safe. The constructor, desctructor and all methods
// must be called on the same thread.
class BufferSetManager {
public:
BufferSetManager() = default;
~BufferSetManager() { FIT_DCHECK_IS_THREAD_VALID(thread_checker_); };
// Determines whether this has a current buffer set.
bool has_current_set() const {
FIT_DCHECK_IS_THREAD_VALID(thread_checker_);
return !!current_set_;
}
// The current buffer set. Do not call this method when |has_current| returns
// false.
BufferSet& current_set() {
FIT_DCHECK_IS_THREAD_VALID(thread_checker_);
FX_DCHECK(current_set_);
return *current_set_;
}
// Applies the specified constraints, creating a new buffer set. If
// |single_vmo_preferred| and |single_buffer_mode_allowed| are true, one vmo
// will be used for all the new buffers. Otherwise, each new buffer will have
// its own vmo. The resulting set's |single_vmo| method with return true in
// former case, false in the latter.
//
// Returns whether the constraints were successfully applied.
bool ApplyConstraints(const fuchsia::media::StreamBufferConstraints& constraints,
bool single_vmo_preferred);
// Releases a reference to the payload buffer previously added using
// |BufferSet::AddRefBufferForProcessor| or
// |BufferSet::AllocateAllBuffersForProcessor|.
void ReleaseBufferForProcessor(uint64_t lifetime_ordinal, uint32_t buffer_index);
private:
FIT_DECLARE_THREAD_CHECKER(thread_checker_);
// The current |BufferSet| this is only null when |ApplyConstraints| has
// never been called. It's important not to clear this arbitrarily, because
// that would prevent the buffer lifetime ordinals from progressing correctly.
fbl::RefPtr<BufferSet> current_set_;
// Disallow copy and assign.
BufferSetManager(const BufferSetManager&) = delete;
BufferSetManager& operator=(const BufferSetManager&) = delete;
};
} // namespace media_player
#endif // SRC_MEDIA_PLAYBACK_MEDIAPLAYER_FIDL_BUFFER_SET_H_