blob: 0bb2570b362d2d709c847d833266b9d080ec0281 [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.
#ifndef SRC_MEDIA_AUDIO_DRIVERS_TESTS_ADMIN_TEST_H_
#define SRC_MEDIA_AUDIO_DRIVERS_TESTS_ADMIN_TEST_H_
#include <fuchsia/hardware/audio/cpp/fidl.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/time.h>
#include <zircon/device/audio.h>
#include <zircon/errors.h>
#include <zircon/rights.h>
#include <optional>
#include "src/media/audio/drivers/tests/test_base.h"
namespace media::audio::drivers::test {
// BasicTest cases must run in environments where an audio driver may already have an active client.
// AdminTest cases, by contrast, need not worry about interfering with any other client. AdminTest
// cases, by definition, can reconfigure devices without worrying about restoring previous state.
//
// A driver can have only one RingBuffer client connection at any time, so BasicTest avoids any
// usage of the RingBuffer interface. AdminTest includes (but is not limited to) RingBuffer tests.
// AdminTest cases may also change signalprocessing topology/elements or other device state.
class AdminTest : public TestBase {
public:
explicit AdminTest(const DeviceEntry& dev_entry) : TestBase(dev_entry) {}
protected:
static constexpr zx_rights_t kRightsVmoIncoming =
ZX_RIGHT_READ | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER;
static constexpr zx_rights_t kRightsVmoOutgoing = kRightsVmoIncoming | ZX_RIGHT_WRITE;
void TearDown() override;
void DropSignalProcessing();
void DropRingBuffer();
void ResetAndExpectResponse();
void RequestCodecStartAndExpectResponse();
void RequestCodecStopAndExpectResponse();
void RequestRingBufferChannelWithMinFormat();
void RequestRingBufferChannelWithMaxFormat();
void CalculateRingBufferFrameSize();
void RequestRingBufferProperties();
void RequestBuffer(uint32_t min_ring_buffer_frames, uint32_t notifications_per_ring);
enum SetActiveChannelsOutcome : uint8_t {
SUCCESS = 1, // Successful call.
CHANGE, // Successful call. As intended, the active-channels state was changed.
NO_CHANGE, // Successful call. As intended, the active-channels state was NOT changed.
FAILURE, // Unsuccessful.
};
void ActivateChannelsAndExpectOutcome(uint64_t active_channels_bitmask,
SetActiveChannelsOutcome expected_outcome);
void RetrieveRingBufferFormats() override;
void RetrieveDaiFormats() override;
zx::time RequestRingBufferStart();
void RequestRingBufferStartAndExpectCallback();
void RequestRingBufferStartAndExpectDisconnect(zx_status_t expected_error);
void WaitUntilAfterStartTime();
void RequestRingBufferStopAndExpectCallback();
void RequestRingBufferStopAndExpectNoPositionNotifications();
void RequestRingBufferStopAndExpectDisconnect(zx_status_t expected_error);
void RequestPositionNotification();
virtual void PositionNotificationCallback(
fuchsia::hardware::audio::RingBufferPositionInfo position_info);
// Clear flag so position notifications (even already-enqueued ones) do not cause failures.
void ExpectPositionNotifications() { fail_on_position_notification_ = false; }
// Set flag so position notifications (even already-enqueued ones!) cause failures.
void ExpectNoPositionNotifications() { fail_on_position_notification_ = true; }
void WatchDelayAndExpectUpdate();
void WatchDelayAndExpectNoUpdate();
void ValidateInternalDelay();
void ValidateExternalDelay();
void SignalProcessingConnect();
void RequestElements();
void ValidateElements();
void ValidateDaiElements();
void ValidateDynamicsElements();
void ValidateEqualizerElements();
void ValidateGainElements();
void ValidateVendorSpecificElements();
void RequestTopologies();
void RetrieveInitialTopology();
void ValidateElementTopologyClosure();
void WatchForTopology(fuchsia::hardware::audio::signalprocessing::TopologyId id);
void FailOnWatchTopologyCompletion();
void WatchTopologyAndExpectDisconnect(zx_status_t expected_error);
void SetAllTopologies();
void SetTopologyAndExpectCallback(fuchsia::hardware::audio::signalprocessing::TopologyId id);
void SetTopologyUnknownIdAndExpectError();
void SetTopologyNoChangeAndExpectNoWatch();
void RetrieveInitialElementStates();
void ValidateElementStates();
void ValidateDaiElementStates();
void ValidateDynamicsElementStates();
void ValidateEqualizerElementStates();
void ValidateGainElementStates();
void ValidateVendorSpecificElementStates();
void SetAllElementStates();
void SetAllDynamicsElementStates();
void SetAllEqualizerElementStates();
void SetAllGainElementStates();
void SetAllGainElementStatesNoChange();
void SetAllGainElementStatesInvalidGainShouldError();
void SetAllElementStatesNoChange();
void SetElementStateUnknownIdAndExpectError();
void SetElementStateNoChange(fuchsia::hardware::audio::signalprocessing::ElementId id);
void FailOnWatchElementStateCompletion(fuchsia::hardware::audio::signalprocessing::ElementId id);
void WatchElementStateAndExpectDisconnect(
fuchsia::hardware::audio::signalprocessing::ElementId id, zx_status_t expected_error);
void WatchElementStateUnknownIdAndExpectDisconnect(zx_status_t expected_error);
fidl::InterfacePtr<fuchsia::hardware::audio::RingBuffer>& ring_buffer() { return ring_buffer_; }
uint32_t ring_buffer_frames() const { return ring_buffer_frames_; }
fuchsia::hardware::audio::PcmFormat ring_buffer_pcm_format() const {
return ring_buffer_pcm_format_;
}
void SetRingBufferIncoming(std::optional<bool> is_incoming) {
ring_buffer_is_incoming_ = is_incoming;
}
bool ElementIsRingBuffer(fuchsia::hardware::audio::ElementId element_id);
bool RingBufferElementIsIncoming(fuchsia::hardware::audio::ElementId element_id);
std::optional<bool> ElementIsIncoming(
std::optional<fuchsia::hardware::audio::ElementId> ring_buffer_element_id);
uint32_t notifications_per_ring() const { return notifications_per_ring_; }
const zx::time& start_time() const { return start_time_; }
uint16_t frame_size() const { return frame_size_; }
std::optional<uint64_t>& ring_buffer_id() { return ring_buffer_id_; }
fidl::InterfacePtr<fuchsia::hardware::audio::signalprocessing::SignalProcessing>&
signal_processing() {
return sp_;
}
const std::vector<fuchsia::hardware::audio::signalprocessing::Topology>& topologies() const {
return topologies_;
}
const std::vector<fuchsia::hardware::audio::signalprocessing::Element>& elements() const {
return elements_;
}
private:
void RequestRingBufferChannel();
static void ValidateElement(const fuchsia::hardware::audio::signalprocessing::Element& element);
static void ValidateDaiElement(
const fuchsia::hardware::audio::signalprocessing::Element& element);
static void ValidateDynamicsElement(
const fuchsia::hardware::audio::signalprocessing::Element& element);
static void ValidateEqualizerElement(
const fuchsia::hardware::audio::signalprocessing::Element& element);
static void ValidateGainElement(
const fuchsia::hardware::audio::signalprocessing::Element& element);
static void ValidateVendorSpecificElement(
const fuchsia::hardware::audio::signalprocessing::Element& element);
static void ValidateElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& state);
static void ValidateDaiElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& state);
static void ValidateDynamicsElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& state);
static void ValidateEqualizerElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& state);
static void ValidateGainElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& state);
static void ValidateVendorSpecificElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& state);
void TestSetElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& initial_state);
void TestSetDynamicsElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& initial_state);
void TestSetEqualizerElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& initial_state);
void TestSetGainElementState(
const fuchsia::hardware::audio::signalprocessing::Element& element,
const fuchsia::hardware::audio::signalprocessing::ElementState& initial_state);
void TestSetGainElementStateNoChange(
fuchsia::hardware::audio::signalprocessing::ElementId element_id, float current_gain);
void TestSetGainElementStateInvalidGain(
fuchsia::hardware::audio::signalprocessing::ElementId element_id);
fidl::InterfacePtr<fuchsia::hardware::audio::RingBuffer> ring_buffer_;
std::optional<bool> ring_buffer_is_incoming_ = std::nullopt;
std::optional<fuchsia::hardware::audio::RingBufferProperties> ring_buffer_props_;
std::optional<fuchsia::hardware::audio::DelayInfo> delay_info_;
uint32_t min_ring_buffer_frames_ = 0;
uint32_t notifications_per_ring_ = 0;
uint32_t ring_buffer_frames_ = 0;
fzl::VmoMapper ring_buffer_mapper_;
zx::time start_time_;
// Ring buffer PCM format.
fuchsia::hardware::audio::PcmFormat ring_buffer_pcm_format_;
// DAI interconnect format.
fuchsia::hardware::audio::DaiFormat dai_format_;
uint16_t frame_size_ = 0;
// Position notifications are hanging-gets. On receipt, should we register the next one or fail?
bool fail_on_position_notification_ = false;
fidl::InterfacePtr<fuchsia::hardware::audio::signalprocessing::SignalProcessing> sp_;
std::optional<bool> signalprocessing_is_supported_ = std::nullopt;
std::vector<fuchsia::hardware::audio::signalprocessing::Topology> topologies_;
std::vector<fuchsia::hardware::audio::signalprocessing::Element> elements_;
std::optional<fuchsia::hardware::audio::signalprocessing::TopologyId> initial_topology_id_ =
std::nullopt;
std::optional<fuchsia::hardware::audio::signalprocessing::TopologyId> pending_set_topology_id_;
std::optional<fuchsia::hardware::audio::signalprocessing::TopologyId> current_topology_id_ =
std::nullopt;
std::map<fuchsia::hardware::audio::signalprocessing::TopologyId,
fuchsia::hardware::audio::signalprocessing::ElementState>
initial_element_states_;
std::optional<uint64_t> ring_buffer_id_; // Ring buffer process element id.
std::optional<uint64_t> dai_id_; // DAI interconnect process element id.
};
} // namespace media::audio::drivers::test
#endif // SRC_MEDIA_AUDIO_DRIVERS_TESTS_ADMIN_TEST_H_