Upload upstream chromium 85.0.4183.84
[platform/framework/web/chromium-efl.git] / media / filters / audio_timestamp_validator_unittest.cc
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/filters/audio_timestamp_validator.h"
6
7 #include <tuple>
8
9 #include "base/stl_util.h"
10 #include "base/time/time.h"
11 #include "media/base/audio_decoder_config.h"
12 #include "media/base/media_util.h"
13 #include "media/base/mock_media_log.h"
14 #include "media/base/test_helpers.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using ::testing::HasSubstr;
18
19 namespace media {
20
21 // Constants to specify the type of audio data used.
22 static const AudioCodec kCodec = kCodecVorbis;
23 static const SampleFormat kSampleFormat = kSampleFormatPlanarF32;
24 static const base::TimeDelta kSeekPreroll;
25 static const int kSamplesPerSecond = 10000;
26 static const base::TimeDelta kBufferDuration =
27     base::TimeDelta::FromMilliseconds(20);
28 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
29 static const int kChannelCount = 2;
30 static const int kChannels = ChannelLayoutToChannelCount(kChannelLayout);
31 static const int kFramesPerBuffer = kBufferDuration.InMicroseconds() *
32                                     kSamplesPerSecond /
33                                     base::Time::kMicrosecondsPerSecond;
34
35 // Params are:
36 // 1. Output delay: number of encoded buffers before first decoded output
37 // 2. Codec delay: number of frames of codec delay in decoder config
38 // 3. Front discard: front discard for the first buffer
39 using ValidatorTestParams = testing::tuple<int, int, base::TimeDelta>;
40
41 class AudioTimestampValidatorTest
42     : public testing::Test,
43       public ::testing::WithParamInterface<ValidatorTestParams> {
44  public:
45   AudioTimestampValidatorTest() = default;
46
47  protected:
48   void SetUp() override {
49     output_delay_ = testing::get<0>(GetParam());
50     codec_delay_ = testing::get<1>(GetParam());
51     front_discard_ = testing::get<2>(GetParam());
52   }
53
54   int output_delay_;
55
56   int codec_delay_;
57
58   base::TimeDelta front_discard_;
59
60   testing::StrictMock<MockMediaLog> media_log_;
61 };
62
63 TEST_P(AudioTimestampValidatorTest, WarnForEraticTimes) {
64   AudioDecoderConfig decoder_config;
65   decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
66                             kSamplesPerSecond, EmptyExtraData(),
67                             EncryptionScheme::kUnencrypted, kSeekPreroll,
68                             codec_delay_);
69
70   // Validator should fail to stabilize pattern for timestamp expectations.
71   EXPECT_MEDIA_LOG(
72       HasSubstr("Failed to reconcile encoded audio times "
73                 "with decoded output."));
74
75   // No gap warnings should be emitted because the timestamps expectations never
76   // stabilized.
77   EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected")).Times(0);
78
79   AudioTimestampValidator validator(decoder_config, &media_log_);
80
81   const base::TimeDelta kRandomOffsets[] = {
82       base::TimeDelta::FromMilliseconds(100),
83       base::TimeDelta::FromMilliseconds(350)};
84
85   for (int i = 0; i < 100; ++i) {
86     // Each buffer's timestamp is kBufferDuration from the previous buffer.
87     scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
88
89     // Ping-pong between two random offsets to prevent validator from
90     // stabilizing timestamp pattern.
91     base::TimeDelta randomOffset =
92         kRandomOffsets[i % base::size(kRandomOffsets)];
93     encoded_buffer->set_timestamp(i * kBufferDuration + randomOffset);
94
95     if (i == 0) {
96       encoded_buffer->set_discard_padding(
97           std::make_pair(front_discard_, base::TimeDelta()));
98     }
99
100     validator.CheckForTimestampGap(*encoded_buffer);
101
102     if (i >= output_delay_) {
103       // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
104       // no gaps exists as long as timestamps are exactly kBufferDuration apart.
105       scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
106           kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
107           0.0f, kFramesPerBuffer, i * kBufferDuration);
108       validator.RecordOutputDuration(*decoded_buffer);
109     }
110   }
111 }
112
113 TEST_P(AudioTimestampValidatorTest, NoWarningForValidTimes) {
114   AudioDecoderConfig decoder_config;
115   decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
116                             kSamplesPerSecond, EmptyExtraData(),
117                             EncryptionScheme::kUnencrypted, kSeekPreroll,
118                             codec_delay_);
119
120   // Validator should quickly stabilize pattern for timestamp expectations.
121   EXPECT_MEDIA_LOG(HasSubstr("Failed to reconcile encoded audio times "
122                              "with decoded output."))
123       .Times(0);
124
125   // Expect no gap warnings for series of buffers with valid timestamps.
126   EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected")).Times(0);
127
128   AudioTimestampValidator validator(decoder_config, &media_log_);
129
130   for (int i = 0; i < 100; ++i) {
131     // Each buffer's timestamp is kBufferDuration from the previous buffer.
132     scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
133     encoded_buffer->set_timestamp(i * kBufferDuration);
134
135     if (i == 0) {
136       encoded_buffer->set_discard_padding(
137           std::make_pair(front_discard_, base::TimeDelta()));
138     }
139
140     validator.CheckForTimestampGap(*encoded_buffer);
141
142     if (i >= output_delay_) {
143       // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
144       // no gaps exists as long as timestamps are exactly kBufferDuration apart.
145       scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
146           kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
147           0.0f, kFramesPerBuffer, i * kBufferDuration);
148       validator.RecordOutputDuration(*decoded_buffer);
149     }
150   }
151 }
152
153 TEST_P(AudioTimestampValidatorTest, SingleWarnForSingleLargeGap) {
154   AudioDecoderConfig decoder_config;
155   decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
156                             kSamplesPerSecond, EmptyExtraData(),
157                             EncryptionScheme::kUnencrypted, kSeekPreroll,
158                             codec_delay_);
159
160   AudioTimestampValidator validator(decoder_config, &media_log_);
161
162   // Validator should quickly stabilize pattern for timestamp expectations.
163   EXPECT_MEDIA_LOG(HasSubstr("Failed to reconcile encoded audio times "
164                              "with decoded output."))
165       .Times(0);
166
167   for (int i = 0; i < 100; ++i) {
168     // Halfway through the stream, introduce sudden gap of 50 milliseconds.
169     base::TimeDelta offset;
170     if (i >= 50)
171       offset = base::TimeDelta::FromMilliseconds(100);
172
173     // This gap never widens, so expect only a single warning when its first
174     // introduced.
175     if (i == 50)
176       EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected"));
177
178     scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
179     encoded_buffer->set_timestamp(i * kBufferDuration + offset);
180
181     if (i == 0) {
182       encoded_buffer->set_discard_padding(
183           std::make_pair(front_discard_, base::TimeDelta()));
184     }
185
186     validator.CheckForTimestampGap(*encoded_buffer);
187
188     if (i >= output_delay_) {
189       // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
190       // no gaps exists as long as timestamps are exactly kBufferDuration apart.
191       scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
192           kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
193           0.0f, kFramesPerBuffer, i * kBufferDuration);
194       validator.RecordOutputDuration(*decoded_buffer);
195     }
196   }
197 }
198
199 TEST_P(AudioTimestampValidatorTest, RepeatedWarnForSlowAccumulatingDrift) {
200   AudioDecoderConfig decoder_config;
201   decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
202                             kSamplesPerSecond, EmptyExtraData(),
203                             EncryptionScheme::kUnencrypted, kSeekPreroll,
204                             codec_delay_);
205
206   AudioTimestampValidator validator(decoder_config, &media_log_);
207
208   EXPECT_MEDIA_LOG(HasSubstr("Failed to reconcile encoded audio times "
209                              "with decoded output."))
210       .Times(0);
211
212   int num_timestamp_gap_warnings = 0;
213   const int kMaxTimestampGapWarnings = 10;  // Must be the same as in .cc
214
215   for (int i = 0; i < 100; ++i) {
216     // Wait for delayed output to begin plus an additional two iterations to
217     // start using drift offset. The the two iterations without offset will
218     // allow the validator to stabilize the pattern of timestamps and begin
219     // checking for gaps. Once stable, increase offset by 1 millisecond for each
220     // iteration.
221     base::TimeDelta offset;
222     if (i >= output_delay_ + 2)
223       offset = i * base::TimeDelta::FromMilliseconds(1);
224
225     scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
226     encoded_buffer->set_timestamp((i * kBufferDuration) + offset);
227
228     // Expect gap warnings to start when drift hits 50 milliseconds. Warnings
229     // should continue as the gap widens until log limit is hit.
230
231     if (offset > base::TimeDelta::FromMilliseconds(50)) {
232       EXPECT_LIMITED_MEDIA_LOG(HasSubstr("timestamp gap detected"),
233                                num_timestamp_gap_warnings,
234                                kMaxTimestampGapWarnings);
235     }
236
237     validator.CheckForTimestampGap(*encoded_buffer);
238
239     if (i >= output_delay_) {
240       // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
241       // no gaps exists as long as timestamps are exactly kBufferDuration apart.
242       scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
243           kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
244           0.0f, kFramesPerBuffer, i * kBufferDuration);
245       validator.RecordOutputDuration(*decoded_buffer);
246     }
247   }
248 }
249
250 // Test with cartesian product of various output delay, codec delay, and front
251 // discard values. These simulate configurations for different containers/codecs
252 // which present different challenges when building timestamp expectations.
253 INSTANTIATE_TEST_SUITE_P(
254     All,
255     AudioTimestampValidatorTest,
256     ::testing::Combine(
257         ::testing::Values(0, 10),             // output delay
258         ::testing::Values(0, 512),            // codec delay
259         ::testing::Values(base::TimeDelta(),  // front discard
260                           base::TimeDelta::FromMilliseconds(65))));
261
262 }  // namespace media