blob: 870f4d74f49aa15df1c364c73e810e387e54c804 [file] [log] [blame]
// Copyright 2019 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/audio_core/shared/select_best_format.h"
#include <zircon/errors.h>
#include <cstdint>
#include <unordered_map>
#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
namespace media::audio {
namespace {
void AddChannelSet(fuchsia::hardware::audio::PcmSupportedFormats& formats,
size_t number_of_channels) {
fuchsia::hardware::audio::ChannelSet channel_set = {};
std::vector<fuchsia::hardware::audio::ChannelAttributes> attributes(number_of_channels);
channel_set.set_attributes(std::move(attributes));
formats.mutable_channel_sets()->push_back(std::move(channel_set));
}
void AddChannelSet(fuchsia_audio_device::PcmFormatSet& formats, size_t number_of_channels) {
fuchsia_audio_device::ChannelSet channel_set;
channel_set.attributes(std::vector<fuchsia_audio_device::ChannelAttributes>(number_of_channels));
if (!formats.channel_sets()) {
formats.channel_sets({{}});
}
formats.channel_sets()->push_back(std::move(channel_set));
}
TEST(SelectBestFormatTest, SelectBestFormatFound) {
std::vector<fuchsia::hardware::audio::PcmSupportedFormats> fmts;
fuchsia::hardware::audio::PcmSupportedFormats formats = {};
AddChannelSet(formats, 1);
AddChannelSet(formats, 2);
AddChannelSet(formats, 4);
AddChannelSet(formats, 8);
formats.mutable_sample_formats()->push_back(fuchsia::hardware::audio::SampleFormat::PCM_FLOAT);
formats.mutable_bytes_per_sample()->push_back(4);
formats.mutable_valid_bits_per_sample()->push_back(32);
formats.mutable_frame_rates()->push_back(12'000);
formats.mutable_frame_rates()->push_back(24'000);
formats.mutable_frame_rates()->push_back(48'000);
formats.mutable_frame_rates()->push_back(96'000);
fmts.push_back(std::move(formats));
fuchsia::media::AudioSampleFormat sample_format_inout = fuchsia::media::AudioSampleFormat::FLOAT;
uint32_t frames_per_second_inout = 96'000;
uint32_t channels_inout = 1;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_OK);
ASSERT_EQ(sample_format_inout, fuchsia::media::AudioSampleFormat::FLOAT);
ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(96'000));
ASSERT_EQ(channels_inout, static_cast<uint32_t>(1));
// Add a second format range.
fuchsia::hardware::audio::PcmSupportedFormats formats2 = {};
AddChannelSet(formats2, 4);
AddChannelSet(formats2, 5);
AddChannelSet(formats2, 6);
AddChannelSet(formats2, 7);
AddChannelSet(formats2, 8);
formats2.mutable_sample_formats()->push_back(fuchsia::hardware::audio::SampleFormat::PCM_SIGNED);
formats2.mutable_bytes_per_sample()->push_back(2);
formats2.mutable_valid_bits_per_sample()->push_back(16);
formats2.mutable_frame_rates()->push_back(22'050);
formats2.mutable_frame_rates()->push_back(44'100);
formats2.mutable_frame_rates()->push_back(88'200);
formats2.mutable_frame_rates()->push_back(176'400);
fmts.push_back(std::move(formats2));
sample_format_inout = fuchsia::media::AudioSampleFormat::SIGNED_16;
frames_per_second_inout = 88'200;
channels_inout = 5;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_OK);
ASSERT_EQ(sample_format_inout, fuchsia::media::AudioSampleFormat::SIGNED_16);
ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(88'200));
ASSERT_EQ(channels_inout, static_cast<uint32_t>(5));
}
TEST(SelectBestFormatTest, SelectBestFormatFoundNewFidl) {
std::vector<fuchsia_audio_device::PcmFormatSet> fmts;
fuchsia_audio_device::PcmFormatSet formats;
AddChannelSet(formats, 1);
AddChannelSet(formats, 2);
AddChannelSet(formats, 4);
AddChannelSet(formats, 8);
formats.sample_types({{fuchsia_audio::SampleType::kFloat32}});
formats.frame_rates({{12'000, 24'000, 48'000, 96'000}});
fmts.push_back(std::move(formats));
auto pref = media_audio::Format::CreateOrDie({
.sample_type = fuchsia_audio::SampleType::kFloat32,
.channels = 1,
.frames_per_second = 96'000,
});
auto result = SelectBestFormat(fmts, pref);
ASSERT_TRUE(result.is_ok());
EXPECT_EQ(result->sample_type(), fuchsia_audio::SampleType::kFloat32);
EXPECT_EQ(result->frames_per_second(), 96'000);
EXPECT_EQ(result->channels(), 1);
// Add a second format range.
fuchsia_audio_device::PcmFormatSet formats2;
AddChannelSet(formats2, 4);
AddChannelSet(formats2, 5);
AddChannelSet(formats2, 6);
AddChannelSet(formats2, 7);
AddChannelSet(formats2, 8);
formats2.sample_types({{fuchsia_audio::SampleType::kInt16}});
formats2.frame_rates({{22'050, 44'100, 88'200, 176'400}});
fmts.push_back(std::move(formats2));
pref = media_audio::Format::CreateOrDie({
.sample_type = fuchsia_audio::SampleType::kInt16,
.channels = 5,
.frames_per_second = 88'200,
});
result = SelectBestFormat(fmts, pref);
ASSERT_TRUE(result.is_ok());
EXPECT_EQ(result->sample_type(), fuchsia_audio::SampleType::kInt16);
EXPECT_EQ(result->frames_per_second(), 88'200);
EXPECT_EQ(result->channels(), 5);
}
TEST(SelectBestFormatTest, SelectBestFormatOutsideRanges) {
std::vector<fuchsia::hardware::audio::PcmSupportedFormats> fmts;
fuchsia::hardware::audio::PcmSupportedFormats formats = {};
AddChannelSet(formats, 1);
AddChannelSet(formats, 2);
AddChannelSet(formats, 4);
AddChannelSet(formats, 8);
formats.mutable_sample_formats()->push_back(fuchsia::hardware::audio::SampleFormat::PCM_SIGNED);
formats.mutable_bytes_per_sample()->push_back(2);
formats.mutable_valid_bits_per_sample()->push_back(16);
formats.mutable_frame_rates()->push_back(16'000);
formats.mutable_frame_rates()->push_back(24'000);
formats.mutable_frame_rates()->push_back(48'000);
formats.mutable_frame_rates()->push_back(96'000);
fmts.push_back(std::move(formats));
fuchsia::media::AudioSampleFormat sample_format_inout =
fuchsia::media::AudioSampleFormat::SIGNED_16;
uint32_t frames_per_second_inout = 0;
uint32_t channels_inout = 0;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_OK);
ASSERT_EQ(sample_format_inout, fuchsia::media::AudioSampleFormat::SIGNED_16);
ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(16'000)); // Prefer closest available.
ASSERT_EQ(channels_inout, static_cast<uint32_t>(2)); // Prefer 2 channels.
sample_format_inout = fuchsia::media::AudioSampleFormat::UNSIGNED_8;
frames_per_second_inout = 192'000;
channels_inout = 200;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_OK);
ASSERT_EQ(sample_format_inout, fuchsia::media::AudioSampleFormat::SIGNED_16);
ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(96'000)); // Pick closest available.
ASSERT_EQ(channels_inout, static_cast<uint32_t>(2)); // Prefer 2 channels.
// Add a second format range.
fuchsia::hardware::audio::PcmSupportedFormats formats2 = {};
AddChannelSet(formats2, 4);
AddChannelSet(formats2, 5);
AddChannelSet(formats2, 6);
AddChannelSet(formats2, 7);
AddChannelSet(formats2, 8);
formats2.mutable_sample_formats()->push_back(fuchsia::hardware::audio::SampleFormat::PCM_FLOAT);
formats2.mutable_bytes_per_sample()->push_back(4);
formats2.mutable_valid_bits_per_sample()->push_back(32);
formats2.mutable_frame_rates()->push_back(16'000);
formats2.mutable_frame_rates()->push_back(24'000);
fmts.push_back(std::move(formats2));
frames_per_second_inout = 0;
channels_inout = 0;
sample_format_inout = fuchsia::media::AudioSampleFormat::UNSIGNED_8;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_OK);
ASSERT_EQ(sample_format_inout, fuchsia::media::AudioSampleFormat::FLOAT); // Pick float.
ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(16'000)); // Pick closest.
ASSERT_EQ(channels_inout, static_cast<uint32_t>(8)); // Pick highest.
}
TEST(SelectBestFormatTest, SelectBestFormatOutsideRangesNewFidl) {
std::vector<fuchsia_audio_device::PcmFormatSet> fmts;
fuchsia_audio_device::PcmFormatSet formats;
AddChannelSet(formats, 1);
AddChannelSet(formats, 2);
AddChannelSet(formats, 4);
AddChannelSet(formats, 8);
formats.sample_types({{fuchsia_audio::SampleType::kInt16}});
formats.frame_rates({{16'000, 24'000, 48'000, 96'000}});
fmts.push_back(std::move(formats));
auto pref = media_audio::Format::CreateOrDie({
.sample_type = fuchsia_audio::SampleType::kInt16,
.channels = 3,
.frames_per_second = 1,
});
auto result = SelectBestFormat(fmts, pref);
ASSERT_TRUE(result.is_ok());
EXPECT_EQ(result->sample_type(), fuchsia_audio::SampleType::kInt16);
EXPECT_EQ(result->frames_per_second(), 16'000); // pick closest available
EXPECT_EQ(result->channels(), 2); // prefer 2 channels
pref = media_audio::Format::CreateOrDie({
.sample_type = fuchsia_audio::SampleType::kUint8,
.channels = 200,
.frames_per_second = 192'000,
});
result = SelectBestFormat(fmts, pref);
ASSERT_TRUE(result.is_ok());
EXPECT_EQ(result->sample_type(), fuchsia_audio::SampleType::kInt16);
EXPECT_EQ(result->frames_per_second(), 96'000); // pick closest available
EXPECT_EQ(result->channels(), 2); // prefer 2 channels
// Add a second format range.
fuchsia_audio_device::PcmFormatSet formats2;
AddChannelSet(formats2, 4);
AddChannelSet(formats2, 5);
AddChannelSet(formats2, 6);
AddChannelSet(formats2, 7);
AddChannelSet(formats2, 8);
formats2.sample_types({{fuchsia_audio::SampleType::kFloat32}});
formats2.frame_rates({{16'000, 24'000}});
fmts.push_back(std::move(formats2));
pref = media_audio::Format::CreateOrDie({
.sample_type = fuchsia_audio::SampleType::kUint8,
.channels = 3,
.frames_per_second = 1,
});
result = SelectBestFormat(fmts, pref);
ASSERT_TRUE(result.is_ok());
EXPECT_EQ(result->sample_type(), fuchsia_audio::SampleType::kFloat32); // pick float
EXPECT_EQ(result->frames_per_second(), 16'000); // pick closest
EXPECT_EQ(result->channels(), 8); // pick highest
}
TEST(SelectBestFormatTest, SelectBestFormatError) {
std::vector<fuchsia::hardware::audio::PcmSupportedFormats> fmts;
fuchsia::hardware::audio::PcmSupportedFormats formats = {};
AddChannelSet(formats, 1);
AddChannelSet(formats, 2);
AddChannelSet(formats, 4);
AddChannelSet(formats, 8);
formats.mutable_sample_formats()->push_back(fuchsia::hardware::audio::SampleFormat::PCM_FLOAT);
formats.mutable_bytes_per_sample()->push_back(1);
formats.mutable_valid_bits_per_sample()->push_back(32);
formats.mutable_frame_rates()->push_back(8'000);
formats.mutable_frame_rates()->push_back(16'000);
formats.mutable_frame_rates()->push_back(24'000);
formats.mutable_frame_rates()->push_back(48'000);
formats.mutable_frame_rates()->push_back(96'000);
formats.mutable_frame_rates()->push_back(192'000);
formats.mutable_frame_rates()->push_back(384'000);
formats.mutable_frame_rates()->push_back(768'000);
fmts.push_back(std::move(formats));
fuchsia::media::AudioSampleFormat sample_format_inout = {}; // Bad format
uint32_t frames_per_second_inout = 0;
uint32_t channels_inout = 0;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_ERR_INVALID_ARGS);
sample_format_inout = fuchsia::media::AudioSampleFormat::SIGNED_16;
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, nullptr, // Bad pointer.
&sample_format_inout),
ZX_ERR_INVALID_ARGS);
ASSERT_EQ(SelectBestFormat(fmts, &frames_per_second_inout, &channels_inout, nullptr),
ZX_ERR_INVALID_ARGS); // Bad pointer.
std::vector<fuchsia::hardware::audio::PcmSupportedFormats> empty_fmts;
ASSERT_EQ(
SelectBestFormat(empty_fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout),
ZX_ERR_NOT_SUPPORTED);
}
TEST(SelectBestFormatTest, SelectBestFormatErrorNewFidl) {
// Most of the SelectBestFormatError test cases are impossible by construction. Only this
// `empty_fmts` case is possible.
std::vector<fuchsia_audio_device::PcmFormatSet> empty_fmts;
auto pref = media_audio::Format::CreateOrDie({
.sample_type = fuchsia_audio::SampleType::kInt16,
.channels = 3,
.frames_per_second = 1,
});
auto result = SelectBestFormat(empty_fmts, pref);
ASSERT_FALSE(result.is_ok());
EXPECT_EQ(result.error_value(), ZX_ERR_NOT_SUPPORTED);
}
} // namespace
} // namespace media::audio