Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: media/filters/decrypting_audio_decoder_unittest.cc

Issue 11198017: Add DecryptingAudioDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 <string>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/message_loop.h"
11 #include "media/base/buffers.h"
12 #include "media/base/data_buffer.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/decrypt_config.h"
15 #include "media/base/mock_callback.h"
16 #include "media/base/mock_filters.h"
17 #include "media/filters/decrypting_audio_decoder.h"
18 #include "media/filters/ffmpeg_decoder_unittest.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20
21 using ::testing::_;
22 using ::testing::AtMost;
23 using ::testing::Invoke;
24 using ::testing::IsNull;
25 using ::testing::ReturnRef;
26 using ::testing::SaveArg;
27 using ::testing::StrictMock;
28
29 namespace media {
30
31 static const int kFakeAudioFrameSize = 16;
32 static const uint8 kFakeKeyId[] = { 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44 };
33 static const uint8 kFakeIv[DecryptConfig::kDecryptionKeySize] = { 0 };
34
35 // Create a fake non-empty encrypted buffer.
36 static scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer() {
37 const int buffer_size = 16; // Need a non-empty buffer;
38 scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(buffer_size));
39 buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
40 std::string(reinterpret_cast<const char*>(kFakeKeyId),
41 arraysize(kFakeKeyId)),
42 std::string(reinterpret_cast<const char*>(kFakeIv), arraysize(kFakeIv)),
43 0,
44 std::vector<SubsampleEntry>())));
45 return buffer;
46 }
47
48 // Use anonymous namespace here to prevent the actions to be defined multiple
49 // times across multiple test files. Sadly we can't use static for them.
50 namespace {
51
52 ACTION_P(ReturnBuffer, buffer) {
53 arg0.Run(buffer ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
54 }
55
56 ACTION(ReturnConfigChanged) {
57 arg0.Run(DemuxerStream::kConfigChanged, scoped_refptr<DecoderBuffer>(NULL));
58 }
59
60 ACTION_P(RunCallback0, param) {
61 if (!arg0.is_null())
62 arg0.Run(param);
63 }
64
65 ACTION_P(RunCallback1, param) {
66 arg1.Run(param);
67 }
68
69 ACTION_P2(RunCallback2, param1, param2) {
70 arg1.Run(param1, param2);
71 }
72
73 ACTION_P2(ResetAndRunCallback, callback, param) {
74 base::ResetAndReturn(callback).Run(param);
75 }
76
77 MATCHER(IsNullCallback, "") {
78 return (arg.is_null());
79 }
80
81 } // namespace
82
83 class DecryptingAudioDecoderTest : public testing::Test {
84 public:
85 DecryptingAudioDecoderTest()
86 : decoder_(new StrictMock<DecryptingAudioDecoder>(
87 base::Bind(&Identity<scoped_refptr<base::MessageLoopProxy> >,
88 message_loop_.message_loop_proxy()),
89 base::Bind(
90 &DecryptingAudioDecoderTest::RequestDecryptorNotification,
91 base::Unretained(this)))),
92 decryptor_(new StrictMock<MockDecryptor>()),
93 demuxer_(new StrictMock<MockDemuxerStream>()),
94 encrypted_buffer_(CreateFakeEncryptedBuffer()),
95 decoded_frame_(new DataBuffer(kFakeAudioFrameSize)),
96 end_of_stream_frame_(new DataBuffer(0)),
97 decoded_frame_list_(1, decoded_frame_) {
98 }
99
100 void InitializeAndExpectStatus(const AudioDecoderConfig& config,
101 PipelineStatus status) {
102 EXPECT_CALL(*demuxer_, audio_decoder_config())
103 .WillRepeatedly(ReturnRef(config));
104 EXPECT_CALL(*this, RequestDecryptorNotification(_))
105 .WillRepeatedly(RunCallback0(decryptor_.get()));
106
107 decoder_->Initialize(demuxer_, NewExpectedStatusCB(status),
108 base::Bind(&MockStatisticsCB::OnStatistics,
109 base::Unretained(&statistics_cb_)));
110 message_loop_.RunAllPending();
111 }
112
113 void Initialize() {
114 EXPECT_CALL(*decryptor_, InitializeAudioDecoderMock(_, _, _))
115 .Times(AtMost(1))
116 .WillOnce(DoAll(RunCallback1(true), SaveArg<2>(&key_added_cb_)));
117
118 config_.Initialize(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
119 NULL, 0, true, true);
120
121 InitializeAndExpectStatus(config_, PIPELINE_OK);
122 EXPECT_EQ(16, decoder_->bits_per_channel());
123 EXPECT_EQ(CHANNEL_LAYOUT_STEREO, decoder_->channel_layout());
124 EXPECT_EQ(44100, decoder_->samples_per_second());
125 }
126
127 void ReadAndExpectFrameReadyWith(
128 AudioDecoder::Status status,
129 const scoped_refptr<Buffer>& audio_frame) {
130 if (status != AudioDecoder::kOk)
131 EXPECT_CALL(*this, FrameReady(status, IsNull()));
132 else
133 EXPECT_CALL(*this, FrameReady(status, audio_frame));
134
135 decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
136 base::Unretained(this)));
137 message_loop_.RunAllPending();
138 }
139
140 // Sets up expectations and actions to put DecryptingAudioDecoder in an
141 // active normal decoding state.
142 void EnterNormalDecodingState() {
143 Decryptor::AudioBuffers end_of_stream_frames_(1, end_of_stream_frame_);
144
145 EXPECT_CALL(*demuxer_, Read(_))
146 .WillOnce(ReturnBuffer(encrypted_buffer_))
147 .WillRepeatedly(ReturnBuffer(DecoderBuffer::CreateEOSBuffer()));
148 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
149 .WillOnce(RunCallback2(Decryptor::kSuccess,
150 decoded_frame_list_))
151 .WillRepeatedly(RunCallback2(Decryptor::kSuccess,
152 end_of_stream_frames_));
153 EXPECT_CALL(statistics_cb_, OnStatistics(_));
154
155 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
156 }
157
158 // Sets up expectations and actions to put DecryptingAudioDecoder in an end
159 // of stream state. This function must be called after
160 // EnterNormalDecodingState() to work.
161 void EnterEndOfStreamState() {
162 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, end_of_stream_frame_);
163 }
164
165 // Make the read callback pending by saving and not firing it.
166 void EnterPendingReadState() {
167 EXPECT_TRUE(pending_demuxer_read_cb_.is_null());
168 EXPECT_CALL(*demuxer_, Read(_))
169 .WillOnce(SaveArg<0>(&pending_demuxer_read_cb_));
170 decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
171 base::Unretained(this)));
172 message_loop_.RunAllPending();
173 // Make sure the Read() on the decoder triggers a Read() on the demuxer.
174 EXPECT_FALSE(pending_demuxer_read_cb_.is_null());
175 }
176
177 // Make the audio decode callback pending by saving and not firing it.
178 void EnterPendingDecodeState() {
179 EXPECT_TRUE(pending_audio_decode_cb_.is_null());
180 EXPECT_CALL(*demuxer_, Read(_))
181 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
182 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
183 .WillOnce(SaveArg<1>(&pending_audio_decode_cb_));
184
185 decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
186 base::Unretained(this)));
187 message_loop_.RunAllPending();
188 // Make sure the Read() on the decoder triggers a DecryptAndDecode() on the
189 // decryptor.
190 EXPECT_FALSE(pending_audio_decode_cb_.is_null());
191 }
192
193 void EnterWaitingForKeyState() {
194 EXPECT_CALL(*demuxer_, Read(_))
195 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
196 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
197 .WillRepeatedly(RunCallback2(Decryptor::kNoKey,
198 Decryptor::AudioBuffers()));
199 decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
200 base::Unretained(this)));
201 message_loop_.RunAllPending();
202 }
203
204 void AbortPendingAudioDecodeCB() {
205 if (!pending_audio_decode_cb_.is_null()) {
206 base::ResetAndReturn(&pending_audio_decode_cb_).Run(
207 Decryptor::kSuccess, Decryptor::AudioBuffers());
208 }
209 }
210
211 void Reset() {
212 EXPECT_CALL(*decryptor_, ResetDecoder(Decryptor::kAudio))
213 .WillRepeatedly(InvokeWithoutArgs(
214 this, &DecryptingAudioDecoderTest::AbortPendingAudioDecodeCB));
215
216 decoder_->Reset(NewExpectedClosure());
217 message_loop_.RunAllPending();
218 }
219
220 MOCK_METHOD1(RequestDecryptorNotification,
221 void(const DecryptingAudioDecoder::DecryptorNotificationCB&));
222
223 MOCK_METHOD2(FrameReady, void(AudioDecoder::Status,
224 const scoped_refptr<Buffer>&));
225
226 MessageLoop message_loop_;
227 scoped_refptr<StrictMock<DecryptingAudioDecoder> > decoder_;
228 scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
229 scoped_refptr<StrictMock<MockDemuxerStream> > demuxer_;
230 MockStatisticsCB statistics_cb_;
231 AudioDecoderConfig config_;
232
233 DemuxerStream::ReadCB pending_demuxer_read_cb_;
234 Decryptor::DecoderInitCB pending_init_cb_;
235 Decryptor::KeyAddedCB key_added_cb_;
236 Decryptor::AudioDecodeCB pending_audio_decode_cb_;
237
238 // Constant buffer/frames to be returned by the |demuxer_| and |decryptor_|.
239 scoped_refptr<DecoderBuffer> encrypted_buffer_;
240 scoped_refptr<Buffer> decoded_frame_;
241 scoped_refptr<Buffer> end_of_stream_frame_;
242 Decryptor::AudioBuffers decoded_frame_list_;
243
244 private:
245 DISALLOW_COPY_AND_ASSIGN(DecryptingAudioDecoderTest);
246 };
247
248 TEST_F(DecryptingAudioDecoderTest, Initialize_Normal) {
249 Initialize();
250 }
251
252 // Ensure that DecryptingAudioDecoder only accepts encrypted audio.
253 TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) {
254 AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
255 NULL, 0, false);
256
257 InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
258 }
259
260 // Ensure decoder handles invalid audio configs without crashing.
261 TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) {
262 AudioDecoderConfig config(kUnknownAudioCodec, 0, CHANNEL_LAYOUT_STEREO, 0,
263 NULL, 0, true);
264
265 InitializeAndExpectStatus(config, PIPELINE_ERROR_DECODE);
266 }
267
268 // Ensure decoder handles unsupported audio configs without crashing.
269 TEST_F(DecryptingAudioDecoderTest, Initialize_UnsupportedAudioConfig) {
270 EXPECT_CALL(*decryptor_, InitializeAudioDecoderMock(_, _, _))
271 .WillOnce(RunCallback1(false));
272
273 AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
274 NULL, 0, true);
275 InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
276 }
277
278 // Test normal decrypt and decode case.
279 TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_Normal) {
280 Initialize();
281 EnterNormalDecodingState();
282 }
283
284 // Test the case where the decryptor returns error when doing decrypt and
285 // decode.
286 TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_DecodeError) {
287 Initialize();
288
289 EXPECT_CALL(*demuxer_, Read(_))
290 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
291 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
292 .WillRepeatedly(RunCallback2(Decryptor::kError,
293 Decryptor::AudioBuffers()));
294
295 ReadAndExpectFrameReadyWith(AudioDecoder::kDecodeError, NULL);
296 }
297
298 // Test the case where the decryptor returns kNeedMoreData to ask for more
299 // buffers before it can produce a frame.
300 TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_NeedMoreData) {
301 Initialize();
302
303 EXPECT_CALL(*demuxer_, Read(_))
304 .Times(2)
305 .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
306 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
307 .WillOnce(RunCallback2(Decryptor::kNeedMoreData,
308 Decryptor::AudioBuffers()))
309 .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
310 EXPECT_CALL(statistics_cb_, OnStatistics(_))
311 .Times(2);
312
313 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
314 }
315
316 // Test the case where the decryptor returns multiple decoded frames.
317 TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_MultipleFrames) {
318 Initialize();
319
320 scoped_refptr<Buffer> decoded_frame_a(new DataBuffer(kFakeAudioFrameSize));
321 scoped_refptr<Buffer> decoded_frame_b(new DataBuffer(kFakeAudioFrameSize));
322 decoded_frame_list_.push_back(decoded_frame_a);
323 decoded_frame_list_.push_back(decoded_frame_b);
324
325 EXPECT_CALL(*demuxer_, Read(_))
326 .WillOnce(ReturnBuffer(encrypted_buffer_));
327 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
328 .WillOnce(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
329 EXPECT_CALL(statistics_cb_, OnStatistics(_));
330
331 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
332 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_a);
333 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_b);
334 }
335
336 // Test the case where the decryptor receives end-of-stream buffer.
337 TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_EndOfStream) {
338 Initialize();
339 EnterNormalDecodingState();
340 EnterEndOfStreamState();
341 }
342
343 // Test the case where the decryptor returns multiple decoded frames, the last
344 // of which is end-of-stream frame.
345 TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_MultipleFramesWithEos) {
346 Initialize();
347
348 scoped_refptr<Buffer> decoded_frame_a(new DataBuffer(kFakeAudioFrameSize));
349 scoped_refptr<Buffer> decoded_frame_b(new DataBuffer(kFakeAudioFrameSize));
350 Decryptor::AudioBuffers second_decoded_frame_list;
351 second_decoded_frame_list.push_back(decoded_frame_a);
352 second_decoded_frame_list.push_back(decoded_frame_b);
353 second_decoded_frame_list.push_back(end_of_stream_frame_);
354
355 EXPECT_CALL(*demuxer_, Read(_))
356 .WillOnce(ReturnBuffer(encrypted_buffer_))
357 .WillOnce(ReturnBuffer(DecoderBuffer::CreateEOSBuffer()));
358 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
359 .WillOnce(RunCallback2(Decryptor::kSuccess, decoded_frame_list_))
360 .WillOnce(RunCallback2(Decryptor::kSuccess, second_decoded_frame_list));
361 // Expect only one OnStatistics() here because EOS input buffer doesn't
362 // trigger statistics reporting.
363 EXPECT_CALL(statistics_cb_, OnStatistics(_));
364
365 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
366 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_a);
367 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_b);
368 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, end_of_stream_frame_);
369 }
370
371 // Test the case where the a key is added when the decryptor is in
372 // kWaitingForKey state.
373 TEST_F(DecryptingAudioDecoderTest, KeyAdded_DuringWaitingForKey) {
374 Initialize();
375 EnterWaitingForKeyState();
376
377 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
378 .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
379 EXPECT_CALL(statistics_cb_, OnStatistics(_));
380 EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, decoded_frame_));
381 key_added_cb_.Run();
382 message_loop_.RunAllPending();
383 }
384
385 // Test the case where the a key is added when the decryptor is in
386 // kPendingDecode state.
387 TEST_F(DecryptingAudioDecoderTest, KeyAdded_DruingPendingDecode) {
388 Initialize();
389 EnterPendingDecodeState();
390
391 EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
392 .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
393 EXPECT_CALL(statistics_cb_, OnStatistics(_));
394 EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, decoded_frame_));
395 // The audio decode callback is returned after the correct decryption key is
396 // added.
397 key_added_cb_.Run();
398 base::ResetAndReturn(&pending_audio_decode_cb_).Run(
399 Decryptor::kNoKey, Decryptor::AudioBuffers());
400 message_loop_.RunAllPending();
401 }
402
403 // Test resetting when the decoder is in kIdle state but has not decoded any
404 // frame.
405 TEST_F(DecryptingAudioDecoderTest, Reset_DuringIdleAfterInitialization) {
406 Initialize();
407 Reset();
408 }
409
410 // Test resetting when the decoder is in kIdle state after it has decoded one
411 // frame.
412 TEST_F(DecryptingAudioDecoderTest, Reset_DuringIdleAfterDecodedOneFrame) {
413 Initialize();
414 EnterNormalDecodingState();
415 Reset();
416 }
417
418 // Test resetting when the decoder is in kPendingDemuxerRead state.
419 TEST_F(DecryptingAudioDecoderTest, Reset_DuringPendingDemuxerRead) {
420 Initialize();
421 EnterPendingReadState();
422
423 EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
424
425 Reset();
426 base::ResetAndReturn(&pending_demuxer_read_cb_).Run(DemuxerStream::kOk,
427 encrypted_buffer_);
428 message_loop_.RunAllPending();
429 }
430
431 // Test resetting when the decoder is in kPendingDecode state.
432 TEST_F(DecryptingAudioDecoderTest, Reset_DuringPendingDecode) {
433 Initialize();
434 EnterPendingDecodeState();
435
436 EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
437
438 Reset();
439 }
440
441 // Test resetting when the decoder is in kWaitingForKey state.
442 TEST_F(DecryptingAudioDecoderTest, Reset_DuringWaitingForKey) {
443 Initialize();
444 EnterWaitingForKeyState();
445
446 EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
447
448 Reset();
449 }
450
451 // Test resetting when the decoder has hit end of stream and is in
452 // kDecodeFinished state.
453 TEST_F(DecryptingAudioDecoderTest, Reset_AfterDecodeFinished) {
454 Initialize();
455 EnterNormalDecodingState();
456 EnterEndOfStreamState();
457 Reset();
458 }
459
460 // Test resetting after the decoder has been reset.
461 TEST_F(DecryptingAudioDecoderTest, Reset_AfterReset) {
462 Initialize();
463 EnterNormalDecodingState();
464 Reset();
465 Reset();
466 }
467
468 // Test aborted read on the demuxer stream.
469 TEST_F(DecryptingAudioDecoderTest, DemuxerRead_Aborted) {
470 Initialize();
471
472 // ReturnBuffer() with NULL triggers aborted demuxer read.
473 EXPECT_CALL(*demuxer_, Read(_))
474 .WillOnce(ReturnBuffer(scoped_refptr<DecoderBuffer>()));
475
476 ReadAndExpectFrameReadyWith(AudioDecoder::kOk, NULL);
477 }
478
479 // Test aborted read on the demuxer stream when the decoder is being reset.
480 TEST_F(DecryptingAudioDecoderTest, DemuxerRead_AbortedDuringReset) {
481 Initialize();
482 EnterPendingReadState();
483
484 // Make sure we get a NULL audio frame returned.
485 EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
486
487 Reset();
488 base::ResetAndReturn(&pending_demuxer_read_cb_).Run(DemuxerStream::kAborted,
489 NULL);
490 message_loop_.RunAllPending();
491 }
492
493 // Test config change on the demuxer stream.
494 TEST_F(DecryptingAudioDecoderTest, DemuxerRead_ConfigChanged) {
495 Initialize();
496
497 EXPECT_CALL(*demuxer_, Read(_))
498 .WillOnce(ReturnConfigChanged());
499
500 // TODO(xhwang): Update this test when kConfigChanged is supported in
501 // DecryptingAudioDecoder.
502 ReadAndExpectFrameReadyWith(AudioDecoder::kDecodeError, NULL);
503 }
504
505 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698