blob: ccb8e8c2896cc93dfd609296696121100a5be28c [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 <fuchsia/media/cpp/fidl.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/clock.h>
#include <zircon/device/audio.h>
#include "src/lib/fxl/strings/string_printf.h"
#include "src/media/audio/lib/test/hermetic_audio_test.h"
#include "src/media/audio/lib/test/renderer_shim.h"
namespace media::audio::test {
constexpr auto kSampleFormat = fuchsia::media::AudioSampleFormat::SIGNED_16;
constexpr int32_t kSampleRate = 8000;
constexpr int kChannelCount = 1;
static const auto kFormat = Format::Create<kSampleFormat>(kChannelCount, kSampleRate).value();
constexpr int kRingBufferFrames = kSampleRate; // 1s
static const int kRingBufferSamples = kRingBufferFrames * kFormat.channels();
static const int kRingBufferBytes = kRingBufferFrames * kFormat.bytes_per_frame();
//
// AudioAdminTest
//
// Base Class for testing simple playback and capture with policy rules.
class AudioAdminTest : public HermeticAudioTest {
protected:
// We add this duration, in MS, to our lead time to make sure mixing has
// completed. 5ms had a 0.5% failure rate when running in a loop.
static const int kSampleDelayAddition = 5;
static constexpr int16_t kInitialCaptureData = 0x7fff;
static constexpr int16_t kPlaybackData1 = 0x1111;
static constexpr int16_t kDuckedPlaybackData1 = 0x4e; // reduced by 35dB
static constexpr int16_t kPlaybackData2 = 0x2222;
static constexpr int16_t kVirtualInputSampleValue = 0x3333;
void SetUp() override;
void TearDown() override;
void SetUpVirtualAudioOutput();
void SetUpVirtualAudioInput();
AudioRendererShim<kSampleFormat>* SetUpRenderer(fuchsia::media::AudioRenderUsage usage,
int16_t data);
AudioCapturerShim<kSampleFormat>* SetUpCapturer(
fuchsia::media::AudioCapturerConfiguration configuration);
AudioCapturerShim<kSampleFormat>* SetUpCapturer(fuchsia::media::AudioCaptureUsage usage) {
fuchsia::media::InputAudioCapturerConfiguration input;
input.set_usage(usage);
return SetUpCapturer(fuchsia::media::AudioCapturerConfiguration::WithInput(std::move(input)));
}
AudioCapturerShim<kSampleFormat>* SetUpLoopbackCapturer() {
return SetUpCapturer(fuchsia::media::AudioCapturerConfiguration::WithLoopback(
fuchsia::media::LoopbackAudioCapturerConfiguration()));
}
zx_duration_t GetMinLeadTime(std::initializer_list<AudioRendererShim<kSampleFormat>*> renderers);
// Expect that the given packet contains nothing but the given samples.
void ExpectPacketContains(std::string label, const fuchsia::media::StreamPacket& packet,
const AudioBuffer<kSampleFormat>& payload,
size_t expected_frames_per_packet, int16_t expected_data);
};
// AudioAdminTest implementation
//
void AudioAdminTest::SetUp() {
HermeticAudioTest::SetUp();
SetUpVirtualAudioOutput();
SetUpVirtualAudioInput();
}
void AudioAdminTest::TearDown() {
ExpectNoOverflowsOrUnderflows();
HermeticAudioTest::TearDown();
}
// SetUpVirtualAudioOutput
//
// For loopback tests, setup the required audio output, using virtualaudio.
void AudioAdminTest::SetUpVirtualAudioOutput() {
const audio_stream_unique_id_t kUniqueId{{0x4a, 0x41, 0x49, 0x4a, 0x4a, 0x41, 0x49, 0x4a, 0x4a,
0x41, 0x49, 0x4a, 0x4a, 0x41, 0x49, 0x4a}};
CreateOutput(kUniqueId, kFormat, kRingBufferFrames);
}
void AudioAdminTest::SetUpVirtualAudioInput() {
const audio_stream_unique_id_t kUniqueId{{0x4a, 0x41, 0x49, 0x4a, 0x4a, 0x41, 0x49, 0x4a, 0x4a,
0x41, 0x49, 0x4a, 0x4a, 0x41, 0x49, 0x4b}};
auto input = CreateInput(kUniqueId, kFormat, kRingBufferFrames);
AudioBuffer buf(kFormat, kRingBufferFrames);
for (size_t k = 0; k < buf.samples().size(); k++) {
buf.samples()[k] = kVirtualInputSampleValue;
}
input->WriteRingBufferAt(0, &buf);
}
// SetUpRenderer
//
// For loopback tests, setup the first audio_renderer interface.
AudioRendererShim<kSampleFormat>* AudioAdminTest::SetUpRenderer(
fuchsia::media::AudioRenderUsage usage, int16_t data) {
auto r = CreateAudioRenderer(kFormat, kRingBufferFrames, usage);
AudioBuffer buf(kFormat, kRingBufferFrames);
for (size_t k = 0; k < buf.samples().size(); k++) {
buf.samples()[k] = data;
}
r->payload().Append(AudioBufferSlice(&buf));
return r;
}
// SetUpCapturer
//
// For loopback tests, setup an audio_capturer interface
AudioCapturerShim<kSampleFormat>* AudioAdminTest::SetUpCapturer(
fuchsia::media::AudioCapturerConfiguration configuration) {
auto c = CreateAudioCapturer(kFormat, kRingBufferFrames, std::move(configuration));
c->payload().Memset<kSampleFormat>(kInitialCaptureData);
return c;
}
zx_duration_t AudioAdminTest::GetMinLeadTime(
std::initializer_list<AudioRendererShim<kSampleFormat>*> renderers) {
zx_duration_t max_min_lead_time = 0;
for (auto renderer : renderers) {
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface. We use the longest
// latency of any of the renderers, but they should all have the same value.
max_min_lead_time = std::max(max_min_lead_time, renderer->min_lead_time().get());
}
return max_min_lead_time;
}
void AudioAdminTest::ExpectPacketContains(std::string label,
const fuchsia::media::StreamPacket& packet,
const AudioBuffer<kSampleFormat>& payload,
size_t expected_frames_per_packet,
int16_t expected_data) {
ASSERT_EQ(packet.payload_size, expected_frames_per_packet * kFormat.bytes_per_frame())
<< "unexpected frame count for packet " << label;
for (size_t f = 0; f < expected_frames_per_packet; f++) {
for (size_t c = 0; c < kFormat.channels(); c++) {
size_t offset =
(packet.payload_offset + f * kFormat.bytes_per_frame() + c * kFormat.bytes_per_sample()) %
kRingBufferBytes;
size_t sample = offset / kFormat.bytes_per_sample();
ASSERT_EQ(fxl::StringPrintf("0x%x", payload.samples()[sample]),
fxl::StringPrintf("0x%x", expected_data))
<< "unexpected value at sample[" << sample << "] for packet " << label;
}
}
}
// SingleRenderStream
//
// Creates a single output stream and a loopback capture and verifies it gets
// back what it puts in.
TEST_F(AudioAdminTest, SingleRenderStream) {
// Setup a policy rule that MEDIA being active will not affect a BACKGROUND
// capture.
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::MEDIA);
affected.set_capture_usage(fuchsia::media::AudioCaptureUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::NONE);
}
fuchsia::media::StreamPacket packet, captured;
// SetUp playback stream
auto renderer = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData1);
auto capturer = SetUpLoopbackCapturer();
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface
zx_duration_t sleep_duration = GetMinLeadTime({renderer});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
renderer->fidl()->Play(zx::clock::get_monotonic().get(), 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GE(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Add a callback for when we get our captured packet.
capturer->fidl().events().OnPacketProduced =
AddCallback("OnPacketProduced", [&captured](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured.payload_size == 0) {
captured = packet;
}
});
// Capture 10 frames of audio.
capturer->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that we got 10 frames as we expected.
ExpectPacketContains("captured", captured, capturer->SnapshotPayload(), 10, kPlaybackData1);
}
// RenderMuteCapture
//
// Creates a single output stream and a loopback capture that is muted due to
// the output stream and verifies it gets silence on it.
TEST_F(AudioAdminTest, RenderMuteCapture) {
// Setup a policy rule that MEDIA being active will mute a BACKGROUND
// capture.
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::SYSTEM_AGENT);
affected.set_capture_usage(fuchsia::media::AudioCaptureUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::MUTE);
}
fuchsia::media::StreamPacket packet, captured;
// SetUp playback stream
auto renderer = SetUpRenderer(fuchsia::media::AudioRenderUsage::SYSTEM_AGENT, kPlaybackData1);
auto capturer = SetUpCapturer(fuchsia::media::AudioCaptureUsage::BACKGROUND);
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface
zx_duration_t sleep_duration = GetMinLeadTime({renderer});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
renderer->fidl()->Play(zx::clock::get_monotonic().get(), 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GE(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Capture 10 samples of audio.
capturer->fidl().events().OnPacketProduced =
AddCallback("OnPacketProduced", [&captured](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured.payload_size == 0) {
captured = packet;
}
});
capturer->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that we got 10 samples as we expected.
ExpectPacketContains("captured", captured, capturer->SnapshotPayload(), 10, 0x0);
}
// CaptureMuteRender
//
// Creates a single output stream and a loopback capture and verifies that the
// Render stream is muted in the capturer.
TEST_F(AudioAdminTest, CaptureMuteRender) {
// Setup a policy rule that MEDIA being active will mute a BACKGROUND
// capture.
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_capture_usage(fuchsia::media::AudioCaptureUsage::SYSTEM_AGENT);
affected.set_render_usage(fuchsia::media::AudioRenderUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::MUTE);
}
// SetUp playback stream
auto renderer = SetUpRenderer(fuchsia::media::AudioRenderUsage::BACKGROUND, kPlaybackData1);
auto capturer = SetUpCapturer(fuchsia::media::AudioCaptureUsage::SYSTEM_AGENT);
// Immediately start this capturer so that it impacts policy.
capturer->fidl()->StartAsyncCapture(10);
auto loopback_capturer = SetUpLoopbackCapturer();
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface
zx_duration_t sleep_duration = GetMinLeadTime({renderer});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
{
fuchsia::media::StreamPacket packet;
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
}
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
renderer->fidl()->Play(zx::clock::get_monotonic().get(), 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GE(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Add a callback for when we get our captured packet.
fuchsia::media::StreamPacket loopback_captured;
bool produced_loopback_packet = false;
loopback_capturer->fidl().events().OnPacketProduced =
AddCallback("OnPacketProduced", [&loopback_captured, &produced_loopback_packet,
ref_time_received](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (packet.pts > ref_time_received && loopback_captured.payload_size == 0) {
loopback_captured = packet;
produced_loopback_packet = true;
}
});
// Capture 10 samples of audio.
loopback_capturer->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that we got 10 samples as we expected.
ExpectPacketContains("loopback_captured", loopback_captured, loopback_capturer->SnapshotPayload(),
10, 0x0);
}
// DualRenderStreamMix
//
// Creates a pair of output streams with different usages that the policy is to
// mix together, and a loopback capture and verifies it gets back what it puts
// in.
TEST_F(AudioAdminTest, DualRenderStreamMix) {
// Setup expected behavior from policy for this test
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::MEDIA);
affected.set_capture_usage(fuchsia::media::AudioCaptureUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::NONE);
}
// SetUp playback streams
auto renderer1 = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData1);
auto renderer2 = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData2);
// SetUp loopback capture
auto capturer = SetUpLoopbackCapturer();
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface.
zx_duration_t sleep_duration = GetMinLeadTime({renderer1, renderer2});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
for (auto renderer : {renderer1, renderer2}) {
fuchsia::media::StreamPacket packet;
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
}
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
auto playat = zx::clock::get_monotonic().get();
renderer1->fidl()->PlayNoReply(playat, 0);
// Only get the callback for the second renderer.
renderer2->fidl()->Play(playat, 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GT(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Capture 10 samples of audio.
fuchsia::media::StreamPacket captured;
capturer->fidl().events().OnPacketProduced =
AddCallback("OnPacketProduced", [&captured](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured.payload_size == 0) {
captured = packet;
}
});
capturer->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that we got 10 samples as we expected.
ExpectPacketContains("captured", captured, capturer->SnapshotPayload(), 10,
kPlaybackData1 + kPlaybackData2);
}
// DualRenderStreamDucking
//
// Creates a pair of output streams and a loopback capture and verifies it gets
// back what it puts in.
TEST_F(AudioAdminTest, DualRenderStreamDucking) {
// Setup expected behavior from policy for this test
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::INTERRUPTION);
affected.set_render_usage(fuchsia::media::AudioRenderUsage::MEDIA);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::DUCK);
}
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::INTERRUPTION);
affected.set_render_usage(fuchsia::media::AudioRenderUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::NONE);
}
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::MEDIA);
affected.set_render_usage(fuchsia::media::AudioRenderUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::NONE);
}
// SetUp playback streams
auto renderer1 = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData1);
auto renderer2 = SetUpRenderer(fuchsia::media::AudioRenderUsage::INTERRUPTION, kPlaybackData2);
// SetUp loopback capture
auto capturer = SetUpLoopbackCapturer();
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface.
zx_duration_t sleep_duration = GetMinLeadTime({renderer1, renderer2});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
for (auto renderer : {renderer1, renderer2}) {
fuchsia::media::StreamPacket packet;
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
}
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
auto playat = zx::clock::get_monotonic().get();
renderer1->fidl()->PlayNoReply(playat, 0);
// Only get the callback for the second renderer.
renderer2->fidl()->Play(playat, 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GT(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Capture 10 samples of audio.
fuchsia::media::StreamPacket captured;
capturer->fidl().events().OnPacketProduced =
AddCallback("OnPacketProduced", [&captured](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured.payload_size == 0) {
captured = packet;
}
});
capturer->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that we got 10 samples as we expected.
ExpectPacketContains("captured", captured, capturer->SnapshotPayload(), 10,
kDuckedPlaybackData1 + kPlaybackData2);
}
// DualRenderStreamMute
//
// Creates a pair of output streams and a loopback capture and verifies it gets
// back what it puts in.
TEST_F(AudioAdminTest, DualRenderStreamMute) {
// Setup expected behavior from policy for this test
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::MEDIA);
affected.set_render_usage(fuchsia::media::AudioRenderUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::MUTE);
}
// SetUp playback streams
auto renderer1 = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData1);
auto renderer2 = SetUpRenderer(fuchsia::media::AudioRenderUsage::BACKGROUND, kPlaybackData2);
// SetUp loopback capture
auto capturer = SetUpLoopbackCapturer();
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface.
zx_duration_t sleep_duration = GetMinLeadTime({renderer1});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
for (auto renderer : {renderer1, renderer2}) {
fuchsia::media::StreamPacket packet;
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
}
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
auto playat = zx::clock::get_monotonic().get();
renderer1->fidl()->PlayNoReply(playat, 0);
// Only get the callback for the second renderer.
renderer2->fidl()->Play(playat, 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GT(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Capture 10 samples of audio.
fuchsia::media::StreamPacket captured;
capturer->fidl().events().OnPacketProduced =
AddCallback("OnPacketProduced", [&captured](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured.payload_size == 0) {
captured = packet;
}
});
capturer->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that we got 10 samples as we expected.
ExpectPacketContains("captured", captured, capturer->SnapshotPayload(), 10, kPlaybackData1);
}
// DualCaptureStreamNone
//
// Creates a pair of loopback capture streams and a render stream and verifies
// capture streams both remain unaffected.
TEST_F(AudioAdminTest, DualCaptureStreamNone) {
// Setup expected behavior from policy for this test
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_render_usage(fuchsia::media::AudioRenderUsage::MEDIA);
affected.set_capture_usage(fuchsia::media::AudioCaptureUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::NONE);
}
// SetUp playback streams
auto renderer = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData1);
// SetUp loopback capture
auto capturer1 = SetUpCapturer(fuchsia::media::AudioCaptureUsage::BACKGROUND);
auto capturer2 = SetUpCapturer(fuchsia::media::AudioCaptureUsage::BACKGROUND);
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface.
zx_duration_t sleep_duration = GetMinLeadTime({renderer});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
{
fuchsia::media::StreamPacket packet;
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
}
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
auto playat = zx::clock::get_monotonic().get();
renderer->fidl()->Play(playat, 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GT(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Capture 10 samples of audio.
fuchsia::media::StreamPacket captured1;
capturer1->fidl().events().OnPacketProduced =
AddCallbackUnordered("OnPacketProduced", [&captured1](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured1.payload_size == 0) {
captured1 = packet;
}
});
fuchsia::media::StreamPacket captured2;
capturer2->fidl().events().OnPacketProduced =
AddCallbackUnordered("OnPacketProduced", [&captured2](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured2.payload_size == 0) {
captured2 = packet;
}
});
capturer1->fidl()->StartAsyncCapture(10);
capturer2->fidl()->StartAsyncCapture(10);
ExpectCallback();
// Check that all of the samples contain the expected data.
ExpectPacketContains("captured1", captured1, capturer1->SnapshotPayload(), 10,
kVirtualInputSampleValue);
ExpectPacketContains("captured2", captured2, capturer2->SnapshotPayload(), 10,
kVirtualInputSampleValue);
}
// DualCaptureStreamMute
//
// Creates a pair of loopback capture streams and a render stream and verifies
// capture streams of different usages can mute each other.
TEST_F(AudioAdminTest, DISABLED_DualCaptureStreamMute) {
// Setup expected behavior from policy for this test
audio_core_->ResetInteractions();
{
fuchsia::media::Usage active, affected;
active.set_capture_usage(fuchsia::media::AudioCaptureUsage::SYSTEM_AGENT);
affected.set_capture_usage(fuchsia::media::AudioCaptureUsage::BACKGROUND);
audio_core_->SetInteraction(std::move(active), std::move(affected),
fuchsia::media::Behavior::MUTE);
}
// SetUp playback streams
auto renderer = SetUpRenderer(fuchsia::media::AudioRenderUsage::MEDIA, kPlaybackData1);
// SetUp loopback capture
auto capturer1 = SetUpCapturer(fuchsia::media::AudioCaptureUsage::SYSTEM_AGENT);
auto capturer2 = SetUpCapturer(fuchsia::media::AudioCaptureUsage::BACKGROUND);
// Add a callback for when we get our captured packet.
fuchsia::media::StreamPacket captured1;
bool produced_packet1 = false;
capturer1->fidl().events().OnPacketProduced = AddCallback(
"OnPacketProduced", [&captured1, &produced_packet1](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured1.payload_size == 0) {
captured1 = packet;
produced_packet1 = true;
}
});
fuchsia::media::StreamPacket captured2;
bool produced_packet2 = false;
capturer2->fidl().events().OnPacketProduced = AddCallback(
"OnPacketProduced", [&captured2, &produced_packet2](fuchsia::media::StreamPacket packet) {
// We only care about the first set of captured samples
if (captured2.payload_size == 0) {
captured2 = packet;
produced_packet2 = true;
}
});
// Get the minimum duration after submitting a packet to when we can start
// capturing what we sent on the loopback interface.
zx_duration_t sleep_duration = GetMinLeadTime({renderer});
ASSERT_NE(sleep_duration, 0) << "Failed to get MinLeadTime";
{
fuchsia::media::StreamPacket packet;
packet.payload_offset = 0;
packet.payload_size = kRingBufferBytes;
renderer->fidl()->SendPacketNoReply(packet);
}
int64_t ref_time_received = -1;
int64_t media_time_received = -1;
// Start playing right now, so that after we've delayed at least 1 leadtime,
// we should have mixed audio available for capture. Our playback is sized
// to be much much larger than our capture to prevent test flakes.
auto playat = zx::clock::get_monotonic().get();
renderer->fidl()->Play(playat, 0,
AddCallback("Play", [&ref_time_received, &media_time_received](
int64_t ref_time, int64_t media_time) {
ref_time_received = ref_time;
media_time_received = media_time;
}));
ExpectCallback();
// We expect that media_time 0 played back at some point after the 'zero'
// time on the system.
EXPECT_EQ(media_time_received, 0);
EXPECT_GT(ref_time_received, 0);
// Give the playback some time to get mixed.
zx_nanosleep(zx_deadline_after(sleep_duration));
// Capture 10 samples of audio.
capturer1->fidl()->StartAsyncCapture(10);
capturer2->fidl()->StartAsyncCapture(10);
RunLoopUntil(
[&produced_packet1, &produced_packet2]() { return produced_packet1 && produced_packet2; });
// Check that we got 10 samples as we expected.
ExpectPacketContains("captured1", captured1, capturer1->SnapshotPayload(), 10, kPlaybackData1);
ExpectPacketContains("captured2", captured2, capturer2->SnapshotPayload(), 10, 0x0);
}
} // namespace media::audio::test