blob: 90b6857e2e1e274474347e64eb5b69e7c7d249cf [file] [log] [blame]
// Copyright 2016 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 "src/media/playback/mediaplayer/test/fakes/fake_audio_renderer.h"
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/zx/clock.h>
#include <iomanip>
#include <iostream>
#include <limits>
namespace media_player {
namespace test {
FakeAudioRenderer::FakeAudioRenderer()
: dispatcher_(async_get_default_dispatcher()), binding_(this) {}
FakeAudioRenderer::~FakeAudioRenderer() {}
void FakeAudioRenderer::Bind(fidl::InterfaceRequest<fuchsia::media::AudioRenderer> request) {
binding_.Bind(std::move(request));
}
void FakeAudioRenderer::SetPcmStreamType(fuchsia::media::AudioStreamType format) {
format_ = format;
}
void FakeAudioRenderer::AddPayloadBuffer(uint32_t id, zx::vmo payload_buffer) {
FX_DCHECK(id == 0) << "Only ID 0 is currently supported.";
vmo_mapper_.Map(std::move(payload_buffer), 0, 0, ZX_VM_PERM_READ);
}
void FakeAudioRenderer::RemovePayloadBuffer(uint32_t id) { FX_NOTIMPLEMENTED(); }
void FakeAudioRenderer::SetPtsUnits(uint32_t tick_per_second_numerator,
uint32_t tick_per_second_denominator) {
pts_rate_ = media::TimelineRate(tick_per_second_numerator, tick_per_second_denominator);
}
void FakeAudioRenderer::SetPtsContinuityThreshold(float threshold_seconds) {
threshold_seconds_ = threshold_seconds;
}
void FakeAudioRenderer::SetReferenceClock(zx::clock ref_clock) { FX_NOTIMPLEMENTED(); }
void FakeAudioRenderer::GetReferenceClock(GetReferenceClockCallback callback) {
callback(zx::clock(ZX_HANDLE_INVALID));
FX_NOTIMPLEMENTED();
}
void FakeAudioRenderer::SendPacket(fuchsia::media::StreamPacket packet,
SendPacketCallback callback) {
packets_received_++;
if (dump_packets_) {
std::cerr << "{ " << packet.pts << ", " << packet.payload_size << ", 0x" << std::hex
<< std::setw(16) << std::setfill('0')
<< PacketInfo::Hash(
reinterpret_cast<uint8_t*>(vmo_mapper_.start()) + packet.payload_offset,
packet.payload_size)
<< std::dec << " },\n";
}
if (!packet_expecters_.empty()) {
bool expecter_ok = false;
for (auto& expecter : packet_expecters_) {
if (expecter.IsExpected(packet, vmo_mapper_.start())) {
expecter_ok = true;
}
}
if (!expecter_ok) {
FX_LOGS(ERROR) << "supplied packet doesn't match expected packet info";
expected_ = false;
}
}
packet_queue_.push(std::make_pair(packet, std::move(callback)));
if (packet_queue_.size() == 1) {
MaybeScheduleRetirement();
}
}
void FakeAudioRenderer::SendPacketNoReply(fuchsia::media::StreamPacket packet) {
SendPacket(std::move(packet), []() {});
}
void FakeAudioRenderer::EndOfStream() { FX_NOTIMPLEMENTED(); }
void FakeAudioRenderer::DiscardAllPackets(DiscardAllPacketsCallback callback) {
while (!packet_queue_.empty()) {
packet_queue_.front().second();
packet_queue_.pop();
}
callback();
}
void FakeAudioRenderer::DiscardAllPacketsNoReply() {
DiscardAllPackets([]() {});
}
void FakeAudioRenderer::Play(int64_t reference_time, int64_t media_time, PlayCallback callback) {
if (vmo_mapper_.start() == nullptr) {
FX_LOGS(ERROR) << "Play called with no buffer added";
expected_ = false;
binding_.Unbind();
return;
}
if (reference_time == fuchsia::media::NO_TIMESTAMP) {
reference_time = zx::clock::get_monotonic().get();
}
if (media_time == fuchsia::media::NO_TIMESTAMP) {
if (restart_media_time_ != fuchsia::media::NO_TIMESTAMP) {
media_time = restart_media_time_;
} else if (packet_queue_.empty()) {
media_time = 0;
} else {
media_time = packet_queue_.front().first.pts;
}
}
callback(reference_time, media_time);
timeline_function_ = media::TimelineFunction(media_time, reference_time,
pts_rate_ / media::TimelineRate::NsPerSecond);
MaybeScheduleRetirement();
}
void FakeAudioRenderer::PlayNoReply(int64_t reference_time, int64_t media_time) {
Play(reference_time, media_time, [](int64_t reference_time, int64_t media_time) {});
}
void FakeAudioRenderer::Pause(PauseCallback callback) {
if (vmo_mapper_.start() == nullptr) {
FX_LOGS(ERROR) << "Pause called with no buffer added";
expected_ = false;
binding_.Unbind();
return;
}
int64_t reference_time = zx::clock::get_monotonic().get();
int64_t media_time = timeline_function_(reference_time);
timeline_function_ = media::TimelineFunction(media_time, reference_time, 0, 1);
callback(reference_time, media_time);
}
void FakeAudioRenderer::PauseNoReply() {
Pause([](int64_t reference_time, int64_t media_time) {});
}
void FakeAudioRenderer::BindGainControl(
fidl::InterfaceRequest<fuchsia::media::audio::GainControl> request) {
FX_NOTIMPLEMENTED();
}
void FakeAudioRenderer::EnableMinLeadTimeEvents(bool enabled) {
if (enabled) {
binding_.events().OnMinLeadTimeChanged(min_lead_time_ns_);
}
}
void FakeAudioRenderer::GetMinLeadTime(GetMinLeadTimeCallback callback) {
callback(min_lead_time_ns_);
}
void FakeAudioRenderer::SetGain(float gain_db) { gain_ = gain_db; }
void FakeAudioRenderer::SetMute(bool muted) { mute_ = muted; }
void FakeAudioRenderer::MaybeScheduleRetirement() {
if (retain_packets_ || !progressing() || packet_queue_.empty()) {
return;
}
int64_t packet_pts = packet_queue_.front().first.pts;
int64_t reference_time = timeline_function_.ApplyInverse(packet_pts);
if (packet_pts == delay_packet_retirement_pts_) {
reference_time += ZX_SEC(1);
}
async::PostTaskForTime(
dispatcher_,
[this]() {
if (!progressing() || packet_queue_.empty()) {
return;
}
int64_t reference_time = timeline_function_.ApplyInverse(packet_queue_.front().first.pts);
if (reference_time <= zx::clock::get_monotonic().get()) {
packet_queue_.front().second();
packet_queue_.pop();
}
MaybeScheduleRetirement();
},
zx::time(reference_time));
}
FakeAudioRenderer::PacketExpecter::PacketExpecter(const std::vector<PacketInfo>&& info)
: info_(std::move(info)), iter_(info_.begin()) {}
bool FakeAudioRenderer::PacketExpecter::IsExpected(const fuchsia::media::StreamPacket& packet,
const void* start) {
if (iter_ == info_.end()) {
return false;
}
if (iter_->pts() != packet.pts || iter_->size() != packet.payload_size ||
iter_->hash() !=
PacketInfo::Hash(reinterpret_cast<const uint8_t*>(start) + packet.payload_offset,
packet.payload_size)) {
}
++iter_;
return true;
}
} // namespace test
} // namespace media_player