OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/renderers/audio_renderer_impl.h" | 5 #include "media/renderers/audio_renderer_impl.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 static double kOutputMicrosPerFrame = | 59 static double kOutputMicrosPerFrame = |
60 static_cast<double>(base::Time::kMicrosecondsPerSecond) / | 60 static_cast<double>(base::Time::kMicrosecondsPerSecond) / |
61 kOutputSamplesPerSecond; | 61 kOutputSamplesPerSecond; |
62 | 62 |
63 ACTION_P(EnterPendingDecoderInitStateAction, test) { | 63 ACTION_P(EnterPendingDecoderInitStateAction, test) { |
64 test->EnterPendingDecoderInitState(arg2); | 64 test->EnterPendingDecoderInitState(arg2); |
65 } | 65 } |
66 | 66 |
67 class AudioRendererImplTest : public ::testing::Test, public RendererClient { | 67 class AudioRendererImplTest : public ::testing::Test, public RendererClient { |
68 public: | 68 public: |
| 69 ScopedVector<AudioDecoder> CreateAudioDecoderForTest() { |
| 70 MockAudioDecoder* decoder = new MockAudioDecoder(); |
| 71 if (!enter_pending_decoder_init_) { |
| 72 EXPECT_CALL(*decoder, Initialize(_, _, _, _)) |
| 73 .WillOnce(DoAll(SaveArg<3>(&output_cb_), |
| 74 RunCallback<2>(expected_init_result_))); |
| 75 } else { |
| 76 EXPECT_CALL(*decoder, Initialize(_, _, _, _)) |
| 77 .WillOnce(EnterPendingDecoderInitStateAction(this)); |
| 78 } |
| 79 EXPECT_CALL(*decoder, Decode(_, _)) |
| 80 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::DecodeDecoder)); |
| 81 EXPECT_CALL(*decoder, Reset(_)) |
| 82 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::ResetDecoder)); |
| 83 ScopedVector<AudioDecoder> decoders; |
| 84 decoders.push_back(decoder); |
| 85 return decoders; |
| 86 } |
| 87 |
69 // Give the decoder some non-garbage media properties. | 88 // Give the decoder some non-garbage media properties. |
70 AudioRendererImplTest() | 89 AudioRendererImplTest() |
71 : hardware_params_(AudioParameters::AUDIO_PCM_LOW_LATENCY, | 90 : hardware_params_(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
72 kChannelLayout, | 91 kChannelLayout, |
73 kOutputSamplesPerSecond, | 92 kOutputSamplesPerSecond, |
74 SampleFormatToBytesPerChannel(kSampleFormat) * 8, | 93 SampleFormatToBytesPerChannel(kSampleFormat) * 8, |
75 512), | 94 512), |
76 sink_(new FakeAudioRendererSink(hardware_params_)), | 95 sink_(new FakeAudioRendererSink(hardware_params_)), |
77 tick_clock_(new base::SimpleTestTickClock()), | 96 tick_clock_(new base::SimpleTestTickClock()), |
78 demuxer_stream_(DemuxerStream::AUDIO), | 97 demuxer_stream_(DemuxerStream::AUDIO), |
79 decoder_(new MockAudioDecoder()), | 98 expected_init_result_(true), |
| 99 enter_pending_decoder_init_(false), |
80 ended_(false) { | 100 ended_(false) { |
81 AudioDecoderConfig audio_config(kCodec, kSampleFormat, kChannelLayout, | 101 AudioDecoderConfig audio_config(kCodec, kSampleFormat, kChannelLayout, |
82 kInputSamplesPerSecond, EmptyExtraData(), | 102 kInputSamplesPerSecond, EmptyExtraData(), |
83 Unencrypted()); | 103 Unencrypted()); |
84 demuxer_stream_.set_audio_decoder_config(audio_config); | 104 demuxer_stream_.set_audio_decoder_config(audio_config); |
85 | 105 |
86 ConfigureDecoder(); | |
87 ConfigureDemuxerStream(true); | 106 ConfigureDemuxerStream(true); |
88 | 107 |
89 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY, | 108 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
90 kChannelLayout, | 109 kChannelLayout, |
91 kOutputSamplesPerSecond, | 110 kOutputSamplesPerSecond, |
92 SampleFormatToBytesPerChannel(kSampleFormat) * 8, | 111 SampleFormatToBytesPerChannel(kSampleFormat) * 8, |
93 512); | 112 512); |
94 ScopedVector<AudioDecoder> decoders; | 113 renderer_.reset(new AudioRendererImpl( |
95 decoders.push_back(decoder_); | 114 message_loop_.task_runner(), sink_.get(), |
96 renderer_.reset(new AudioRendererImpl(message_loop_.task_runner(), | 115 base::Bind(&AudioRendererImplTest::CreateAudioDecoderForTest, |
97 sink_.get(), std::move(decoders), | 116 base::Unretained(this)), |
98 new MediaLog())); | 117 new MediaLog())); |
99 renderer_->tick_clock_.reset(tick_clock_); | 118 renderer_->tick_clock_.reset(tick_clock_); |
100 tick_clock_->Advance(base::TimeDelta::FromSeconds(1)); | 119 tick_clock_->Advance(base::TimeDelta::FromSeconds(1)); |
101 } | 120 } |
102 | 121 |
103 virtual ~AudioRendererImplTest() { | 122 virtual ~AudioRendererImplTest() { |
104 SCOPED_TRACE("~AudioRendererImplTest()"); | 123 SCOPED_TRACE("~AudioRendererImplTest()"); |
105 } | 124 } |
106 | 125 |
107 // Used to save callbacks and run them at a later time. | |
108 void ConfigureDecoder() { | |
109 EXPECT_CALL(*decoder_, Decode(_, _)) | |
110 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::DecodeDecoder)); | |
111 EXPECT_CALL(*decoder_, Reset(_)) | |
112 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::ResetDecoder)); | |
113 } | |
114 | |
115 // Mock out demuxer reads. | 126 // Mock out demuxer reads. |
116 void ConfigureDemuxerStream(bool supports_config_changes) { | 127 void ConfigureDemuxerStream(bool supports_config_changes) { |
117 EXPECT_CALL(demuxer_stream_, Read(_)) | 128 EXPECT_CALL(demuxer_stream_, Read(_)) |
118 .WillRepeatedly( | 129 .WillRepeatedly( |
119 RunCallback<0>(DemuxerStream::kOk, | 130 RunCallback<0>(DemuxerStream::kOk, |
120 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0)))); | 131 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0)))); |
121 EXPECT_CALL(demuxer_stream_, SupportsConfigChanges()) | 132 EXPECT_CALL(demuxer_stream_, SupportsConfigChanges()) |
122 .WillRepeatedly(Return(supports_config_changes)); | 133 .WillRepeatedly(Return(supports_config_changes)); |
123 } | 134 } |
124 | 135 |
125 // Reconfigures a renderer without config change support using given params. | 136 // Reconfigures a renderer without config change support using given params. |
126 void ConfigureBasicRenderer(const AudioParameters& params) { | 137 void ConfigureBasicRenderer(const AudioParameters& params) { |
127 hardware_params_ = params; | 138 hardware_params_ = params; |
128 sink_ = new FakeAudioRendererSink(hardware_params_); | 139 sink_ = new FakeAudioRendererSink(hardware_params_); |
129 decoder_ = new MockAudioDecoder(); | 140 renderer_.reset(new AudioRendererImpl( |
130 ConfigureDecoder(); | 141 message_loop_.task_runner(), sink_.get(), |
131 ScopedVector<AudioDecoder> decoders; | 142 base::Bind(&AudioRendererImplTest::CreateAudioDecoderForTest, |
132 decoders.push_back(decoder_); | 143 base::Unretained(this)), |
133 renderer_.reset(new AudioRendererImpl(message_loop_.task_runner(), | 144 new MediaLog())); |
134 sink_.get(), std::move(decoders), | |
135 new MediaLog())); | |
136 testing::Mock::VerifyAndClearExpectations(&demuxer_stream_); | 145 testing::Mock::VerifyAndClearExpectations(&demuxer_stream_); |
137 ConfigureDemuxerStream(false); | 146 ConfigureDemuxerStream(false); |
138 } | 147 } |
139 | 148 |
140 // Reconfigures a renderer with config change support using given params. | 149 // Reconfigures a renderer with config change support using given params. |
141 void ConfigureConfigChangeRenderer(const AudioParameters& params, | 150 void ConfigureConfigChangeRenderer(const AudioParameters& params, |
142 const AudioParameters& hardware_params) { | 151 const AudioParameters& hardware_params) { |
143 hardware_params_ = hardware_params; | 152 hardware_params_ = hardware_params; |
144 sink_ = new FakeAudioRendererSink(hardware_params_); | 153 sink_ = new FakeAudioRendererSink(hardware_params_); |
145 decoder_ = new MockAudioDecoder(); | 154 renderer_.reset(new AudioRendererImpl( |
146 ConfigureDecoder(); | 155 message_loop_.task_runner(), sink_.get(), |
147 ScopedVector<AudioDecoder> decoders; | 156 base::Bind(&AudioRendererImplTest::CreateAudioDecoderForTest, |
148 decoders.push_back(decoder_); | 157 base::Unretained(this)), |
149 renderer_.reset(new AudioRendererImpl(message_loop_.task_runner(), | 158 new MediaLog())); |
150 sink_.get(), std::move(decoders), | |
151 new MediaLog())); | |
152 testing::Mock::VerifyAndClearExpectations(&demuxer_stream_); | 159 testing::Mock::VerifyAndClearExpectations(&demuxer_stream_); |
153 ConfigureDemuxerStream(true); | 160 ConfigureDemuxerStream(true); |
154 } | 161 } |
155 | 162 |
156 void ExpectUnsupportedAudioDecoder() { | |
157 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)) | |
158 .WillOnce(DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(false))); | |
159 } | |
160 | |
161 // RendererClient implementation. | 163 // RendererClient implementation. |
162 MOCK_METHOD1(OnError, void(PipelineStatus)); | 164 MOCK_METHOD1(OnError, void(PipelineStatus)); |
163 void OnEnded() override { | 165 void OnEnded() override { |
164 CHECK(!ended_); | 166 CHECK(!ended_); |
165 ended_ = true; | 167 ended_ = true; |
166 } | 168 } |
167 void OnStatisticsUpdate(const PipelineStatistics& stats) override { | 169 void OnStatisticsUpdate(const PipelineStatistics& stats) override { |
168 last_statistics_.audio_memory_usage += stats.audio_memory_usage; | 170 last_statistics_.audio_memory_usage += stats.audio_memory_usage; |
169 } | 171 } |
170 MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); | 172 MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); |
171 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); | 173 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); |
172 MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); | 174 MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); |
173 MOCK_METHOD1(OnVideoOpacityChange, void(bool)); | 175 MOCK_METHOD1(OnVideoOpacityChange, void(bool)); |
174 MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); | 176 MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); |
175 | 177 |
176 void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) { | 178 void InitializeRenderer(DemuxerStream* demuxer_stream, |
| 179 const PipelineStatusCB& pipeline_status_cb) { |
177 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); | 180 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); |
178 EXPECT_CALL(*this, OnVideoNaturalSizeChange(_)).Times(0); | 181 EXPECT_CALL(*this, OnVideoNaturalSizeChange(_)).Times(0); |
179 EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(0); | 182 EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(0); |
180 renderer_->Initialize(&demuxer_stream_, nullptr, this, pipeline_status_cb); | 183 renderer_->Initialize(demuxer_stream, nullptr, this, pipeline_status_cb); |
181 } | 184 } |
182 | 185 |
183 void Initialize() { | 186 void Initialize() { |
184 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)) | |
185 .WillOnce(DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(true))); | |
186 InitializeWithStatus(PIPELINE_OK); | 187 InitializeWithStatus(PIPELINE_OK); |
187 | 188 |
188 next_timestamp_.reset(new AudioTimestampHelper(kInputSamplesPerSecond)); | 189 next_timestamp_.reset(new AudioTimestampHelper(kInputSamplesPerSecond)); |
189 } | 190 } |
190 | 191 |
191 void InitializeWithStatus(PipelineStatus expected) { | 192 void InitializeWithStatus(PipelineStatus expected) { |
192 SCOPED_TRACE(base::StringPrintf("InitializeWithStatus(%d)", expected)); | 193 SCOPED_TRACE(base::StringPrintf("InitializeWithStatus(%d)", expected)); |
193 | 194 |
194 WaitableMessageLoopEvent event; | 195 WaitableMessageLoopEvent event; |
195 InitializeRenderer(event.GetPipelineStatusCB()); | 196 InitializeRenderer(&demuxer_stream_, event.GetPipelineStatusCB()); |
196 event.RunAndWaitForStatus(expected); | 197 event.RunAndWaitForStatus(expected); |
197 | 198 |
198 // We should have no reads. | 199 // We should have no reads. |
199 EXPECT_TRUE(decode_cb_.is_null()); | 200 EXPECT_TRUE(decode_cb_.is_null()); |
200 } | 201 } |
201 | 202 |
202 void InitializeAndDestroy() { | 203 void InitializeAndDestroy() { |
203 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)) | |
204 .WillOnce(RunCallback<2>(true)); | |
205 | |
206 WaitableMessageLoopEvent event; | 204 WaitableMessageLoopEvent event; |
207 InitializeRenderer(event.GetPipelineStatusCB()); | 205 InitializeRenderer(&demuxer_stream_, event.GetPipelineStatusCB()); |
208 | 206 |
209 // Destroy the |renderer_| before we let the MessageLoop run, this simulates | 207 // Destroy the |renderer_| before we let the MessageLoop run, this simulates |
210 // an interleaving in which we end up destroying the |renderer_| while the | 208 // an interleaving in which we end up destroying the |renderer_| while the |
211 // OnDecoderSelected callback is in flight. | 209 // OnDecoderSelected callback is in flight. |
212 renderer_.reset(); | 210 renderer_.reset(); |
213 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT); | 211 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT); |
214 } | 212 } |
215 | 213 |
216 void InitializeAndDestroyDuringDecoderInit() { | 214 void InitializeAndDestroyDuringDecoderInit() { |
217 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)) | 215 enter_pending_decoder_init_ = true; |
218 .WillOnce(EnterPendingDecoderInitStateAction(this)); | |
219 | 216 |
220 WaitableMessageLoopEvent event; | 217 WaitableMessageLoopEvent event; |
221 InitializeRenderer(event.GetPipelineStatusCB()); | 218 InitializeRenderer(&demuxer_stream_, event.GetPipelineStatusCB()); |
222 base::RunLoop().RunUntilIdle(); | 219 base::RunLoop().RunUntilIdle(); |
223 DCHECK(!init_decoder_cb_.is_null()); | 220 DCHECK(!init_decoder_cb_.is_null()); |
224 | 221 |
225 renderer_.reset(); | 222 renderer_.reset(); |
226 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT); | 223 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT); |
227 } | 224 } |
228 | 225 |
229 void EnterPendingDecoderInitState(const AudioDecoder::InitCB& cb) { | 226 void EnterPendingDecoderInitState(const AudioDecoder::InitCB& cb) { |
230 init_decoder_cb_ = cb; | 227 init_decoder_cb_ = cb; |
231 } | 228 } |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 | 447 |
451 // Fixture members. | 448 // Fixture members. |
452 AudioParameters hardware_params_; | 449 AudioParameters hardware_params_; |
453 base::MessageLoop message_loop_; | 450 base::MessageLoop message_loop_; |
454 std::unique_ptr<AudioRendererImpl> renderer_; | 451 std::unique_ptr<AudioRendererImpl> renderer_; |
455 scoped_refptr<FakeAudioRendererSink> sink_; | 452 scoped_refptr<FakeAudioRendererSink> sink_; |
456 base::SimpleTestTickClock* tick_clock_; | 453 base::SimpleTestTickClock* tick_clock_; |
457 PipelineStatistics last_statistics_; | 454 PipelineStatistics last_statistics_; |
458 | 455 |
459 MockDemuxerStream demuxer_stream_; | 456 MockDemuxerStream demuxer_stream_; |
460 MockAudioDecoder* decoder_; | |
461 | 457 |
462 // Used for satisfying reads. | 458 // Used for satisfying reads. |
463 AudioDecoder::OutputCB output_cb_; | 459 AudioDecoder::OutputCB output_cb_; |
464 AudioDecoder::DecodeCB decode_cb_; | 460 AudioDecoder::DecodeCB decode_cb_; |
465 base::Closure reset_cb_; | 461 base::Closure reset_cb_; |
466 std::unique_ptr<AudioTimestampHelper> next_timestamp_; | 462 std::unique_ptr<AudioTimestampHelper> next_timestamp_; |
467 | 463 |
468 // Run during DecodeDecoder() to unblock WaitForPendingRead(). | 464 // Run during DecodeDecoder() to unblock WaitForPendingRead(). |
469 base::Closure wait_for_pending_decode_cb_; | 465 base::Closure wait_for_pending_decode_cb_; |
470 | 466 |
471 AudioDecoder::InitCB init_decoder_cb_; | 467 AudioDecoder::InitCB init_decoder_cb_; |
| 468 bool expected_init_result_; |
| 469 bool enter_pending_decoder_init_; |
472 bool ended_; | 470 bool ended_; |
473 | 471 |
474 DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest); | 472 DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest); |
475 }; | 473 }; |
476 | 474 |
477 TEST_F(AudioRendererImplTest, Initialize_Successful) { | 475 TEST_F(AudioRendererImplTest, Initialize_Successful) { |
478 Initialize(); | 476 Initialize(); |
479 } | 477 } |
480 | 478 |
481 TEST_F(AudioRendererImplTest, Initialize_DecoderInitFailure) { | 479 TEST_F(AudioRendererImplTest, Initialize_DecoderInitFailure) { |
482 ExpectUnsupportedAudioDecoder(); | 480 expected_init_result_ = false; |
483 InitializeWithStatus(DECODER_ERROR_NOT_SUPPORTED); | 481 InitializeWithStatus(DECODER_ERROR_NOT_SUPPORTED); |
484 } | 482 } |
485 | 483 |
| 484 TEST_F(AudioRendererImplTest, ReinitializeForDifferentStream) { |
| 485 // Initialize and start playback |
| 486 Initialize(); |
| 487 Preroll(); |
| 488 StartTicking(); |
| 489 EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256))); |
| 490 WaitForPendingRead(); |
| 491 |
| 492 // Stop playback and flush |
| 493 StopTicking(); |
| 494 EXPECT_TRUE(IsReadPending()); |
| 495 // Flush and expect to be notified that we have nothing. |
| 496 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); |
| 497 FlushDuringPendingRead(); |
| 498 |
| 499 // Prepare a new demuxer stream. |
| 500 MockDemuxerStream new_stream(DemuxerStream::AUDIO); |
| 501 EXPECT_CALL(new_stream, SupportsConfigChanges()).WillOnce(Return(false)); |
| 502 AudioDecoderConfig audio_config(kCodec, kSampleFormat, kChannelLayout, |
| 503 kInputSamplesPerSecond, EmptyExtraData(), |
| 504 Unencrypted()); |
| 505 new_stream.set_audio_decoder_config(audio_config); |
| 506 |
| 507 // The renderer is now in the flushed state and can be reinitialized. |
| 508 WaitableMessageLoopEvent event; |
| 509 InitializeRenderer(&new_stream, event.GetPipelineStatusCB()); |
| 510 event.RunAndWaitForStatus(PIPELINE_OK); |
| 511 } |
| 512 |
486 TEST_F(AudioRendererImplTest, Preroll) { | 513 TEST_F(AudioRendererImplTest, Preroll) { |
487 Initialize(); | 514 Initialize(); |
488 Preroll(); | 515 Preroll(); |
489 } | 516 } |
490 | 517 |
491 TEST_F(AudioRendererImplTest, StartTicking) { | 518 TEST_F(AudioRendererImplTest, StartTicking) { |
492 Initialize(); | 519 Initialize(); |
493 Preroll(); | 520 Preroll(); |
494 StartTicking(); | 521 StartTicking(); |
495 | 522 |
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1063 // Advance far enough that we shouldn't be clamped to current time (tested | 1090 // Advance far enough that we shouldn't be clamped to current time (tested |
1064 // already above). | 1091 // already above). |
1065 tick_clock_->Advance(kOneSecond); | 1092 tick_clock_->Advance(kOneSecond); |
1066 EXPECT_EQ( | 1093 EXPECT_EQ( |
1067 current_time + timestamp_helper.GetFrameDuration(frames_to_consume.value), | 1094 current_time + timestamp_helper.GetFrameDuration(frames_to_consume.value), |
1068 CurrentMediaWallClockTime(&is_time_moving)); | 1095 CurrentMediaWallClockTime(&is_time_moving)); |
1069 EXPECT_TRUE(is_time_moving); | 1096 EXPECT_TRUE(is_time_moving); |
1070 } | 1097 } |
1071 | 1098 |
1072 } // namespace media | 1099 } // namespace media |
OLD | NEW |