blob: aaf5b9ee4c45c73014ec138b3c79b17e9716834e [file] [log] [blame]
// Copyright 2020 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/audio/lib/test/renderer_shim.h"
#include <algorithm>
#include "src/media/audio/lib/logging/logging.h"
namespace media::audio::test {
namespace internal {
size_t renderer_shim_next_inspect_id = 1; // ids start at 1
} // namespace internal
RendererShimImpl::~RendererShimImpl() { ResetEvents(); }
void RendererShimImpl::ResetEvents() {
renderer_->EnableMinLeadTimeEvents(false);
renderer_.events().OnMinLeadTimeChanged = nullptr;
}
void RendererShimImpl::WatchEvents() {
renderer_->EnableMinLeadTimeEvents(true);
renderer_.events().OnMinLeadTimeChanged = [this](int64_t min_lead_time_nsec) {
received_min_lead_time_ = true;
AUDIO_LOG(DEBUG) << "OnMinLeadTimeChanged: " << min_lead_time_nsec;
min_lead_time_ = min_lead_time_nsec;
};
}
void RendererShimImpl::SetPtsUnits(uint32_t ticks_per_second_numerator,
uint32_t ticks_per_second_denominator) {
renderer_->SetPtsUnits(ticks_per_second_numerator, ticks_per_second_denominator);
pts_ticks_per_second_ = TimelineRate(ticks_per_second_numerator, ticks_per_second_denominator);
pts_ticks_per_frame_ =
TimelineRate::Product(pts_ticks_per_second_, TimelineRate(1, format_.frames_per_second()));
}
void RendererShimImpl::Play(TestFixture* fixture, int64_t reference_time, int64_t media_time) {
renderer_->Play(reference_time, media_time, fixture->AddCallback("Play"));
fixture->ExpectCallback();
}
template <fuchsia::media::AudioSampleFormat SampleFormat>
RendererShimImpl::PacketVector RendererShimImpl::AppendPackets(
const std::vector<AudioBufferSlice<SampleFormat>>& slices, int64_t initial_pts) {
// Where in the payload to write the next packet.
size_t payload_offset = payload_buffer_.GetCurrentOffset();
// Where in the media timeline to write the next packet.
int64_t pts = initial_pts;
PacketVector out;
for (auto& slice : slices) {
payload_buffer_.Append(slice);
for (size_t frame = 0; frame < slice.NumFrames(); frame += num_packet_frames()) {
// Every packet is kPacketMs long, except the last packet might be shorter.
size_t num_frames = std::min(num_packet_frames(), slice.NumFrames() - frame);
auto packet = std::make_shared<Packet>();
packet->start_pts = pts;
packet->end_pts = initial_pts + pts_ticks_per_frame_.Scale(frame + num_frames);
out.push_back(packet);
fuchsia::media::StreamPacket stream_packet{
.pts = pts,
.payload_offset = payload_offset,
.payload_size = num_frames * slice.format().bytes_per_frame(),
};
AUDIO_LOG(TRACE) << " sending pkt at pts " << packet->start_pts << ", frame " << frame
<< " of slice";
renderer_->SendPacket(stream_packet, [packet]() {
AUDIO_LOG(TRACE) << " return pkt at pts " << packet->start_pts;
packet->returned = true;
});
pts = packet->end_pts;
payload_offset += stream_packet.payload_size;
}
}
return out;
}
void RendererShimImpl::WaitForPackets(TestFixture* fixture, int64_t reference_time,
const std::vector<std::shared_ptr<Packet>>& packets,
size_t ring_out_frames) {
FX_CHECK(!packets.empty());
int64_t start_pts = (*packets.begin())->start_pts;
int64_t end_pts = (*packets.rbegin())->end_pts + pts_ticks_per_frame_.Scale(ring_out_frames);
TimelineRate ns_per_tick =
TimelineRate::Product(pts_ticks_per_second_.Inverse(), TimelineRate(1'000'000'000, 1));
auto end_time = zx::time(reference_time) + zx::nsec(ns_per_tick.Scale(end_pts - start_pts));
auto timeout = end_time - zx::clock::get_monotonic();
// Wait until all packets are rendered AND the timeout is reached.
// It's not sufficient to wait for just the packets, because that may not include ring_out_frames.
// It's not sufficient to just wait for the timeout, because the SendPacket callbacks may not have
// executed yet.
fixture->RunLoopWithTimeout(timeout);
fixture->RunLoopUntil([packets]() {
for (auto& p : packets) {
if (!p->returned) {
return false;
}
}
return true;
});
fixture->ExpectNoUnexpectedErrors("during WaitForPackets");
}
// Explicitly instantiate all possible implementations.
#define INSTANTIATE(T) \
template RendererShimImpl::PacketVector RendererShimImpl::AppendPackets<T>( \
const std::vector<AudioBufferSlice<T>>&, int64_t);
INSTANTIATE_FOR_ALL_FORMATS(INSTANTIATE)
} // namespace media::audio::test