blob: 522958e5a9ece3f1de95fd5d074ac3c491124e12 [file]
// 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.
#ifndef SRC_MEDIA_AUDIO_LIB_TEST_VIRTUAL_DEVICE_H_
#define SRC_MEDIA_AUDIO_LIB_TEST_VIRTUAL_DEVICE_H_
#include <fuchsia/media/cpp/fidl.h>
#include <fuchsia/virtualaudio/cpp/fidl.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <zircon/device/audio.h>
#include <memory>
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
#include "src/media/audio/lib/format/audio_buffer.h"
#include "src/media/audio/lib/test/hermetic_audio_environment.h"
#include "src/media/audio/lib/test/inspect.h"
#include "src/media/audio/lib/test/test_fixture.h"
#include "src/media/audio/lib/test/vmo_backed_buffer.h"
namespace media::audio::test {
namespace internal {
// These IDs are scoped to the lifetime of this process.
extern size_t virtual_output_next_inspect_id;
extern size_t virtual_input_next_inspect_id;
} // namespace internal
// This class is thread hostile: none of its methods can be called concurrently.
template <class Interface>
class VirtualDevice {
public:
static constexpr uint32_t kNotifyMs = 10;
static constexpr uint32_t kFifoDepthBytes = 0;
static constexpr auto kExternalDelay = zx::msec(0);
~VirtualDevice();
fidl::InterfacePtr<Interface>& virtual_device() { return device_; }
size_t frame_count() const { return frame_count_; }
// Reports whether the device has started.
bool Ready() const { return received_start_; }
// Returns a timestamp in the future that corresponds to byte 0 of the ring buffer.
// This is a reference time that can be passed to AudioRenderer::Play().
// The fixture is used to loop through time to locate the boundaries of the ring buffer.
int64_t NextSynchronizedTimestamp(TestFixture* fixture) const;
// For validating properties exported by inspect.
// By default, there are no expectations.
size_t inspect_id() const { return inspect_id_; }
ExpectedInspectProperties& expected_inspect_properties() { return expected_inspect_properties_; }
protected:
VirtualDevice(TestFixture* fixture, HermeticAudioEnvironment* environment,
const audio_stream_unique_id_t& device_id, Format format, size_t frame_count,
size_t inspect_id);
void ResetEvents();
void WatchEvents();
const Format format_;
const size_t frame_count_;
const size_t inspect_id_;
fidl::InterfacePtr<Interface> device_;
audio_sample_format_t driver_format_;
zx::vmo rb_vmo_;
VmoBackedBuffer rb_;
bool received_set_format_ = false;
bool received_start_ = false;
bool received_stop_ = false;
zx_time_t start_time_ = 0;
zx_time_t stop_time_ = 0;
uint64_t stop_pos_ = 0;
uint64_t ring_pos_ = 0;
uint64_t running_ring_pos_ = 0;
ExpectedInspectProperties expected_inspect_properties_;
};
template <fuchsia::media::AudioSampleFormat SampleFormat>
class VirtualOutput : public VirtualDevice<fuchsia::virtualaudio::Output> {
public:
using SampleT = typename AudioBuffer<SampleFormat>::SampleT;
// Take a snapshot of the device's ring buffer.
AudioBuffer<SampleFormat> SnapshotRingBuffer() { return rb_.Snapshot<SampleFormat>(); }
// Don't call this directly. Use HermeticAudioTest::CreateOutput so the object is
// appropriately bound into the test environment.
VirtualOutput(TestFixture* fixture, HermeticAudioEnvironment* environment,
const audio_stream_unique_id_t& device_id, Format format, size_t frame_count)
: VirtualDevice(fixture, environment, device_id, format, frame_count,
internal::virtual_output_next_inspect_id++) {}
};
template <fuchsia::media::AudioSampleFormat SampleFormat>
class VirtualInput : public VirtualDevice<fuchsia::virtualaudio::Input> {
public:
using SampleT = typename AudioBuffer<SampleFormat>::SampleT;
// Write a slice to the ring buffer at the given position.
void WriteRingBufferAt(size_t ring_pos_in_frames, AudioBufferSlice<SampleFormat> slice) {
rb_.WriteAt<SampleFormat>(ring_pos_in_frames, slice);
}
// Don't call this directly. Use HermeticAudioTest::CreateInput so the object is
// appropriately bound into the test environment.
VirtualInput(TestFixture* fixture, HermeticAudioEnvironment* environment,
const audio_stream_unique_id_t& device_id, Format format, size_t frame_count)
: VirtualDevice(fixture, environment, device_id, format, frame_count,
internal::virtual_input_next_inspect_id++) {}
};
} // namespace media::audio::test
#endif // SRC_MEDIA_AUDIO_LIB_TEST_VIRTUAL_DEVICE_H_