blob: bf51ea8297e07b21758f65046ca457825ac968b4 [file] [log] [blame]
// Copyright 2023 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/zx/clock.h>
#include "src/media/audio/audio_core/test/api/audio_capturer_test_shared.h"
#include "src/media/audio/lib/clock/clone_mono.h"
namespace media::audio::test {
class AudioCapturerErrorTestOldAPI : public AudioCapturerTestOldAPI {};
class AudioCapturerErrorTest : public AudioCapturerTest {};
//
// Test cases
//
// AudioCapturer implements the base classes StreamBufferSet and StreamSource, in addition to its
// own FIDL methods.
// TODO(https://fxbug.dev/318431483): more extensively test StreamBufferSet
// - AddPayloadBuffer(uint32 id, handle<vmo> payload_buffer);
// Also: null or bad handle
// - RemovePayloadBuffer(uint32 id);
// unknown or already-removed id
// - also, apply same tests to AudioRenderer and AudioCapturer
// (although their implementations within AudioCore differ somewhat).
// TODO(https://fxbug.dev/318432150): more extensively test StreamSource
// - ->OnPacketProduced(StreamPacket packet);
// Always received for every packet - even malformed ones?
// - ->OnEndOfStream();
// Also proper sequence vis-a-vis other completion and disconnect callbacks
// - DiscardAllPacketsNoReply() post-stop
// - all capture StreamPacket flags
// TODO(https://fxbug.dev/318433705): more extensively test capture data pipeline methods
// - SetPcmStreamType(AudioStreamType stream_type);
// Also when already set, when packets submitted, when started, malformed StreamType
// - CaptureAt(uint32 id, uint32 offset, uint32 num_frames)
// -> (StreamPacket captured_packet);
// Also when in async capture, before format set, before packets submitted
// negative testing: bad id, bad offset, 0/tiny/huge num_frames
// - StartAsyncCapture(uint32 frames_per_packet);
// Also when already started, before format set, before packets submitted
// negative testing: 0/tiny/huge frames_per_packet (bigger than packet)
// - StopAsyncCapture() before format set, before packets submitted
// - StopAsyncCaptureNoReply() same
// - GetStreamType() -> (StreamType stream_type);
// negative testing: before format set
TEST_F(AudioCapturerErrorTestOldAPI, AddPayloadBufferBadIdShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer(1);
ExpectDisconnect(audio_capturer());
}
TEST_F(AudioCapturerErrorTestOldAPI, DiscardAllWithNoVmoShouldDisconnect) {
SetFormat();
audio_capturer()->DiscardAllPackets(AddUnexpectedCallback("DiscardAllPackets"));
ExpectDisconnect(audio_capturer());
}
// DiscardAllPackets should fail, if async capture is active
TEST_F(AudioCapturerErrorTestOldAPI, DiscardAllDuringAsyncCaptureShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer().events().OnPacketProduced = AddCallback("OnPacketProduced");
audio_capturer()->StartAsyncCapture(1600);
ExpectCallbacks();
audio_capturer()->DiscardAllPackets(AddUnexpectedCallback("DiscardAllPackets"));
ExpectDisconnect(audio_capturer());
}
// DiscardAllPackets should fail, if async capture is in the process of stopping
TEST_F(AudioCapturerErrorTestOldAPI, DISABLED_DiscardAllAsyncCaptureStoppingShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer().events().OnPacketProduced = AddCallback("OnPacketProduced");
audio_capturer()->StartAsyncCapture(1600);
ExpectCallbacks();
audio_capturer()->StopAsyncCaptureNoReply();
audio_capturer()->DiscardAllPackets(AddUnexpectedCallback("DiscardAllPackets"));
ExpectDisconnect(audio_capturer());
}
TEST_F(AudioCapturerErrorTestOldAPI, DiscardAllNoReplyWithNoVmoShouldDisconnect) {
SetFormat();
audio_capturer()->DiscardAllPacketsNoReply();
ExpectDisconnect(audio_capturer());
}
// DiscardAllPacketsNoReply should fail, if async capture is active
TEST_F(AudioCapturerErrorTestOldAPI, DiscardAllNoReplyDuringAsyncCaptureShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer().events().OnPacketProduced = AddCallback("OnPacketProduced");
audio_capturer()->StartAsyncCapture(1600);
ExpectCallbacks();
audio_capturer()->DiscardAllPacketsNoReply();
ExpectDisconnect(audio_capturer());
}
// DiscardAllPacketsNoReply should fail, if async capture is in the process of stopping
TEST_F(AudioCapturerErrorTestOldAPI,
DISABLED_DiscardAllNoReplyAsyncCaptureStoppingShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer().events().OnPacketProduced = AddCallback("OnPacketProduced");
audio_capturer()->StartAsyncCapture(1600);
ExpectCallbacks();
audio_capturer()->StopAsyncCaptureNoReply();
audio_capturer()->DiscardAllPacketsNoReply();
ExpectDisconnect(audio_capturer());
}
TEST_F(AudioCapturerErrorTestOldAPI, StopWhenStoppedShouldDisconnect) {
audio_capturer()->StopAsyncCapture(AddUnexpectedCallback("StopAsyncCapture"));
ExpectDisconnect(audio_capturer());
}
TEST_F(AudioCapturerErrorTestOldAPI, StopNoReplyWhenStoppedShouldDisconnect) {
audio_capturer()->StopAsyncCaptureNoReply();
ExpectDisconnect(audio_capturer());
}
// Setting a payload buffer should fail, if format has not yet been set (even if it was retrieved).
TEST_F(AudioCapturerErrorTestOldAPI, AddPayloadBufferBeforeSetFormatShouldDisconnect) {
// Give time for Disconnect to occur, if it must.
audio_capturer()->GetStreamType(AddCallback("GetStreamType"));
ExpectCallbacks();
// Calling this before SetPcmStreamType should fail
SetUpPayloadBuffer();
ExpectDisconnect(audio_capturer());
}
// inadequate ZX_RIGHTS -- no DUPLICATE should cause GetReferenceClock to fail.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockNoDuplicateShouldDisconnect) {
zx::clock dupe_clock, orig_clock = clock::CloneOfMonotonic();
ASSERT_EQ(orig_clock.duplicate(kClockRights & ~ZX_RIGHT_DUPLICATE, &dupe_clock), ZX_OK);
audio_capturer()->SetReferenceClock(std::move(dupe_clock));
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// inadequate ZX_RIGHTS -- no READ should cause GetReferenceClock to fail.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockNoReadShouldDisconnect) {
zx::clock dupe_clock, orig_clock = clock::CloneOfMonotonic();
ASSERT_EQ(orig_clock.duplicate(kClockRights & ~ZX_RIGHT_READ, &dupe_clock), ZX_OK);
audio_capturer()->SetReferenceClock(std::move(dupe_clock));
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Regardless of the type of clock, calling SetReferenceClock a second time should fail.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockCustomThenFlexibleShouldDisconnect) {
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
audio_capturer()->SetReferenceClock(zx::clock(ZX_HANDLE_INVALID));
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Regardless of the type of clock, calling SetReferenceClock a second time should fail.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockSecondCustomShouldDisconnect) {
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Regardless of the type of clock, calling SetReferenceClock a second time should fail.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockSecondFlexibleShouldDisconnect) {
audio_capturer()->SetReferenceClock(zx::clock(ZX_HANDLE_INVALID));
audio_capturer()->SetReferenceClock(zx::clock(ZX_HANDLE_INVALID));
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Regardless of the type of clock, calling SetReferenceClock a second time should fail.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockFlexibleThenCustomShouldDisconnect) {
audio_capturer()->SetReferenceClock(zx::clock(ZX_HANDLE_INVALID));
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Setting the reference clock should fail, once payload buffer has been added.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockAfterBufferShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Setting the reference clock should fail, any time after payload buffer has been added.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockDuringCaptureShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer()->CaptureAt(0, 0, 8000, [](fuchsia::media::StreamPacket) {
// Don't fail if this completes before SetReferenceClock can run.
GTEST_SKIP() << "CaptureAt completed before SetReferenceClock could cancel it";
});
audio_capturer()->SetReferenceClock(clock::CloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Setting the reference clock should fail, even after all active capture packets have returned.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockAfterCaptureShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer()->CaptureAt(0, 0, 8000, AddCallback("CaptureAt"));
ExpectCallbacks();
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Setting the reference clock should fail, any time after capture has started (even if cancelled).
//
// TODO(https://fxbug.dev/42134885): deflake and re-enable.
TEST_F(AudioCapturerClockTestOldAPI, DISABLED_SetRefClockCaptureCancelledShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer()->CaptureAt(0, 0, 8000, [](fuchsia::media::StreamPacket) {});
audio_capturer()->DiscardAllPackets(AddCallback("DiscardAllPackets"));
ExpectCallbacks();
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Setting the reference clock should fail, if at least one capture packet is active.
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockDuringAsyncCaptureShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer().events().OnPacketProduced = AddCallback("OnPacketProduced");
audio_capturer()->StartAsyncCapture(1600);
ExpectCallbacks();
audio_capturer()->SetReferenceClock(clock::CloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
// Setting the reference clock should fail, any time after capture has started (even if stopped).
TEST_F(AudioCapturerClockTestOldAPI, SetRefClockAfterAsyncCaptureShouldDisconnect) {
SetFormat();
SetUpPayloadBuffer();
audio_capturer().events().OnPacketProduced = AddCallback("OnPacketProduced");
audio_capturer()->StartAsyncCapture(1600);
ExpectCallbacks();
audio_capturer()->StopAsyncCapture(AddCallback("StopAsyncCapture"));
ExpectCallbacks();
audio_capturer()->SetReferenceClock(clock::AdjustableCloneOfMonotonic());
WaitBeforeClockRelatedDisconnect();
ExpectDisconnect(audio_capturer());
}
} // namespace media::audio::test