| Index: services/media/framework/stages/lpcm_stage_input.cc
|
| diff --git a/services/media/framework/stages/lpcm_stage_input.cc b/services/media/framework/stages/lpcm_stage_input.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b215334fe68594385bc282eb670fddd73a23fd4d
|
| --- /dev/null
|
| +++ b/services/media/framework/stages/lpcm_stage_input.cc
|
| @@ -0,0 +1,211 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "services/media/framework/engine.h"
|
| +#include "services/media/framework/stages/lpcm_stage_input.h"
|
| +#include "services/media/framework/stages/lpcm_stage_output.h"
|
| +#include "services/media/framework/stages/stage.h"
|
| +
|
| +namespace mojo {
|
| +namespace media {
|
| +
|
| +LpcmStageInput::LpcmStageInput() :
|
| + demand_pending_(false),
|
| + buffer_(nullptr),
|
| + frame_count_(0),
|
| + mix_(false),
|
| + synchronous_(false),
|
| + end_of_stream_(false) {
|
| + packet_exhausted_function_ = [this]() {
|
| + DCHECK(packet_from_upstream());
|
| + packet_from_upstream().reset();
|
| + };
|
| +}
|
| +
|
| +LpcmStageInput::~LpcmStageInput() {}
|
| +
|
| +void LpcmStageInput::set_stream_type(const LpcmStreamType& stream_type) {
|
| + lpcm_util_ = LpcmUtil::Create(stream_type);
|
| + lpcm_supply_.set_bytes_per_frame(stream_type.bytes_per_frame());
|
| + packet_frames_.set_bytes_per_frame(stream_type.bytes_per_frame());
|
| + demand_frames_.set_bytes_per_frame(stream_type.bytes_per_frame());
|
| +}
|
| +
|
| +void LpcmStageInput::SuggestDemand(uint64_t frame_count, Engine* engine) {
|
| + DCHECK(engine);
|
| +
|
| + if (demand_pending_ || lpcm_supply_.frame_count() != 0) {
|
| + // We've already demanded. Too late for this suggestion.
|
| + return;
|
| + }
|
| +
|
| + if (frame_count == 0) {
|
| + // No demand is suggested.
|
| + SetDemand(Demand::kNegative, engine);
|
| + return;
|
| + }
|
| +
|
| + if (!connected_to_lpcm()) {
|
| + // Upstream output isn't LPCM. Demand packets.
|
| + demand_pending_ = true;
|
| + SetDemand(Demand::kPositive, engine);
|
| + return;
|
| + }
|
| +
|
| + SetLpcmDemand(
|
| + GetDemandBuffer(frame_count),
|
| + frame_count,
|
| + false,
|
| + false,
|
| + engine);
|
| +}
|
| +
|
| +void LpcmStageInput::SetLpcmDemand(
|
| + void* buffer,
|
| + uint64_t frame_count,
|
| + bool mix,
|
| + bool synchronous,
|
| + Engine* engine) {
|
| + DCHECK(engine);
|
| + DCHECK(connected());
|
| +
|
| + demand_pending_ = true;
|
| +
|
| + buffer_ = buffer;
|
| + frame_count_ = frame_count;
|
| + mix_ = mix;
|
| + synchronous_ = synchronous;
|
| +
|
| + if (synchronous) {
|
| + // TODO
|
| + //engine->AddToFallback([lpcm_mate](Engine* engine) {
|
| + // lpcm_mate->fallback(engine);
|
| + //});
|
| + }
|
| +
|
| + LpcmStageOutput* lpcm_mate = mate().get_lpcm();
|
| + if (lpcm_mate != nullptr) {
|
| + // The upstream output is LPCM.
|
| + DCHECK(!packet_from_upstream());
|
| + lpcm_mate->UpdateLpcmDemand(buffer, frame_count, mix, synchronous);
|
| + engine->PushToDemandBacklogUnsafe(upstream_stage());
|
| + return;
|
| + }
|
| +
|
| + demand_frames_.Set(buffer, frame_count);
|
| +
|
| + // The upstream output isn't LPCM. See if we can satisfy demand with the
|
| + // packet from upstream, if there is one.
|
| + if (CopyOrMixFrames()) {
|
| + // Frames supplied. Add this stage to the supply backlog.
|
| + engine->PushToSupplyBacklogUnsafe(mate().downstream_stage());
|
| + } else {
|
| + // Frames not supplied. Demand another packet.
|
| + SetDemand(Demand::kPositive, engine);
|
| + }
|
| +}
|
| +
|
| +bool LpcmStageInput::SupplyPacketFromOutput(PacketPtr packet) {
|
| + StageInput::SupplyPacketFromOutput(std::move(packet));
|
| +
|
| + demand_pending_ = false;
|
| +
|
| + if (connected_to_lpcm()) {
|
| + // The upstream output is LPCM, so the packet should be a wrapper for the
|
| + // demand buffer (buffer_). In this case, we can release the packet,
|
| + // because the frames are already where we want them.
|
| + DCHECK(packet_from_upstream()->payload() == buffer_);
|
| + DCHECK(packet_from_upstream()->duration() <= frame_count_);
|
| + end_of_stream_ = packet_from_upstream()->end_of_stream();
|
| + lpcm_supply_.Set(
|
| + packet_from_upstream()->payload(),
|
| + packet_from_upstream()->duration());
|
| + packet_from_upstream().reset();
|
| + return true;
|
| + }
|
| +
|
| + if (buffer_ == nullptr) {
|
| + // The upstream output isn't LPCM, and the stage hasn't supplied a buffer.
|
| + // We'll supply frames right out of the packet payload and reset the
|
| + // packet pointer when the frames are exhausted.
|
| + DCHECK(!mix_);
|
| + end_of_stream_ = packet_from_upstream()->end_of_stream();
|
| + lpcm_supply_.Set(
|
| + packet_from_upstream()->payload(),
|
| + packet_from_upstream()->duration(),
|
| + packet_exhausted_function_);
|
| + return true;
|
| + }
|
| +
|
| + // The upstream output isn't LPCM, and the stage has supplied a buffer. That
|
| + // means we have to copy or mix from the packet to the supplied buffer. We
|
| + // initialize packet_frames_ for that purpose and call CopyOrMixFrames.
|
| + packet_frames_.Set(
|
| + packet_from_upstream()->payload(),
|
| + packet_from_upstream()->duration(),
|
| + packet_exhausted_function_);
|
| +
|
| + return CopyOrMixFrames();
|
| +}
|
| +
|
| +LpcmStageInput* LpcmStageInput::get_lpcm() {
|
| + return this;
|
| +}
|
| +
|
| +bool LpcmStageInput::connected_to_lpcm() {
|
| + return mate().get_lpcm() != nullptr;
|
| +}
|
| +
|
| +bool LpcmStageInput::CopyOrMixFrames() {
|
| + DCHECK(buffer_);
|
| + DCHECK(demand_frames_.buffer());
|
| +
|
| + uint64_t frame_count = std::min(
|
| + packet_frames_.frame_count(),
|
| + demand_frames_.frame_count());
|
| +
|
| + if (frame_count == 0) {
|
| + return false;
|
| + }
|
| +
|
| + DCHECK(packet_from_upstream());
|
| +
|
| + if (mix_) {
|
| + lpcm_util_->Mix(
|
| + packet_frames_.buffer(),
|
| + demand_frames_.buffer(),
|
| + frame_count);
|
| + } else {
|
| + lpcm_util_->Copy(
|
| + packet_frames_.buffer(),
|
| + demand_frames_.buffer(),
|
| + frame_count);
|
| + }
|
| +
|
| + bool end_of_stream = packet_from_upstream()->end_of_stream();
|
| +
|
| + packet_frames_.Advance(frame_count);
|
| + demand_frames_.Advance(frame_count);
|
| +
|
| + if (demand_frames_.frame_count() == 0 ||
|
| + (packet_frames_.frame_count() == 0 && end_of_stream)) {
|
| + end_of_stream_ = end_of_stream;
|
| + lpcm_supply_.Set(buffer_, frame_count_ - demand_frames_.frame_count());
|
| + demand_frames_.Reset();
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void* LpcmStageInput::GetDemandBuffer(uint64_t frame_count) {
|
| + if (demand_buffer_.size() < frame_count) {
|
| + demand_buffer_.clear();
|
| + demand_buffer_.resize(frame_count);
|
| + }
|
| + return &demand_buffer_[0];
|
| +}
|
| +
|
| +} // namespace media
|
| +} // namespace mojo
|
|
|