blob: 1105aaae91f6ea9e292def3c635f4cf7022e325e [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.
#include "garnet/bin/mediaplayer/test/command_queue.h"
#include <fcntl.h>
#include <lib/async/cpp/task.h>
#include <iostream>
#include "garnet/bin/mediaplayer/graph/formatting.h"
#include "lib/fsl/io/fd.h"
#include "lib/fxl/logging.h"
#include "lib/media/timeline/type_converters.h"
#include "lib/url/gurl.h"
namespace media_player {
namespace test {
CommandQueue::CommandQueue() : dispatcher_(async_get_default_dispatcher()) {
wait_for_position_task_.set_handler([this]() {
if (wait_for_position_ != fuchsia::media::NO_TIMESTAMP) {
wait_for_position_ = fuchsia::media::NO_TIMESTAMP;
if (verbose_) {
std::cerr << "WaitForPosition done\n";
}
ExecuteNextCommand();
}
});
}
CommandQueue::~CommandQueue() {}
void CommandQueue::NotifyStatusChanged(
const fuchsia::mediaplayer::PlayerStatus& status) {
// Process status received from the player.
if (status.duration_ns != 0) {
content_loaded_ = true;
MaybeFinishWaitingForContentLoaded();
}
if (status.timeline_function) {
timeline_function_ =
fxl::To<media::TimelineFunction>(*status.timeline_function);
MaybeScheduleWaitForPositionTask();
MaybeFinishWaitingForSeekCompletion();
}
at_end_of_stream_ = status.end_of_stream;
MaybeFinishWaitingForEndOfStream();
}
void CommandQueue::NotifyViewReady() {
view_ready_ = true;
MaybeFinishWaitingForViewReady();
}
void CommandQueue::MaybeFinishWaitingForContentLoaded() {
if (content_loaded_ && wait_for_content_loaded_) {
wait_for_content_loaded_ = false;
if (verbose_) {
std::cerr << "WaitForContentLoaded done\n";
}
ExecuteNextCommand();
}
}
void CommandQueue::MaybeFinishWaitingForViewReady() {
if (view_ready_ && wait_for_view_ready_) {
wait_for_view_ready_ = false;
if (verbose_) {
std::cerr << "WaitForViewReady done\n";
}
ExecuteNextCommand();
}
}
void CommandQueue::MaybeScheduleWaitForPositionTask() {
if (wait_for_position_ != fuchsia::media::NO_TIMESTAMP) {
wait_for_position_task_.Cancel();
if (timeline_function_.invertable()) {
// Apply the timeline function in reverse to find the CLOCK_MONOTONIC
// time at which we should resume executing commands.
int64_t wait_for_time =
timeline_function_.ApplyInverse(wait_for_position_);
wait_for_position_task_.PostForTime(dispatcher_, zx::time(wait_for_time));
}
}
}
void CommandQueue::MaybeFinishWaitingForSeekCompletion() {
if (wait_for_seek_completion_position_ != fuchsia::media::NO_TIMESTAMP &&
timeline_function_.subject_time() == wait_for_seek_completion_position_) {
wait_for_seek_completion_position_ = fuchsia::media::NO_TIMESTAMP;
if (verbose_) {
std::cerr << "WaitForSeekCompletion done\n";
}
ExecuteNextCommand();
}
}
void CommandQueue::MaybeFinishWaitingForEndOfStream() {
if (at_end_of_stream_ && wait_for_end_of_stream_) {
wait_for_end_of_stream_ = false;
if (verbose_) {
std::cerr << "WaitForEndOfStream done\n";
}
ExecuteNextCommand();
}
}
void CommandQueue::ExecuteNextCommand() {
if (command_queue_.empty()) {
return;
}
async::PostTask(dispatcher_, [this]() {
if (command_queue_.empty()) {
return;
}
auto command = std::move(command_queue_.front());
command_queue_.pop();
command->Execute(this);
});
}
void CommandQueue::SetUrlCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "SetUrl " << url_ << "\n";
}
url::GURL url = url::GURL(url_);
if (url.SchemeIsFile()) {
auto fd = fxl::UniqueFD(open(url.path().c_str(), O_RDONLY));
FXL_CHECK(fd.is_valid());
command_queue->player_->SetFileSource(
fsl::CloneChannelFromFileDescriptor(fd.get()));
} else {
command_queue->player_->SetHttpSource(url_, nullptr);
}
command_queue->prev_seek_position_ = 0;
command_queue->at_end_of_stream_ = false;
command_queue->ExecuteNextCommand();
}
void CommandQueue::SetFileCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "SetFile\n";
}
auto fd = fxl::UniqueFD(open(path_.c_str(), O_RDONLY));
FXL_CHECK(fd.is_valid());
command_queue->player_->SetFileSource(
fsl::CloneChannelFromFileDescriptor(fd.get()));
command_queue->prev_seek_position_ = 0;
command_queue->at_end_of_stream_ = false;
command_queue->ExecuteNextCommand();
}
void CommandQueue::PlayCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "Play\n";
}
command_queue->player_->Play();
command_queue->ExecuteNextCommand();
}
void CommandQueue::PauseCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "Pause\n";
}
command_queue->player_->Pause();
command_queue->ExecuteNextCommand();
}
void CommandQueue::SeekCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "Seek " << AsNs(position_.get()) << "\n";
}
command_queue->player_->Seek(position_.get());
command_queue->prev_seek_position_ = position_.get();
command_queue->at_end_of_stream_ = false;
command_queue->ExecuteNextCommand();
}
void CommandQueue::InvokeCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "Invoke\n";
}
FXL_DCHECK(action_);
action_();
command_queue->ExecuteNextCommand();
}
void CommandQueue::WaitForContentLoadedCommand::Execute(
CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "WaitForContentLoaded\n";
}
command_queue->wait_for_content_loaded_ = true;
command_queue->MaybeFinishWaitingForContentLoaded();
}
void CommandQueue::WaitForViewReadyCommand::Execute(
CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "WaitForViewReady\n";
}
command_queue->wait_for_view_ready_ = true;
command_queue->MaybeFinishWaitingForViewReady();
}
void CommandQueue::WaitForPositionCommand::Execute(
CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "WaitForPosition " << AsNs(position_.get()) << "\n";
}
command_queue->wait_for_position_ = position_.get();
command_queue->MaybeScheduleWaitForPositionTask();
}
void CommandQueue::WaitForSeekCompletionCommand::Execute(
CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "WaitForSeekCompletion\n";
}
command_queue->wait_for_seek_completion_position_ =
command_queue->prev_seek_position_;
command_queue->MaybeFinishWaitingForSeekCompletion();
}
void CommandQueue::WaitForEndOfStreamCommand::Execute(
CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "WaitForEndOfStream\n";
}
command_queue->wait_for_end_of_stream_ = true;
command_queue->MaybeFinishWaitingForEndOfStream();
}
void CommandQueue::SleepCommand::Execute(CommandQueue* command_queue) {
if (command_queue->verbose_) {
std::cerr << "Sleep " << AsNs(duration_.get()) << "\n";
}
async::PostDelayedTask(
command_queue->dispatcher_,
[command_queue]() { command_queue->ExecuteNextCommand(); },
zx::duration(duration_));
}
} // namespace test
} // namespace media_player