[go: nahoru, domu]

blob: 4f4201f34c00b6bdd6a73115b1d6616b028e8c76 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/media/cma/backend/proxy/push_buffer_pending_handler.h"
#include <utility>
#include "base/functional/callback.h"
#include "chromecast/media/cma/backend/proxy/push_buffer_queue.h"
#include "chromecast/public/media/decoder_config.h"
#include "chromecast/public/task_runner.h"
namespace chromecast {
namespace media {
namespace {
constexpr uint64_t kDelayBetweenDataPushAttemptsInMs = 10;
} // namespace
PushBufferPendingHandler::PushBufferPendingHandler(
TaskRunner* task_runner,
AudioChannelPushBufferHandler::Client* client)
: PushBufferPendingHandler(task_runner,
client,
std::make_unique<PushBufferQueue>()) {}
PushBufferPendingHandler::PushBufferPendingHandler(
TaskRunner* task_runner,
AudioChannelPushBufferHandler::Client* client,
std::unique_ptr<AudioChannelPushBufferHandler> handler)
: delegated_handler_(std::move(handler)),
client_(client),
task_runner_(task_runner),
weak_factory_(this) {
DCHECK(delegated_handler_.get());
DCHECK(client_);
DCHECK(task_runner_);
}
PushBufferPendingHandler::~PushBufferPendingHandler() = default;
CmaBackend::BufferStatus PushBufferPendingHandler::PushBuffer(
const PushBufferRequest& request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Try and push the data to |delegated_handler_|.
if (!IsCallPending()) {
auto delegated_result = delegated_handler_->PushBuffer(request);
if (delegated_result != CmaBackend::BufferStatus::kBufferFailed) {
return delegated_result;
}
}
// Store the request to be processed later, and schedule that processing if it
// isn't scheduled already.
const bool had_data = IsCallPending();
if (request.has_buffer()) {
DCHECK(!has_push_buffer_queued_);
has_push_buffer_queued_ = true;
}
pushed_data_.push(std::move(request));
if (!had_data) {
ScheduleDataPush();
}
return CmaBackend::BufferStatus::kBufferPending;
}
bool PushBufferPendingHandler::HasBufferedData() const {
// The pending data is only considered by the producer sequence, so this
// consumer sequence call does not consider it.
return delegated_handler_->HasBufferedData();
}
absl::optional<AudioChannelPushBufferHandler::PushBufferRequest>
PushBufferPendingHandler::GetBufferedData() {
// The pending data is only considered by the producer sequence, so this
// consumer sequence call does not consider it.
return delegated_handler_->GetBufferedData();
}
bool PushBufferPendingHandler::IsCallPending() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return !pushed_data_.empty();
}
void PushBufferPendingHandler::TryPushPendingData() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Process as much
for (auto push_result = CmaBackend::BufferStatus::kBufferSuccess;
push_result == CmaBackend::BufferStatus::kBufferSuccess &&
IsCallPending();) {
push_result = delegated_handler_->PushBuffer(pushed_data_.front());
if (push_result != CmaBackend::BufferStatus::kBufferFailed) {
// If we removed the buffer containing data from a PushBuffer() call,
// update the associated variable.
if (pushed_data_.front().has_buffer()) {
DCHECK(has_push_buffer_queued_);
has_push_buffer_queued_ = false;
}
// If we didn't fail, pop the front element.
pushed_data_.pop();
}
}
if (IsCallPending()) {
ScheduleDataPush();
} else {
client_->OnAudioChannelPushBufferComplete(
CmaBackend::BufferStatus::kBufferSuccess);
}
}
void PushBufferPendingHandler::ScheduleDataPush() {
auto* task = new TaskRunner::CallbackTask<base::OnceClosure>(
base::BindOnce(&PushBufferPendingHandler::TryPushPendingData,
weak_factory_.GetWeakPtr()));
task_runner_->PostTask(task, kDelayBetweenDataPushAttemptsInMs);
}
} // namespace media
} // namespace chromecast