| // 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/utils.h" |
| |
| #include <fuchsia/scheduler/cpp/fidl.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/gtest/test_loop_fixture.h> |
| #include <lib/sys/cpp/testing/component_context_provider.h> |
| #include <zircon/errors.h> |
| |
| #include <cstdint> |
| #include <unordered_map> |
| |
| #include "src/media/audio/audio_core/testing/fake_profile_provider.h" |
| |
| namespace media::audio { |
| namespace { |
| |
| class UtilsTest : public gtest::TestLoopFixture { |
| protected: |
| void SetUp() override { |
| TestLoopFixture::SetUp(); |
| auto svc = context_provider_.service_directory_provider(); |
| ASSERT_EQ(ZX_OK, svc->AddService(profile_provider_.GetHandler())); |
| } |
| |
| FakeProfileProvider* profile_provider() { return &profile_provider_; } |
| |
| sys::ComponentContext* context() { return context_provider_.context(); } |
| |
| private: |
| FakeProfileProvider profile_provider_; |
| sys::testing::ComponentContextProvider context_provider_; |
| }; |
| |
| TEST_F(UtilsTest, AcquireAudioCoreImplProfile) { |
| ASSERT_TRUE(profile_provider()->SetProfile(24)); |
| zx_status_t status = ZX_ERR_NOT_FOUND; |
| |
| AcquireAudioCoreImplProfile(context(), [&status](zx_status_t s, zx::profile p) { status = s; }); |
| RunLoopUntilIdle(); |
| |
| ASSERT_EQ(status, ZX_OK); |
| } |
| |
| TEST_F(UtilsTest, AcquireAudioCoreImplProfile_ProfileUnavailable) { |
| bool callback_invoked = false; |
| zx_status_t status = ZX_ERR_NOT_FOUND; |
| AcquireAudioCoreImplProfile(context(), [&](zx_status_t s, zx::profile p) { |
| status = s; |
| callback_invoked = true; |
| }); |
| RunLoopUntilIdle(); |
| |
| ASSERT_NE(status, ZX_OK); |
| ASSERT_TRUE(callback_invoked); |
| } |
| |
| TEST(UtilsFormatTest, SelectBestFormatFound) { |
| std::vector<audio_stream_format_range_t> fmts; |
| fmts.push_back(audio_stream_format_range_t{ |
| .sample_formats = AUDIO_SAMPLE_FORMAT_32BIT_FLOAT, |
| .min_frames_per_second = 12'000, |
| .max_frames_per_second = 96'000, |
| .min_channels = 1, |
| .max_channels = 8, |
| .flags = ASF_RANGE_FLAG_FPS_48000_FAMILY, |
| }); |
| 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. |
| fmts.push_back(audio_stream_format_range_t{ |
| .sample_formats = AUDIO_SAMPLE_FORMAT_16BIT, |
| .min_frames_per_second = 22'050, |
| .max_frames_per_second = 176'400, |
| .min_channels = 4, |
| .max_channels = 8, |
| .flags = ASF_RANGE_FLAG_FPS_44100_FAMILY, |
| }); |
| 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(UtilsFormatTest, SelectBestFormatFoundFidl) { |
| std::vector<fuchsia::hardware::audio::PcmSupportedFormats> fmts; |
| |
| fuchsia::hardware::audio::PcmSupportedFormats formats = {}; |
| formats.number_of_channels.push_back(1); |
| formats.number_of_channels.push_back(2); |
| formats.number_of_channels.push_back(4); |
| formats.number_of_channels.push_back(8); |
| formats.sample_formats.push_back(fuchsia::hardware::audio::SampleFormat::PCM_FLOAT); |
| formats.bytes_per_sample.push_back(4); |
| formats.valid_bits_per_sample.push_back(32); |
| formats.frame_rates.push_back(12'000); |
| formats.frame_rates.push_back(24'000); |
| formats.frame_rates.push_back(48'000); |
| formats.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 = {}; |
| formats2.number_of_channels.push_back(4); |
| formats2.number_of_channels.push_back(5); |
| formats2.number_of_channels.push_back(6); |
| formats2.number_of_channels.push_back(7); |
| formats2.number_of_channels.push_back(8); |
| formats2.sample_formats.push_back(fuchsia::hardware::audio::SampleFormat::PCM_SIGNED); |
| formats2.bytes_per_sample.push_back(2); |
| formats2.valid_bits_per_sample.push_back(16); |
| formats2.frame_rates.push_back(22'050); |
| formats2.frame_rates.push_back(44'100); |
| formats2.frame_rates.push_back(88'200); |
| formats2.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(UtilsFormatTest, SelectBestFormatOutsideRanges) { |
| std::vector<audio_stream_format_range_t> fmts; |
| fmts.push_back(audio_stream_format_range_t{ |
| .sample_formats = AUDIO_SAMPLE_FORMAT_32BIT_FLOAT, |
| .min_frames_per_second = 16'000, |
| .max_frames_per_second = 96'000, |
| .min_channels = 1, |
| .max_channels = 8, |
| .flags = ASF_RANGE_FLAG_FPS_48000_FAMILY, |
| }); |
| 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::FLOAT); |
| ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(16'000)); // Prefer closest. |
| 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::FLOAT); |
| ASSERT_EQ(frames_per_second_inout, static_cast<uint32_t>(96'000)); // Pick closest. |
| ASSERT_EQ(channels_inout, static_cast<uint32_t>(2)); // Prefer 2 channels. |
| |
| // Add a second format range. |
| fmts.push_back(audio_stream_format_range_t{ |
| .sample_formats = AUDIO_SAMPLE_FORMAT_16BIT, |
| .min_frames_per_second = 16'000, |
| .max_frames_per_second = 24'000, |
| .min_channels = 4, |
| .max_channels = 8, |
| .flags = ASF_RANGE_FLAG_FPS_48000_FAMILY, |
| }); |
| 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::SIGNED_16); // Pick 16 bits. |
| 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(UtilsFormatTest, SelectBestFormatOutsideRangesFidl) { |
| std::vector<fuchsia::hardware::audio::PcmSupportedFormats> fmts; |
| fuchsia::hardware::audio::PcmSupportedFormats formats = {}; |
| formats.number_of_channels.push_back(1); |
| formats.number_of_channels.push_back(2); |
| formats.number_of_channels.push_back(4); |
| formats.number_of_channels.push_back(8); |
| formats.sample_formats.push_back(fuchsia::hardware::audio::SampleFormat::PCM_FLOAT); |
| formats.bytes_per_sample.push_back(4); |
| formats.valid_bits_per_sample.push_back(32); |
| formats.frame_rates.push_back(16'000); |
| formats.frame_rates.push_back(24'000); |
| formats.frame_rates.push_back(48'000); |
| formats.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::FLOAT); |
| 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::FLOAT); |
| 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 = {}; |
| formats2.number_of_channels.push_back(4); |
| formats2.number_of_channels.push_back(5); |
| formats2.number_of_channels.push_back(6); |
| formats2.number_of_channels.push_back(7); |
| formats2.number_of_channels.push_back(8); |
| formats2.sample_formats.push_back(fuchsia::hardware::audio::SampleFormat::PCM_SIGNED); |
| formats2.bytes_per_sample.push_back(2); |
| formats2.valid_bits_per_sample.push_back(16); |
| formats2.frame_rates.push_back(16'000); |
| formats2.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::SIGNED_16); // Pick 16 bits. |
| 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(UtilsFormatTest, SelectBestFormatError) { |
| std::vector<audio_stream_format_range_t> fmts; |
| fmts.push_back(audio_stream_format_range_t{ |
| .sample_formats = AUDIO_SAMPLE_FORMAT_32BIT_FLOAT, |
| .min_frames_per_second = 8'000, |
| .max_frames_per_second = 768'000, |
| .min_channels = 1, |
| .max_channels = 8, |
| .flags = ASF_RANGE_FLAG_FPS_48000_FAMILY, |
| }); |
| 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; // Fix format. |
| |
| 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<audio_stream_format_range_t> empty_fmts; |
| ASSERT_EQ( |
| SelectBestFormat(empty_fmts, &frames_per_second_inout, &channels_inout, &sample_format_inout), |
| ZX_ERR_NOT_SUPPORTED); |
| } |
| |
| TEST(UtilsFormatTest, SelectBestFormatErrorFidl) { |
| std::vector<fuchsia::hardware::audio::PcmSupportedFormats> fmts; |
| |
| fuchsia::hardware::audio::PcmSupportedFormats formats = {}; |
| formats.number_of_channels.push_back(1); |
| formats.number_of_channels.push_back(2); |
| formats.number_of_channels.push_back(4); |
| formats.number_of_channels.push_back(8); |
| formats.sample_formats.push_back(fuchsia::hardware::audio::SampleFormat::PCM_FLOAT); |
| formats.bytes_per_sample.push_back(1); |
| formats.valid_bits_per_sample.push_back(32); |
| formats.frame_rates.push_back(8'000); |
| formats.frame_rates.push_back(16'000); |
| formats.frame_rates.push_back(24'000); |
| formats.frame_rates.push_back(48'000); |
| formats.frame_rates.push_back(96'000); |
| formats.frame_rates.push_back(192'000); |
| formats.frame_rates.push_back(384'000); |
| formats.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); |
| } |
| |
| } // namespace |
| } // namespace media::audio |