blob: 29d5118b770d90348324126a0acbce45b304b97e [file] [log] [blame]
// Copyright 2022 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/ring_buffer_server.h"
#include <fidl/fuchsia.audio.device/cpp/markers.h>
#include <fidl/fuchsia.audio.device/cpp/natural_types.h>
#include <fidl/fuchsia.audio/cpp/common_types.h>
#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
#include <lib/fidl/cpp/wire/internal/transport_channel.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/clock.h>
#include <zircon/errors.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/media/audio/services/common/testing/test_server_and_async_client.h"
#include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
#include "src/media/audio/services/device_registry/common_unittest.h"
#include "src/media/audio/services/device_registry/testing/fake_composite.h"
#include "src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h"
#include "src/media/audio/services/device_registry/testing/fake_stream_config.h"
namespace media_audio {
namespace {
using ::testing::Optional;
using Control = fuchsia_audio_device::Control;
using RingBuffer = fuchsia_audio_device::RingBuffer;
using DriverClient = fuchsia_audio_device::DriverClient;
class RingBufferServerTest : public AudioDeviceRegistryServerTestBase,
public fidl::AsyncEventHandler<fuchsia_audio_device::RingBuffer> {
protected:
static inline const fuchsia_audio_device::RingBufferOptions kDefaultRingBufferOptions{{
.format = fuchsia_audio::Format{{.sample_type = fuchsia_audio::SampleType::kInt16,
.channel_count = 2,
.frames_per_second = 48000}},
.ring_buffer_min_bytes = 2000,
}};
std::optional<TokenId> WaitForAddedDeviceTokenId(
fidl::Client<fuchsia_audio_device::Registry>& reg_client);
std::pair<fidl::Client<fuchsia_audio_device::RingBuffer>,
fidl::ServerEnd<fuchsia_audio_device::RingBuffer>>
CreateRingBufferClient();
std::pair<std::unique_ptr<TestServerAndNaturalAsyncClient<ControlServer>>,
fidl::Client<fuchsia_audio_device::RingBuffer>>
SetupForCleanShutdownTesting(
ElementId element_id = fuchsia_audio_device::kDefaultRingBufferElementId,
const fuchsia_audio_device::RingBufferOptions& options = kDefaultRingBufferOptions);
};
std::optional<TokenId> RingBufferServerTest::WaitForAddedDeviceTokenId(
fidl::Client<fuchsia_audio_device::Registry>& reg_client) {
std::optional<TokenId> added_device_id;
reg_client->WatchDevicesAdded().Then(
[&added_device_id](
fidl::Result<fuchsia_audio_device::Registry::WatchDevicesAdded>& result) mutable {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->devices());
ASSERT_EQ(result->devices()->size(), 1u);
ASSERT_TRUE(result->devices()->at(0).token_id());
added_device_id = *result->devices()->at(0).token_id();
});
RunLoopUntilIdle();
return added_device_id;
}
std::pair<fidl::Client<fuchsia_audio_device::RingBuffer>,
fidl::ServerEnd<fuchsia_audio_device::RingBuffer>>
RingBufferServerTest::CreateRingBufferClient() {
auto [ring_buffer_client_end, ring_buffer_server_end] =
CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
std::move(ring_buffer_client_end), dispatcher(), this);
return std::make_pair(std::move(ring_buffer_client), std::move(ring_buffer_server_end));
}
std::pair<std::unique_ptr<TestServerAndNaturalAsyncClient<ControlServer>>,
fidl::Client<fuchsia_audio_device::RingBuffer>>
RingBufferServerTest::SetupForCleanShutdownTesting(
ElementId element_id, const fuchsia_audio_device::RingBufferOptions& options) {
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
FX_CHECK(token_id);
auto control_creator = CreateTestControlCreatorServer();
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_TRUE(presence == AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{element_id, options, std::move(ring_buffer_server_end)}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
return std::make_pair(std::move(control), std::move(ring_buffer_client));
}
class RingBufferServerCompositeTest : public RingBufferServerTest {
protected:
std::shared_ptr<Device> EnableDriverAndAddDevice(
const std::shared_ptr<FakeComposite>& fake_driver) {
auto device = Device::Create(adr_service_, dispatcher(), "Test composite name",
fuchsia_audio_device::DeviceType::kComposite,
DriverClient::WithComposite(fake_driver->Enable()));
adr_service_->AddDevice(device);
RunLoopUntilIdle();
return device;
}
};
TEST_F(RingBufferServerCompositeTest, CleanClientDrop) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto [control, ring_buffer_client] = SetupForCleanShutdownTesting(
element_id,
fuchsia_audio_device::RingBufferOptions{{.format = format, .ring_buffer_min_bytes = 2000}});
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
RunLoopUntilIdle();
// If RingBuffer client doesn't drop cleanly, RingBufferServer emits a WARNING, which will fail.
}
TEST_F(RingBufferServerCompositeTest, DriverRingBufferDropCausesCleanRingBufferServerShutdown) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto [control, ring_buffer_client] = SetupForCleanShutdownTesting(
element_id,
fuchsia_audio_device::RingBufferOptions{{.format = format, .ring_buffer_min_bytes = 2000}});
fake_driver->DropRingBuffer(element_id);
RunLoopUntilIdle();
// If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
}
TEST_F(RingBufferServerCompositeTest, DriverCompositeDropCausesCleanRingBufferServerShutdown) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto [control, ring_buffer_client] = SetupForCleanShutdownTesting(
element_id,
fuchsia_audio_device::RingBufferOptions{{.format = format, .ring_buffer_min_bytes = 2000}});
fake_driver->DropComposite();
RunLoopUntilIdle();
// If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
}
// Verify that Control/CreateRingBuffer succeeds and returns the expected parameters.
TEST_F(RingBufferServerCompositeTest, CreateRingBufferReturnParameters) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId; // Element is an Outgoing RingBuffer.
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto requested_ring_buffer_bytes = 2000u;
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = requested_ring_buffer_bytes}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback, format,
requested_ring_buffer_bytes](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->properties());
ASSERT_TRUE(result->properties()->valid_bits_per_sample());
EXPECT_EQ(*result->properties()->valid_bits_per_sample(),
FakeComposite::kDefaultRbValidBitsPerSample2);
ASSERT_TRUE(result->properties()->turn_on_delay());
EXPECT_EQ(*result->properties()->turn_on_delay(), 0);
ASSERT_TRUE(result->ring_buffer());
ASSERT_TRUE(result->ring_buffer()->buffer());
ASSERT_TRUE(result->ring_buffer()->producer_bytes());
ASSERT_TRUE(result->ring_buffer()->consumer_bytes());
ASSERT_TRUE(result->ring_buffer()->reference_clock());
EXPECT_TRUE(result->ring_buffer()->buffer()->vmo().is_valid());
EXPECT_GE(
result->ring_buffer()->buffer()->size(),
requested_ring_buffer_bytes + FakeCompositeRingBuffer::kDefaultDriverTransferBytes);
EXPECT_EQ(*result->ring_buffer()->format(), format);
EXPECT_GE(result->ring_buffer()->producer_bytes(), requested_ring_buffer_bytes);
EXPECT_EQ(result->ring_buffer()->consumer_bytes(),
FakeCompositeRingBuffer::kDefaultDriverTransferBytes);
EXPECT_TRUE(result->ring_buffer()->reference_clock()->is_valid());
EXPECT_EQ(result->ring_buffer()->reference_clock_domain().value_or(
fuchsia_hardware_audio::kClockDomainMonotonic),
fuchsia_hardware_audio::kClockDomainMonotonic);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/SetActiveChannels succeeds and returns an expected set_time.
TEST_F(RingBufferServerCompositeTest, DriverSupportsSetActiveChannels) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
fake_driver->EnableActiveChannelsSupport(element_id);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
received_callback = true;
EXPECT_TRUE(result.is_ok()) << result.error_value();
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_TRUE(ring_buffer_client.is_valid());
received_callback = false;
auto before_set_active_channels = zx::clock::get_monotonic();
ring_buffer_client
->SetActiveChannels({{
.channel_bitmask = 0x0,
}})
.Then([&received_callback,
before_set_active_channels](fidl::Result<RingBuffer::SetActiveChannels>& result) {
received_callback = true;
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->set_time());
EXPECT_GT(*result->set_time(), before_set_active_channels.get());
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(fake_driver->active_channels_bitmask(element_id), 0x0u);
EXPECT_GT(fake_driver->active_channels_set_time(element_id), before_set_active_channels);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
TEST_F(RingBufferServerCompositeTest, DriverDoesNotSupportSetActiveChannels) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
// Set this fake hardware to NOT support powering-down channels.
fake_driver->DisableActiveChannelsSupport(element_id);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto channel_count = *format.channel_count();
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(added_device);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_TRUE(ring_buffer_client.is_valid());
received_callback = false;
ring_buffer_client->SetActiveChannels({{0}}).Then(
[&received_callback](fidl::Result<RingBuffer::SetActiveChannels>& result) {
ASSERT_TRUE(result.is_error()) << result.error_value();
ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
EXPECT_EQ(result.error_value().domain_error(),
fuchsia_audio_device::RingBufferSetActiveChannelsError::kMethodNotSupported)
<< result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(fake_driver->active_channels_bitmask(element_id), (1u << channel_count) - 1u);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/Start and /Stop function as expected, including start_time.
TEST_F(RingBufferServerCompositeTest, StartAndStop) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->DisableActiveChannelsSupport(element_id);
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started(element_id));
received_callback = false;
auto before_start = zx::clock::get_monotonic();
ring_buffer_client->Start({}).Then([&received_callback, before_start, &fake_driver,
element_id](fidl::Result<RingBuffer::Start>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->start_time());
EXPECT_EQ(*result->start_time(), fake_driver->mono_start_time(element_id).get());
EXPECT_GT(*result->start_time(), before_start.get());
EXPECT_TRUE(fake_driver->started(element_id));
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
// Now that we are started, we want the RingBuffer server to take definitive action on some OTHER
// request before we stop. We will use SetActiveChannels, which we expressly set as 'unsupported'
// above, in the fake driver test fixture.
received_callback = false;
ring_buffer_client
->SetActiveChannels({{
.channel_bitmask = 0x0,
}})
.Then([&received_callback](fidl::Result<RingBuffer::SetActiveChannels>& result) {
ASSERT_TRUE(result.is_error());
ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
EXPECT_EQ(result.error_value().domain_error(),
fuchsia_audio_device::RingBufferSetActiveChannelsError::kMethodNotSupported)
<< result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
received_callback = false;
ring_buffer_client->Stop({}).Then(
[&received_callback, &fake_driver, element_id](fidl::Result<RingBuffer::Stop>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
EXPECT_FALSE(fake_driver->started(element_id));
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/WatchDelayInfo notifies of the delay received during initialization.
// While we are here, validate a non-default value for turn_on_delay.
TEST_F(RingBufferServerCompositeTest, WatchDelayInfoInitialValues) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->PresetTurnOnDelay(element_id, zx::msec(42));
fake_driver->PresetInternalExternalDelays(element_id, zx::nsec(987'654'321),
zx::nsec(123'456'789));
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->properties());
ASSERT_TRUE(result->properties()->turn_on_delay());
EXPECT_EQ(*result->properties()->turn_on_delay(), 42'000'000);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started(element_id));
received_callback = false;
ring_buffer_client->WatchDelayInfo().Then(
[&received_callback](fidl::Result<RingBuffer::WatchDelayInfo>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->delay_info());
ASSERT_TRUE(result->delay_info()->internal_delay());
ASSERT_TRUE(result->delay_info()->external_delay());
EXPECT_EQ(*result->delay_info()->internal_delay(), 987'654'321u);
EXPECT_EQ(*result->delay_info()->external_delay(), 123'456'789u);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/WatchDelayInfo notifies of delay changes after initialization.
TEST_F(RingBufferServerCompositeTest, WatchDelayInfoDynamicUpdates) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started(element_id));
received_callback = false;
ring_buffer_client->WatchDelayInfo().Then(
[&received_callback](fidl::Result<RingBuffer::WatchDelayInfo>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->delay_info());
ASSERT_TRUE(result->delay_info()->internal_delay());
EXPECT_FALSE(result->delay_info()->external_delay());
EXPECT_EQ(result->delay_info()->internal_delay().value(),
FakeCompositeRingBuffer::kDefaultInternalDelay->get());
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
received_callback = false;
ring_buffer_client->WatchDelayInfo().Then(
[&received_callback](fidl::Result<RingBuffer::WatchDelayInfo>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->delay_info());
ASSERT_TRUE(result->delay_info()->internal_delay());
ASSERT_TRUE(result->delay_info()->external_delay());
EXPECT_EQ(*result->delay_info()->internal_delay(), 987'654'321u);
EXPECT_EQ(*result->delay_info()->external_delay(), 123'456'789u);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_FALSE(received_callback);
fake_driver->InjectDelayUpdate(element_id, zx::nsec(987'654'321), zx::nsec(123'456'789));
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that the RingBufferServer is destructed if the client drops the Control.
TEST_F(RingBufferServerCompositeTest, ControlClientDropCausesRingBufferDrop) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(ControlServer::count(), 1u);
(void)control->client().UnbindMaybeGetEndpoint();
RunLoopUntilIdle();
EXPECT_TRUE(control->server().WaitForShutdown());
EXPECT_EQ(RingBufferServer::count(), 0u);
}
// Verify that the RingBufferServer is destructed if the ControlServer shuts down.
TEST_F(RingBufferServerCompositeTest, ControlServerShutdownCausesRingBufferDrop) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(ControlServer::count(), 1u);
EXPECT_EQ(RingBufferServer::count(), 1u);
control->server().Shutdown(ZX_ERR_PEER_CLOSED);
RunLoopUntilIdle();
EXPECT_TRUE(control->server().WaitForShutdown());
EXPECT_EQ(RingBufferServer::count(), 0u);
}
// Verify that RingBuffer works as expected, after RingBuffer being created/destroyed/recreated.
TEST_F(RingBufferServerCompositeTest, SecondRingBufferAfterDrop) {
auto fake_driver = CreateFakeComposite();
auto element_id = FakeComposite::kMaxRingBufferElementId;
fake_driver->DisableActiveChannelsSupport(element_id);
fake_driver->ReserveRingBufferSize(element_id, 8192);
auto device = EnableDriverAndAddDevice(fake_driver);
auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
element_id, device->ring_buffer_format_sets());
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
{
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
ASSERT_TRUE(control->client().is_valid());
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
ASSERT_TRUE(received_callback);
ASSERT_FALSE(fake_driver->started(element_id));
received_callback = false;
auto before_start = zx::clock::get_monotonic();
ring_buffer_client->Start({}).Then([&received_callback, before_start, &fake_driver,
element_id](fidl::Result<RingBuffer::Start>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->start_time());
EXPECT_EQ(*result->start_time(), fake_driver->mono_start_time(element_id).get());
EXPECT_GT(*result->start_time(), before_start.get());
EXPECT_TRUE(fake_driver->started(element_id));
received_callback = true;
});
RunLoopUntilIdle();
ASSERT_TRUE(received_callback);
// Now that we are started, we want to suddenly drop the RingBuffer connection.
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
(void)control->client().UnbindMaybeGetEndpoint();
RunLoopUntilIdle();
control->server().WaitForShutdown();
}
{
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
auto received_callback = false;
ASSERT_TRUE(control->client().is_valid());
control->client()
->CreateRingBuffer({{
element_id,
fuchsia_audio_device::RingBufferOptions{
{.format = format, .ring_buffer_min_bytes = 2000}},
std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started(element_id));
received_callback = false;
auto before_start = zx::clock::get_monotonic();
ring_buffer_client->Start({}).Then([&received_callback, before_start, &fake_driver,
element_id](fidl::Result<RingBuffer::Start>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->start_time());
EXPECT_EQ(*result->start_time(), fake_driver->mono_start_time(element_id).get());
EXPECT_GT(*result->start_time(), before_start.get());
EXPECT_TRUE(fake_driver->started(element_id));
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
}
}
class RingBufferServerStreamConfigTest : public RingBufferServerTest {
protected:
std::shared_ptr<Device> EnableDriverAndAddDevice(
const std::shared_ptr<FakeStreamConfig>& fake_driver) {
auto device = Device::Create(adr_service_, dispatcher(), "Test output name",
fuchsia_audio_device::DeviceType::kOutput,
DriverClient::WithStreamConfig(fake_driver->Enable()));
adr_service_->AddDevice(device);
RunLoopUntilIdle();
return device;
}
};
// Verify that RingBuffer clients and servers shutdown cleanly (without warnings).
TEST_F(RingBufferServerStreamConfigTest, CleanClientDrop) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto [control, ring_buffer_client] = SetupForCleanShutdownTesting();
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
RunLoopUntilIdle();
// If RingBuffer client doesn't drop cleanly, RingBufferServer emits a WARNING, which will fail.
}
TEST_F(RingBufferServerStreamConfigTest, DriverRingBufferDropCausesCleanRingBufferServerShutdown) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto [control, ring_buffer_client] = SetupForCleanShutdownTesting();
fake_driver->DropRingBuffer();
RunLoopUntilIdle();
// If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
}
TEST_F(RingBufferServerStreamConfigTest,
DriverStreamConfigDropCausesCleanRingBufferServerShutdown) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto [control, ring_buffer_client] = SetupForCleanShutdownTesting();
fake_driver->DropStreamConfig();
RunLoopUntilIdle();
// If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
}
// Verify that Control/CreateRingBuffer succeeds and returns the expected parameters.
TEST_F(RingBufferServerStreamConfigTest, CreateRingBufferReturnParameters) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->properties());
ASSERT_TRUE(result->properties()->valid_bits_per_sample());
EXPECT_EQ(*result->properties()->valid_bits_per_sample(), 16);
ASSERT_TRUE(result->properties()->turn_on_delay());
EXPECT_EQ(*result->properties()->turn_on_delay(), 0);
ASSERT_TRUE(result->ring_buffer());
ASSERT_TRUE(result->ring_buffer()->buffer());
ASSERT_TRUE(result->ring_buffer()->producer_bytes());
ASSERT_TRUE(result->ring_buffer()->consumer_bytes());
ASSERT_TRUE(result->ring_buffer()->reference_clock());
EXPECT_TRUE(result->ring_buffer()->buffer()->vmo().is_valid());
EXPECT_GT(result->ring_buffer()->buffer()->size(), 2000u);
ASSERT_TRUE(result->ring_buffer()->format());
EXPECT_EQ(*result->ring_buffer()->format(), *kDefaultRingBufferOptions.format());
EXPECT_EQ(result->ring_buffer()->producer_bytes(), 2000u);
// consumer_bytes is minimal, based on driver_transfer_bytes
EXPECT_EQ(result->ring_buffer()->consumer_bytes(), 12u);
EXPECT_TRUE(result->ring_buffer()->reference_clock()->is_valid());
EXPECT_EQ(result->ring_buffer()->reference_clock_domain().value_or(
fuchsia_hardware_audio::kClockDomainMonotonic),
fuchsia_hardware_audio::kClockDomainMonotonic);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/SetActiveChannels succeeds and returns an expected set_time.
TEST_F(RingBufferServerStreamConfigTest, DriverSupportsSetActiveChannels) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_TRUE(ring_buffer_client.is_valid());
received_callback = false;
auto before_set_active_channels = zx::clock::get_monotonic();
ring_buffer_client
->SetActiveChannels({{
.channel_bitmask = 0x0,
}})
.Then([&received_callback,
before_set_active_channels](fidl::Result<RingBuffer::SetActiveChannels>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->set_time());
EXPECT_GT(*result->set_time(), before_set_active_channels.get());
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(fake_driver->active_channels_bitmask(), 0x0u);
EXPECT_GT(fake_driver->active_channels_set_time(), before_set_active_channels);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
TEST_F(RingBufferServerStreamConfigTest, DriverDoesNotSupportSetActiveChannels) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
// Set this fake hardware to NOT support powering-down channels.
fake_driver->set_active_channels_supported(false);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(added_device);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_TRUE(ring_buffer_client.is_valid());
received_callback = false;
ring_buffer_client->SetActiveChannels({{0}}).Then(
[&received_callback](fidl::Result<RingBuffer::SetActiveChannels>& result) {
ASSERT_TRUE(result.is_error()) << result.error_value();
ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
EXPECT_EQ(result.error_value().domain_error(),
fuchsia_audio_device::RingBufferSetActiveChannelsError::kMethodNotSupported)
<< result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(fake_driver->active_channels_bitmask(), 0x3u);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/Start and /Stop function as expected, including start_time.
TEST_F(RingBufferServerStreamConfigTest, StartAndStop) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->set_active_channels_supported(false);
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started());
received_callback = false;
auto before_start = zx::clock::get_monotonic();
ring_buffer_client->Start({}).Then(
[&received_callback, before_start, &fake_driver](fidl::Result<RingBuffer::Start>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->start_time());
EXPECT_EQ(*result->start_time(), fake_driver->mono_start_time().get());
EXPECT_GT(*result->start_time(), before_start.get());
EXPECT_TRUE(fake_driver->started());
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
// Now that we are started, we want the RingBuffer server to take definitive action on some OTHER
// request before we stop. We will use SetActiveChannels, which we expressly set as 'unsupported'
// above, in the fake driver test fixture.
received_callback = false;
ring_buffer_client
->SetActiveChannels({{
.channel_bitmask = 0x0,
}})
.Then([&received_callback](fidl::Result<RingBuffer::SetActiveChannels>& result) {
ASSERT_TRUE(result.is_error());
ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
EXPECT_EQ(result.error_value().domain_error(),
fuchsia_audio_device::RingBufferSetActiveChannelsError::kMethodNotSupported)
<< result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
received_callback = false;
ring_buffer_client->Stop({}).Then(
[&received_callback, &fake_driver](fidl::Result<RingBuffer::Stop>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
EXPECT_FALSE(fake_driver->started());
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/WatchDelayInfo notifies of the delay received during initialization.
// While we are here, validate a non-default value for turn_on_delay.
TEST_F(RingBufferServerStreamConfigTest, WatchDelayInfoInitialValues) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->set_turn_on_delay(zx::msec(42));
fake_driver->InjectDelayUpdate(zx::nsec(987'654'321), zx::nsec(123'456'789));
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->properties());
ASSERT_TRUE(result->properties()->turn_on_delay());
EXPECT_EQ(*result->properties()->turn_on_delay(), 42'000'000);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started());
received_callback = false;
ring_buffer_client->WatchDelayInfo().Then(
[&received_callback](fidl::Result<RingBuffer::WatchDelayInfo>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->delay_info());
ASSERT_TRUE(result->delay_info()->internal_delay());
ASSERT_TRUE(result->delay_info()->external_delay());
EXPECT_EQ(*result->delay_info()->internal_delay(), 987'654'321u);
EXPECT_EQ(*result->delay_info()->external_delay(), 123'456'789u);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that RingBuffer/WatchDelayInfo notifies of delay changes after initialization.
TEST_F(RingBufferServerStreamConfigTest, WatchDelayInfoDynamicUpdates) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started());
received_callback = false;
ring_buffer_client->WatchDelayInfo().Then(
[&received_callback](fidl::Result<RingBuffer::WatchDelayInfo>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->delay_info());
ASSERT_TRUE(result->delay_info()->internal_delay());
EXPECT_FALSE(result->delay_info()->external_delay());
EXPECT_EQ(*result->delay_info()->internal_delay(), 0u);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
received_callback = false;
ring_buffer_client->WatchDelayInfo().Then(
[&received_callback](fidl::Result<RingBuffer::WatchDelayInfo>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->delay_info());
ASSERT_TRUE(result->delay_info()->internal_delay());
ASSERT_TRUE(result->delay_info()->external_delay());
EXPECT_EQ(*result->delay_info()->internal_delay(), 987'654'321u);
EXPECT_EQ(*result->delay_info()->external_delay(), 123'456'789u);
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_FALSE(received_callback);
fake_driver->InjectDelayUpdate(zx::nsec(987'654'321), zx::nsec(123'456'789));
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
}
// Verify that the RingBufferServer is destructed if the client drops the Control.
TEST_F(RingBufferServerStreamConfigTest, ControlClientDropCausesRingBufferDrop) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(ControlServer::count(), 1u);
(void)control->client().UnbindMaybeGetEndpoint();
RunLoopUntilIdle();
EXPECT_TRUE(control->server().WaitForShutdown());
EXPECT_EQ(RingBufferServer::count(), 0u);
}
// Verify that the RingBufferServer is destructed if the ControlServer shuts down.
TEST_F(RingBufferServerStreamConfigTest, ControlServerShutdownCausesRingBufferDrop) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_EQ(ControlServer::count(), 1u);
EXPECT_EQ(RingBufferServer::count(), 1u);
control->server().Shutdown(ZX_ERR_PEER_CLOSED);
RunLoopUntilIdle();
EXPECT_TRUE(control->server().WaitForShutdown());
EXPECT_EQ(RingBufferServer::count(), 0u);
}
// Verify that RingBuffer works as expected, after RingBuffer being created/destroyed/recreated.
TEST_F(RingBufferServerStreamConfigTest, SecondRingBufferAfterDrop) {
auto fake_driver = CreateFakeStreamConfigOutput();
fake_driver->set_active_channels_supported(false);
fake_driver->AllocateRingBuffer(8192);
EnableDriverAndAddDevice(fake_driver);
auto registry = CreateTestRegistryServer();
auto token_id = WaitForAddedDeviceTokenId(registry->client());
ASSERT_TRUE(token_id);
auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
{
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
bool received_callback = false;
ASSERT_TRUE(control->client().is_valid());
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
ASSERT_TRUE(received_callback);
ASSERT_FALSE(fake_driver->started());
received_callback = false;
auto before_start = zx::clock::get_monotonic();
ring_buffer_client->Start({}).Then(
[&received_callback, before_start, &fake_driver](fidl::Result<RingBuffer::Start>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->start_time());
EXPECT_EQ(*result->start_time(), fake_driver->mono_start_time().get());
EXPECT_GT(*result->start_time(), before_start.get());
EXPECT_TRUE(fake_driver->started());
received_callback = true;
});
RunLoopUntilIdle();
ASSERT_TRUE(received_callback);
// Now that we are started, we want to suddenly drop the RingBuffer connection.
(void)ring_buffer_client.UnbindMaybeGetEndpoint();
(void)control->client().UnbindMaybeGetEndpoint();
RunLoopUntilIdle();
control->server().WaitForShutdown();
}
{
auto control = CreateTestControlServer(device_to_control);
auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
auto received_callback = false;
ASSERT_TRUE(control->client().is_valid());
control->client()
->CreateRingBuffer({{
.options = kDefaultRingBufferOptions,
.ring_buffer_server = std::move(ring_buffer_server_end),
}})
.Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
EXPECT_TRUE(result.is_ok()) << result.error_value();
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
EXPECT_FALSE(fake_driver->started());
received_callback = false;
auto before_start = zx::clock::get_monotonic();
ring_buffer_client->Start({}).Then(
[&received_callback, before_start, &fake_driver](fidl::Result<RingBuffer::Start>& result) {
ASSERT_TRUE(result.is_ok()) << result.error_value();
ASSERT_TRUE(result->start_time());
EXPECT_EQ(*result->start_time(), fake_driver->mono_start_time().get());
EXPECT_GT(*result->start_time(), before_start.get());
EXPECT_TRUE(fake_driver->started());
received_callback = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(received_callback);
}
}
} // namespace
} // namespace media_audio