blob: 4ed7d66932fc4045144538b107f30478ccd59eb2 [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/audio_capturer.h"
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <gtest/gtest.h>
#include "src/media/audio/audio_core/audio_admin.h"
#include "src/media/audio/audio_core/audio_device_manager.h"
#include "src/media/audio/audio_core/audio_driver.h"
#include "src/media/audio/audio_core/audio_input.h"
#include "src/media/audio/audio_core/stream_volume_manager.h"
#include "src/media/audio/audio_core/testing/fake_audio_driver.h"
#include "src/media/audio/audio_core/testing/threading_model_fixture.h"
#include "src/media/audio/lib/logging/logging.h"
namespace media::audio {
namespace {
constexpr uint32_t kAudioCapturerUnittestFrameRate = 48000;
constexpr size_t kAudioCapturerUnittestVmarSize = 16ull * 1024;
class AudioCapturerTest : public testing::ThreadingModelFixture {
public:
AudioCapturerTest() {
FX_CHECK(vmo_mapper_.CreateAndMap(kAudioCapturerUnittestVmarSize,
/*flags=*/0, nullptr, &vmo_) == ZX_OK);
}
protected:
void SetUp() override {
testing::ThreadingModelFixture::SetUp();
auto format = Format::Create(stream_type_).take_value();
fuchsia::media::InputAudioCapturerConfiguration input_configuration;
input_configuration.set_usage(fuchsia::media::AudioCaptureUsage::BACKGROUND);
auto capturer = std::unique_ptr<AudioCapturer>(new AudioCapturer(
fuchsia::media::AudioCapturerConfiguration::WithInput(std::move(input_configuration)),
{format}, fidl_capturer_.NewRequest(), &context()));
capturer_ = capturer.get();
EXPECT_NE(capturer_, nullptr);
context().route_graph().AddCapturer(std::move(capturer));
}
void TearDown() override {
// Dropping the channel queues up a reference to the Capturer through its error handler, which
// will not work since the rest of this class is destructed before the loop and its
// queued functions are. Here, we ensure the error handler runs before this class' destructors
// run.
{ auto r = std::move(fidl_capturer_); }
RunLoopUntilIdle();
testing::ThreadingModelFixture::TearDown();
}
protected:
AudioCapturer* capturer_;
fuchsia::media::AudioCapturerPtr fidl_capturer_;
fzl::VmoMapper vmo_mapper_;
zx::vmo vmo_;
fuchsia::media::AudioStreamType stream_type_ = {
.sample_format = fuchsia::media::AudioSampleFormat::FLOAT,
.channels = 1,
.frames_per_second = kAudioCapturerUnittestFrameRate,
};
};
TEST_F(AudioCapturerTest, CanShutdownWithUnusedBuffer) {
zx::vmo duplicate;
ASSERT_EQ(
vmo_.duplicate(ZX_RIGHT_TRANSFER | ZX_RIGHT_WRITE | ZX_RIGHT_READ | ZX_RIGHT_MAP, &duplicate),
ZX_OK);
fidl_capturer_->AddPayloadBuffer(0, std::move(duplicate));
RunLoopUntilIdle();
}
TEST_F(AudioCapturerTest, RegistersWithRouteGraphIfHasUsageStreamTypeAndBuffers) {
EXPECT_EQ(context().link_matrix().SourceLinkCount(*capturer_), 0u);
zx::vmo duplicate;
ASSERT_EQ(
vmo_.duplicate(ZX_RIGHT_TRANSFER | ZX_RIGHT_WRITE | ZX_RIGHT_READ | ZX_RIGHT_MAP, &duplicate),
ZX_OK);
zx::channel c1, c2;
ASSERT_EQ(ZX_OK, zx::channel::create(0, &c1, &c2));
auto input = AudioInput::Create(zx::channel(), &threading_model(), &context().device_manager(),
&context().link_matrix());
auto fake_driver =
testing::FakeAudioDriver(std::move(c1), threading_model().FidlDomain().dispatcher());
auto vmo = fake_driver.CreateRingBuffer(PAGE_SIZE);
input->driver()->Init(std::move(c2));
fake_driver.Start();
input->driver()->GetDriverInfo();
RunLoopUntilIdle();
input->driver()->Start();
fake_driver.set_formats({audio_stream_format_range_t{
.sample_formats = AUDIO_SAMPLE_FORMAT_32BIT_FLOAT,
.min_frames_per_second = 0,
.max_frames_per_second = 96000,
.min_channels = 1,
.max_channels = 100,
.flags = 0,
}});
context().route_graph().AddDevice(input.get());
RunLoopUntilIdle();
fidl_capturer_->AddPayloadBuffer(0, std::move(duplicate));
RunLoopUntilIdle();
EXPECT_EQ(context().link_matrix().SourceLinkCount(*capturer_), 1u);
}
TEST_F(AudioCapturerTest, CanReleasePacketWithoutDroppingConnection) {
bool channel_dropped = false;
fidl_capturer_.set_error_handler([&channel_dropped](auto _) { channel_dropped = true; });
fidl_capturer_->ReleasePacket(fuchsia::media::StreamPacket{});
RunLoopUntilIdle();
// The RouteGraph should still own our capturer.
EXPECT_FALSE(channel_dropped);
}
} // namespace
} // namespace media::audio