blob: 1648fb7785b1e3455e3f6d59ce43e4990efc8a0e [file] [log] [blame]
// Copyright 2024 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/services/device_registry/common_unittest.h"
#include <fidl/fuchsia.audio.device/cpp/fidl.h>
#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
#include <lib/syslog/cpp/macros.h>
#include <gtest/gtest.h>
#include "src/media/audio/services/device_registry/logging.h"
#include "src/media/audio/services/device_registry/validate.h"
namespace media_audio {
////////////////////////////////////////////////////////////////////////////////////////////////
// Helper functions that are useful for both low- (Device) and high-level (AdrServer) unittests.
//
///////////////////////////////
// Codec-related functions
//
// From a multi-element collection, each with many fuchsia_hardware_audio:DaiSupportedFormats,
// get a fuchsia_hardware_audio::DaiFormat.
fuchsia_hardware_audio::DaiFormat SafeDaiFormatFromElementDaiFormatSets(
ElementId element_id,
const std::vector<fuchsia_audio_device::ElementDaiFormatSet>& element_dai_format_sets) {
std::vector<fuchsia_hardware_audio::DaiSupportedFormats> dai_format_sets;
for (const auto& element_entry : element_dai_format_sets) {
if (element_entry.element_id() && *element_entry.element_id() == element_id) {
return SafeDaiFormatFromDaiFormatSets(*element_entry.format_sets());
}
}
ADD_FAILURE()
<< "SafeDaiFormatFromDaiFormatSets: No element_dai_format_sets entry found with specified element_id "
<< element_id;
return {{}};
}
// From a multi-element collection, each with many fuchsia_hardware_audio:DaiSupportedFormats,
// get a DIFFERENT fuchsia_hardware_audio::DaiFormat.
fuchsia_hardware_audio::DaiFormat SecondDaiFormatFromElementDaiFormatSets(
ElementId element_id,
const std::vector<fuchsia_audio_device::ElementDaiFormatSet>& element_dai_format_sets) {
std::vector<fuchsia_hardware_audio::DaiSupportedFormats> dai_format_sets;
for (const auto& element_entry : element_dai_format_sets) {
if (element_entry.element_id() && *element_entry.element_id() == element_id) {
return SecondDaiFormatFromDaiFormatSets(*element_entry.format_sets());
}
}
ADD_FAILURE() << "Could not create a second valid DaiFormat for specified element_id "
<< element_id;
return {{}};
}
// From a multi-element collection, each with many fuchsia_hardware_audio:DaiSupportedFormats,
// get a fuchsia_hardware_audio::DaiFormat that is UNSUPPORTED (but still a valid format).
fuchsia_hardware_audio::DaiFormat UnsupportedDaiFormatFromElementDaiFormatSets(
ElementId element_id,
const std::vector<fuchsia_audio_device::ElementDaiFormatSet>& element_dai_format_sets) {
std::vector<fuchsia_hardware_audio::DaiSupportedFormats> dai_format_sets;
for (const auto& element_entry : element_dai_format_sets) {
if (element_entry.element_id() && *element_entry.element_id() == element_id) {
return UnsupportedDaiFormatFromDaiFormatSets(*element_entry.format_sets());
}
}
ADD_FAILURE()
<< "UnsupportedDaiFormatFromDaiFormatSets could not find an invalid dai_format for element_id "
<< element_id;
return {{}};
}
// From many fuchsia_hardware_audio:DaiSupportedFormats,
// get a fuchsia_hardware_audio::DaiFormat.
fuchsia_hardware_audio::DaiFormat SafeDaiFormatFromDaiFormatSets(
const std::vector<fuchsia_hardware_audio::DaiSupportedFormats>& dai_format_sets) {
fuchsia_hardware_audio::DaiFormat dai_format{{
.number_of_channels = dai_format_sets[0].number_of_channels()[0],
.channels_to_use_bitmask = (dai_format_sets[0].number_of_channels()[0] < 64
? (1ull << dai_format_sets[0].number_of_channels()[0]) - 1ull
: 0xFFFFFFFFFFFFFFFFull),
.sample_format = dai_format_sets[0].sample_formats()[0],
.frame_format = dai_format_sets[0].frame_formats()[0],
.frame_rate = dai_format_sets[0].frame_rates()[0],
.bits_per_slot = dai_format_sets[0].bits_per_slot()[0],
.bits_per_sample = dai_format_sets[0].bits_per_sample()[0],
}};
if (!ValidateDaiFormat(dai_format)) {
ADD_FAILURE() << "first entries did not create a valid DaiFormat";
}
return dai_format;
}
// From many fuchsia_hardware_audio:DaiSupportedFormats,
// get a DIFFERENT fuchsia_hardware_audio::DaiFormat.
fuchsia_hardware_audio::DaiFormat SecondDaiFormatFromDaiFormatSets(
const std::vector<fuchsia_hardware_audio::DaiSupportedFormats>& dai_format_sets) {
auto safe_format_2 = SafeDaiFormatFromDaiFormatSets(dai_format_sets);
if (safe_format_2.channels_to_use_bitmask() > 1) {
safe_format_2.channels_to_use_bitmask() -= 1;
} else if (dai_format_sets[0].number_of_channels().size() > 1) {
safe_format_2.number_of_channels() = dai_format_sets[0].number_of_channels()[1];
} else if (dai_format_sets[0].sample_formats().size() > 1) {
safe_format_2.sample_format() = dai_format_sets[0].sample_formats()[1];
} else if (dai_format_sets[0].frame_formats().size() > 1) {
safe_format_2.frame_format() = dai_format_sets[0].frame_formats()[1];
} else if (dai_format_sets[0].frame_rates().size() > 1) {
safe_format_2.frame_rate() = dai_format_sets[0].frame_rates()[1];
} else if (dai_format_sets[0].bits_per_slot().size() > 1) {
safe_format_2.bits_per_slot() = dai_format_sets[0].bits_per_slot()[1];
} else if (dai_format_sets[0].bits_per_sample().size() > 1) {
safe_format_2.bits_per_sample() = dai_format_sets[0].bits_per_sample()[1];
} else if (dai_format_sets.size() > 1) {
return fuchsia_hardware_audio::DaiFormat{{
.number_of_channels = dai_format_sets[1].number_of_channels()[0],
.channels_to_use_bitmask =
(dai_format_sets[1].number_of_channels()[0] < 64
? (1ull << dai_format_sets[1].number_of_channels()[0]) - 1ull
: 0xFFFFFFFFFFFFFFFFull),
.sample_format = dai_format_sets[1].sample_formats()[0],
.frame_format = dai_format_sets[1].frame_formats()[0],
.frame_rate = dai_format_sets[1].frame_rates()[0],
.bits_per_slot = dai_format_sets[1].bits_per_slot()[0],
.bits_per_sample = dai_format_sets[1].bits_per_sample()[0],
}};
} else {
ADD_FAILURE() << "Dai format set has only one possible valid format";
return {{}};
}
if (!ValidateDaiFormat(safe_format_2)) {
ADD_FAILURE() << "Could not create a second valid DaiFormat";
}
return safe_format_2;
}
// From many fuchsia_hardware_audio:DaiSupportedFormats,
// get a fuchsia_hardware_audio::DaiFormat that is UNSUPPORTED (but still a valid format).
fuchsia_hardware_audio::DaiFormat UnsupportedDaiFormatFromDaiFormatSets(
const std::vector<fuchsia_hardware_audio::DaiSupportedFormats>& dai_format_sets) {
auto dai_format = SafeDaiFormatFromDaiFormatSets(dai_format_sets);
if (dai_format.number_of_channels() > 1) {
dai_format.number_of_channels() -= 1;
dai_format.channels_to_use_bitmask() = (1ull << dai_format.number_of_channels()) - 1ull;
} else if (dai_format.frame_rate() > kMinSupportedDaiFrameRate) {
dai_format.frame_rate() -= 1;
} else if (dai_format.bits_per_slot() > 1) {
dai_format.bits_per_slot() -= 1;
} else if (dai_format.bits_per_sample() > 1) {
dai_format.bits_per_sample() -= 1;
} else {
ADD_FAILURE() << "No unsupported DaiFormat found for these format_sets";
return {{}};
}
return dai_format;
}
///////////////////////////////
// RingBuffer-related functions
//
// From many fuchsia_audio_device::PcmFormatSet,
// get a fuchsia_audio::Format.
fuchsia_audio::Format SafeRingBufferFormatFromRingBufferFormatSets(
const std::vector<fuchsia_audio_device::PcmFormatSet>& ring_buffer_format_sets) {
return {{
.sample_type = ring_buffer_format_sets.front().sample_types()->front(),
.channel_count = ring_buffer_format_sets.front().channel_sets()->front().attributes()->size(),
.frames_per_second = ring_buffer_format_sets.front().frame_rates()->front(),
}};
}
// From many fuchsia_audio_device::PcmFormatSet,
// get a DIFFERENT fuchsia_audio::Format.
fuchsia_audio::Format SecondRingBufferFormatFromRingBufferFormatSets(
const std::vector<fuchsia_audio_device::PcmFormatSet>& ring_buffer_format_sets) {
auto safe_format = SafeRingBufferFormatFromRingBufferFormatSets(ring_buffer_format_sets);
auto& first_format_set = ring_buffer_format_sets.front();
if (first_format_set.channel_sets()->size() > 1) {
safe_format.channel_count() = first_format_set.channel_sets()->rbegin()->attributes()->size();
} else if (first_format_set.sample_types()->size() > 1) {
safe_format.sample_type() = *first_format_set.sample_types()->rbegin();
} else if (first_format_set.frame_rates()->size() > 1) {
safe_format.frames_per_second() = *first_format_set.frame_rates()->rbegin();
} else {
ADD_FAILURE() << "SecondRingBufferFormatFromRingBufferFormatSets: Only one format is possible";
return {};
}
return safe_format;
}
// From a multi-element collection, each with many fuchsia_audio_device::PcmFormatSet,
// get a fuchsia_audio::Format.
fuchsia_audio::Format SafeRingBufferFormatFromElementRingBufferFormatSets(
ElementId element_id, const std::vector<fuchsia_audio_device::ElementRingBufferFormatSet>&
element_ring_buffer_format_sets) {
std::vector<fuchsia_audio::Format> ring_buffer_format_sets;
for (const auto& element_entry : element_ring_buffer_format_sets) {
if (element_entry.element_id() && *element_entry.element_id() == element_id) {
return SafeRingBufferFormatFromRingBufferFormatSets(*element_entry.format_sets());
}
}
ADD_FAILURE()
<< "SafeRingBufferFormatFromElementRingBufferFormatSets: No element_ring_buffer_format_sets entry found with specified element_id "
<< element_id;
return {};
}
// From a multi-element collection, each with many fuchsia_audio_device::PcmFormatSet,
// get a DIFFERENT fuchsia_audio::Format.
fuchsia_audio::Format SecondRingBufferFormatFromElementRingBufferFormatSets(
ElementId element_id, const std::vector<fuchsia_audio_device::ElementRingBufferFormatSet>&
element_ring_buffer_format_sets) {
std::vector<fuchsia_audio::Format> ring_buffer_format_sets;
for (const auto& element_entry : element_ring_buffer_format_sets) {
if (element_entry.element_id() && *element_entry.element_id() == element_id) {
return SecondRingBufferFormatFromRingBufferFormatSets(*element_entry.format_sets());
}
}
ADD_FAILURE()
<< "SecondRingBufferFormatFromElementRingBufferFormatSets: No element_ring_buffer_format_sets entry found with specified element_id "
<< element_id;
return {};
}
// From many fuchsia_hardware_audio::SupportedFormats,
// get a fuchsia_hardware_audio::Format.
fuchsia_hardware_audio::Format SafeDriverRingBufferFormatFromDriverRingBufferFormatSets(
const std::vector<fuchsia_hardware_audio::SupportedFormats>& driver_ring_buffer_format_sets) {
auto first_format_set = *driver_ring_buffer_format_sets.front().pcm_supported_formats();
fuchsia_hardware_audio::Format ring_buffer_format{{
.pcm_format = fuchsia_hardware_audio::PcmFormat{{
.number_of_channels =
static_cast<uint8_t>(first_format_set.channel_sets()->front().attributes()->size()),
.sample_format = first_format_set.sample_formats()->front(),
.bytes_per_sample = first_format_set.bytes_per_sample()->front(),
.valid_bits_per_sample = first_format_set.valid_bits_per_sample()->front(),
.frame_rate = first_format_set.frame_rates()->front(),
}},
}};
if (!ValidateRingBufferFormat(ring_buffer_format)) {
ADD_FAILURE() << "first entries did not create a valid DaiFormat";
return {};
}
return ring_buffer_format;
}
// From many fuchsia_hardware_audio::SupportedFormats,
// get a DIFFERENT fuchsia_hardware_audio::Format.
fuchsia_hardware_audio::Format SecondDriverRingBufferFormatFromDriverRingBufferFormatSets(
const std::vector<fuchsia_hardware_audio::SupportedFormats>& driver_ring_buffer_format_sets) {
auto safe_format =
SafeDriverRingBufferFormatFromDriverRingBufferFormatSets(driver_ring_buffer_format_sets);
auto driver_rb_format_set = *driver_ring_buffer_format_sets.begin()->pcm_supported_formats();
if (safe_format.pcm_format().has_value()) {
if (driver_rb_format_set.channel_sets()->size() > 1) {
safe_format.pcm_format()->number_of_channels() =
static_cast<uint8_t>(driver_rb_format_set.channel_sets()->rbegin()->attributes()->size());
return safe_format;
}
if (driver_rb_format_set.sample_formats()->size() > 1) {
safe_format.pcm_format()->sample_format() = *driver_rb_format_set.sample_formats()->rbegin();
return safe_format;
}
if (driver_rb_format_set.bytes_per_sample()->size() > 1) {
safe_format.pcm_format()->bytes_per_sample() =
*driver_rb_format_set.bytes_per_sample()->rbegin();
return safe_format;
}
if (driver_rb_format_set.frame_rates()->size() > 1) {
safe_format.pcm_format()->frame_rate() = *driver_rb_format_set.frame_rates()->rbegin();
return safe_format;
}
}
ADD_FAILURE()
<< "SecondDriverRingBufferFormatFromDriverRingBufferFormatSets: Only one format is possible";
return {};
}
// From a multi-element collection, each with many fuchsia_hardware_audio::SupportedFormats,
// get a fuchsia_hardware_audio::Format.
fuchsia_hardware_audio::Format SafeDriverRingBufferFormatFromElementDriverRingBufferFormatSets(
ElementId element_id,
const std::vector<std::pair<ElementId, std::vector<fuchsia_hardware_audio::SupportedFormats>>>&
element_driver_ring_buffer_format_sets) {
for (const auto& element_entry : element_driver_ring_buffer_format_sets) {
if (element_entry.first == element_id) {
return SafeDriverRingBufferFormatFromDriverRingBufferFormatSets(element_entry.second);
}
}
ADD_FAILURE()
<< "SafeDriverRingBufferFormatFromElementDriverRingBufferFormatSets: No element_driver_ring_buffer_format_sets entry found with specified element_id "
<< element_id;
return {};
}
// From a multi-element collection, each with many fuchsia_hardware_audio::SupportedFormats,
// get ANOTHER fuchsia_hardware_audio::Format.
fuchsia_hardware_audio::Format SecondDriverRingBufferFormatFromElementDriverRingBufferFormatSets(
ElementId element_id,
const std::vector<std::pair<ElementId, std::vector<fuchsia_hardware_audio::SupportedFormats>>>&
element_driver_ring_buffer_format_sets) {
for (const auto& element_entry : element_driver_ring_buffer_format_sets) {
if (element_entry.first == element_id) {
return SecondDriverRingBufferFormatFromDriverRingBufferFormatSets(element_entry.second);
}
}
ADD_FAILURE()
<< "SecondDriverRingBufferFormatFromElementDriverRingBufferFormatSets: No element_driver_ring_buffer_format_sets entry found with specified element_id "
<< element_id;
return {};
}
} // namespace media_audio