diff options
author | jrummell <jrummell@chromium.org> | 2015-03-02 14:48:27 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-02 22:49:21 +0000 |
commit | 74fc4f9447f3ea2e277350dccce4de67e5ee4ea4 (patch) | |
tree | 5421eca29629684887a485bac69460fc6cbd5032 /media | |
parent | e86e411c3038fd5be67438da29f0ff17828f226f (diff) | |
download | chromium_src-74fc4f9447f3ea2e277350dccce4de67e5ee4ea4.zip chromium_src-74fc4f9447f3ea2e277350dccce4de67e5ee4ea4.tar.gz chromium_src-74fc4f9447f3ea2e277350dccce4de67e5ee4ea4.tar.bz2 |
Decryptors can report kNoKey to WebMediaPlayer
Add callback so that kNoKey can get passed to blink in order
to generate the HTMLMediaElement.waitingforkey event.
BUG=337975
TEST=updated tests pass
Review URL: https://codereview.chromium.org/935243002
Cr-Commit-Position: refs/heads/master@{#318787}
Diffstat (limited to 'media')
41 files changed, 253 insertions, 104 deletions
diff --git a/media/base/audio_renderer.h b/media/base/audio_renderer.h index 7d0e3d7..586936a 100644 --- a/media/base/audio_renderer.h +++ b/media/base/audio_renderer.h @@ -39,13 +39,18 @@ class MEDIA_EXPORT AudioRenderer { // |ended_cb| is executed when audio rendering has reached the end of stream. // // |error_cb| is executed if an error was encountered after initialization. - virtual void Initialize(DemuxerStream* stream, - const PipelineStatusCB& init_cb, - const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) = 0; + // + // |waiting_for_decryption_key_cb| is called whenever the key needed to + // decrypt the stream is not available. + virtual void Initialize( + DemuxerStream* stream, + const PipelineStatusCB& init_cb, + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) = 0; // Returns the TimeSource associated with audio rendering. virtual TimeSource* GetTimeSource() = 0; diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index c8d1c82..9731fd0 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -121,16 +121,17 @@ class MockVideoRenderer : public VideoRenderer { virtual ~MockVideoRenderer(); // VideoRenderer implementation. - MOCK_METHOD9(Initialize, - void(DemuxerStream* stream, - const PipelineStatusCB& init_cb, - const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb)); + MOCK_METHOD10(Initialize, + void(DemuxerStream* stream, + const PipelineStatusCB& init_cb, + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb)); MOCK_METHOD1(Flush, void(const base::Closure& callback)); MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta)); @@ -144,14 +145,15 @@ class MockAudioRenderer : public AudioRenderer { virtual ~MockAudioRenderer(); // AudioRenderer implementation. - MOCK_METHOD7(Initialize, + MOCK_METHOD8(Initialize, void(DemuxerStream* stream, const PipelineStatusCB& init_cb, const SetDecryptorReadyCB& set_decryptor_ready_cb, const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb)); + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb)); MOCK_METHOD0(GetTimeSource, TimeSource*()); MOCK_METHOD1(Flush, void(const base::Closure& callback)); MOCK_METHOD0(StartPlaying, void()); @@ -167,13 +169,15 @@ class MockRenderer : public Renderer { virtual ~MockRenderer(); // Renderer implementation. - MOCK_METHOD7(Initialize, void(DemuxerStreamProvider* demuxer_stream_provider, - const PipelineStatusCB& init_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb)); + MOCK_METHOD8(Initialize, + void(DemuxerStreamProvider* demuxer_stream_provider, + const PipelineStatusCB& init_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb)); MOCK_METHOD1(Flush, void(const base::Closure& flush_cb)); MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta timestamp)); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc index e9c52d6..d1fae01 100644 --- a/media/base/pipeline.cc +++ b/media/base/pipeline.cc @@ -70,7 +70,8 @@ void Pipeline::Start(Demuxer* demuxer, const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& duration_change_cb, - const AddTextTrackCB& add_text_track_cb) { + const AddTextTrackCB& add_text_track_cb, + const base::Closure& waiting_for_decryption_key_cb) { DCHECK(!ended_cb.is_null()); DCHECK(!error_cb.is_null()); DCHECK(!seek_cb.is_null()); @@ -92,6 +93,7 @@ void Pipeline::Start(Demuxer* demuxer, paint_cb_ = paint_cb; duration_change_cb_ = duration_change_cb; add_text_track_cb_ = add_text_track_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; task_runner_->PostTask( FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr())); @@ -724,7 +726,8 @@ void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) { base::Bind(&Pipeline::BufferingStateChanged, weak_this), base::ResetAndReturn(&paint_cb_), base::Bind(&Pipeline::OnRendererEnded, weak_this), - base::Bind(&Pipeline::OnError, weak_this)); + base::Bind(&Pipeline::OnError, weak_this), + waiting_for_decryption_key_cb_); } void Pipeline::ReportMetadata() { diff --git a/media/base/pipeline.h b/media/base/pipeline.h index 6bca477..30707b3 100644 --- a/media/base/pipeline.h +++ b/media/base/pipeline.h @@ -105,6 +105,8 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost { // |duration_change_cb| optional callback that will be executed whenever the // presentation duration changes. // |add_text_track_cb| will be executed whenever a text track is added. + // |waiting_for_decryption_key_cb| will be executed whenever the key needed + // to decrypt the stream is not available. // It is an error to call this method after the pipeline has already started. void Start(Demuxer* demuxer, scoped_ptr<Renderer> renderer, @@ -115,7 +117,8 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost { const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& duration_change_cb, - const AddTextTrackCB& add_text_track_cb); + const AddTextTrackCB& add_text_track_cb, + const base::Closure& waiting_for_decryption_key_cb); // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline // teardown has completed. @@ -360,6 +363,7 @@ class MEDIA_EXPORT Pipeline : public DemuxerHost { PaintCB paint_cb_; base::Closure duration_change_cb_; AddTextTrackCB add_text_track_cb_; + base::Closure waiting_for_decryption_key_cb_; // Holds the initialized demuxer. Used for seeking. Owned by client. Demuxer* demuxer_; diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc index affb643..147e744 100644 --- a/media/base/pipeline_unittest.cc +++ b/media/base/pipeline_unittest.cc @@ -170,7 +170,7 @@ class PipelineTest : public ::testing::Test { // Sets up expectations to allow the video renderer to initialize. void SetRendererExpectations() { - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_), SaveArg<5>(&ended_cb_), PostCallback<1>(PIPELINE_OK))); @@ -187,6 +187,7 @@ class PipelineTest : public ::testing::Test { } void StartPipeline() { + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); pipeline_->Start( demuxer_.get(), scoped_renderer_.Pass(), base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)), @@ -199,7 +200,9 @@ class PipelineTest : public ::testing::Test { base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnDurationChange, base::Unretained(&callbacks_)), - base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this))); + base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)), + base::Bind(&PipelineTest::OnWaitingForDecryptionKey, + base::Unretained(this))); } // Sets up expectations on the callback and initializes the pipeline. Called @@ -296,6 +299,7 @@ class PipelineTest : public ::testing::Test { MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&, const AddTextTrackDoneCB&)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); void DoOnAddTextTrack(const TextTrackConfig& config, const AddTextTrackDoneCB& done_cb) { @@ -857,13 +861,13 @@ class PipelineTeardownTest : public PipelineTest { if (state == kInitRenderer) { if (stop_or_error == kStop) { - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), PostCallback<1>(PIPELINE_OK))); ExpectPipelineStopAndDestroyPipeline(); } else { status = PIPELINE_ERROR_INITIALIZATION_FAILED; - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(PostCallback<1>(status)); } @@ -872,7 +876,7 @@ class PipelineTeardownTest : public PipelineTest { return status; } - EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _)) + EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_), PostCallback<1>(PIPELINE_OK))); diff --git a/media/base/renderer.h b/media/base/renderer.h index 1c7afbd..e3647f7 100644 --- a/media/base/renderer.h +++ b/media/base/renderer.h @@ -43,13 +43,17 @@ class MEDIA_EXPORT Renderer { // be called from any thread. // - |ended_cb|: Executed when rendering has reached the end of stream. // - |error_cb|: Executed if any error was encountered after initialization. - virtual void Initialize(DemuxerStreamProvider* demuxer_stream_provider, - const PipelineStatusCB& init_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) = 0; + // - |waiting_for_decryption_key_cb|: Executed whenever the key needed to + // decrypt the stream is not available. + virtual void Initialize( + DemuxerStreamProvider* demuxer_stream_provider, + const PipelineStatusCB& init_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) = 0; // Associates the |cdm_context| with this Renderer for decryption (and // decoding) of media data, then fires |cdm_attached_cb| with the result. diff --git a/media/base/video_renderer.h b/media/base/video_renderer.h index 1e44333..7a764b3 100644 --- a/media/base/video_renderer.h +++ b/media/base/video_renderer.h @@ -53,15 +53,20 @@ class MEDIA_EXPORT VideoRenderer { // |error_cb| is executed if an error was encountered after initialization. // // |get_time_cb| is used to query the current media playback time. - virtual void Initialize(DemuxerStream* stream, - const PipelineStatusCB& init_cb, - const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb) = 0; + // + // |waiting_for_decryption_key_cb| is executed whenever the key needed to + // decrypt the stream is not available. + virtual void Initialize( + DemuxerStream* stream, + const PipelineStatusCB& init_cb, + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb) = 0; // Discards any video data and stops reading from |stream|, executing // |callback| when completed. diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index a7a7201..148daf61 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc @@ -692,6 +692,15 @@ void WebMediaPlayerImpl::OnEncryptedMediaInitData( base::saturated_cast<unsigned int>(init_data.size())); } +void WebMediaPlayerImpl::OnWaitingForDecryptionKey() { + client_->didBlockPlaybackWaitingForKey(); + + // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called + // when a key has been successfully added (e.g. OnSessionKeysChange() with + // |has_additional_usable_key| = true). http://crbug.com/461903 + client_->didResumePlaybackBlockedForKey(); +} + void WebMediaPlayerImpl::SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) { pipeline_.SetCdm(cdm_context, cdm_attached_cb); @@ -903,7 +912,8 @@ void WebMediaPlayerImpl::StartPipeline() { BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged), base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)), BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged), - BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack)); + BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack), + BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey)); } void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) { diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index acfdf97..0dc60db 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h @@ -212,6 +212,10 @@ class MEDIA_EXPORT WebMediaPlayerImpl void OnEncryptedMediaInitData(const std::string& init_data_type, const std::vector<uint8>& init_data); + // Called when a decoder detects that the key needed to decrypt the stream + // is not available. + void OnWaitingForDecryptionKey(); + void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); // Called when a CDM has been attached to the |pipeline_|. diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc index 36f7ca64..2bb1f6d 100644 --- a/media/filters/audio_decoder_selector_unittest.cc +++ b/media/filters/audio_decoder_selector_unittest.cc @@ -135,7 +135,8 @@ class AudioDecoderSelectorTest : public ::testing::Test { base::Unretained(this)), base::Bind(&AudioDecoderSelectorTest::MockOnDecoderSelected, base::Unretained(this)), - base::Bind(&AudioDecoderSelectorTest::OnDecoderOutput)); + base::Bind(&AudioDecoderSelectorTest::OnDecoderOutput), + base::Bind(&AudioDecoderSelectorTest::OnWaitingForDecryptionKey)); message_loop_.RunUntilIdle(); } @@ -151,6 +152,10 @@ class AudioDecoderSelectorTest : public ::testing::Test { NOTREACHED(); } + static void OnWaitingForDecryptionKey() { + NOTREACHED(); + } + // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|. scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_; diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc index f026acd..555a411 100644 --- a/media/filters/decoder_selector.cc +++ b/media/filters/decoder_selector.cc @@ -75,13 +75,15 @@ void DecoderSelector<StreamType>::SelectDecoder( DemuxerStream* stream, const SetDecryptorReadyCB& set_decryptor_ready_cb, const SelectDecoderCB& select_decoder_cb, - const typename Decoder::OutputCB& output_cb) { + const typename Decoder::OutputCB& output_cb, + const base::Closure& waiting_for_decryption_key_cb) { DVLOG(2) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(stream); DCHECK(select_decoder_cb_.is_null()); set_decryptor_ready_cb_ = set_decryptor_ready_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; // Make sure |select_decoder_cb| runs on a different execution stack. select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb); @@ -107,7 +109,7 @@ void DecoderSelector<StreamType>::SelectDecoder( } decoder_.reset(new typename StreamTraits::DecryptingDecoderType( - task_runner_, set_decryptor_ready_cb_)); + task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_)); DecoderStreamTraits<StreamType>::InitializeDecoder( decoder_.get(), input_stream_, @@ -130,8 +132,8 @@ void DecoderSelector<StreamType>::DecryptingDecoderInitDone( decoder_.reset(); - decrypted_stream_.reset( - new DecryptingDemuxerStream(task_runner_, set_decryptor_ready_cb_)); + decrypted_stream_.reset(new DecryptingDemuxerStream( + task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_)); decrypted_stream_->Initialize( input_stream_, diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h index d13eb9b..59c90f5 100644 --- a/media/filters/decoder_selector.h +++ b/media/filters/decoder_selector.h @@ -70,7 +70,8 @@ class MEDIA_EXPORT DecoderSelector { void SelectDecoder(DemuxerStream* stream, const SetDecryptorReadyCB& set_decryptor_ready_cb, const SelectDecoderCB& select_decoder_cb, - const typename Decoder::OutputCB& output_cb); + const typename Decoder::OutputCB& output_cb, + const base::Closure& waiting_for_decryption_key_cb); private: void DecryptingDecoderInitDone(PipelineStatus status); @@ -86,6 +87,7 @@ class MEDIA_EXPORT DecoderSelector { SetDecryptorReadyCB set_decryptor_ready_cb_; SelectDecoderCB select_decoder_cb_; typename Decoder::OutputCB output_cb_; + base::Closure waiting_for_decryption_key_cb_; scoped_ptr<Decoder> decoder_; scoped_ptr<DecryptingDemuxerStream> decrypted_stream_; diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc index f9fa8b2..3a366d8 100644 --- a/media/filters/decoder_stream.cc +++ b/media/filters/decoder_stream.cc @@ -83,7 +83,8 @@ void DecoderStream<StreamType>::Initialize( DemuxerStream* stream, const InitCB& init_cb, const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb) { + const StatisticsCB& statistics_cb, + const base::Closure& waiting_for_decryption_key_cb) { FUNCTION_DVLOG(2); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, STATE_UNINITIALIZED); @@ -92,6 +93,7 @@ void DecoderStream<StreamType>::Initialize( statistics_cb_ = statistics_cb; init_cb_ = init_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; stream_ = stream; state_ = STATE_INITIALIZING; @@ -212,7 +214,8 @@ void DecoderStream<StreamType>::SelectDecoder( base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, weak_factory_.GetWeakPtr()), base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady, - weak_factory_.GetWeakPtr())); + weak_factory_.GetWeakPtr()), + waiting_for_decryption_key_cb_); } template <DemuxerStream::Type StreamType> diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h index b8a0d04..3c0e23e 100644 --- a/media/filters/decoder_stream.h +++ b/media/filters/decoder_stream.h @@ -61,7 +61,8 @@ class MEDIA_EXPORT DecoderStream { void Initialize(DemuxerStream* stream, const InitCB& init_cb, const SetDecryptorReadyCB& set_decryptor_ready_cb, - const StatisticsCB& statistics_cb); + const StatisticsCB& statistics_cb, + const base::Closure& waiting_for_decryption_key_cb); // Reads a decoded Output and returns it via the |read_cb|. Note that // |read_cb| is always called asynchronously. This method should only be @@ -170,6 +171,7 @@ class MEDIA_EXPORT DecoderStream { StatisticsCB statistics_cb_; InitCB init_cb_; + base::Closure waiting_for_decryption_key_cb_; ReadCB read_cb_; base::Closure reset_cb_; diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc index 0ca20f7..3425d0c2 100644 --- a/media/filters/decrypting_audio_decoder.cc +++ b/media/filters/decrypting_audio_decoder.cc @@ -34,13 +34,16 @@ static inline bool IsOutOfSync(const base::TimeDelta& timestamp_1, DecryptingAudioDecoder::DecryptingAudioDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb) + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb) : task_runner_(task_runner), state_(kUninitialized), + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb), set_decryptor_ready_cb_(set_decryptor_ready_cb), decryptor_(NULL), key_added_while_decode_pending_(false), - weak_factory_(this) {} + weak_factory_(this) { +} std::string DecryptingAudioDecoder::GetDisplayName() const { return "DecryptingAudioDecoder"; @@ -288,6 +291,7 @@ void DecryptingAudioDecoder::DeliverFrame( } state_ = kWaitingForKey; + waiting_for_decryption_key_cb_.Run(); return; } diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h index 67da6c0..30b0a63 100644 --- a/media/filters/decrypting_audio_decoder.h +++ b/media/filters/decrypting_audio_decoder.h @@ -32,7 +32,8 @@ class MEDIA_EXPORT DecryptingAudioDecoder : public AudioDecoder { public: DecryptingAudioDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb); + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb); ~DecryptingAudioDecoder() override; // AudioDecoder implementation. @@ -96,6 +97,7 @@ class MEDIA_EXPORT DecryptingAudioDecoder : public AudioDecoder { OutputCB output_cb_; DecodeCB decode_cb_; base::Closure reset_cb_; + base::Closure waiting_for_decryption_key_cb_; // The current decoder configuration. AudioDecoderConfig config_; diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc index 49df3ce..1f8395b 100644 --- a/media/filters/decrypting_audio_decoder_unittest.cc +++ b/media/filters/decrypting_audio_decoder_unittest.cc @@ -63,7 +63,9 @@ class DecryptingAudioDecoderTest : public testing::Test { message_loop_.message_loop_proxy(), base::Bind( &DecryptingAudioDecoderTest::RequestDecryptorNotification, - base::Unretained(this)))), + base::Unretained(this)), + base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey, + base::Unretained(this)))), decryptor_(new StrictMock<MockDecryptor>()), num_decrypt_and_decode_calls_(0), num_frames_in_decryptor_(0), @@ -204,6 +206,7 @@ class DecryptingAudioDecoderTest : public testing::Test { EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _)) .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey, Decryptor::AudioFrames())); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); decoder_->Decode(encrypted_buffer_, base::Bind(&DecryptingAudioDecoderTest::DecodeDone, base::Unretained(this))); @@ -252,6 +255,8 @@ class DecryptingAudioDecoderTest : public testing::Test { MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; scoped_ptr<DecryptingAudioDecoder> decoder_; scoped_ptr<StrictMock<MockDecryptor> > decryptor_; diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc index 601fd46..7a6f43c 100644 --- a/media/filters/decrypting_demuxer_stream.cc +++ b/media/filters/decrypting_demuxer_stream.cc @@ -30,14 +30,17 @@ static bool IsStreamValidAndEncrypted(DemuxerStream* stream) { DecryptingDemuxerStream::DecryptingDemuxerStream( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb) + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb) : task_runner_(task_runner), state_(kUninitialized), + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb), demuxer_stream_(NULL), set_decryptor_ready_cb_(set_decryptor_ready_cb), decryptor_(NULL), key_added_while_decrypt_pending_(false), - weak_factory_(this) {} + weak_factory_(this) { +} void DecryptingDemuxerStream::Initialize(DemuxerStream* stream, const PipelineStatusCB& status_cb) { @@ -311,6 +314,7 @@ void DecryptingDemuxerStream::DeliverBuffer( } state_ = kWaitingForKey; + waiting_for_decryption_key_cb_.Run(); return; } diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h index f66f9ab..e8d8222 100644 --- a/media/filters/decrypting_demuxer_stream.h +++ b/media/filters/decrypting_demuxer_stream.h @@ -30,7 +30,8 @@ class MEDIA_EXPORT DecryptingDemuxerStream : public DemuxerStream { public: DecryptingDemuxerStream( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb); + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb); // Cancels all pending operations immediately and fires all pending callbacks. ~DecryptingDemuxerStream() override; @@ -104,6 +105,7 @@ class MEDIA_EXPORT DecryptingDemuxerStream : public DemuxerStream { PipelineStatusCB init_cb_; ReadCB read_cb_; base::Closure reset_cb_; + base::Closure waiting_for_decryption_key_cb_; // Pointer to the input demuxer stream that will feed us encrypted buffers. DemuxerStream* demuxer_stream_; diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc index fa2a36c..3cba1f7 100644 --- a/media/filters/decrypting_demuxer_stream_unittest.cc +++ b/media/filters/decrypting_demuxer_stream_unittest.cc @@ -77,7 +77,9 @@ class DecryptingDemuxerStreamTest : public testing::Test { message_loop_.message_loop_proxy(), base::Bind( &DecryptingDemuxerStreamTest::RequestDecryptorNotification, - base::Unretained(this)))), + base::Unretained(this)), + base::Bind(&DecryptingDemuxerStreamTest::OnWaitingForDecryptionKey, + base::Unretained(this)))), decryptor_(new StrictMock<MockDecryptor>()), is_decryptor_set_(false), input_audio_stream_( @@ -225,6 +227,7 @@ class DecryptingDemuxerStreamTest : public testing::Test { EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _)) .WillRepeatedly(RunCallback<2>(Decryptor::kNoKey, scoped_refptr<DecoderBuffer>())); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady, base::Unretained(this))); message_loop_.RunUntilIdle(); @@ -260,6 +263,8 @@ class DecryptingDemuxerStreamTest : public testing::Test { MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; scoped_ptr<DecryptingDemuxerStream> demuxer_stream_; scoped_ptr<StrictMock<MockDecryptor> > decryptor_; diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc index f4aa375..d9bba50 100644 --- a/media/filters/decrypting_video_decoder.cc +++ b/media/filters/decrypting_video_decoder.cc @@ -23,14 +23,17 @@ const char DecryptingVideoDecoder::kDecoderName[] = "DecryptingVideoDecoder"; DecryptingVideoDecoder::DecryptingVideoDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb) + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb) : task_runner_(task_runner), state_(kUninitialized), + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb), set_decryptor_ready_cb_(set_decryptor_ready_cb), decryptor_(NULL), key_added_while_decode_pending_(false), trace_id_(0), - weak_factory_(this) {} + weak_factory_(this) { +} std::string DecryptingVideoDecoder::GetDisplayName() const { return kDecoderName; @@ -270,6 +273,7 @@ void DecryptingVideoDecoder::DeliverFrame( } state_ = kWaitingForKey; + waiting_for_decryption_key_cb_.Run(); return; } diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h index 8e40502..a2a9528 100644 --- a/media/filters/decrypting_video_decoder.h +++ b/media/filters/decrypting_video_decoder.h @@ -28,7 +28,8 @@ class MEDIA_EXPORT DecryptingVideoDecoder : public VideoDecoder { public: DecryptingVideoDecoder( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - const SetDecryptorReadyCB& set_decryptor_ready_cb); + const SetDecryptorReadyCB& set_decryptor_ready_cb, + const base::Closure& waiting_for_decryption_key_cb); ~DecryptingVideoDecoder() override; // VideoDecoder implementation. @@ -88,6 +89,7 @@ class MEDIA_EXPORT DecryptingVideoDecoder : public VideoDecoder { OutputCB output_cb_; DecodeCB decode_cb_; base::Closure reset_cb_; + base::Closure waiting_for_decryption_key_cb_; VideoDecoderConfig config_; diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc index 11dc52a..285bab6 100644 --- a/media/filters/decrypting_video_decoder_unittest.cc +++ b/media/filters/decrypting_video_decoder_unittest.cc @@ -57,7 +57,9 @@ class DecryptingVideoDecoderTest : public testing::Test { message_loop_.message_loop_proxy(), base::Bind( &DecryptingVideoDecoderTest::RequestDecryptorNotification, - base::Unretained(this)))), + base::Unretained(this)), + base::Bind(&DecryptingVideoDecoderTest::OnWaitingForDecryptionKey, + base::Unretained(this)))), decryptor_(new StrictMock<MockDecryptor>()), num_decrypt_and_decode_calls_(0), num_frames_in_decryptor_(0), @@ -179,6 +181,7 @@ class DecryptingVideoDecoderTest : public testing::Test { void EnterWaitingForKeyState() { EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _)) .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey, null_video_frame_)); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); decoder_->Decode(encrypted_buffer_, base::Bind(&DecryptingVideoDecoderTest::DecodeDone, base::Unretained(this))); @@ -227,6 +230,8 @@ class DecryptingVideoDecoderTest : public testing::Test { MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; scoped_ptr<DecryptingVideoDecoder> decoder_; scoped_ptr<StrictMock<MockDecryptor> > decryptor_; @@ -263,6 +268,7 @@ TEST_F(DecryptingVideoDecoderTest, Initialize_Failure) { .WillRepeatedly(RunCallback<1>(false)); EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _)) .WillRepeatedly(SaveArg<1>(&key_added_cb_)); + EXPECT_CALL(*this, RequestDecryptorNotification(_)).Times(2); InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(), DECODER_ERROR_NOT_SUPPORTED); @@ -333,7 +339,7 @@ TEST_F(DecryptingVideoDecoderTest, KeyAdded_DuringWaitingForKey) { // Test the case where the a key is added when the decryptor is in // kPendingDecode state. -TEST_F(DecryptingVideoDecoderTest, KeyAdded_DruingPendingDecode) { +TEST_F(DecryptingVideoDecoderTest, KeyAdded_DuringPendingDecode) { Initialize(); EnterPendingDecodeState(); diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc index f2dabdf..86f4c0e 100644 --- a/media/filters/video_decoder_selector_unittest.cc +++ b/media/filters/video_decoder_selector_unittest.cc @@ -131,6 +131,8 @@ class VideoDecoderSelectorTest : public ::testing::Test { base::Bind(&VideoDecoderSelectorTest::MockOnDecoderSelected, base::Unretained(this)), base::Bind(&VideoDecoderSelectorTest::FrameReady, + base::Unretained(this)), + base::Bind(&VideoDecoderSelectorTest::OnWaitingForDecryptionKey, base::Unretained(this))); message_loop_.RunUntilIdle(); } @@ -147,6 +149,10 @@ class VideoDecoderSelectorTest : public ::testing::Test { NOTREACHED(); } + void OnWaitingForDecryptionKey() { + NOTREACHED(); + } + // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|. scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_; diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc index f71c07f..a9f3b60 100644 --- a/media/filters/video_frame_stream_unittest.cc +++ b/media/filters/video_frame_stream_unittest.cc @@ -125,6 +125,7 @@ class VideoFrameStreamTest MOCK_METHOD1(OnNewSpliceBuffer, void(base::TimeDelta)); MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&)); MOCK_METHOD1(DecryptorSet, void(bool)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); void OnStatistics(const PipelineStatistics& statistics) { num_decoded_bytes_unreported_ -= statistics.video_bytes_decoded; @@ -155,7 +156,8 @@ class VideoFrameStreamTest base::Unretained(this)), base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback, base::Unretained(this)), - base::Bind(&VideoFrameStreamTest::OnStatistics, + base::Bind(&VideoFrameStreamTest::OnStatistics, base::Unretained(this)), + base::Bind(&VideoFrameStreamTest::OnWaitingForDecryptionKey, base::Unretained(this))); message_loop_.RunUntilIdle(); } @@ -276,6 +278,8 @@ class VideoFrameStreamTest break; case DECRYPTOR_NO_KEY: + if (GetParam().is_encrypted) + EXPECT_CALL(*this, OnWaitingForDecryptionKey()); ExpectDecryptorNotification(); has_no_key_ = true; ReadOneFrame(); diff --git a/media/mojo/services/mojo_renderer_impl.cc b/media/mojo/services/mojo_renderer_impl.cc index 3bde3b2..e4a1332 100644 --- a/media/mojo/services/mojo_renderer_impl.cc +++ b/media/mojo/services/mojo_renderer_impl.cc @@ -33,7 +33,8 @@ MojoRendererImpl::~MojoRendererImpl() { // Connection to |remote_media_renderer_| will error-out here. } -// TODO(xhwang): Support |paint_cb| if needed. +// TODO(xhwang): Support |paint_cb| and |waiting_for_decryption_key_cb|, +// if needed. void MojoRendererImpl::Initialize( DemuxerStreamProvider* demuxer_stream_provider, const PipelineStatusCB& init_cb, @@ -41,7 +42,8 @@ void MojoRendererImpl::Initialize( const BufferingStateCB& buffering_state_cb, const PaintCB& /* paint_cb */, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) { + const PipelineStatusCB& error_cb, + const base::Closure& /* waiting_for_decryption_key_cb */) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(demuxer_stream_provider); diff --git a/media/mojo/services/mojo_renderer_impl.h b/media/mojo/services/mojo_renderer_impl.h index d1ddc31..338bcb8 100644 --- a/media/mojo/services/mojo_renderer_impl.h +++ b/media/mojo/services/mojo_renderer_impl.h @@ -39,7 +39,8 @@ class MojoRendererImpl : public Renderer, public mojo::MediaRendererClient { const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) override; + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) override; void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) override; void Flush(const base::Closure& flush_cb) override; diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc index a737aa3..d4d2c9a 100644 --- a/media/mojo/services/mojo_renderer_service.cc +++ b/media/mojo/services/mojo_renderer_service.cc @@ -120,7 +120,8 @@ void MojoRendererService::OnStreamReady(const mojo::Closure& callback) { base::Bind(&MojoRendererService::OnBufferingStateChanged, weak_this_), base::Bind(&PaintNothing), base::Bind(&MojoRendererService::OnRendererEnded, weak_this_), - base::Bind(&MojoRendererService::OnError, weak_this_)); + base::Bind(&MojoRendererService::OnError, weak_this_), + base::Bind(base::DoNothing)); } void MojoRendererService::OnRendererInitializeDone( diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc index 56f3da7..74ef1d2 100644 --- a/media/renderers/audio_renderer_impl.cc +++ b/media/renderers/audio_renderer_impl.cc @@ -257,7 +257,8 @@ void AudioRendererImpl::Initialize( const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) { + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(stream); @@ -317,7 +318,7 @@ void AudioRendererImpl::Initialize( audio_buffer_stream_->Initialize( stream, base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, weak_factory_.GetWeakPtr()), - set_decryptor_ready_cb, statistics_cb); + set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb); } void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h index af7251a..1972c87 100644 --- a/media/renderers/audio_renderer_impl.h +++ b/media/renderers/audio_renderer_impl.h @@ -80,7 +80,8 @@ class MEDIA_EXPORT AudioRendererImpl const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) override; + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) override; TimeSource* GetTimeSource() override; void Flush(const base::Closure& callback) override; void StartPlaying() override; diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc index b5035c6..98782c9 100644 --- a/media/renderers/audio_renderer_impl_unittest.cc +++ b/media/renderers/audio_renderer_impl_unittest.cc @@ -113,8 +113,10 @@ class AudioRendererImplTest : public ::testing::Test { MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&)); MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); MOCK_METHOD1(OnError, void(PipelineStatus)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) { + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); renderer_->Initialize( &demuxer_stream_, pipeline_status_cb, SetDecryptorReadyCB(), base::Bind(&AudioRendererImplTest::OnStatistics, @@ -122,7 +124,9 @@ class AudioRendererImplTest : public ::testing::Test { base::Bind(&AudioRendererImplTest::OnBufferingStateChange, base::Unretained(this)), base::Bind(&AudioRendererImplTest::OnEnded, base::Unretained(this)), - base::Bind(&AudioRendererImplTest::OnError, base::Unretained(this))); + base::Bind(&AudioRendererImplTest::OnError, base::Unretained(this)), + base::Bind(&AudioRendererImplTest::OnWaitingForDecryptionKey, + base::Unretained(this))); } void Initialize() { diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc index 74e09d7..9367185 100644 --- a/media/renderers/renderer_impl.cc +++ b/media/renderers/renderer_impl.cc @@ -56,13 +56,15 @@ RendererImpl::~RendererImpl() { base::ResetAndReturn(&flush_cb_).Run(); } -void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider, - const PipelineStatusCB& init_cb, - const StatisticsCB& statistics_cb, - const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, - const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) { +void RendererImpl::Initialize( + DemuxerStreamProvider* demuxer_stream_provider, + const PipelineStatusCB& init_cb, + const StatisticsCB& statistics_cb, + const BufferingStateCB& buffering_state_cb, + const PaintCB& paint_cb, + const base::Closure& ended_cb, + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) { DVLOG(1) << __FUNCTION__; DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, STATE_UNINITIALIZED); @@ -82,6 +84,7 @@ void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider, ended_cb_ = ended_cb; error_cb_ = error_cb; init_cb_ = init_cb; + waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb; state_ = STATE_INITIALIZING; InitializeAudioRenderer(); @@ -258,7 +261,8 @@ void RendererImpl::InitializeAudioRenderer() { base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, &audio_buffering_state_), base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_), - base::Bind(&RendererImpl::OnError, weak_this_)); + base::Bind(&RendererImpl::OnError, weak_this_), + waiting_for_decryption_key_cb_); } void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) { @@ -307,7 +311,8 @@ void RendererImpl::InitializeVideoRenderer() { base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_), base::Bind(&RendererImpl::OnError, weak_this_), base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo, - base::Unretained(this))); + base::Unretained(this)), + waiting_for_decryption_key_cb_); } void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) { diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h index 68a2f7e..befa95c1 100644 --- a/media/renderers/renderer_impl.h +++ b/media/renderers/renderer_impl.h @@ -49,7 +49,8 @@ class MEDIA_EXPORT RendererImpl : public Renderer { const BufferingStateCB& buffering_state_cb, const PaintCB& paint_cb, const base::Closure& ended_cb, - const PipelineStatusCB& error_cb) final; + const PipelineStatusCB& error_cb, + const base::Closure& waiting_for_decryption_key_cb) final; void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) final; void Flush(const base::Closure& flush_cb) final; @@ -133,6 +134,7 @@ class MEDIA_EXPORT RendererImpl : public Renderer { PipelineStatusCB error_cb_; BufferingStateCB buffering_state_cb_; PaintCB paint_cb_; + base::Closure waiting_for_decryption_key_cb_; // Temporary callback used for Initialize() and Flush(). PipelineStatusCB init_cb_; diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc index 8f738b0..30bad2fe 100644 --- a/media/renderers/renderer_impl_unittest.cc +++ b/media/renderers/renderer_impl_unittest.cc @@ -50,6 +50,7 @@ class RendererImplTest : public ::testing::Test { MOCK_METHOD1(OnUpdateStatistics, void(const PipelineStatistics&)); MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); MOCK_METHOD1(OnVideoFramePaint, void(const scoped_refptr<VideoFrame>&)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void()); private: DISALLOW_COPY_AND_ASSIGN(CallbackHelper); @@ -88,7 +89,7 @@ class RendererImplTest : public ::testing::Test { // Sets up expectations to allow the audio renderer to initialize. void SetAudioRendererInitializeExpectations(PipelineStatus status) { EXPECT_CALL(*audio_renderer_, - Initialize(audio_stream_.get(), _, _, _, _, _, _)) + Initialize(audio_stream_.get(), _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<4>(&audio_buffering_state_cb_), SaveArg<5>(&audio_ended_cb_), SaveArg<6>(&audio_error_cb_), RunCallback<1>(status))); @@ -97,13 +98,14 @@ class RendererImplTest : public ::testing::Test { // Sets up expectations to allow the video renderer to initialize. void SetVideoRendererInitializeExpectations(PipelineStatus status) { EXPECT_CALL(*video_renderer_, - Initialize(video_stream_.get(), _, _, _, _, _, _, _, _)) + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<4>(&video_buffering_state_cb_), SaveArg<6>(&video_ended_cb_), RunCallback<1>(status))); } void InitializeAndExpect(PipelineStatus start_status) { EXPECT_CALL(callbacks_, OnInitialize(start_status)); + EXPECT_CALL(callbacks_, OnWaitingForDecryptionKey()).Times(0); if (start_status == PIPELINE_OK && audio_stream_) { EXPECT_CALL(*audio_renderer_, GetTimeSource()) @@ -121,7 +123,9 @@ class RendererImplTest : public ::testing::Test { base::Bind(&CallbackHelper::OnVideoFramePaint, base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)), - base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_))); + base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)), + base::Bind(&CallbackHelper::OnWaitingForDecryptionKey, + base::Unretained(&callbacks_))); base::RunLoop().RunUntilIdle(); } @@ -433,7 +437,7 @@ TEST_F(RendererImplTest, ErrorDuringInitialize) { // Force an audio error to occur during video renderer initialization. EXPECT_CALL(*video_renderer_, - Initialize(video_stream_.get(), _, _, _, _, _, _, _, _)) + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _)) .WillOnce(DoAll(AudioError(&audio_error_cb_, PIPELINE_ERROR_DECODE), SaveArg<4>(&video_buffering_state_cb_), SaveArg<6>(&video_ended_cb_), diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc index 5e2819d..0ad19e4 100644 --- a/media/renderers/video_renderer_impl.cc +++ b/media/renderers/video_renderer_impl.cc @@ -109,7 +109,8 @@ void VideoRendererImpl::Initialize( const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb) { + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb) { DCHECK(task_runner_->BelongsToCurrentThread()); base::AutoLock auto_lock(lock_); DCHECK(stream); @@ -139,7 +140,7 @@ void VideoRendererImpl::Initialize( video_frame_stream_->Initialize( stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized, weak_factory_.GetWeakPtr()), - set_decryptor_ready_cb, statistics_cb); + set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb); } void VideoRendererImpl::CreateVideoThread() { diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h index 69cf140..eec8b15 100644 --- a/media/renderers/video_renderer_impl.h +++ b/media/renderers/video_renderer_impl.h @@ -60,7 +60,8 @@ class MEDIA_EXPORT VideoRendererImpl const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, - const TimeDeltaCB& get_time_cb) override; + const TimeDeltaCB& get_time_cb, + const base::Closure& waiting_for_decryption_key_cb) override; void Flush(const base::Closure& callback) override; void StartPlayingFrom(base::TimeDelta timestamp) override; diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index c771ad4..d9cad51 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc @@ -94,6 +94,7 @@ class VideoRendererImplTest : public ::testing::Test { demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE); EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce( DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status))); + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); renderer_->Initialize( &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(), base::Bind(&VideoRendererImplTest::OnStatisticsUpdate, @@ -102,7 +103,9 @@ class VideoRendererImplTest : public ::testing::Test { base::Unretained(&mock_cb_)), base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)), ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(), - base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this))); + base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)), + base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey, + base::Unretained(this))); } void StartPlayingFrom(int milliseconds) { @@ -289,6 +292,8 @@ class VideoRendererImplTest : public ::testing::Test { void OnStatisticsUpdate(const PipelineStatistics& stats) {} + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); + base::MessageLoop message_loop_; // Used to protect |time_|. diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index c2e23f8..55bba58 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc @@ -659,6 +659,10 @@ class PipelineIntegrationTest : public PipelineIntegrationTestHost { .WillRepeatedly(SaveArg<0>(&metadata_)); EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH)) .Times(AtMost(1)); + + // Encrypted content not used, so this is never called. + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); + demuxer_ = source->GetDemuxer().Pass(); pipeline_->Start( demuxer_.get(), CreateRenderer(), @@ -673,7 +677,9 @@ class PipelineIntegrationTest : public PipelineIntegrationTestHost { base::Bind(&PipelineIntegrationTest::OnVideoFramePaint, base::Unretained(this)), base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack, - base::Unretained(this))); + base::Unretained(this)), + base::Bind(&PipelineIntegrationTest::OnWaitingForDecryptionKey, + base::Unretained(this))); message_loop_.Run(); EXPECT_EQ(PIPELINE_OK, pipeline_status_); } @@ -694,6 +700,10 @@ class PipelineIntegrationTest : public PipelineIntegrationTestHost { .Times(AtMost(1)); EXPECT_CALL(*this, DecryptorAttached(true)); + // Encrypted content used but keys provided in advance, so this is + // never called. + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); + demuxer_ = source->GetDemuxer().Pass(); pipeline_->SetCdm(encrypted_media->GetCdmContext(), @@ -713,7 +723,9 @@ class PipelineIntegrationTest : public PipelineIntegrationTestHost { base::Bind(&PipelineIntegrationTest::OnVideoFramePaint, base::Unretained(this)), base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack, - base::Unretained(this))); + base::Unretained(this)), + base::Bind(&PipelineIntegrationTest::OnWaitingForDecryptionKey, + base::Unretained(this))); source->set_encrypted_media_init_data_cb( base::Bind(&FakeEncryptedMedia::OnEncryptedMediaInitData, diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc index d40b0dc..e122d9a 100644 --- a/media/test/pipeline_integration_test_base.cc +++ b/media/test/pipeline_integration_test_base.cc @@ -121,6 +121,10 @@ PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename, base::Unretained(this))); } + // Should never be called as the required decryption keys for the encrypted + // media files are provided in advance. + EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); + pipeline_->Start( demuxer_.get(), CreateRenderer(), base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)), @@ -134,7 +138,9 @@ PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename, base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint, base::Unretained(this)), base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack, - base::Unretained(this))); + base::Unretained(this)), + base::Bind(&PipelineIntegrationTestBase::OnWaitingForDecryptionKey, + base::Unretained(this))); message_loop_.Run(); return pipeline_status_; } diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h index de6c0e0..716e27c 100644 --- a/media/test/pipeline_integration_test_base.h +++ b/media/test/pipeline_integration_test_base.h @@ -140,6 +140,7 @@ class PipelineIntegrationTestBase { MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig& config, const AddTextTrackDoneCB& done_cb)); + MOCK_METHOD0(OnWaitingForDecryptionKey, void(void)); }; } // namespace media diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc index afd5d0b..60eb45c 100644 --- a/media/tools/player_x11/player_x11.cc +++ b/media/tools/player_x11/player_x11.cc @@ -149,7 +149,8 @@ void InitPipeline( base::Bind(&OnBufferingStateChanged), paint_cb, base::Bind(&DoNothing), - base::Bind(&OnAddTextTrack)); + base::Bind(&OnAddTextTrack), + base::Bind(&DoNothing)); // Wait until the pipeline is fully initialized. event.Wait(); |