blob: c52826ac64f1907faeed79ec95c559b441c6403c [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/source_impl.h"
#include <fuchsia/mediaplayer/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/fit/function.h>
#include <sstream>
#include "garnet/bin/mediaplayer/core/demux_source_segment.h"
#include "garnet/bin/mediaplayer/fidl/fidl_type_conversions.h"
#include "garnet/bin/mediaplayer/util/safe_clone.h"
#include "lib/fidl/cpp/optional.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/type_converter.h"
namespace media_player {
SourceImpl::SourceImpl(Graph* graph, fit::closure connection_failure_callback)
: graph_(graph),
connection_failure_callback_(std::move(connection_failure_callback)),
dispatcher_(async_get_default_dispatcher()) {
FXL_DCHECK(graph_);
FXL_DCHECK(dispatcher_);
}
SourceImpl::~SourceImpl() {}
void SourceImpl::CompleteConstruction(SourceSegment* source_segment) {
FXL_DCHECK(source_segment);
source_segment_ = source_segment;
source_segment_->Provision(
graph_, dispatcher_,
[this]() {
// This callback notifies this |SourceImpl| of
// changes to source_segment_'s problem() and/or
// metadata() values.
SendStatusUpdates();
},
[this](size_t index, const SourceSegment::Stream* stream, bool more) {
if (stream) {
OnStreamUpdated(index, *stream);
} else {
OnStreamRemoved(index);
}
if (!more) {
SendStatusUpdates();
}
});
}
void SourceImpl::OnStreamUpdated(size_t index,
const SourceSegment::Stream& update_stream) {
if (streams_.size() < index + 1) {
streams_.resize(index + 1);
}
Stream& stream = streams_[index];
stream.stream_type_ = update_stream.type().Clone();
stream.output_ = update_stream.output();
}
void SourceImpl::OnStreamRemoved(size_t index) {
if (streams_.size() < index + 1) {
return;
}
Stream& stream = streams_[index];
stream.stream_type_ = nullptr;
stream.output_ = nullptr;
// Remove unused entries at the back of streams_.
while (!streams_.empty() && !streams_.back().stream_type_) {
streams_.pop_back();
}
}
void SourceImpl::SendStatusUpdates() { UpdateStatus(); }
void SourceImpl::Clear() {
source_segment_ = nullptr;
streams_.clear();
status_ = fuchsia::mediaplayer::SourceStatus();
}
void SourceImpl::Remove() {
if (connection_failure_callback_) {
connection_failure_callback_();
}
}
void SourceImpl::UpdateStatus() {
status_.has_audio = false;
status_.has_video = false;
for (auto& stream : streams_) {
if (stream.stream_type_) {
switch (stream.stream_type_->medium()) {
case StreamType::Medium::kAudio:
status_.has_audio = true;
break;
case StreamType::Medium::kVideo:
status_.has_video = true;
break;
case StreamType::Medium::kText:
case StreamType::Medium::kSubpicture:
FXL_NOTIMPLEMENTED();
break;
}
}
}
status_.duration_ns = source_segment_->duration_ns();
status_.can_pause = source_segment_->can_pause();
status_.can_seek = source_segment_->can_seek();
auto metadata = source_segment_->metadata();
status_.metadata =
metadata ? fidl::MakeOptional(
fxl::To<fuchsia::mediaplayer::Metadata>(*metadata))
: nullptr;
status_.problem = SafeClone(source_segment_->problem());
}
////////////////////////////////////////////////////////////////////////////////
// DemuxSourceImpl implementation.
// static
std::unique_ptr<DemuxSourceImpl> DemuxSourceImpl::Create(
std::shared_ptr<Demux> demux, Graph* graph,
fidl::InterfaceRequest<fuchsia::mediaplayer::Source> request,
fit::closure connection_failure_callback) {
FXL_DCHECK(demux);
FXL_DCHECK(graph);
return std::make_unique<DemuxSourceImpl>(
demux, graph, std::move(request), std::move(connection_failure_callback));
}
DemuxSourceImpl::DemuxSourceImpl(
std::shared_ptr<Demux> demux, Graph* graph,
fidl::InterfaceRequest<fuchsia::mediaplayer::Source> request,
fit::closure connection_failure_callback)
: SourceImpl(graph, std::move(connection_failure_callback)),
demux_(demux),
binding_(this),
demux_source_segment_(DemuxSourceSegment::Create(demux_)) {
FXL_DCHECK(demux_);
if (request) {
binding_.Bind(std::move(request));
binding_.set_error_handler([this]() { Remove(); });
}
SourceImpl::CompleteConstruction(demux_source_segment_.get());
}
DemuxSourceImpl::~DemuxSourceImpl() {}
std::unique_ptr<SourceSegment> DemuxSourceImpl::TakeSourceSegment() {
Clear();
return std::move(demux_source_segment_);
}
void DemuxSourceImpl::SendStatusUpdates() {
SourceImpl::SendStatusUpdates();
if (binding_.is_bound()) {
binding_.events().OnStatusChanged(fidl::Clone(status()));
}
}
} // namespace media_player