// Copyright (c) 2012 The Chromium 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 "base/macros.h" #include "base/memory/scoped_ptr.h" #include "media/base/audio_buffer.h" #include "media/base/audio_bus.h" #include "media/base/audio_splicer.h" #include "media/base/audio_timestamp_helper.h" #include "media/base/test_helpers.h" #include "media/base/timestamp_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { // Do not change this format. AddInput() and GetValue() only work with float. static const SampleFormat kSampleFormat = kSampleFormatF32; static_assert(kSampleFormat == kSampleFormatF32, "invalid splice format"); static const int kChannels = 1; static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_MONO; static const int kDefaultSampleRate = 44100; static const int kDefaultBufferSize = 100; class AudioSplicerTest : public ::testing::Test { public: AudioSplicerTest() : splicer_(kDefaultSampleRate, new MediaLog()), input_timestamp_helper_(kDefaultSampleRate) { input_timestamp_helper_.SetBaseTimestamp(base::TimeDelta()); } scoped_refptr GetNextInputBuffer(float value) { return GetNextInputBuffer(value, kDefaultBufferSize); } scoped_refptr GetNextInputBuffer(float value, int frame_size) { scoped_refptr buffer = MakeAudioBuffer(kSampleFormat, kChannelLayout, kChannels, kDefaultSampleRate, value, 0.0f, frame_size, input_timestamp_helper_.GetTimestamp()); input_timestamp_helper_.AddFrames(frame_size); return buffer; } float GetValue(const scoped_refptr& buffer) { return reinterpret_cast(buffer->channel_data()[0])[0]; } bool VerifyData(const scoped_refptr& buffer, float value) { int frames = buffer->frame_count(); scoped_ptr bus = AudioBus::Create(kChannels, frames); buffer->ReadFrames(frames, 0, 0, bus.get()); for (int ch = 0; ch < buffer->channel_count(); ++ch) { for (int i = 0; i < frames; ++i) { if (bus->channel(ch)[i] != value) return false; } } return true; } void VerifyNextBuffer(const scoped_refptr& input) { ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr output = splicer_.GetNextBuffer(); EXPECT_EQ(input->timestamp(), output->timestamp()); EXPECT_EQ(input->duration(), output->duration()); EXPECT_EQ(input->frame_count(), output->frame_count()); EXPECT_TRUE(VerifyData(output, GetValue(input))); } void VerifyPreSpliceOutput( const scoped_refptr& overlapped_buffer, const scoped_refptr& overlapping_buffer, int expected_pre_splice_size, base::TimeDelta expected_pre_splice_duration) { ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr pre_splice_output = splicer_.GetNextBuffer(); EXPECT_EQ(overlapped_buffer->timestamp(), pre_splice_output->timestamp()); EXPECT_EQ(expected_pre_splice_size, pre_splice_output->frame_count()); EXPECT_EQ(expected_pre_splice_duration, pre_splice_output->duration()); EXPECT_TRUE(VerifyData(pre_splice_output, GetValue(overlapped_buffer))); } void VerifyCrossfadeOutput( const scoped_refptr& overlapped_buffer_1, const scoped_refptr& overlapped_buffer_2, const scoped_refptr& overlapping_buffer, int second_overlap_index, int expected_crossfade_size, base::TimeDelta expected_crossfade_duration) { ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr crossfade_output = splicer_.GetNextBuffer(); EXPECT_EQ(expected_crossfade_size, crossfade_output->frame_count()); EXPECT_EQ(expected_crossfade_duration, crossfade_output->duration()); // The splice timestamp may be adjusted by a microsecond. EXPECT_NEAR(overlapping_buffer->timestamp().InMicroseconds(), crossfade_output->timestamp().InMicroseconds(), 1); // Verify the actual crossfade. const int frames = crossfade_output->frame_count(); float overlapped_value = GetValue(overlapped_buffer_1); const float overlapping_value = GetValue(overlapping_buffer); scoped_ptr bus = AudioBus::Create(kChannels, frames); crossfade_output->ReadFrames(frames, 0, 0, bus.get()); for (int ch = 0; ch < crossfade_output->channel_count(); ++ch) { float cf_ratio = 0; const float cf_increment = 1.0f / frames; for (int i = 0; i < frames; ++i, cf_ratio += cf_increment) { if (overlapped_buffer_2.get() && i >= second_overlap_index) overlapped_value = GetValue(overlapped_buffer_2); const float actual = bus->channel(ch)[i]; const float expected = (1.0f - cf_ratio) * overlapped_value + cf_ratio * overlapping_value; ASSERT_FLOAT_EQ(expected, actual) << "i=" << i; } } } bool AddInput(const scoped_refptr& input) { // Since the splicer doesn't make copies it's working directly on the input // buffers. We must make a copy before adding to ensure the original buffer // is not modified in unexpected ways. scoped_refptr buffer_copy = input->end_of_stream() ? AudioBuffer::CreateEOSBuffer() : AudioBuffer::CopyFrom(kSampleFormat, input->channel_layout(), input->channel_count(), input->sample_rate(), input->frame_count(), &input->channel_data()[0], input->timestamp()); return splicer_.AddInput(buffer_copy); } base::TimeDelta max_crossfade_duration() { return splicer_.max_crossfade_duration_; } protected: AudioSplicer splicer_; AudioTimestampHelper input_timestamp_helper_; DISALLOW_COPY_AND_ASSIGN(AudioSplicerTest); }; TEST_F(AudioSplicerTest, PassThru) { EXPECT_FALSE(splicer_.HasNextBuffer()); // Test single buffer pass-thru behavior. scoped_refptr input_1 = GetNextInputBuffer(0.1f); EXPECT_TRUE(AddInput(input_1)); VerifyNextBuffer(input_1); EXPECT_FALSE(splicer_.HasNextBuffer()); // Test that multiple buffers can be queued in the splicer. scoped_refptr input_2 = GetNextInputBuffer(0.2f); scoped_refptr input_3 = GetNextInputBuffer(0.3f); EXPECT_TRUE(AddInput(input_2)); EXPECT_TRUE(AddInput(input_3)); VerifyNextBuffer(input_2); VerifyNextBuffer(input_3); EXPECT_FALSE(splicer_.HasNextBuffer()); } TEST_F(AudioSplicerTest, Reset) { scoped_refptr input_1 = GetNextInputBuffer(0.1f); EXPECT_TRUE(AddInput(input_1)); ASSERT_TRUE(splicer_.HasNextBuffer()); splicer_.Reset(); EXPECT_FALSE(splicer_.HasNextBuffer()); // Add some bytes to the timestamp helper so that the // next buffer starts many frames beyond the end of // |input_1|. This is to make sure that Reset() actually // clears its state and doesn't try to insert a gap. input_timestamp_helper_.AddFrames(100); // Verify that a new input buffer passes through as expected. scoped_refptr input_2 = GetNextInputBuffer(0.2f); EXPECT_TRUE(AddInput(input_2)); VerifyNextBuffer(input_2); EXPECT_FALSE(splicer_.HasNextBuffer()); } TEST_F(AudioSplicerTest, EndOfStream) { scoped_refptr input_1 = GetNextInputBuffer(0.1f); scoped_refptr input_2 = AudioBuffer::CreateEOSBuffer(); scoped_refptr input_3 = GetNextInputBuffer(0.2f); EXPECT_TRUE(input_2->end_of_stream()); EXPECT_TRUE(AddInput(input_1)); EXPECT_TRUE(AddInput(input_2)); VerifyNextBuffer(input_1); scoped_refptr output_2 = splicer_.GetNextBuffer(); EXPECT_FALSE(splicer_.HasNextBuffer()); EXPECT_TRUE(output_2->end_of_stream()); // Verify that buffers can be added again after Reset(). splicer_.Reset(); EXPECT_TRUE(AddInput(input_3)); VerifyNextBuffer(input_3); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test the gap insertion code. // +--------------+ +--------------+ // |11111111111111| |22222222222222| // +--------------+ +--------------+ // Results in: // +--------------+----+--------------+ // |11111111111111|0000|22222222222222| // +--------------+----+--------------+ TEST_F(AudioSplicerTest, GapInsertion) { scoped_refptr input_1 = GetNextInputBuffer(0.1f); // Add bytes to the timestamp helper so that the next buffer // will have a starting timestamp that indicates a gap is // present. const int kGapSize = 7; input_timestamp_helper_.AddFrames(kGapSize); scoped_refptr input_2 = GetNextInputBuffer(0.2f); EXPECT_TRUE(AddInput(input_1)); EXPECT_TRUE(AddInput(input_2)); // Verify that the first input buffer passed through unmodified. VerifyNextBuffer(input_1); // Verify the contents of the gap buffer. scoped_refptr output_2 = splicer_.GetNextBuffer(); base::TimeDelta gap_timestamp = input_1->timestamp() + input_1->duration(); base::TimeDelta gap_duration = input_2->timestamp() - gap_timestamp; EXPECT_GT(gap_duration, base::TimeDelta()); EXPECT_EQ(gap_timestamp, output_2->timestamp()); EXPECT_NEAR( gap_duration.InMicroseconds(), output_2->duration().InMicroseconds(), 1); EXPECT_EQ(kGapSize, output_2->frame_count()); EXPECT_TRUE(VerifyData(output_2, 0.0f)); // Verify that the second input buffer passed through unmodified. VerifyNextBuffer(input_2); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test that an error is signalled when the gap between input buffers is // too large. TEST_F(AudioSplicerTest, GapTooLarge) { scoped_refptr input_1 = GetNextInputBuffer(0.1f); // Add a seconds worth of bytes so that an unacceptably large // gap exists between |input_1| and |input_2|. const int kGapSize = kDefaultSampleRate; input_timestamp_helper_.AddFrames(kGapSize); scoped_refptr input_2 = GetNextInputBuffer(0.2f); EXPECT_TRUE(AddInput(input_1)); EXPECT_FALSE(AddInput(input_2)); VerifyNextBuffer(input_1); // Verify that the second buffer is not available. EXPECT_FALSE(splicer_.HasNextBuffer()); // Reset the timestamp helper so it can generate a buffer that is // right after |input_1|. input_timestamp_helper_.SetBaseTimestamp( input_1->timestamp() + input_1->duration()); // Verify that valid buffers are still accepted. scoped_refptr input_3 = GetNextInputBuffer(0.3f); EXPECT_TRUE(AddInput(input_3)); VerifyNextBuffer(input_3); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Verifies that an error is signalled if AddInput() is called // with a timestamp that is earlier than the first buffer added. TEST_F(AudioSplicerTest, BufferAddedBeforeBase) { input_timestamp_helper_.SetBaseTimestamp( base::TimeDelta::FromMicroseconds(10)); scoped_refptr input_1 = GetNextInputBuffer(0.1f); // Reset the timestamp helper so the next buffer will have a timestamp earlier // than |input_1|. input_timestamp_helper_.SetBaseTimestamp(base::TimeDelta::FromSeconds(0)); scoped_refptr input_2 = GetNextInputBuffer(0.1f); EXPECT_GT(input_1->timestamp(), input_2->timestamp()); EXPECT_TRUE(AddInput(input_1)); EXPECT_FALSE(AddInput(input_2)); } // Test when one buffer partially overlaps another. // +--------------+ // |11111111111111| // +--------------+ // +--------------+ // |22222222222222| // +--------------+ // Results in: // +--------------+----------+ // |11111111111111|2222222222| // +--------------+----------+ TEST_F(AudioSplicerTest, PartialOverlap) { scoped_refptr input_1 = GetNextInputBuffer(0.1f); // Reset timestamp helper so that the next buffer will have a // timestamp that starts in the middle of |input_1|. const int kOverlapSize = input_1->frame_count() / 4; input_timestamp_helper_.SetBaseTimestamp(input_1->timestamp()); input_timestamp_helper_.AddFrames(input_1->frame_count() - kOverlapSize); scoped_refptr input_2 = GetNextInputBuffer(0.2f); EXPECT_TRUE(AddInput(input_1)); EXPECT_TRUE(AddInput(input_2)); // Verify that the first input buffer passed through unmodified. VerifyNextBuffer(input_1); ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr output_2 = splicer_.GetNextBuffer(); EXPECT_FALSE(splicer_.HasNextBuffer()); // Verify that the second input buffer was truncated to only contain // the samples that are after the end of |input_1|. base::TimeDelta expected_timestamp = input_1->timestamp() + input_1->duration(); base::TimeDelta expected_duration = (input_2->timestamp() + input_2->duration()) - expected_timestamp; EXPECT_EQ(expected_timestamp, output_2->timestamp()); EXPECT_EQ(expected_duration, output_2->duration()); EXPECT_TRUE(VerifyData(output_2, GetValue(input_2))); } // Test that an input buffer that is completely overlapped by a buffer // that was already added is dropped. // +--------------+ // |11111111111111| // +--------------+ // +-----+ // |22222| // +-----+ // +-------------+ // |3333333333333| // +-------------+ // Results in: // +--------------+-------------+ // |11111111111111|3333333333333| // +--------------+-------------+ TEST_F(AudioSplicerTest, DropBuffer) { scoped_refptr input_1 = GetNextInputBuffer(0.1f); // Reset timestamp helper so that the next buffer will have a // timestamp that starts in the middle of |input_1|. const int kOverlapOffset = input_1->frame_count() / 2; const int kOverlapSize = input_1->frame_count() / 4; input_timestamp_helper_.SetBaseTimestamp(input_1->timestamp()); input_timestamp_helper_.AddFrames(kOverlapOffset); scoped_refptr input_2 = GetNextInputBuffer(0.2f, kOverlapSize); // Reset the timestamp helper so the next buffer will be right after // |input_1|. input_timestamp_helper_.SetBaseTimestamp(input_1->timestamp()); input_timestamp_helper_.AddFrames(input_1->frame_count()); scoped_refptr input_3 = GetNextInputBuffer(0.3f); EXPECT_TRUE(AddInput(input_1)); EXPECT_TRUE(AddInput(input_2)); EXPECT_TRUE(AddInput(input_3)); VerifyNextBuffer(input_1); VerifyNextBuffer(input_3); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test crossfade when one buffer partially overlaps another. // +--------------+ // |11111111111111| // +--------------+ // +--------------+ // |22222222222222| // +--------------+ // Results in: // +----------+----+----------+ // |1111111111|xxxx|2222222222| // +----------+----+----------+ // Where "xxxx" represents the crossfaded portion of the signal. TEST_F(AudioSplicerTest, PartialOverlapCrossfade) { const int kCrossfadeSize = input_timestamp_helper_.GetFramesToTarget(max_crossfade_duration()); const int kBufferSize = kCrossfadeSize * 2; scoped_refptr extra_pre_splice_buffer = GetNextInputBuffer(0.2f, kBufferSize); scoped_refptr overlapped_buffer = GetNextInputBuffer(1.0f, kBufferSize); // Reset timestamp helper so that the next buffer will have a timestamp that // starts in the middle of |overlapped_buffer|. input_timestamp_helper_.SetBaseTimestamp(overlapped_buffer->timestamp()); input_timestamp_helper_.AddFrames(overlapped_buffer->frame_count() - kCrossfadeSize); splicer_.SetSpliceTimestamp(input_timestamp_helper_.GetTimestamp()); scoped_refptr overlapping_buffer = GetNextInputBuffer(0.0f, kBufferSize); // |extra_pre_splice_buffer| is entirely before the splice and should be ready // for output. EXPECT_TRUE(AddInput(extra_pre_splice_buffer)); VerifyNextBuffer(extra_pre_splice_buffer); // The splicer should be internally queuing input since |overlapped_buffer| is // part of the splice. EXPECT_TRUE(AddInput(overlapped_buffer)); EXPECT_FALSE(splicer_.HasNextBuffer()); // |overlapping_buffer| completes the splice. splicer_.SetSpliceTimestamp(kNoTimestamp()); EXPECT_TRUE(AddInput(overlapping_buffer)); ASSERT_TRUE(splicer_.HasNextBuffer()); // Add one more buffer to make sure it's passed through untouched. scoped_refptr extra_post_splice_buffer = GetNextInputBuffer(0.5f, kBufferSize); EXPECT_TRUE(AddInput(extra_post_splice_buffer)); VerifyPreSpliceOutput(overlapped_buffer, overlapping_buffer, 221, base::TimeDelta::FromMicroseconds(5011)); // Due to rounding the crossfade size may vary by up to a frame. const int kExpectedCrossfadeSize = 220; EXPECT_NEAR(kExpectedCrossfadeSize, kCrossfadeSize, 1); VerifyCrossfadeOutput(overlapped_buffer, NULL, overlapping_buffer, 0, kExpectedCrossfadeSize, base::TimeDelta::FromMicroseconds(4988)); // Retrieve the remaining portion after crossfade. ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr post_splice_output = splicer_.GetNextBuffer(); EXPECT_EQ(base::TimeDelta::FromMicroseconds(20022), post_splice_output->timestamp()); EXPECT_EQ(overlapping_buffer->frame_count() - kExpectedCrossfadeSize, post_splice_output->frame_count()); EXPECT_EQ(base::TimeDelta::FromMicroseconds(5034), post_splice_output->duration()); EXPECT_TRUE(VerifyData(post_splice_output, GetValue(overlapping_buffer))); VerifyNextBuffer(extra_post_splice_buffer); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test crossfade when one buffer partially overlaps another, but an end of // stream buffer is received before the crossfade duration is reached. // +--------------+ // |11111111111111| // +--------------+ // +---------++---+ // |222222222||EOS| // +---------++---+ // Results in: // +----------+----+----++---+ // |1111111111|xxxx|2222||EOS| // +----------+----+----++---+ // Where "x" represents the crossfaded portion of the signal. TEST_F(AudioSplicerTest, PartialOverlapCrossfadeEndOfStream) { const int kCrossfadeSize = input_timestamp_helper_.GetFramesToTarget(max_crossfade_duration()); scoped_refptr overlapped_buffer = GetNextInputBuffer(1.0f, kCrossfadeSize * 2); // Reset timestamp helper so that the next buffer will have a timestamp that // starts 3/4 of the way into |overlapped_buffer|. input_timestamp_helper_.SetBaseTimestamp(overlapped_buffer->timestamp()); input_timestamp_helper_.AddFrames(3 * overlapped_buffer->frame_count() / 4); splicer_.SetSpliceTimestamp(input_timestamp_helper_.GetTimestamp()); scoped_refptr overlapping_buffer = GetNextInputBuffer(0.0f, kCrossfadeSize / 3); // The splicer should be internally queuing input since |overlapped_buffer| is // part of the splice. EXPECT_TRUE(AddInput(overlapped_buffer)); EXPECT_FALSE(splicer_.HasNextBuffer()); // |overlapping_buffer| should not have enough data to complete the splice, so // ensure output is not available. splicer_.SetSpliceTimestamp(kNoTimestamp()); EXPECT_TRUE(AddInput(overlapping_buffer)); EXPECT_FALSE(splicer_.HasNextBuffer()); // Now add an EOS buffer which should complete the splice. EXPECT_TRUE(AddInput(AudioBuffer::CreateEOSBuffer())); VerifyPreSpliceOutput(overlapped_buffer, overlapping_buffer, 331, base::TimeDelta::FromMicroseconds(7505)); VerifyCrossfadeOutput(overlapped_buffer, NULL, overlapping_buffer, 0, overlapping_buffer->frame_count(), overlapping_buffer->duration()); // Ensure the last buffer is an EOS buffer. ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr post_splice_output = splicer_.GetNextBuffer(); EXPECT_TRUE(post_splice_output->end_of_stream()); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test crossfade when one buffer partially overlaps another, but the amount of // overlapped data is less than the crossfade duration. // +------------+ // |111111111111| // +------------+ // +--------------+ // |22222222222222| // +--------------+ // Results in: // +----------+-+------------+ // |1111111111|x|222222222222| // +----------+-+------------+ // Where "x" represents the crossfaded portion of the signal. TEST_F(AudioSplicerTest, PartialOverlapCrossfadeShortPreSplice) { const int kCrossfadeSize = input_timestamp_helper_.GetFramesToTarget(max_crossfade_duration()); scoped_refptr overlapped_buffer = GetNextInputBuffer(1.0f, kCrossfadeSize / 2); // Reset timestamp helper so that the next buffer will have a timestamp that // starts in the middle of |overlapped_buffer|. input_timestamp_helper_.SetBaseTimestamp(overlapped_buffer->timestamp()); input_timestamp_helper_.AddFrames(overlapped_buffer->frame_count() / 2); splicer_.SetSpliceTimestamp(input_timestamp_helper_.GetTimestamp()); scoped_refptr overlapping_buffer = GetNextInputBuffer(0.0f, kCrossfadeSize * 2); // The splicer should be internally queuing input since |overlapped_buffer| is // part of the splice. EXPECT_TRUE(AddInput(overlapped_buffer)); EXPECT_FALSE(splicer_.HasNextBuffer()); // |overlapping_buffer| completes the splice. splicer_.SetSpliceTimestamp(kNoTimestamp()); EXPECT_TRUE(AddInput(overlapping_buffer)); const int kExpectedPreSpliceSize = 55; const base::TimeDelta kExpectedPreSpliceDuration = base::TimeDelta::FromMicroseconds(1247); VerifyPreSpliceOutput(overlapped_buffer, overlapping_buffer, kExpectedPreSpliceSize, kExpectedPreSpliceDuration); VerifyCrossfadeOutput(overlapped_buffer, NULL, overlapping_buffer, 0, kExpectedPreSpliceSize, kExpectedPreSpliceDuration); // Retrieve the remaining portion after crossfade. ASSERT_TRUE(splicer_.HasNextBuffer()); scoped_refptr post_splice_output = splicer_.GetNextBuffer(); EXPECT_EQ(overlapping_buffer->timestamp() + kExpectedPreSpliceDuration, post_splice_output->timestamp()); EXPECT_EQ(overlapping_buffer->frame_count() - kExpectedPreSpliceSize, post_splice_output->frame_count()); EXPECT_EQ(overlapping_buffer->duration() - kExpectedPreSpliceDuration, post_splice_output->duration()); EXPECT_TRUE(VerifyData(post_splice_output, GetValue(overlapping_buffer))); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test behavior when a splice frame is incorrectly marked and does not actually // overlap. // +----------+ // |1111111111| // +----------+ // +--------------+ // |22222222222222| // +--------------+ // Results in: // +----------+--------------+ // |1111111111|22222222222222| // +----------+--------------+ TEST_F(AudioSplicerTest, IncorrectlyMarkedSplice) { const int kBufferSize = input_timestamp_helper_.GetFramesToTarget(max_crossfade_duration()) * 2; scoped_refptr first_buffer = GetNextInputBuffer(1.0f, kBufferSize); // Fuzz the duration slightly so that the buffer overlaps the splice timestamp // by a microsecond, which is not enough to crossfade. const base::TimeDelta kSpliceTimestamp = input_timestamp_helper_.GetTimestamp() - base::TimeDelta::FromMicroseconds(1); splicer_.SetSpliceTimestamp(kSpliceTimestamp); scoped_refptr second_buffer = GetNextInputBuffer(0.0f, kBufferSize); second_buffer->set_timestamp(kSpliceTimestamp); // The splicer should be internally queuing input since |first_buffer| is part // of the supposed splice. EXPECT_TRUE(AddInput(first_buffer)); EXPECT_FALSE(splicer_.HasNextBuffer()); // |second_buffer| should complete the supposed splice, so ensure output is // now available. splicer_.SetSpliceTimestamp(kNoTimestamp()); EXPECT_TRUE(AddInput(second_buffer)); VerifyNextBuffer(first_buffer); VerifyNextBuffer(second_buffer); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test behavior when a splice frame is incorrectly marked and there is a gap // between whats in the pre splice and post splice. // +--------+ // |11111111| // +--------+ // +--------------+ // |22222222222222| // +--------------+ // Results in: // +--------+-+--------------+ // |11111111|0|22222222222222| // +--------+-+--------------+ TEST_F(AudioSplicerTest, IncorrectlyMarkedSpliceWithGap) { const int kBufferSize = input_timestamp_helper_.GetFramesToTarget(max_crossfade_duration()) * 2; const int kGapSize = 2; scoped_refptr first_buffer = GetNextInputBuffer(1.0f, kBufferSize - kGapSize); scoped_refptr gap_buffer = GetNextInputBuffer(0.0f, kGapSize); splicer_.SetSpliceTimestamp(input_timestamp_helper_.GetTimestamp()); scoped_refptr second_buffer = GetNextInputBuffer(0.0f, kBufferSize); // The splicer should pass through the first buffer since it's not part of the // splice. EXPECT_TRUE(AddInput(first_buffer)); VerifyNextBuffer(first_buffer); // Do not add |gap_buffer|. // |second_buffer| will complete the supposed splice. splicer_.SetSpliceTimestamp(kNoTimestamp()); EXPECT_TRUE(AddInput(second_buffer)); VerifyNextBuffer(gap_buffer); VerifyNextBuffer(second_buffer); EXPECT_FALSE(splicer_.HasNextBuffer()); } // Test behavior when a splice frame is incorrectly marked and there is a gap // between what's in the pre splice and post splice that is too large to recover // from. // +--------+ // |11111111| // +--------+ // +------+ // |222222| // +------+ // Results in an error and not a crash. TEST_F(AudioSplicerTest, IncorrectlyMarkedSpliceWithBadGap) { const int kBufferSize = input_timestamp_helper_.GetFramesToTarget(max_crossfade_duration()) * 2; const int kGapSize = kBufferSize + input_timestamp_helper_.GetFramesToTarget( base::TimeDelta::FromMilliseconds( AudioSplicer::kMaxTimeDeltaInMilliseconds + 1)); scoped_refptr first_buffer = GetNextInputBuffer(1.0f, kBufferSize); scoped_refptr gap_buffer = GetNextInputBuffer(0.0f, kGapSize); splicer_.SetSpliceTimestamp(input_timestamp_helper_.GetTimestamp()); scoped_refptr second_buffer = GetNextInputBuffer(0.0f, kBufferSize); // The splicer should pass through the first buffer since it's not part of the // splice. EXPECT_TRUE(AddInput(first_buffer)); VerifyNextBuffer(first_buffer); // Do not add |gap_buffer|. // |second_buffer| will complete the supposed splice. splicer_.SetSpliceTimestamp(kNoTimestamp()); EXPECT_FALSE(AddInput(second_buffer)); } // Ensure we don't crash when a splice frame is incorrectly marked such that the // splice timestamp has already passed when SetSpliceTimestamp() is called. // This can happen if the encoded timestamps are too far behind the decoded // timestamps. TEST_F(AudioSplicerTest, IncorrectlyMarkedPastSplice) { const int kBufferSize = 200; scoped_refptr first_buffer = GetNextInputBuffer(1.0f, kBufferSize); EXPECT_TRUE(AddInput(first_buffer)); VerifyNextBuffer(first_buffer); // Start the splice at a timestamp which has already occurred. splicer_.SetSpliceTimestamp(base::TimeDelta()); scoped_refptr second_buffer = GetNextInputBuffer(0.5f, kBufferSize); EXPECT_TRUE(AddInput(second_buffer)); EXPECT_FALSE(splicer_.HasNextBuffer()); // |third_buffer| will complete the supposed splice. The buffer size is set // such that unchecked the splicer would try to trim off a negative number of // frames. splicer_.SetSpliceTimestamp(kNoTimestamp()); scoped_refptr third_buffer = GetNextInputBuffer(0.0f, kBufferSize * 10); third_buffer->set_timestamp(base::TimeDelta()); EXPECT_TRUE(AddInput(third_buffer)); // The second buffer should come through unmodified. VerifyNextBuffer(second_buffer); // The third buffer should be partially dropped since it overlaps the second. ASSERT_TRUE(splicer_.HasNextBuffer()); const base::TimeDelta second_buffer_end_ts = second_buffer->timestamp() + second_buffer->duration(); scoped_refptr output = splicer_.GetNextBuffer(); EXPECT_EQ(second_buffer_end_ts, output->timestamp()); EXPECT_EQ(third_buffer->duration() - (second_buffer_end_ts - third_buffer->timestamp()), output->duration()); EXPECT_TRUE(VerifyData(output, GetValue(third_buffer))); } } // namespace media