summaryrefslogtreecommitdiff
path: root/chromium/chromecast/media
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-08-01 12:59:39 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-08-04 12:40:43 +0000
commit28b1110370900897ab652cb420c371fab8857ad4 (patch)
tree41b32127d23b0df4f2add2a27e12dc87bddb260e /chromium/chromecast/media
parent399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (diff)
downloadqtwebengine-chromium-28b1110370900897ab652cb420c371fab8857ad4.tar.gz
BASELINE: Update Chromium to 53.0.2785.41
Also adds a few extra files for extensions. Change-Id: Iccdd55d98660903331cf8b7b29188da781830af4 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/chromecast/media')
-rw-r--r--chromium/chromecast/media/BUILD.gn1
-rw-r--r--chromium/chromecast/media/audio/cast_audio_manager.cc12
-rw-r--r--chromium/chromecast/media/audio/cast_audio_manager.h12
-rw-r--r--chromium/chromecast/media/audio/cast_audio_output_stream.cc4
-rw-r--r--chromium/chromecast/media/audio/cast_audio_output_stream.h2
-rw-r--r--chromium/chromecast/media/audio/cast_audio_output_stream_unittest.cc14
-rw-r--r--chromium/chromecast/media/base/decrypt_context_impl.cc32
-rw-r--r--chromium/chromecast/media/base/decrypt_context_impl.h38
-rw-r--r--chromium/chromecast/media/base/decrypt_context_impl_clearkey.cc16
-rw-r--r--chromium/chromecast/media/base/decrypt_context_impl_clearkey.h15
-rw-r--r--chromium/chromecast/media/base/media_resource_tracker.cc36
-rw-r--r--chromium/chromecast/media/base/media_resource_tracker.h28
-rw-r--r--chromium/chromecast/media/base/media_resource_tracker_unittest.cc18
-rw-r--r--chromium/chromecast/media/cdm/BUILD.gn10
-rw-r--r--chromium/chromecast/media/cdm/browser_cdm_cast.cc252
-rw-r--r--chromium/chromecast/media/cdm/cast_cdm.cc108
-rw-r--r--chromium/chromecast/media/cdm/cast_cdm.h (renamed from chromium/chromecast/media/cdm/browser_cdm_cast.h)81
-rw-r--r--chromium/chromecast/media/cdm/cast_cdm_context.cc54
-rw-r--r--chromium/chromecast/media/cdm/cast_cdm_context.h64
-rw-r--r--chromium/chromecast/media/cdm/cast_cdm_proxy.cc167
-rw-r--r--chromium/chromecast/media/cdm/cast_cdm_proxy.h71
-rw-r--r--chromium/chromecast/media/cma/DEPS4
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/BUILD.gn33
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/audio_filter_factory.h28
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/audio_filter_factory_default.cc18
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/audio_filter_interface.h28
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/cast_media_shlib.cc6
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc118
-rw-r--r--chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h5
-rw-r--r--chromium/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc4
-rw-r--r--chromium/chromecast/media/cma/backend/multizone_backend_unittest.cc53
-rw-r--r--chromium/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc9
-rw-r--r--chromium/chromecast/media/cma/base/cast_decrypt_config_impl.cc21
-rw-r--r--chromium/chromecast/media/cma/base/cast_decrypt_config_impl.h11
-rw-r--r--chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc23
-rw-r--r--chromium/chromecast/media/cma/base/decoder_buffer_adapter.h2
-rw-r--r--chromium/chromecast/media/cma/base/decoder_buffer_adapter_unittest.cc161
-rw-r--r--chromium/chromecast/media/cma/base/demuxer_stream_adapter.cc4
-rw-r--r--chromium/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc14
-rw-r--r--chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc15
-rw-r--r--chromium/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc22
-rw-r--r--chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc84
-rw-r--r--chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h24
-rw-r--r--chromium/chromecast/media/cma/pipeline/decrypt_util.cc31
-rw-r--r--chromium/chromecast/media/cma/pipeline/decrypt_util.h15
-rw-r--r--chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc81
-rw-r--r--chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h14
-rw-r--r--chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc1
48 files changed, 1268 insertions, 596 deletions
diff --git a/chromium/chromecast/media/BUILD.gn b/chromium/chromecast/media/BUILD.gn
index c79adce6d46..fc6291d6c0f 100644
--- a/chromium/chromecast/media/BUILD.gn
+++ b/chromium/chromecast/media/BUILD.gn
@@ -22,6 +22,7 @@ test("cast_media_unittests") {
"cma/base/balanced_media_task_runner_unittest.cc",
"cma/base/buffering_controller_unittest.cc",
"cma/base/buffering_frame_provider_unittest.cc",
+ "cma/base/decoder_buffer_adapter_unittest.cc",
"cma/base/demuxer_stream_adapter_unittest.cc",
"cma/base/demuxer_stream_for_test.cc",
"cma/base/demuxer_stream_for_test.h",
diff --git a/chromium/chromecast/media/audio/cast_audio_manager.cc b/chromium/chromecast/media/audio/cast_audio_manager.cc
index e3b56d9c769..d5367f6692b 100644
--- a/chromium/chromecast/media/audio/cast_audio_manager.cc
+++ b/chromium/chromecast/media/audio/cast_audio_manager.cc
@@ -73,28 +73,32 @@ CastAudioManager::CreateMediaPipelineBackend(
}
::media::AudioOutputStream* CastAudioManager::MakeLinearOutputStream(
- const ::media::AudioParameters& params) {
+ const ::media::AudioParameters& params,
+ const ::media::AudioManager::LogCallback& log_callback) {
DCHECK_EQ(::media::AudioParameters::AUDIO_PCM_LINEAR, params.format());
return new CastAudioOutputStream(params, this);
}
::media::AudioOutputStream* CastAudioManager::MakeLowLatencyOutputStream(
const ::media::AudioParameters& params,
- const std::string& device_id) {
+ const std::string& device_id,
+ const ::media::AudioManager::LogCallback& log_callback) {
DCHECK_EQ(::media::AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return new CastAudioOutputStream(params, this);
}
::media::AudioInputStream* CastAudioManager::MakeLinearInputStream(
const ::media::AudioParameters& params,
- const std::string& device_id) {
+ const std::string& device_id,
+ const ::media::AudioManager::LogCallback& log_callback) {
LOG(WARNING) << "No support for input audio devices";
return nullptr;
}
::media::AudioInputStream* CastAudioManager::MakeLowLatencyInputStream(
const ::media::AudioParameters& params,
- const std::string& device_id) {
+ const std::string& device_id,
+ const ::media::AudioManager::LogCallback& log_callback) {
LOG(WARNING) << "No support for input audio devices";
return nullptr;
}
diff --git a/chromium/chromecast/media/audio/cast_audio_manager.h b/chromium/chromecast/media/audio/cast_audio_manager.h
index 213e52c82a5..346a7f73b0a 100644
--- a/chromium/chromecast/media/audio/cast_audio_manager.h
+++ b/chromium/chromecast/media/audio/cast_audio_manager.h
@@ -45,16 +45,20 @@ class CastAudioManager : public ::media::AudioManagerBase {
private:
// AudioManagerBase implementation.
::media::AudioOutputStream* MakeLinearOutputStream(
- const ::media::AudioParameters& params) override;
+ const ::media::AudioParameters& params,
+ const ::media::AudioManager::LogCallback& log_callback) override;
::media::AudioOutputStream* MakeLowLatencyOutputStream(
const ::media::AudioParameters& params,
- const std::string& device_id) override;
+ const std::string& device_id,
+ const ::media::AudioManager::LogCallback& log_callback) override;
::media::AudioInputStream* MakeLinearInputStream(
const ::media::AudioParameters& params,
- const std::string& device_id) override;
+ const std::string& device_id,
+ const ::media::AudioManager::LogCallback& log_callback) override;
::media::AudioInputStream* MakeLowLatencyInputStream(
const ::media::AudioParameters& params,
- const std::string& device_id) override;
+ const std::string& device_id,
+ const ::media::AudioManager::LogCallback& log_callback) override;
::media::AudioParameters GetPreferredOutputStreamParameters(
const std::string& output_device_id,
const ::media::AudioParameters& input_params) override;
diff --git a/chromium/chromecast/media/audio/cast_audio_output_stream.cc b/chromium/chromecast/media/audio/cast_audio_output_stream.cc
index 3af92654267..215827fd9e1 100644
--- a/chromium/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromium/chromecast/media/audio/cast_audio_output_stream.cc
@@ -168,6 +168,7 @@ CastAudioOutputStream::CastAudioOutputStream(
audio_manager_(audio_manager),
volume_(1.0),
source_callback_(nullptr),
+ timestamp_helper_(audio_params_.sample_rate()),
backend_(new Backend()),
buffer_duration_(audio_params.GetBufferDuration()),
push_in_progress_(false),
@@ -203,6 +204,7 @@ bool CastAudioOutputStream::Open() {
audio_bus_ = ::media::AudioBus::Create(audio_params_);
decoder_buffer_ = new DecoderBufferAdapter(
new ::media::DecoderBuffer(audio_params_.GetBytesPerBuffer()));
+ timestamp_helper_.SetBaseTimestamp(base::TimeDelta());
VLOG(1) << __FUNCTION__ << " : " << this;
return true;
@@ -279,6 +281,8 @@ void CastAudioOutputStream::PushBuffer() {
frame_count * audio_params_.GetBytesPerFrame());
audio_bus_->ToInterleaved(frame_count, audio_params_.bits_per_sample() / 8,
decoder_buffer_->writable_data());
+ decoder_buffer_->set_timestamp(timestamp_helper_.GetTimestamp());
+ timestamp_helper_.AddFrames(frame_count);
auto completion_cb = base::Bind(&CastAudioOutputStream::OnPushBufferComplete,
weak_factory_.GetWeakPtr());
diff --git a/chromium/chromecast/media/audio/cast_audio_output_stream.h b/chromium/chromecast/media/audio/cast_audio_output_stream.h
index fd2c6042afe..47764360289 100644
--- a/chromium/chromecast/media/audio/cast_audio_output_stream.h
+++ b/chromium/chromecast/media/audio/cast_audio_output_stream.h
@@ -10,6 +10,7 @@
#include "base/time/time.h"
#include "media/audio/audio_io.h"
#include "media/base/audio_parameters.h"
+#include "media/base/audio_timestamp_helper.h"
namespace chromecast {
namespace media {
@@ -44,6 +45,7 @@ class CastAudioOutputStream : public ::media::AudioOutputStream {
AudioSourceCallback* source_callback_;
std::unique_ptr<::media::AudioBus> audio_bus_;
scoped_refptr<media::DecoderBufferBase> decoder_buffer_;
+ ::media::AudioTimestampHelper timestamp_helper_;
std::unique_ptr<Backend> backend_;
const base::TimeDelta buffer_duration_;
bool push_in_progress_;
diff --git a/chromium/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromium/chromecast/media/audio/cast_audio_output_stream_unittest.cc
index 77db4c26dd5..e65aa25631c 100644
--- a/chromium/chromecast/media/audio/cast_audio_output_stream_unittest.cc
+++ b/chromium/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -4,6 +4,7 @@
#include "chromecast/media/audio/cast_audio_output_stream.h"
+#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "chromecast/base/metrics/cast_metrics_test_helper.h"
#include "chromecast/media/audio/cast_audio_manager.h"
@@ -104,8 +105,8 @@ class FakeMediaPipelineBackend : public MediaPipelineBackend {
// MediaPipelineBackend implementation:
AudioDecoder* CreateAudioDecoder() override {
DCHECK(!audio_decoder_);
- audio_decoder_ = new FakeAudioDecoder();
- return audio_decoder_;
+ audio_decoder_ = base::MakeUnique<FakeAudioDecoder>();
+ return audio_decoder_.get();
}
VideoDecoder* CreateVideoDecoder() override {
NOTREACHED();
@@ -137,11 +138,11 @@ class FakeMediaPipelineBackend : public MediaPipelineBackend {
bool SetPlaybackRate(float rate) override { return true; }
State state() const { return state_; }
- FakeAudioDecoder* decoder() const { return audio_decoder_; }
+ FakeAudioDecoder* decoder() const { return audio_decoder_.get(); }
private:
State state_;
- FakeAudioDecoder* audio_decoder_;
+ std::unique_ptr<FakeAudioDecoder> audio_decoder_;
};
class FakeAudioSourceCallback
@@ -235,8 +236,9 @@ class CastAudioOutputStreamTest : public ::testing::Test {
}
::media::AudioOutputStream* CreateStream() {
- return audio_manager_->MakeAudioOutputStream(GetAudioParams(),
- kDefaultDeviceId);
+ return audio_manager_->MakeAudioOutputStream(
+ GetAudioParams(), kDefaultDeviceId,
+ ::media::AudioManager::LogCallback());
}
// Runs the messsage loop for duration equivalent to the given number of
diff --git a/chromium/chromecast/media/base/decrypt_context_impl.cc b/chromium/chromecast/media/base/decrypt_context_impl.cc
index 945ba9672a3..cc04405785f 100644
--- a/chromium/chromecast/media/base/decrypt_context_impl.cc
+++ b/chromium/chromecast/media/base/decrypt_context_impl.cc
@@ -4,12 +4,23 @@
#include "chromecast/media/base/decrypt_context_impl.h"
+#include <memory>
#include <vector>
+#include "base/bind.h"
+#include "base/logging.h"
#include "chromecast/public/media/cast_decoder_buffer.h"
namespace chromecast {
namespace media {
+namespace {
+void BufferDecryptCB(bool* called, bool* ret, bool success) {
+ DCHECK(called);
+ DCHECK(ret);
+ *called = true;
+ *ret = success;
+}
+}
DecryptContextImpl::DecryptContextImpl(CastKeySystem key_system)
: key_system_(key_system) {}
@@ -23,11 +34,26 @@ CastKeySystem DecryptContextImpl::GetKeySystem() {
bool DecryptContextImpl::Decrypt(CastDecoderBuffer* buffer,
std::vector<uint8_t>* output) {
output->resize(buffer->data_size());
- return Decrypt(buffer, output->data());
+ return Decrypt(buffer, output->data(), 0);
}
-bool DecryptContextImpl::Decrypt(CastDecoderBuffer* buffer, uint8_t* output) {
- return false;
+bool DecryptContextImpl::Decrypt(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset) {
+ bool called = false;
+ bool success = false;
+ DecryptAsync(buffer, output, data_offset,
+ base::Bind(&BufferDecryptCB, &called, &success));
+ CHECK(called) << "Sync Decrypt isn't supported";
+
+ return success;
+}
+
+void DecryptContextImpl::DecryptAsync(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset,
+ const DecryptCB& decrypt_cb) {
+ decrypt_cb.Run(false);
}
bool DecryptContextImpl::CanDecryptToBuffer() const {
diff --git a/chromium/chromecast/media/base/decrypt_context_impl.h b/chromium/chromecast/media/base/decrypt_context_impl.h
index bb83a646dd6..e41ff48930c 100644
--- a/chromium/chromecast/media/base/decrypt_context_impl.h
+++ b/chromium/chromecast/media/base/decrypt_context_impl.h
@@ -5,11 +5,13 @@
#ifndef CHROMECAST_MEDIA_BASE_DECRYPT_CONTEXT_IMPL_H_
#define CHROMECAST_MEDIA_BASE_DECRYPT_CONTEXT_IMPL_H_
+#include <stddef.h>
#include <stdint.h>
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "chromecast/media/base/key_systems_common.h"
+#include <memory>
+
+#include "base/callback.h"
+#include "chromecast/public/media/cast_key_system.h"
#include "chromecast/public/media/decrypt_context.h"
namespace chromecast {
@@ -21,6 +23,8 @@ namespace media {
// decryption context.
class DecryptContextImpl : public DecryptContext {
public:
+ using DecryptCB = base::Callback<void(bool)>;
+
explicit DecryptContextImpl(CastKeySystem key_system);
~DecryptContextImpl() override;
@@ -29,12 +33,25 @@ class DecryptContextImpl : public DecryptContext {
bool Decrypt(CastDecoderBuffer* buffer,
std::vector<uint8_t>* output) final;
- // TODO(yucliu): replace DecryptContext::Decrypt with this one in next
+ // TODO(smcgruer): Replace DecryptContext::Decrypt with this one in next
// public api releasing.
- // Decrypts the given buffer. Returns true/false for success/failure,
- // and places the decrypted data in |output| if successful.
- // Decrypted data in |output| has the same length as |buffer|.
- virtual bool Decrypt(CastDecoderBuffer* buffer, uint8_t* output);
+ // Decrypts the given buffer. Returns true/false for success/failure.
+ //
+ // The decrypted data will be of size |buffer.data_size()| and there must be
+ // enough space in |output| to store that data.
+ //
+ // If non-zero, |data_offset| specifies an offset to be applied to |output|
+ // before the decrypted data is written.
+ virtual bool Decrypt(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset);
+
+ // Similar as the above one. Decryption success or not will be returned in
+ // |decrypt_cb|. |decrypt_cb| will be called on caller's thread.
+ virtual void DecryptAsync(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset,
+ const DecryptCB& decrypt_cb);
// Returns whether the data can be decrypted into user memory.
// If the key system doesn't support secure output or the app explicitly
@@ -46,7 +63,10 @@ class DecryptContextImpl : public DecryptContext {
private:
CastKeySystem key_system_;
- DISALLOW_COPY_AND_ASSIGN(DecryptContextImpl);
+ // TODO(smcgruer): Restore macro usage next public API release.
+ // DISALLOW_COPY_AND_ASSIGN(DecryptContextImpl);
+ DecryptContextImpl(const DecryptContextImpl&) = delete;
+ void operator=(const DecryptContextImpl&) = delete;
};
} // namespace media
diff --git a/chromium/chromecast/media/base/decrypt_context_impl_clearkey.cc b/chromium/chromecast/media/base/decrypt_context_impl_clearkey.cc
index f1f83419b3a..c4539cbe44a 100644
--- a/chromium/chromecast/media/base/decrypt_context_impl_clearkey.cc
+++ b/chromium/chromecast/media/base/decrypt_context_impl_clearkey.cc
@@ -7,6 +7,7 @@
#include <openssl/aes.h>
#include <string.h>
+#include <memory>
#include <string>
#include <vector>
@@ -26,8 +27,16 @@ DecryptContextImplClearKey::DecryptContextImplClearKey(
DecryptContextImplClearKey::~DecryptContextImplClearKey() {}
-bool DecryptContextImplClearKey::Decrypt(CastDecoderBuffer* buffer,
- uint8_t* output) {
+void DecryptContextImplClearKey::DecryptAsync(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset,
+ const DecryptCB& decrypt_cb) {
+ decrypt_cb.Run(DoDecrypt(buffer, output, data_offset));
+}
+
+bool DecryptContextImplClearKey::DoDecrypt(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset) {
DCHECK(buffer);
DCHECK(output);
@@ -38,6 +47,9 @@ bool DecryptContextImplClearKey::Decrypt(CastDecoderBuffer* buffer,
if (!decrypt_config || decrypt_config->iv().size() == 0)
return false;
+ // Apply the |data_offset|, if requested.
+ output += data_offset;
+
// Get the key.
std::string raw_key;
if (!key_->GetRawKey(&raw_key)) {
diff --git a/chromium/chromecast/media/base/decrypt_context_impl_clearkey.h b/chromium/chromecast/media/base/decrypt_context_impl_clearkey.h
index 8e0706e287e..d21a188bf98 100644
--- a/chromium/chromecast/media/base/decrypt_context_impl_clearkey.h
+++ b/chromium/chromecast/media/base/decrypt_context_impl_clearkey.h
@@ -5,6 +5,10 @@
#ifndef CHROMECAST_MEDIA_BASE_DECRYPT_CONTEXT_IMPL_CLEARKEY_H_
#define CHROMECAST_MEDIA_BASE_DECRYPT_CONTEXT_IMPL_CLEARKEY_H_
+#include <stddef.h>
+
+#include <vector>
+
#include "base/macros.h"
#include "chromecast/media/base/decrypt_context_impl.h"
@@ -21,13 +25,18 @@ class DecryptContextImplClearKey : public DecryptContextImpl {
explicit DecryptContextImplClearKey(crypto::SymmetricKey* key);
~DecryptContextImplClearKey() override;
- // DecryptContext implementation.
- bool Decrypt(CastDecoderBuffer* buffer, uint8_t* output) override;
-
// DecryptContextImpl implementation.
+ void DecryptAsync(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset,
+ const DecryptCB& decrypt_cb) override;
+
bool CanDecryptToBuffer() const override;
private:
+ bool DoDecrypt(CastDecoderBuffer* buffer,
+ uint8_t* output,
+ size_t data_offset);
crypto::SymmetricKey* const key_;
DISALLOW_COPY_AND_ASSIGN(DecryptContextImplClearKey);
diff --git a/chromium/chromecast/media/base/media_resource_tracker.cc b/chromium/chromecast/media/base/media_resource_tracker.cc
index 29fb3b27e6f..79b4c12f5d0 100644
--- a/chromium/chromecast/media/base/media_resource_tracker.cc
+++ b/chromium/chromecast/media/base/media_resource_tracker.cc
@@ -15,8 +15,7 @@ namespace media {
MediaResourceTracker::MediaResourceTracker(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner)
- : delegate_(nullptr),
- media_use_count_(0),
+ : media_use_count_(0),
media_lib_initialized_(false),
delete_on_finalize_(false),
ui_task_runner_(ui_task_runner),
@@ -28,11 +27,6 @@ MediaResourceTracker::MediaResourceTracker(
MediaResourceTracker::~MediaResourceTracker() {}
-void MediaResourceTracker::SetDelegate(Delegate* delegate) {
- DCHECK(ui_task_runner_->BelongsToCurrentThread());
- delegate_ = delegate;
-}
-
void MediaResourceTracker::InitializeMediaLib() {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
media_task_runner_->PostTask(
@@ -53,7 +47,6 @@ void MediaResourceTracker::FinalizeMediaLib(
void MediaResourceTracker::FinalizeAndDestroy() {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
- delegate_ = nullptr;
media_task_runner_->PostTask(
FROM_HERE,
@@ -67,41 +60,18 @@ void MediaResourceTracker::IncrementUsageCount() {
DCHECK(media_lib_initialized_);
DCHECK(finalize_completion_cb_.is_null());
media_use_count_++;
-
- if (media_use_count_ == 1) {
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&MediaResourceTracker::CallDelegateStartOnUiThread,
- base::Unretained(this)));
- }
}
void MediaResourceTracker::DecrementUsageCount() {
DCHECK(media_task_runner_->BelongsToCurrentThread());
media_use_count_--;
- if (media_use_count_ == 0) {
- ui_task_runner_->PostTask(
- FROM_HERE, base::Bind(&MediaResourceTracker::CallDelegateStopOnUiThread,
- base::Unretained(this)));
-
- if (delete_on_finalize_ || !finalize_completion_cb_.is_null())
+ if (media_use_count_ == 0 &&
+ (delete_on_finalize_ || !finalize_completion_cb_.is_null())) {
CallFinalizeOnMediaThread();
}
}
-void MediaResourceTracker::CallDelegateStartOnUiThread() {
- DCHECK(ui_task_runner_->BelongsToCurrentThread());
- if (delegate_)
- delegate_->OnStartUsingMedia();
-}
-
-void MediaResourceTracker::CallDelegateStopOnUiThread() {
- DCHECK(ui_task_runner_->BelongsToCurrentThread());
- if (delegate_)
- delegate_->OnStopUsingMedia();
-}
-
void MediaResourceTracker::CallInitializeOnMediaThread() {
DCHECK(media_task_runner_->BelongsToCurrentThread());
if (media_lib_initialized_)
diff --git a/chromium/chromecast/media/base/media_resource_tracker.h b/chromium/chromecast/media/base/media_resource_tracker.h
index e714a163984..52a3011fddd 100644
--- a/chromium/chromecast/media/base/media_resource_tracker.h
+++ b/chromium/chromecast/media/base/media_resource_tracker.h
@@ -27,34 +27,15 @@ namespace media {
// * This class interacts on both UI and media threads (task runners required
// by ctor to perform thread hopping and checks). See function-level comments
// on which thread to use for which operations.
-// * All interaction with delegate is performed on UI thread.
// * The application should instantiate a single MediaResourceTracker instance.
// Destruction should be performed by calling FinalizeAndDestroy from the UI
// thread.
class MediaResourceTracker {
public:
- class Delegate {
- public:
- // Called on UI thread when media usage starts (i.e. count steps 0->1).
- // Does not mean Initialize has happened.
- virtual void OnStartUsingMedia() = 0;
-
- // Called on UI thread when media usage stops (i.e. count steps 1->0).
- // Does not mean Finalize has happened.
- virtual void OnStopUsingMedia() = 0;
-
- protected:
- virtual ~Delegate() {}
- };
-
MediaResourceTracker(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner);
- // Sets the delegate to receive start/stop media usage notifications. Must
- // call on UI thread. Set to nullptr to clear existing delegate.
- void SetDelegate(Delegate* delegate);
-
// Media resource acquire implementation. Must call on ui thread; runs
// CastMediaShlib::Initialize on media thread. Safe to call even if media lib
// already initialized.
@@ -73,7 +54,7 @@ class MediaResourceTracker {
// (2) Calls CastMediaShlib::Finalize on media thread
// (3) Deletes this object
// Must be called on UI thread. No further calls should be made on UI thread
- // after this. Delegate is implicitly cleared.
+ // after this.
void FinalizeAndDestroy();
// Users of media resource (e.g. CMA pipeline) should call these when they
@@ -86,10 +67,6 @@ class MediaResourceTracker {
friend class TestMediaResourceTracker;
virtual ~MediaResourceTracker();
- // Tasks posted to UI thread
- void CallDelegateStartOnUiThread();
- void CallDelegateStopOnUiThread();
-
// Tasks posted to media thread
void CallInitializeOnMediaThread();
void MaybeCallFinalizeOnMediaThread(const base::Closure& completion_cb);
@@ -100,9 +77,6 @@ class MediaResourceTracker {
virtual void DoInitializeMediaLib();
virtual void DoFinalizeMediaLib();
- // Accessed on UI thread
- Delegate* delegate_;
-
// Accessed on media thread + ctor
size_t media_use_count_;
bool media_lib_initialized_;
diff --git a/chromium/chromecast/media/base/media_resource_tracker_unittest.cc b/chromium/chromecast/media/base/media_resource_tracker_unittest.cc
index dd83f7f8bd7..01eac0341d6 100644
--- a/chromium/chromecast/media/base/media_resource_tracker_unittest.cc
+++ b/chromium/chromecast/media/base/media_resource_tracker_unittest.cc
@@ -20,7 +20,9 @@ namespace chromecast {
namespace media {
void RunUntilIdle(base::TaskRunner* task_runner) {
- base::WaitableEvent completion_event(false, false);
+ base::WaitableEvent completion_event(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
task_runner->PostTask(FROM_HERE,
base::Bind(&base::WaitableEvent::Signal,
base::Unretained(&completion_event)));
@@ -28,16 +30,12 @@ void RunUntilIdle(base::TaskRunner* task_runner) {
}
// Collection of mocks to verify MediaResourceTracker takes the correct actions.
-class MediaResourceTrackerTestMocks : public MediaResourceTracker::Delegate {
+class MediaResourceTrackerTestMocks {
public:
MOCK_METHOD0(Initialize, void()); // CastMediaShlib::Initialize
MOCK_METHOD0(Finalize, void()); // CastMediaShlib::Finalize
MOCK_METHOD0(Destroyed, void()); // ~CastMediaResourceTracker
MOCK_METHOD0(FinalizeCallback, void()); // callback to Finalize
-
- // MediaResourceTracker::Delegate implementation:
- MOCK_METHOD0(OnStartUsingMedia, void());
- MOCK_METHOD0(OnStopUsingMedia, void());
};
class TestMediaResourceTracker : public MediaResourceTracker {
@@ -83,7 +81,6 @@ class MediaResourceTrackerTest : public ::testing::Test {
resource_tracker_ = new TestMediaResourceTracker(
test_mocks_.get(), message_loop_->task_runner(),
media_task_runner_);
- resource_tracker_->SetDelegate(test_mocks_.get());
}
void TearDown() override { media_thread_.reset(); }
@@ -173,7 +170,6 @@ TEST_F(MediaResourceTrackerTest, FinalizeResourceInUse) {
resource_tracker_->InitializeMediaLib();
IncrementMediaUsageCount();
- EXPECT_CALL(*test_mocks_, OnStartUsingMedia()).Times(1);
RunUntilIdle(media_task_runner_.get());
base::RunLoop().RunUntilIdle();
@@ -188,7 +184,6 @@ TEST_F(MediaResourceTrackerTest, FinalizeResourceInUse) {
DecrementMediaUsageCount();
EXPECT_CALL(*test_mocks_, FinalizeCallback()).Times(1);
- EXPECT_CALL(*test_mocks_, OnStopUsingMedia()).Times(1);
RunUntilIdle(media_task_runner_.get());
base::RunLoop().RunUntilIdle();
@@ -205,7 +200,6 @@ TEST_F(MediaResourceTrackerTest, DestroyWaitForNoUsers) {
resource_tracker_->InitializeMediaLib();
IncrementMediaUsageCount();
- EXPECT_CALL(*test_mocks_, OnStartUsingMedia()).Times(1);
RunUntilIdle(media_task_runner_.get());
base::RunLoop().RunUntilIdle();
@@ -214,8 +208,6 @@ TEST_F(MediaResourceTrackerTest, DestroyWaitForNoUsers) {
resource_tracker_->FinalizeAndDestroy();
RunUntilIdle(media_task_runner_.get());
- // Note, OnStop delegate call should not be made during shutdown
- EXPECT_CALL(*test_mocks_, OnStopUsingMedia()).Times(0);
EXPECT_CALL(*test_mocks_, Finalize()).Times(1);
EXPECT_CALL(*test_mocks_, Destroyed()).Times(1);
DecrementMediaUsageCount();
@@ -231,7 +223,6 @@ TEST_F(MediaResourceTrackerTest, DestroyWithPendingFinalize) {
resource_tracker_->InitializeMediaLib();
IncrementMediaUsageCount();
- EXPECT_CALL(*test_mocks_, OnStartUsingMedia()).Times(1);
RunUntilIdle(media_task_runner_.get());
base::RunLoop().RunUntilIdle();
@@ -246,7 +237,6 @@ TEST_F(MediaResourceTrackerTest, DestroyWithPendingFinalize) {
EXPECT_CALL(*test_mocks_, Finalize()).Times(1);
EXPECT_CALL(*test_mocks_, Destroyed()).Times(1);
EXPECT_CALL(*test_mocks_, FinalizeCallback()).Times(1);
- EXPECT_CALL(*test_mocks_, OnStopUsingMedia()).Times(0);
DecrementMediaUsageCount();
diff --git a/chromium/chromecast/media/cdm/BUILD.gn b/chromium/chromecast/media/cdm/BUILD.gn
index cc9fa01f64a..c6a21eba54e 100644
--- a/chromium/chromecast/media/cdm/BUILD.gn
+++ b/chromium/chromecast/media/cdm/BUILD.gn
@@ -7,12 +7,18 @@ import("//chromecast/chromecast.gni")
# GYP target: chromecast/media.gyp:media_cdm
source_set("cdm") {
sources = [
- "browser_cdm_cast.cc",
- "browser_cdm_cast.h",
+ "cast_cdm.cc",
+ "cast_cdm.h",
+ "cast_cdm_context.cc",
+ "cast_cdm_context.h",
+ "cast_cdm_proxy.cc",
+ "cast_cdm_proxy.h",
"chromecast_init_data.cc",
"chromecast_init_data.h",
]
+ configs += [ "//media/mojo/services:mojo_media_config" ]
+
deps = [
"//base",
"//chromecast/media/base",
diff --git a/chromium/chromecast/media/cdm/browser_cdm_cast.cc b/chromium/chromecast/media/cdm/browser_cdm_cast.cc
deleted file mode 100644
index 65c05b5974f..00000000000
--- a/chromium/chromecast/media/cdm/browser_cdm_cast.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/media/cdm/browser_cdm_cast.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chromecast/media/base/media_resource_tracker.h"
-#include "media/base/cdm_key_information.h"
-#include "media/base/cdm_promise.h"
-#include "media/cdm/player_tracker_impl.h"
-
-namespace chromecast {
-namespace media {
-
-namespace {
-
-// media::CdmPromiseTemplate implementation that wraps a promise so as to
-// allow passing to other threads.
-template <typename... T>
-class CdmPromiseInternal : public ::media::CdmPromiseTemplate<T...> {
- public:
- CdmPromiseInternal(std::unique_ptr<::media::CdmPromiseTemplate<T...>> promise)
- : task_runner_(base::ThreadTaskRunnerHandle::Get()),
- promise_(std::move(promise)) {}
-
- ~CdmPromiseInternal() final {
- if (IsPromiseSettled())
- return;
-
- DCHECK(promise_);
- RejectPromiseOnDestruction();
- }
-
- // CdmPromiseTemplate<> implementation.
- void resolve(const T&... result) final;
-
- void reject(::media::MediaKeys::Exception exception,
- uint32_t system_code,
- const std::string& error_message) final {
- MarkPromiseSettled();
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&::media::CdmPromiseTemplate<T...>::reject,
- base::Owned(promise_.release()),
- exception, system_code, error_message));
- }
-
- private:
- using ::media::CdmPromiseTemplate<T...>::IsPromiseSettled;
- using ::media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
- using ::media::CdmPromiseTemplate<T...>::RejectPromiseOnDestruction;
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- std::unique_ptr<::media::CdmPromiseTemplate<T...>> promise_;
-};
-
-template <typename... T>
-void CdmPromiseInternal<T...>::resolve(const T&... result) {
- MarkPromiseSettled();
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&::media::CdmPromiseTemplate<T...>::resolve,
- base::Owned(promise_.release()),
- result...));
-}
-
-template <typename... T>
-std::unique_ptr<CdmPromiseInternal<T...>> BindPromiseToCurrentLoop(
- std::unique_ptr<::media::CdmPromiseTemplate<T...>> promise) {
- return base::WrapUnique(new CdmPromiseInternal<T...>(std::move(promise)));
-}
-
-} // namespace
-
-BrowserCdmCast::BrowserCdmCast(MediaResourceTracker* media_resource_tracker)
- : media_resource_tracker_(media_resource_tracker) {
- DCHECK(media_resource_tracker);
- thread_checker_.DetachFromThread();
-}
-
-BrowserCdmCast::~BrowserCdmCast() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(player_tracker_impl_.get());
- player_tracker_impl_->NotifyCdmUnset();
- media_resource_tracker_->DecrementUsageCount();
-}
-
-void BrowserCdmCast::Initialize(
- const ::media::SessionMessageCB& session_message_cb,
- const ::media::SessionClosedCB& session_closed_cb,
- const ::media::LegacySessionErrorCB& legacy_session_error_cb,
- const ::media::SessionKeysChangeCB& session_keys_change_cb,
- const ::media::SessionExpirationUpdateCB& session_expiration_update_cb) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- media_resource_tracker_->IncrementUsageCount();
- player_tracker_impl_.reset(new ::media::PlayerTrackerImpl());
-
- session_message_cb_ = session_message_cb;
- session_closed_cb_ = session_closed_cb;
- legacy_session_error_cb_ = legacy_session_error_cb;
- session_keys_change_cb_ = session_keys_change_cb;
- session_expiration_update_cb_ = session_expiration_update_cb;
-
- InitializeInternal();
-}
-
-int BrowserCdmCast::RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) {
- DCHECK(thread_checker_.CalledOnValidThread());
- return player_tracker_impl_->RegisterPlayer(new_key_cb, cdm_unset_cb);
-}
-
-void BrowserCdmCast::UnregisterPlayer(int registration_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- player_tracker_impl_->UnregisterPlayer(registration_id);
-}
-
-void BrowserCdmCast::OnSessionMessage(
- const std::string& session_id,
- const std::vector<uint8_t>& message,
- const GURL& destination_url,
- ::media::MediaKeys::MessageType message_type) {
- session_message_cb_.Run(session_id,
- message_type,
- message,
- destination_url);
-}
-
-void BrowserCdmCast::OnSessionClosed(const std::string& session_id) {
- session_closed_cb_.Run(session_id);
-}
-
-void BrowserCdmCast::OnSessionKeysChange(const std::string& session_id,
- bool newly_usable_keys,
- ::media::CdmKeysInfo keys_info) {
- session_keys_change_cb_.Run(session_id, newly_usable_keys,
- std::move(keys_info));
-
- if (newly_usable_keys)
- player_tracker_impl_->NotifyNewKey();
-}
-
-void BrowserCdmCast::KeyIdAndKeyPairsToInfo(
- const ::media::KeyIdAndKeyPairs& keys,
- ::media::CdmKeysInfo* keys_info) {
- DCHECK(keys_info);
- for (const std::pair<std::string, std::string>& key : keys) {
- std::unique_ptr<::media::CdmKeyInformation> cdm_key_information(
- new ::media::CdmKeyInformation(key.first,
- ::media::CdmKeyInformation::USABLE, 0));
- keys_info->push_back(cdm_key_information.release());
- }
-}
-
-// A macro runs current member function on |task_runner_| thread.
-#define FORWARD_ON_CDM_THREAD(param_fn, ...) \
- task_runner_->PostTask( \
- FROM_HERE, \
- base::Bind(&BrowserCdmCast::param_fn, \
- base::Unretained(browser_cdm_cast_.get()), ##__VA_ARGS__))
-
-BrowserCdmCastUi::BrowserCdmCastUi(
- const scoped_refptr<BrowserCdmCast>& browser_cdm_cast,
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
- : browser_cdm_cast_(browser_cdm_cast), task_runner_(task_runner) {}
-
-BrowserCdmCastUi::~BrowserCdmCastUi() {
- DCHECK(thread_checker_.CalledOnValidThread());
- browser_cdm_cast_->AddRef();
- BrowserCdmCast* raw_cdm = browser_cdm_cast_.get();
- browser_cdm_cast_ = nullptr;
- task_runner_->ReleaseSoon(FROM_HERE, raw_cdm);
-}
-
-BrowserCdmCast* BrowserCdmCastUi::browser_cdm_cast() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return browser_cdm_cast_.get();
-}
-
-void BrowserCdmCastUi::SetServerCertificate(
- const std::vector<uint8_t>& certificate,
- std::unique_ptr<::media::SimpleCdmPromise> promise) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FORWARD_ON_CDM_THREAD(
- SetServerCertificate, certificate,
- base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
-}
-
-void BrowserCdmCastUi::CreateSessionAndGenerateRequest(
- ::media::MediaKeys::SessionType session_type,
- ::media::EmeInitDataType init_data_type,
- const std::vector<uint8_t>& init_data,
- std::unique_ptr<::media::NewSessionCdmPromise> promise) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FORWARD_ON_CDM_THREAD(
- CreateSessionAndGenerateRequest, session_type, init_data_type, init_data,
- base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
-}
-
-void BrowserCdmCastUi::LoadSession(
- ::media::MediaKeys::SessionType session_type,
- const std::string& session_id,
- std::unique_ptr<::media::NewSessionCdmPromise> promise) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FORWARD_ON_CDM_THREAD(
- LoadSession, session_type, session_id,
- base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
-}
-
-void BrowserCdmCastUi::UpdateSession(
- const std::string& session_id,
- const std::vector<uint8_t>& response,
- std::unique_ptr<::media::SimpleCdmPromise> promise) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FORWARD_ON_CDM_THREAD(
- UpdateSession, session_id, response,
- base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
-}
-
-void BrowserCdmCastUi::CloseSession(
- const std::string& session_id,
- std::unique_ptr<::media::SimpleCdmPromise> promise) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FORWARD_ON_CDM_THREAD(
- CloseSession, session_id,
- base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
-}
-
-void BrowserCdmCastUi::RemoveSession(
- const std::string& session_id,
- std::unique_ptr<::media::SimpleCdmPromise> promise) {
- DCHECK(thread_checker_.CalledOnValidThread());
- FORWARD_ON_CDM_THREAD(
- RemoveSession, session_id,
- base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
-}
-
-// A default empty implementation for subclasses that don't need to provide
-// any key system specific initialization.
-void BrowserCdmCast::InitializeInternal() {
-}
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/media/cdm/cast_cdm.cc b/chromium/chromecast/media/cdm/cast_cdm.cc
new file mode 100644
index 00000000000..30965c11314
--- /dev/null
+++ b/chromium/chromecast/media/cdm/cast_cdm.cc
@@ -0,0 +1,108 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cdm/cast_cdm.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/media/base/media_resource_tracker.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/decryptor.h"
+#include "media/cdm/player_tracker_impl.h"
+
+namespace chromecast {
+namespace media {
+
+CastCdm::CastCdm(MediaResourceTracker* media_resource_tracker)
+ : media_resource_tracker_(media_resource_tracker),
+ cast_cdm_context_(new CastCdmContext(this)) {
+ DCHECK(media_resource_tracker);
+ thread_checker_.DetachFromThread();
+}
+
+CastCdm::~CastCdm() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(player_tracker_impl_.get());
+ player_tracker_impl_->NotifyCdmUnset();
+ media_resource_tracker_->DecrementUsageCount();
+}
+
+void CastCdm::Initialize(
+ const ::media::SessionMessageCB& session_message_cb,
+ const ::media::SessionClosedCB& session_closed_cb,
+ const ::media::LegacySessionErrorCB& legacy_session_error_cb,
+ const ::media::SessionKeysChangeCB& session_keys_change_cb,
+ const ::media::SessionExpirationUpdateCB& session_expiration_update_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ media_resource_tracker_->IncrementUsageCount();
+ player_tracker_impl_.reset(new ::media::PlayerTrackerImpl());
+
+ session_message_cb_ = session_message_cb;
+ session_closed_cb_ = session_closed_cb;
+ legacy_session_error_cb_ = legacy_session_error_cb;
+ session_keys_change_cb_ = session_keys_change_cb;
+ session_expiration_update_cb_ = session_expiration_update_cb;
+
+ InitializeInternal();
+}
+
+int CastCdm::RegisterPlayer(const base::Closure& new_key_cb,
+ const base::Closure& cdm_unset_cb) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return player_tracker_impl_->RegisterPlayer(new_key_cb, cdm_unset_cb);
+}
+
+void CastCdm::UnregisterPlayer(int registration_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ player_tracker_impl_->UnregisterPlayer(registration_id);
+}
+
+::media::CdmContext* CastCdm::GetCdmContext() {
+ return cast_cdm_context_.get();
+}
+
+void CastCdm::OnSessionMessage(const std::string& session_id,
+ const std::vector<uint8_t>& message,
+ const GURL& destination_url,
+ ::media::MediaKeys::MessageType message_type) {
+ session_message_cb_.Run(session_id, message_type, message, destination_url);
+}
+
+void CastCdm::OnSessionClosed(const std::string& session_id) {
+ session_closed_cb_.Run(session_id);
+}
+
+void CastCdm::OnSessionKeysChange(const std::string& session_id,
+ bool newly_usable_keys,
+ ::media::CdmKeysInfo keys_info) {
+ session_keys_change_cb_.Run(session_id, newly_usable_keys,
+ std::move(keys_info));
+
+ if (newly_usable_keys)
+ player_tracker_impl_->NotifyNewKey();
+}
+
+void CastCdm::KeyIdAndKeyPairsToInfo(const ::media::KeyIdAndKeyPairs& keys,
+ ::media::CdmKeysInfo* keys_info) {
+ DCHECK(keys_info);
+ for (const std::pair<std::string, std::string>& key : keys) {
+ std::unique_ptr<::media::CdmKeyInformation> cdm_key_information(
+ new ::media::CdmKeyInformation(key.first,
+ ::media::CdmKeyInformation::USABLE, 0));
+ keys_info->push_back(cdm_key_information.release());
+ }
+}
+
+// A default empty implementation for subclasses that don't need to provide
+// any key system specific initialization.
+void CastCdm::InitializeInternal() {}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cdm/browser_cdm_cast.h b/chromium/chromecast/media/cdm/cast_cdm.h
index 1f65bcdfebe..e9c7512abed 100644
--- a/chromium/chromecast/media/cdm/browser_cdm_cast.h
+++ b/chromium/chromecast/media/cdm/cast_cdm.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROMECAST_MEDIA_CDM_BROWSER_CDM_CAST_H_
-#define CHROMECAST_MEDIA_CDM_BROWSER_CDM_CAST_H_
+#ifndef CHROMECAST_MEDIA_CDM_cast_cdm_H_
+#define CHROMECAST_MEDIA_CDM_cast_cdm_H_
#include <stdint.h>
@@ -17,7 +17,9 @@
#include "base/sequenced_task_runner_helpers.h"
#include "base/threading/thread_checker.h"
#include "chromecast/media/base/media_resource_tracker.h"
+#include "chromecast/media/cdm/cast_cdm_context.h"
#include "chromecast/public/media/cast_key_status.h"
+#include "media/base/cdm_context.h"
#include "media/base/media_keys.h"
#include "media/base/player_tracker.h"
#include "media/cdm/json_web_key.h"
@@ -34,17 +36,16 @@ namespace chromecast {
namespace media {
class DecryptContextImpl;
-// BrowserCdmCast is an extension of MediaKeys that provides common
+// CastCdm is an extension of MediaKeys that provides common
// functionality across CDM implementations.
// All these additional functions are synchronous so:
// - either both the CDM and the media pipeline must be running on the same
// thread,
-// - or BrowserCdmCast implementations must use some locks.
+// - or CastCdm implementations must use some locks.
//
-class BrowserCdmCast : public ::media::MediaKeys,
- public ::media::PlayerTracker {
+class CastCdm : public ::media::MediaKeys {
public:
- explicit BrowserCdmCast(MediaResourceTracker* media_resource_tracker);
+ explicit CastCdm(MediaResourceTracker* media_resource_tracker);
void Initialize(
const ::media::SessionMessageCB& session_message_cb,
@@ -53,14 +54,12 @@ class BrowserCdmCast : public ::media::MediaKeys,
const ::media::SessionKeysChangeCB& session_keys_change_cb,
const ::media::SessionExpirationUpdateCB& session_expiration_update_cb);
- // ::media::PlayerTracker implementation.
int RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) override;
- void UnregisterPlayer(int registration_id) override;
+ const base::Closure& cdm_unset_cb);
+ void UnregisterPlayer(int registration_id);
// Returns the decryption context needed to decrypt frames encrypted with
- // |key_id|.
- // Returns null if |key_id| is not available.
+ // |key_id|. Returns null if |key_id| is not available.
virtual std::unique_ptr<DecryptContextImpl> GetDecryptContext(
const std::string& key_id) const = 0;
@@ -70,8 +69,11 @@ class BrowserCdmCast : public ::media::MediaKeys,
CastKeyStatus key_status,
uint32_t system_code) = 0;
+ // ::media::MediaKeys implementation.
+ ::media::CdmContext* GetCdmContext() override;
+
protected:
- ~BrowserCdmCast() override;
+ ~CastCdm() override;
void OnSessionMessage(const std::string& session_id,
const std::vector<uint8_t>& message,
@@ -86,8 +88,6 @@ class BrowserCdmCast : public ::media::MediaKeys,
::media::CdmKeysInfo* key_info);
private:
- friend class BrowserCdmCastUi;
-
// Allow subclasses to override to provide key sysytem specific
// initialization.
virtual void InitializeInternal();
@@ -100,59 +100,14 @@ class BrowserCdmCast : public ::media::MediaKeys,
MediaResourceTracker* media_resource_tracker_;
std::unique_ptr<::media::PlayerTrackerImpl> player_tracker_impl_;
+ std::unique_ptr<CastCdmContext> cast_cdm_context_;
base::ThreadChecker thread_checker_;
- DISALLOW_COPY_AND_ASSIGN(BrowserCdmCast);
-};
-
-// MediaKeys implementation that lives on the UI thread and forwards all calls
-// to a BrowserCdmCast instance on the CMA thread. This is used to simplify the
-// UI-CMA threading interaction.
-class BrowserCdmCastUi : public ::media::MediaKeys {
- public:
- BrowserCdmCastUi(
- const scoped_refptr<BrowserCdmCast>& browser_cdm_cast,
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
-
- BrowserCdmCast* browser_cdm_cast() const;
-
- private:
- ~BrowserCdmCastUi() override;
-
- // ::media::MediaKeys implementation:
- void SetServerCertificate(
- const std::vector<uint8_t>& certificate,
- std::unique_ptr<::media::SimpleCdmPromise> promise) override;
- void CreateSessionAndGenerateRequest(
- ::media::MediaKeys::SessionType session_type,
- ::media::EmeInitDataType init_data_type,
- const std::vector<uint8_t>& init_data,
- std::unique_ptr<::media::NewSessionCdmPromise> promise) override;
- void LoadSession(
- ::media::MediaKeys::SessionType session_type,
- const std::string& session_id,
- std::unique_ptr<::media::NewSessionCdmPromise> promise) override;
- void UpdateSession(
- const std::string& session_id,
- const std::vector<uint8_t>& response,
- std::unique_ptr<::media::SimpleCdmPromise> promise) override;
- void CloseSession(
- const std::string& session_id,
- std::unique_ptr<::media::SimpleCdmPromise> promise) override;
- void RemoveSession(
- const std::string& session_id,
- std::unique_ptr<::media::SimpleCdmPromise> promise) override;
-
- scoped_refptr<BrowserCdmCast> browser_cdm_cast_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserCdmCastUi);
+ DISALLOW_COPY_AND_ASSIGN(CastCdm);
};
} // namespace media
} // namespace chromecast
-#endif // CHROMECAST_MEDIA_CDM_BROWSER_CDM_CAST_H_
+#endif // CHROMECAST_MEDIA_CDM_cast_cdm_H_
diff --git a/chromium/chromecast/media/cdm/cast_cdm_context.cc b/chromium/chromecast/media/cdm/cast_cdm_context.cc
new file mode 100644
index 00000000000..742516cab4e
--- /dev/null
+++ b/chromium/chromecast/media/cdm/cast_cdm_context.cc
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cdm/cast_cdm_context.h"
+
+#include "base/logging.h"
+#include "chromecast/media/base/decrypt_context_impl.h"
+#include "chromecast/media/cdm/cast_cdm.h"
+#include "chromecast/public/media/decrypt_context.h"
+
+namespace chromecast {
+namespace media {
+
+CastCdmContext::CastCdmContext(CastCdm* cast_cdm) : cast_cdm_(cast_cdm) {
+ DCHECK(cast_cdm_);
+}
+
+CastCdmContext::~CastCdmContext() {}
+
+::media::Decryptor* CastCdmContext::GetDecryptor() {
+ // Subclasses providing CdmContext for a ClearKey CDM implementation must
+ // override this method to provide the Decryptor. Subclasses providing DRM
+ // implementations should return nullptr here.
+ return nullptr;
+}
+
+int CastCdmContext::GetCdmId() const {
+ // This is a local CDM module.
+ return ::media::CdmContext::kInvalidCdmId;
+}
+
+int CastCdmContext::RegisterPlayer(const base::Closure& new_key_cb,
+ const base::Closure& cdm_unset_cb) {
+ return cast_cdm_->RegisterPlayer(new_key_cb, cdm_unset_cb);
+}
+
+void CastCdmContext::UnregisterPlayer(int registration_id) {
+ cast_cdm_->UnregisterPlayer(registration_id);
+}
+
+std::unique_ptr<DecryptContextImpl> CastCdmContext::GetDecryptContext(
+ const std::string& key_id) {
+ return cast_cdm_->GetDecryptContext(key_id);
+}
+
+void CastCdmContext::SetKeyStatus(const std::string& key_id,
+ CastKeyStatus key_status,
+ uint32_t system_code) {
+ cast_cdm_->SetKeyStatus(key_id, key_status, system_code);
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cdm/cast_cdm_context.h b/chromium/chromecast/media/cdm/cast_cdm_context.h
new file mode 100644
index 00000000000..70fa26ba940
--- /dev/null
+++ b/chromium/chromecast/media/cdm/cast_cdm_context.h
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CDM_CAST_CDM_CONTEXT_H_
+#define CHROMECAST_MEDIA_CDM_CAST_CDM_CONTEXT_H_
+
+#include <memory>
+#include <string>
+
+#include "chromecast/public/media/cast_key_status.h"
+#include "media/base/cdm_context.h"
+
+namespace media {
+class Decryptor;
+}
+
+namespace chromecast {
+namespace media {
+
+class CastCdm;
+class DecryptContextImpl;
+
+// This class exposes only what's needed by CastRenderer.
+class CastCdmContext : public ::media::CdmContext {
+ public:
+ explicit CastCdmContext(CastCdm* cast_cdm);
+ ~CastCdmContext() override;
+
+ // ::media::CdmContext implementation.
+ ::media::Decryptor* GetDecryptor() override;
+ int GetCdmId() const override;
+
+ // Register a player with this CDM. |new_key_cb| will be called when a new
+ // key is available. |cdm_unset_cb| will be called when the CDM is destroyed.
+ int RegisterPlayer(const base::Closure& new_key_cb,
+ const base::Closure& cdm_unset_cb);
+
+ // Unregiester a player with this CDM. |registration_id| should be the id
+ // returned by RegisterPlayer().
+ void UnregisterPlayer(int registration_id);
+
+ // Returns the decryption context needed to decrypt frames encrypted with
+ // |key_id|. Returns null if |key_id| is not available.
+ std::unique_ptr<DecryptContextImpl> GetDecryptContext(
+ const std::string& key_id);
+
+ // Notifies that key status has changed (e.g. if expiry is detected by
+ // hardware decoder).
+ void SetKeyStatus(const std::string& key_id,
+ CastKeyStatus key_status,
+ uint32_t system_code);
+
+ private:
+ // The CastCdm object which owns |this|.
+ CastCdm* const cast_cdm_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastCdmContext);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CDM_CAST_CDM_CONTEXT_H_ \ No newline at end of file
diff --git a/chromium/chromecast/media/cdm/cast_cdm_proxy.cc b/chromium/chromecast/media/cdm/cast_cdm_proxy.cc
new file mode 100644
index 00000000000..eeadabcb05b
--- /dev/null
+++ b/chromium/chromecast/media/cdm/cast_cdm_proxy.cc
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cdm/cast_cdm_proxy.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/cdm_promise.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+// media::CdmPromiseTemplate implementation that wraps a promise so as to
+// allow passing to other threads.
+template <typename... T>
+class CdmPromiseInternal : public ::media::CdmPromiseTemplate<T...> {
+ public:
+ CdmPromiseInternal(std::unique_ptr<::media::CdmPromiseTemplate<T...>> promise)
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ promise_(std::move(promise)) {}
+
+ ~CdmPromiseInternal() final {
+ if (IsPromiseSettled())
+ return;
+
+ DCHECK(promise_);
+ RejectPromiseOnDestruction();
+ }
+
+ // CdmPromiseTemplate<> implementation.
+ void resolve(const T&... result) final;
+
+ void reject(::media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ const std::string& error_message) final {
+ MarkPromiseSettled();
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&::media::CdmPromiseTemplate<T...>::reject,
+ base::Owned(promise_.release()), exception,
+ system_code, error_message));
+ }
+
+ private:
+ using ::media::CdmPromiseTemplate<T...>::IsPromiseSettled;
+ using ::media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
+ using ::media::CdmPromiseTemplate<T...>::RejectPromiseOnDestruction;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ std::unique_ptr<::media::CdmPromiseTemplate<T...>> promise_;
+};
+
+template <typename... T>
+void CdmPromiseInternal<T...>::resolve(const T&... result) {
+ MarkPromiseSettled();
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&::media::CdmPromiseTemplate<T...>::resolve,
+ base::Owned(promise_.release()), result...));
+}
+
+template <typename... T>
+std::unique_ptr<CdmPromiseInternal<T...>> BindPromiseToCurrentLoop(
+ std::unique_ptr<::media::CdmPromiseTemplate<T...>> promise) {
+ return base::WrapUnique(new CdmPromiseInternal<T...>(std::move(promise)));
+}
+
+} // namespace
+
+// A macro runs current member function on |task_runner_| thread.
+#define FORWARD_ON_CDM_THREAD(param_fn, ...) \
+ task_runner_->PostTask( \
+ FROM_HERE, base::Bind(&CastCdm::param_fn, \
+ base::Unretained(cast_cdm_.get()), ##__VA_ARGS__))
+
+CastCdmProxy::CastCdmProxy(
+ const scoped_refptr<CastCdm>& cast_cdm,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : cast_cdm_(cast_cdm), task_runner_(task_runner) {}
+
+CastCdmProxy::~CastCdmProxy() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ cast_cdm_->AddRef();
+ CastCdm* raw_cdm = cast_cdm_.get();
+ cast_cdm_ = nullptr;
+ task_runner_->ReleaseSoon(FROM_HERE, raw_cdm);
+}
+
+CastCdm* CastCdmProxy::cast_cdm() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return cast_cdm_.get();
+}
+
+void CastCdmProxy::SetServerCertificate(
+ const std::vector<uint8_t>& certificate,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FORWARD_ON_CDM_THREAD(
+ SetServerCertificate, certificate,
+ base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
+}
+
+void CastCdmProxy::CreateSessionAndGenerateRequest(
+ ::media::MediaKeys::SessionType session_type,
+ ::media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
+ std::unique_ptr<::media::NewSessionCdmPromise> promise) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FORWARD_ON_CDM_THREAD(
+ CreateSessionAndGenerateRequest, session_type, init_data_type, init_data,
+ base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
+}
+
+void CastCdmProxy::LoadSession(
+ ::media::MediaKeys::SessionType session_type,
+ const std::string& session_id,
+ std::unique_ptr<::media::NewSessionCdmPromise> promise) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FORWARD_ON_CDM_THREAD(
+ LoadSession, session_type, session_id,
+ base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
+}
+
+void CastCdmProxy::UpdateSession(
+ const std::string& session_id,
+ const std::vector<uint8_t>& response,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FORWARD_ON_CDM_THREAD(
+ UpdateSession, session_id, response,
+ base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
+}
+
+void CastCdmProxy::CloseSession(
+ const std::string& session_id,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FORWARD_ON_CDM_THREAD(
+ CloseSession, session_id,
+ base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
+}
+
+void CastCdmProxy::RemoveSession(
+ const std::string& session_id,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ FORWARD_ON_CDM_THREAD(
+ RemoveSession, session_id,
+ base::Passed(BindPromiseToCurrentLoop(std::move(promise))));
+}
+
+::media::CdmContext* CastCdmProxy::GetCdmContext() {
+ // This will be recast as a CastCdmService pointer before being passed to the
+ // media pipeline. The returned object should only be called on the CMA
+ // renderer thread.
+ return cast_cdm_->GetCdmContext();
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cdm/cast_cdm_proxy.h b/chromium/chromecast/media/cdm/cast_cdm_proxy.h
new file mode 100644
index 00000000000..f17c4c199da
--- /dev/null
+++ b/chromium/chromecast/media/cdm/cast_cdm_proxy.h
@@ -0,0 +1,71 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CDM_CAST_CDM_PROXY_H_
+#define CHROMECAST_MEDIA_CDM_CAST_CDM_PROXY_H_
+
+#include <stdint.h>
+
+#include "base/threading/thread_checker.h"
+#include "chromecast/media/cdm/cast_cdm.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace chromecast {
+namespace media {
+
+// MediaKeys implementation that lives on the UI thread and forwards all calls
+// to a CastCdm instance on the CMA thread. This is used to simplify the
+// UI-CMA threading interaction.
+// TODO(slan): Remove this class when CMA is deprecated.
+class CastCdmProxy : public ::media::MediaKeys {
+ public:
+ CastCdmProxy(const scoped_refptr<CastCdm>& cast_cdm,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ // Returns the CDM instance which lives on the CMA thread.
+ CastCdm* cast_cdm() const;
+
+ private:
+ ~CastCdmProxy() override;
+
+ // ::media::MediaKeys implementation:
+ void SetServerCertificate(
+ const std::vector<uint8_t>& certificate,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) override;
+ void CreateSessionAndGenerateRequest(
+ ::media::MediaKeys::SessionType session_type,
+ ::media::EmeInitDataType init_data_type,
+ const std::vector<uint8_t>& init_data,
+ std::unique_ptr<::media::NewSessionCdmPromise> promise) override;
+ void LoadSession(
+ ::media::MediaKeys::SessionType session_type,
+ const std::string& session_id,
+ std::unique_ptr<::media::NewSessionCdmPromise> promise) override;
+ void UpdateSession(
+ const std::string& session_id,
+ const std::vector<uint8_t>& response,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) override;
+ void CloseSession(
+ const std::string& session_id,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) override;
+ void RemoveSession(
+ const std::string& session_id,
+ std::unique_ptr<::media::SimpleCdmPromise> promise) override;
+ ::media::CdmContext* GetCdmContext() override;
+
+ scoped_refptr<CastCdm> cast_cdm_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastCdmProxy);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CDM_CAST_CDM_PROXY_H_
diff --git a/chromium/chromecast/media/cma/DEPS b/chromium/chromecast/media/cma/DEPS
new file mode 100644
index 00000000000..b0625031df6
--- /dev/null
+++ b/chromium/chromecast/media/cma/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "-chromecast/media/cdm",
+ "+chromecast/media/cdm/cast_cdm_context.h",
+]
diff --git a/chromium/chromecast/media/cma/backend/alsa/BUILD.gn b/chromium/chromecast/media/cma/backend/alsa/BUILD.gn
index f0554e13a2b..ec28069cc64 100644
--- a/chromium/chromecast/media/cma/backend/alsa/BUILD.gn
+++ b/chromium/chromecast/media/cma/backend/alsa/BUILD.gn
@@ -4,6 +4,7 @@
import("//build/buildflag_header.gni")
import("//build/config/chromecast_build.gni")
+import("//chromecast/chromecast.gni")
import("//media/media_options.gni")
import("//testing/test.gni")
@@ -24,6 +25,7 @@ shared_library("libcast_media_1.0_audio") {
"cast_media_shlib.cc",
"media_codec_support_cast_audio.cc",
]
+
deps = [
":alsa_cma_backend",
"//base",
@@ -50,8 +52,11 @@ source_set("alsa_cma_backend") {
"stream_mixer_alsa_input_impl.h",
]
+ libs = [ "asound" ]
+
deps = [
":alsa_features",
+ ":audio_filter_includes",
"//base",
"//chromecast/base",
"//chromecast/media/cma/backend",
@@ -61,6 +66,34 @@ source_set("alsa_cma_backend") {
"//media",
"//media:shared_memory_support",
]
+
+ if (chromecast_branding == "public") {
+ deps += [ ":audio_filter_null" ]
+ } else {
+ deps += [ "//chromecast/internal/media/cma/backend/alsa:filter" ]
+ }
+}
+
+source_set("audio_filter_null") {
+ sources = [
+ "audio_filter_factory_default.cc",
+ ]
+
+ deps = [
+ ":audio_filter_includes",
+ ]
+}
+
+source_set("audio_filter_includes") {
+ sources = [
+ "audio_filter_factory.h",
+ "audio_filter_interface.h",
+ ]
+
+ deps = [
+ "//base",
+ "//media",
+ ]
}
# GYP target: chromecast/media/media.gyp:chromecast_alsa_features
diff --git a/chromium/chromecast/media/cma/backend/alsa/audio_filter_factory.h b/chromium/chromecast/media/cma/backend/alsa/audio_filter_factory.h
new file mode 100644
index 00000000000..5f8dcda132e
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/alsa/audio_filter_factory.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_FILTER_FACTORY_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_FILTER_FACTORY_H_
+
+#include <memory>
+
+#include "chromecast/media/cma/backend/alsa/audio_filter_interface.h"
+
+namespace chromecast {
+namespace media {
+
+class AudioFilterFactory {
+ public:
+ // FilterType specifies the usage of the created filter.
+ enum FilterType { PRE_LOOPBACK_FILTER, POST_LOOPBACK_FILTER };
+
+ // Creates a new AudioFilterInterface.
+ static std::unique_ptr<AudioFilterInterface> MakeAudioFilter(
+ FilterType filter_type);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_FILTER_AUDIO_FILTER_FACTORY_H_
diff --git a/chromium/chromecast/media/cma/backend/alsa/audio_filter_factory_default.cc b/chromium/chromecast/media/cma/backend/alsa/audio_filter_factory_default.cc
new file mode 100644
index 00000000000..3333c9a263e
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/alsa/audio_filter_factory_default.cc
@@ -0,0 +1,18 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cma/backend/alsa/audio_filter_factory.h"
+
+// An AudioFilterFactory that just returns nullptrs
+
+namespace chromecast {
+namespace media {
+
+std::unique_ptr<AudioFilterInterface> AudioFilterFactory::MakeAudioFilter(
+ AudioFilterFactory::FilterType filter_type) {
+ return nullptr;
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/alsa/audio_filter_interface.h b/chromium/chromecast/media/cma/backend/alsa/audio_filter_interface.h
new file mode 100644
index 00000000000..afcb4d59dc4
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/alsa/audio_filter_interface.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_FILTER_INTERFACE_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_FILTER_INTERFACE_H_
+
+#include <stdint.h>
+
+#include "media/base/sample_format.h"
+
+namespace chromecast {
+namespace media {
+
+class AudioFilterInterface {
+ public:
+ virtual ~AudioFilterInterface() = default;
+ virtual bool SetSampleRateAndFormat(int sample_rate,
+ ::media::SampleFormat sample_format) = 0;
+
+ // Process data frames. Must be interleaved. |data| will be overwritten.
+ virtual bool ProcessInterleaved(uint8_t* data, int frames) = 0;
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_FILTER_INTERFACE_H_
diff --git a/chromium/chromecast/media/cma/backend/alsa/cast_media_shlib.cc b/chromium/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
index e6e21ccd51a..46f4712d7bb 100644
--- a/chromium/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
+++ b/chromium/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/base/init_command_line_shlib.h"
#include "chromecast/base/task_runner_impl.h"
#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h"
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h"
@@ -88,8 +89,7 @@ std::unique_ptr<base::ThreadTaskRunnerHandle> g_thread_task_runner_handle;
} // namespace
void CastMediaShlib::Initialize(const std::vector<std::string>& argv) {
- base::CommandLine::Init(0, nullptr);
- base::CommandLine::ForCurrentProcess()->InitFromArgv(argv);
+ chromecast::InitCommandLineShlib(argv);
g_video_plane = new DefaultVideoPlane();
@@ -98,8 +98,6 @@ void CastMediaShlib::Initialize(const std::vector<std::string>& argv) {
}
void CastMediaShlib::Finalize() {
- base::CommandLine::Reset();
-
if (g_hardware_controls)
snd_hctl_close(g_hardware_controls);
snd_ctl_elem_value_free(g_rate_offset_ppm);
diff --git a/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc b/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
index 7038d5bd3b5..cdd867339e1 100644
--- a/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
+++ b/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
@@ -14,9 +14,11 @@
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
+#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/base/chromecast_switches.h"
#include "chromecast/media/cma/backend/alsa/alsa_wrapper.h"
+#include "chromecast/media/cma/backend/alsa/audio_filter_factory.h"
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
#include "media/base/audio_bus.h"
#include "media/base/media_switches.h"
@@ -124,8 +126,9 @@ bool GetSwitchValueAsInt(const std::string& switch_name,
}
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
- if (!command_line->HasSwitch(switch_name))
+ if (!command_line->HasSwitch(switch_name)) {
return false;
+ }
int arg_value;
if (!base::StringToInt(command_line->GetSwitchValueASCII(switch_name),
@@ -144,8 +147,9 @@ bool GetSwitchValueAsNonNegativeInt(const std::string& switch_name,
<< " must have a non-negative default value";
DCHECK(value);
- if (!GetSwitchValueAsInt(switch_name, default_value, value))
+ if (!GetSwitchValueAsInt(switch_name, default_value, value)) {
return false;
+ }
if (*value < 0) {
LOG(DFATAL) << "--" << switch_name << " must have a non-negative value";
@@ -204,8 +208,9 @@ StreamMixerAlsa::StreamMixerAlsa()
if (single_threaded_for_test_) {
mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
} else {
- // TODO(kmackay) Start thread with higher priority?
- mixer_thread_->Start();
+ base::Thread::Options options;
+ options.priority = base::ThreadPriority::REALTIME_AUDIO;
+ mixer_thread_->StartWithOptions(options);
mixer_task_runner_ = mixer_thread_->task_runner();
}
@@ -221,10 +226,23 @@ StreamMixerAlsa::StreamMixerAlsa()
int fixed_samples_per_second;
GetSwitchValueAsNonNegativeInt(switches::kAlsaFixedOutputSampleRate,
kInvalidSampleRate, &fixed_samples_per_second);
- if (fixed_samples_per_second != kInvalidSampleRate)
+ if (fixed_samples_per_second != kInvalidSampleRate) {
LOG(INFO) << "Setting fixed sample rate to " << fixed_samples_per_second;
+ }
+
fixed_output_samples_per_second_ = fixed_samples_per_second;
+ low_sample_rate_cutoff_ =
+ chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false)
+ ? kLowSampleRateCutoff
+ : 0;
+
+ // Create filters
+ pre_loopback_filter_ = AudioFilterFactory::MakeAudioFilter(
+ AudioFilterFactory::PRE_LOOPBACK_FILTER);
+ post_loopback_filter_ = AudioFilterFactory::MakeAudioFilter(
+ AudioFilterFactory::POST_LOOPBACK_FILTER);
+
DefineAlsaParameters();
}
@@ -309,7 +327,7 @@ unsigned int StreamMixerAlsa::DetermineOutputRate(unsigned int requested_rate) {
// because some common AV receivers don't support optical out at these
// frequencies. See b/26385501
unsigned int first_choice_sample_rate = requested_rate;
- if (requested_rate < kLowSampleRateCutoff) {
+ if (requested_rate < low_sample_rate_cutoff_) {
first_choice_sample_rate = output_samples_per_second_ != kInvalidSampleRate
? output_samples_per_second_
: kFallbackSampleRate;
@@ -438,6 +456,7 @@ int StreamMixerAlsa::SetAlsaPlaybackParams() {
<< alsa_buffer_size_
<< " frames). Audio playback will not start.";
}
+
RETURN_ERROR_CODE(PcmSwParamsSetAvailMin, pcm_, swparams, alsa_avail_min_);
RETURN_ERROR_CODE(PcmSwParamsSetTstampMode, pcm_, swparams,
SND_PCM_TSTAMP_ENABLE);
@@ -500,6 +519,18 @@ void StreamMixerAlsa::Start() {
return;
}
}
+
+ // Initialize filters
+ if (pre_loopback_filter_) {
+ pre_loopback_filter_->SetSampleRateAndFormat(
+ output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32);
+ }
+
+ if (post_loopback_filter_) {
+ post_loopback_filter_->SetSampleRateAndFormat(
+ output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32);
+ }
+
RETURN_REPORT_ERROR(PcmPrepare, pcm_);
RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_);
@@ -512,6 +543,10 @@ void StreamMixerAlsa::Start() {
}
void StreamMixerAlsa::Stop() {
+ for (auto* observer : loopback_observers_) {
+ observer->OnLoopbackInterrupted();
+ }
+
alsa_->PcmStatusFree(pcm_status_);
pcm_status_ = nullptr;
alsa_->PcmHwParamsFree(pcm_hw_params_);
@@ -519,26 +554,31 @@ void StreamMixerAlsa::Stop() {
state_ = kStateUninitialized;
output_samples_per_second_ = kInvalidSampleRate;
- if (!pcm_)
+ if (!pcm_) {
return;
+ }
// If |pcm_| is RUNNING, drain all pending data.
if (alsa_->PcmState(pcm_) == SND_PCM_STATE_RUNNING) {
int err = alsa_->PcmDrain(pcm_);
- if (err < 0)
+ if (err < 0) {
LOG(ERROR) << "snd_pcm_drain error: " << alsa_->StrError(err);
+ }
} else {
int err = alsa_->PcmDrop(pcm_);
- if (err < 0)
+ if (err < 0) {
LOG(ERROR) << "snd_pcm_drop error: " << alsa_->StrError(err);
+ }
}
}
void StreamMixerAlsa::Close() {
Stop();
- if (!pcm_)
+ if (!pcm_) {
return;
+ }
+
LOG(INFO) << "snd_pcm_close: handle=" << pcm_;
int err = alsa_->PcmClose(pcm_);
if (err < 0) {
@@ -561,8 +601,10 @@ void StreamMixerAlsa::SignalError() {
void StreamMixerAlsa::SetAlsaWrapperForTest(
std::unique_ptr<AlsaWrapper> alsa_wrapper) {
- if (alsa_)
+ if (alsa_) {
Close();
+ }
+
alsa_ = std::move(alsa_wrapper);
}
@@ -579,8 +621,9 @@ void StreamMixerAlsa::ClearInputsForTest() {
void StreamMixerAlsa::AddInput(std::unique_ptr<InputQueue> input) {
RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddInput,
base::Passed(std::move(input)));
- if (!alsa_)
+ if (!alsa_) {
alsa_.reset(new AlsaWrapper());
+ }
DCHECK(input);
// If the new input is a primary one, we may need to change the output
@@ -611,11 +654,14 @@ void StreamMixerAlsa::CheckChangeOutputRate(int input_samples_per_second) {
if (!pcm_ ||
input_samples_per_second == requested_output_samples_per_second_ ||
input_samples_per_second == output_samples_per_second_ ||
- input_samples_per_second < static_cast<int>(kLowSampleRateCutoff))
+ input_samples_per_second < static_cast<int>(low_sample_rate_cutoff_)) {
return;
+ }
+
for (auto&& input : inputs_) {
- if (input->primary() && !input->IsDeleting())
+ if (input->primary() && !input->IsDeleting()) {
return;
+ }
}
// Move all current inputs to the ignored list
@@ -683,10 +729,14 @@ void StreamMixerAlsa::CheckClose() {
}
void StreamMixerAlsa::OnFramesQueued() {
- if (state_ != kStateNormalPlayback)
+ if (state_ != kStateNormalPlayback) {
return;
- if (retry_write_frames_timer_->IsRunning())
+ }
+
+ if (retry_write_frames_timer_->IsRunning()) {
return;
+ }
+
retry_write_frames_timer_->Start(
FROM_HERE, base::TimeDelta(),
base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this)));
@@ -703,8 +753,10 @@ void StreamMixerAlsa::WriteFrames() {
bool StreamMixerAlsa::TryWriteFrames() {
DCHECK(mixer_task_runner_->BelongsToCurrentThread());
- if (state_ != kStateNormalPlayback)
+ if (state_ != kStateNormalPlayback) {
return false;
+ }
+
int chunk_size = output_samples_per_second_ * kMaxWriteSizeMs / 1000;
std::vector<InputQueue*> active_inputs;
for (auto&& input : inputs_) {
@@ -720,24 +772,30 @@ bool StreamMixerAlsa::TryWriteFrames() {
if (active_inputs.empty()) {
// No inputs have any data to provide.
- if (!inputs_.empty())
+ if (!inputs_.empty()) {
return false; // If there are some inputs, don't fill with silence.
+ }
// If we have no inputs, fill with silence to avoid underrun.
chunk_size = kPreventUnderrunChunkSize;
- if (!mixed_ || mixed_->frames() < chunk_size)
+ if (!mixed_ || mixed_->frames() < chunk_size) {
mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
+ }
+
mixed_->Zero();
WriteMixedPcm(*mixed_, chunk_size);
return true;
}
// If |mixed_| has not been allocated, or it is too small, allocate a buffer.
- if (!mixed_ || mixed_->frames() < chunk_size)
+ if (!mixed_ || mixed_->frames() < chunk_size) {
mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
+ }
+
// If |temp_| has not been allocated, or is too small, allocate a buffer.
- if (!temp_ || temp_->frames() < chunk_size)
+ if (!temp_ || temp_->frames() < chunk_size) {
temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
+ }
mixed_->ZeroFramesPartial(0, chunk_size);
@@ -767,29 +825,43 @@ void StreamMixerAlsa::WriteMixedPcm(const ::media::AudioBus& mixed,
size_t interleaved_size = static_cast<size_t>(frames * kNumOutputChannels) *
BytesPerOutputFormatSample();
- if (interleaved_.size() < interleaved_size)
+ if (interleaved_.size() < interleaved_size) {
interleaved_.resize(interleaved_size);
+ }
int64_t expected_playback_time = rendering_delay_.timestamp_microseconds +
rendering_delay_.delay_microseconds;
mixed.ToInterleaved(frames, BytesPerOutputFormatSample(),
interleaved_.data());
+ // Filter, send to observers, and post filter
+ if (pre_loopback_filter_) {
+ pre_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames);
+ }
+
for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) {
observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32,
output_samples_per_second_, kNumOutputChannels,
interleaved_.data(), interleaved_size);
}
+ if (post_loopback_filter_) {
+ post_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames);
+ }
+
// If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need
// to be prepared in order for playback to work.
- if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP)
+ if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) {
RETURN_REPORT_ERROR(PcmPrepare, pcm_);
+ }
int frames_left = frames;
uint8_t* data = &interleaved_[0];
while (frames_left) {
int frames_or_error;
while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) {
+ for (auto* observer : loopback_observers_) {
+ observer->OnLoopbackInterrupted();
+ }
RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error,
kPcmRecoverIsSilent);
}
diff --git a/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h b/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
index 58a51ec1e1b..6366db6324d 100644
--- a/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
+++ b/chromium/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
@@ -16,6 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/threading/thread.h"
#include "base/timer/timer.h"
+#include "chromecast/media/cma/backend/alsa/audio_filter_interface.h"
#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h"
#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h"
#include "chromecast/public/cast_media_shlib.h"
@@ -195,6 +196,7 @@ class StreamMixerAlsa {
scoped_refptr<base::SingleThreadTaskRunner> mixer_task_runner_;
unsigned int fixed_output_samples_per_second_;
+ unsigned int low_sample_rate_cutoff_;
int requested_output_samples_per_second_;
int output_samples_per_second_;
snd_pcm_t* pcm_;
@@ -232,6 +234,9 @@ class StreamMixerAlsa {
std::vector<CastMediaShlib::LoopbackAudioObserver*> loopback_observers_;
+ std::unique_ptr<AudioFilterInterface> pre_loopback_filter_;
+ std::unique_ptr<AudioFilterInterface> post_loopback_filter_;
+
DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsa);
};
diff --git a/chromium/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromium/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
index ec663c9accc..011ac946e16 100644
--- a/chromium/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
+++ b/chromium/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -54,6 +54,9 @@ const base::TimeDelta kMonitorLoopDelay = base::TimeDelta::FromMilliseconds(20);
const int64_t kStartPts = 1000 * 1000;
// Amount that PTS is allowed to progress past the time that Pause() was called.
const int kPausePtsSlackMs = 75;
+// Number of effects streams to open simultaneously when also playing a
+// non-effects stream.
+const int kNumEffectsStreams = 1;
void IgnoreEos() {}
@@ -627,7 +630,6 @@ void AudioVideoPipelineDeviceTest::PauseBeforeEos() {
}
void AudioVideoPipelineDeviceTest::AddEffectsStreams() {
- const int kNumEffectsStreams = 3;
for (int i = 0; i < kNumEffectsStreams; ++i) {
MediaPipelineDeviceParams params(
MediaPipelineDeviceParams::kModeIgnorePts,
diff --git a/chromium/chromecast/media/cma/backend/multizone_backend_unittest.cc b/chromium/chromecast/media/cma/backend/multizone_backend_unittest.cc
index c6248c408ae..c7400bf8078 100644
--- a/chromium/chromecast/media/cma/backend/multizone_backend_unittest.cc
+++ b/chromium/chromecast/media/cma/backend/multizone_backend_unittest.cc
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdlib.h>
+#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
@@ -42,7 +43,7 @@ const int64_t kPushTimeUs = 2 * kMicrosecondsPerSecond;
const int64_t kStartPts = 0;
const int64_t kRenderingDelayGracePeriodUs = 250 * 1000;
const int64_t kMaxRenderingDelayErrorUs = 200;
-const int kNumEffectsStreams = 3;
+const int kNumEffectsStreams = 1;
void IgnoreEos() {}
@@ -57,6 +58,22 @@ class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
void Start();
void Stop();
+ int64_t max_rendering_delay_error_us() {
+ return max_rendering_delay_error_us_;
+ }
+
+ int64_t max_positive_rendering_delay_error_us() {
+ return max_positive_rendering_delay_error_us_;
+ }
+
+ int64_t max_negative_rendering_delay_error_us() {
+ return max_negative_rendering_delay_error_us_;
+ }
+
+ int64_t average_rendering_delay_error_us() {
+ return total_rendering_delay_error_us_ / sample_count_;
+ }
+
private:
void FeedBuffer();
@@ -84,6 +101,11 @@ class BufferFeeder : public MediaPipelineBackend::Decoder::Delegate {
const AudioConfig config_;
const bool effects_only_;
const base::Closure eos_cb_;
+ int64_t max_rendering_delay_error_us_;
+ int64_t max_positive_rendering_delay_error_us_;
+ int64_t max_negative_rendering_delay_error_us_;
+ int64_t total_rendering_delay_error_us_;
+ size_t sample_count_;
bool feeding_completed_;
std::unique_ptr<TaskRunnerImpl> task_runner_;
std::unique_ptr<MediaPipelineBackend> backend_;
@@ -138,6 +160,11 @@ BufferFeeder::BufferFeeder(const AudioConfig& config,
: config_(config),
effects_only_(effects_only),
eos_cb_(eos_cb),
+ max_rendering_delay_error_us_(0),
+ max_positive_rendering_delay_error_us_(0),
+ max_negative_rendering_delay_error_us_(0),
+ total_rendering_delay_error_us_(0),
+ sample_count_(0),
feeding_completed_(false),
task_runner_(new TaskRunnerImpl()),
decoder_(nullptr),
@@ -228,8 +255,17 @@ void BufferFeeder::OnPushBufferComplete(BufferStatus status) {
if (pushed_us_ > kRenderingDelayGracePeriodUs) {
int64_t error =
next_push_playback_timestamp_ - expected_next_push_playback_timestamp;
- EXPECT_LT(std::abs(error), kMaxRenderingDelayErrorUs)
- << "Bad rendering delay after " << pushed_us_ << " us";
+ max_rendering_delay_error_us_ =
+ std::max(max_rendering_delay_error_us_, std::abs(error));
+ total_rendering_delay_error_us_ += std::abs(error);
+ if (error >= 0) {
+ max_positive_rendering_delay_error_us_ =
+ std::max(max_positive_rendering_delay_error_us_, error);
+ } else {
+ max_negative_rendering_delay_error_us_ =
+ std::min(max_negative_rendering_delay_error_us_, error);
+ }
+ sample_count_++;
}
}
pushed_us_ += last_push_length_us_;
@@ -250,7 +286,7 @@ MultizoneBackendTest::~MultizoneBackendTest() {}
void MultizoneBackendTest::Initialize(int sample_rate) {
AudioConfig config;
config.codec = kCodecPCM;
- config.sample_format = kSampleFormatPlanarF32;
+ config.sample_format = kSampleFormatS32;
config.channel_number = 2;
config.bytes_per_channel = 4;
config.samples_per_second = sample_rate;
@@ -291,6 +327,15 @@ void MultizoneBackendTest::OnEndOfStream() {
feeder->Stop();
base::MessageLoop::current()->QuitWhenIdle();
+
+ EXPECT_LT(audio_feeder_->max_rendering_delay_error_us(),
+ kMaxRenderingDelayErrorUs)
+ << "Max positive rendering delay error: "
+ << audio_feeder_->max_positive_rendering_delay_error_us()
+ << "\nMax negative rendering delay error: "
+ << audio_feeder_->max_negative_rendering_delay_error_us()
+ << "\nAverage rendering delay error: "
+ << audio_feeder_->average_rendering_delay_error_us();
}
TEST_P(MultizoneBackendTest, RenderingDelay) {
diff --git a/chromium/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc b/chromium/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc
index fb8e2aaee48..9ccd7ca0653 100644
--- a/chromium/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc
+++ b/chromium/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc
@@ -9,8 +9,10 @@
#include <vector>
#include "base/bind.h"
+#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -122,10 +124,9 @@ void BalancedMediaTaskRunnerTest::SetupTest(
}
void BalancedMediaTaskRunnerTest::ProcessAllTasks() {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&BalancedMediaTaskRunnerTest::OnTestTimeout,
- base::Unretained(this)),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&BalancedMediaTaskRunnerTest::OnTestTimeout,
+ base::Unretained(this)),
base::TimeDelta::FromSeconds(5));
ScheduleTask();
}
diff --git a/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.cc b/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.cc
index 51ef53eb87c..0c6761298f9 100644
--- a/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.cc
+++ b/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.cc
@@ -4,25 +4,16 @@
#include "chromecast/media/cma/base/cast_decrypt_config_impl.h"
-#include "media/base/decrypt_config.h"
-
namespace chromecast {
namespace media {
CastDecryptConfigImpl::CastDecryptConfigImpl(
- const ::media::DecryptConfig& config)
- : key_id_(config.key_id()), iv_(config.iv()) {
- for (const auto& sample : config.subsamples()) {
- subsamples_.push_back(
- SubsampleEntry(sample.clear_bytes, sample.cypher_bytes));
- }
-}
-
-CastDecryptConfigImpl::CastDecryptConfigImpl(
- const std::string& key_id,
- const std::string& iv,
- const std::vector<SubsampleEntry>& subsamples)
- : key_id_(key_id), iv_(iv), subsamples_(subsamples) {}
+ std::string key_id,
+ std::string iv,
+ std::vector<SubsampleEntry> subsamples)
+ : key_id_(std::move(key_id)),
+ iv_(std::move(iv)),
+ subsamples_(std::move(subsamples)) {}
CastDecryptConfigImpl::~CastDecryptConfigImpl() {}
diff --git a/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.h b/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.h
index b78494bb4cc..19bc64e01fb 100644
--- a/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.h
+++ b/chromium/chromecast/media/cma/base/cast_decrypt_config_impl.h
@@ -7,20 +7,15 @@
#include "chromecast/public/media/cast_decrypt_config.h"
-namespace media {
-class DecryptConfig;
-}
-
namespace chromecast {
namespace media {
// Contains all information that a decryptor needs to decrypt a media sample.
class CastDecryptConfigImpl : public CastDecryptConfig {
public:
- CastDecryptConfigImpl(const ::media::DecryptConfig& config);
- CastDecryptConfigImpl(const std::string& key_id,
- const std::string& iv,
- const std::vector<SubsampleEntry>& subsamples);
+ CastDecryptConfigImpl(std::string key_id,
+ std::string iv,
+ std::vector<SubsampleEntry> subsamples);
~CastDecryptConfigImpl() override;
const std::string& key_id() const override;
diff --git a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc
index e4019c851a1..282c0da52ba 100644
--- a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc
+++ b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc
@@ -20,6 +20,24 @@ DecoderBufferAdapter::DecoderBufferAdapter(
StreamId stream_id, const scoped_refptr<::media::DecoderBuffer>& buffer)
: stream_id_(stream_id),
buffer_(buffer) {
+ DCHECK(buffer_);
+
+ const ::media::DecryptConfig* decrypt_config =
+ buffer_->end_of_stream() ? nullptr : buffer_->decrypt_config();
+ if (decrypt_config && decrypt_config->is_encrypted()) {
+ std::vector<SubsampleEntry> subsamples;
+ for (const auto& sample : decrypt_config->subsamples()) {
+ subsamples.emplace_back(sample.clear_bytes, sample.cypher_bytes);
+ }
+ if (subsamples.empty()) {
+ // DecryptConfig may contain 0 subsamples if all content is encrypted.
+ // Map this case to a single fully-encrypted "subsample" for more
+ // consistent backend handling.
+ subsamples.emplace_back(0, buffer_->data_size());
+ }
+ decrypt_config_.reset(new CastDecryptConfigImpl(
+ decrypt_config->key_id(), decrypt_config->iv(), std::move(subsamples)));
+ }
}
DecoderBufferAdapter::~DecoderBufferAdapter() {
@@ -50,11 +68,6 @@ size_t DecoderBufferAdapter::data_size() const {
}
const CastDecryptConfig* DecoderBufferAdapter::decrypt_config() const {
- if (buffer_->decrypt_config() && !decrypt_config_) {
- const ::media::DecryptConfig* config = buffer_->decrypt_config();
- decrypt_config_.reset(new CastDecryptConfigImpl(*config));
- }
-
return decrypt_config_.get();
}
diff --git a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h
index c42fc9184c6..b1ec721245a 100644
--- a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h
+++ b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h
@@ -49,7 +49,7 @@ class DecoderBufferAdapter : public DecoderBufferBase {
StreamId stream_id_;
scoped_refptr<::media::DecoderBuffer> const buffer_;
- mutable std::unique_ptr<CastDecryptConfig> decrypt_config_;
+ std::unique_ptr<CastDecryptConfig> decrypt_config_;
DISALLOW_COPY_AND_ASSIGN(DecoderBufferAdapter);
};
diff --git a/chromium/chromecast/media/cma/base/decoder_buffer_adapter_unittest.cc b/chromium/chromecast/media/cma/base/decoder_buffer_adapter_unittest.cc
new file mode 100644
index 00000000000..71fdf31a3ee
--- /dev/null
+++ b/chromium/chromecast/media/cma/base/decoder_buffer_adapter_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cma/base/decoder_buffer_adapter.h"
+
+#include "chromecast/public/media/cast_decrypt_config.h"
+#include "media/base/decoder_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+static const uint8_t kBufferData[] = "hello";
+static const size_t kBufferDataSize = arraysize(kBufferData);
+static const int64_t kBufferTimestampUs = 31;
+
+scoped_refptr<media::DecoderBuffer> MakeDecoderBuffer() {
+ scoped_refptr<media::DecoderBuffer> buffer =
+ media::DecoderBuffer::CopyFrom(kBufferData, kBufferDataSize);
+ buffer->set_timestamp(base::TimeDelta::FromMicroseconds(kBufferTimestampUs));
+ return buffer;
+}
+} // namespace
+
+namespace chromecast {
+namespace media {
+
+TEST(DecoderBufferAdapterTest, Default) {
+ scoped_refptr<::media::DecoderBuffer> buffer = MakeDecoderBuffer();
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(buffer));
+
+ EXPECT_EQ(kPrimary, buffer_adapter->stream_id());
+ EXPECT_EQ(kBufferTimestampUs, buffer_adapter->timestamp());
+ EXPECT_EQ(0, memcmp(buffer_adapter->data(), kBufferData, kBufferDataSize));
+ EXPECT_EQ(kBufferDataSize, buffer_adapter->data_size());
+ EXPECT_EQ(nullptr, buffer_adapter->decrypt_config());
+ EXPECT_FALSE(buffer_adapter->end_of_stream());
+ EXPECT_EQ(buffer, buffer_adapter->ToMediaBuffer());
+}
+
+TEST(DecoderBufferAdapterTest, Secondary) {
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(kSecondary, MakeDecoderBuffer()));
+ EXPECT_EQ(kSecondary, buffer_adapter->stream_id());
+}
+
+TEST(DecoderBufferAdapterTest, Timestamp) {
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(MakeDecoderBuffer()));
+ EXPECT_EQ(kBufferTimestampUs, buffer_adapter->timestamp());
+
+ const int64_t kTestTimestampUs = 62;
+ buffer_adapter->set_timestamp(
+ base::TimeDelta::FromMicroseconds(kTestTimestampUs));
+ EXPECT_EQ(kTestTimestampUs, buffer_adapter->timestamp());
+}
+
+TEST(DecoderBufferAdapterTest, Data) {
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(MakeDecoderBuffer()));
+ EXPECT_EQ(0, memcmp(buffer_adapter->data(), kBufferData, kBufferDataSize));
+ EXPECT_EQ(kBufferDataSize, buffer_adapter->data_size());
+
+ const uint8_t kTestBufferData[] = "world";
+ const size_t kTestBufferDataSize = arraysize(kTestBufferData);
+ memcpy(buffer_adapter->writable_data(), kTestBufferData, kTestBufferDataSize);
+ EXPECT_EQ(
+ 0, memcmp(buffer_adapter->data(), kTestBufferData, kTestBufferDataSize));
+ EXPECT_EQ(kTestBufferDataSize, buffer_adapter->data_size());
+}
+
+TEST(DecoderBufferAdapterTest, DecryptConfig) {
+ const std::string kKeyId("foo-key");
+ const std::string kIV("0123456789abcdef");
+
+ // NULL DecryptConfig.
+ {
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(MakeDecoderBuffer()));
+ EXPECT_EQ(nullptr, buffer_adapter->decrypt_config());
+ }
+
+ // Empty initialization vector.
+ {
+ std::vector<::media::SubsampleEntry> subsamples;
+ std::unique_ptr<::media::DecryptConfig> decrypt_config(
+ new ::media::DecryptConfig(kKeyId, "", subsamples));
+ EXPECT_FALSE(decrypt_config->is_encrypted());
+
+ scoped_refptr<::media::DecoderBuffer> buffer = MakeDecoderBuffer();
+ buffer->set_decrypt_config(std::move(decrypt_config));
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(buffer));
+ // DecoderBufferAdapter ignores the decrypt config.
+ EXPECT_EQ(nullptr, buffer_adapter->decrypt_config());
+ }
+
+ // Empty subsamples.
+ {
+ std::vector<::media::SubsampleEntry> subsamples;
+ std::unique_ptr<::media::DecryptConfig> decrypt_config(
+ new ::media::DecryptConfig(kKeyId, kIV, subsamples));
+ EXPECT_TRUE(decrypt_config->is_encrypted());
+
+ scoped_refptr<::media::DecoderBuffer> buffer = MakeDecoderBuffer();
+ buffer->set_decrypt_config(std::move(decrypt_config));
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(buffer));
+ const CastDecryptConfig* cast_decrypt_config =
+ buffer_adapter->decrypt_config();
+ EXPECT_NE(nullptr, cast_decrypt_config);
+ EXPECT_EQ(kKeyId, cast_decrypt_config->key_id());
+ EXPECT_EQ(kIV, cast_decrypt_config->iv());
+ // DecoderBufferAdapter creates a single fully-encrypted subsample.
+ EXPECT_EQ(1u, cast_decrypt_config->subsamples().size());
+ EXPECT_EQ(0u, cast_decrypt_config->subsamples()[0].clear_bytes);
+ EXPECT_EQ(kBufferDataSize,
+ cast_decrypt_config->subsamples()[0].cypher_bytes);
+ }
+
+ // Regular DecryptConfig with non-empty subsamples.
+ {
+ uint32_t kClearBytes[] = {10, 15};
+ uint32_t kCypherBytes[] = {5, 7};
+ std::vector<::media::SubsampleEntry> subsamples;
+ subsamples.emplace_back(kClearBytes[0], kCypherBytes[0]);
+ subsamples.emplace_back(kClearBytes[1], kCypherBytes[1]);
+
+ std::unique_ptr<::media::DecryptConfig> decrypt_config(
+ new ::media::DecryptConfig(kKeyId, kIV, subsamples));
+ EXPECT_TRUE(decrypt_config->is_encrypted());
+
+ scoped_refptr<::media::DecoderBuffer> buffer = MakeDecoderBuffer();
+ buffer->set_decrypt_config(std::move(decrypt_config));
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(buffer));
+ const CastDecryptConfig* cast_decrypt_config =
+ buffer_adapter->decrypt_config();
+ EXPECT_NE(nullptr, cast_decrypt_config);
+ EXPECT_EQ(kKeyId, cast_decrypt_config->key_id());
+ EXPECT_EQ(kIV, cast_decrypt_config->iv());
+ // DecoderBufferAdapter copies all subsamples.
+ EXPECT_EQ(2u, cast_decrypt_config->subsamples().size());
+ EXPECT_EQ(kClearBytes[0], cast_decrypt_config->subsamples()[0].clear_bytes);
+ EXPECT_EQ(kCypherBytes[0],
+ cast_decrypt_config->subsamples()[0].cypher_bytes);
+ EXPECT_EQ(kClearBytes[1], cast_decrypt_config->subsamples()[1].clear_bytes);
+ EXPECT_EQ(kCypherBytes[1],
+ cast_decrypt_config->subsamples()[1].cypher_bytes);
+ }
+}
+
+TEST(DecoderBufferAdapterTest, EndOfStream) {
+ scoped_refptr<DecoderBufferAdapter> buffer_adapter(
+ new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer()));
+ EXPECT_TRUE(buffer_adapter->end_of_stream());
+ EXPECT_EQ(nullptr, buffer_adapter->decrypt_config());
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/base/demuxer_stream_adapter.cc b/chromium/chromecast/media/cma/base/demuxer_stream_adapter.cc
index 751965cdbf3..b6be89fe4e4 100644
--- a/chromium/chromecast/media/cma/base/demuxer_stream_adapter.cc
+++ b/chromium/chromecast/media/cma/base/demuxer_stream_adapter.cc
@@ -127,12 +127,12 @@ void DemuxerStreamAdapter::OnNewBuffer(
}
if (status == ::media::DemuxerStream::kAborted) {
- DCHECK(input.get() == NULL);
+ DCHECK(!input);
return;
}
if (status == ::media::DemuxerStream::kConfigChanged) {
- DCHECK(input.get() == NULL);
+ DCHECK(!input);
if (demuxer_stream_->type() == ::media::DemuxerStream::VIDEO)
video_config_ = demuxer_stream_->video_decoder_config();
if (demuxer_stream_->type() == ::media::DemuxerStream::AUDIO)
diff --git a/chromium/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc b/chromium/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc
index 681159fd9d4..5882262f1e8 100644
--- a/chromium/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc
+++ b/chromium/chromecast/media/cma/base/demuxer_stream_adapter_unittest.cc
@@ -8,8 +8,10 @@
#include <memory>
#include "base/bind.h"
+#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -85,10 +87,9 @@ void DemuxerStreamAdapterTest::Start() {
// TODO(damienv): currently, test assertions which fail do not trigger the
// exit of the unit test, the message loop is still running. Find a different
// way to exit the unit test.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&DemuxerStreamAdapterTest::OnTestTimeout,
- base::Unretained(this)),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&DemuxerStreamAdapterTest::OnTestTimeout,
+ base::Unretained(this)),
base::TimeDelta::FromSeconds(5));
coded_frame_provider_->Read(base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
@@ -130,11 +131,10 @@ void DemuxerStreamAdapterTest::OnNewFrame(
base::Closure flush_cb = base::Bind(
&DemuxerStreamAdapterTest::OnFlushCompleted, base::Unretained(this));
if (use_post_task_for_flush_) {
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&CodedFrameProvider::Flush,
- base::Unretained(coded_frame_provider_.get()),
- flush_cb));
+ base::Unretained(coded_frame_provider_.get()), flush_cb));
} else {
coded_frame_provider_->Flush(flush_cb);
}
diff --git a/chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc b/chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc
index 764e4b4b8b7..229e2375632 100644
--- a/chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc
+++ b/chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc
@@ -54,7 +54,7 @@ void MsgProducer(std::unique_ptr<MediaMessageFifo> fifo,
if (msg1)
break;
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- } while(true);
+ } while (true);
}
fifo.reset();
@@ -78,7 +78,7 @@ void MsgConsumer(std::unique_ptr<MediaMessageFifo> fifo,
break;
}
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- } while(true);
+ } while (true);
}
fifo.reset();
@@ -133,7 +133,8 @@ TEST(MediaMessageFifoTest, AlternateWriteRead) {
new FifoMemoryChunk(&buffer[0], buffer_size)),
false));
- base::WaitableEvent event(false, false);
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
thread->task_runner()->PostTask(
FROM_HERE, base::Bind(&MsgProducerConsumer, base::Passed(&producer_fifo),
base::Passed(&consumer_fifo), &event));
@@ -163,8 +164,12 @@ TEST(MediaMessageFifoTest, MultiThreaded) {
new FifoMemoryChunk(&buffer[0], buffer_size)),
false));
- base::WaitableEvent producer_event_done(false, false);
- base::WaitableEvent consumer_event_done(false, false);
+ base::WaitableEvent producer_event_done(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ base::WaitableEvent consumer_event_done(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
const int msg_count = 2048;
producer_thread->task_runner()->PostTask(
diff --git a/chromium/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc b/chromium/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc
index 56c01833513..8d6a9e03ced 100644
--- a/chromium/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc
+++ b/chromium/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc
@@ -170,27 +170,11 @@ void DecoderBufferBaseMarshaller::Write(
CHECK(msg->WritePod(buffer->stream_id()));
CHECK(msg->WritePod(buffer->timestamp()));
- bool has_decrypt_config =
- (buffer->decrypt_config() != NULL &&
- buffer->decrypt_config()->iv().size() > 0);
+ bool has_decrypt_config = buffer->decrypt_config() != nullptr;
CHECK(msg->WritePod(has_decrypt_config));
- if (has_decrypt_config) {
- // DecryptConfig may contain 0 subsamples if all content is encrypted.
- // Map this case to a single fully-encrypted "subsample" for more consistent
- // backend handling.
- if (buffer->decrypt_config()->subsamples().empty()) {
- std::vector<SubsampleEntry> encrypted_subsample_list(1);
- encrypted_subsample_list[0].clear_bytes = 0;
- encrypted_subsample_list[0].cypher_bytes = buffer->data_size();
- CastDecryptConfigImpl full_sample_config(
- buffer->decrypt_config()->key_id(), buffer->decrypt_config()->iv(),
- encrypted_subsample_list);
- DecryptConfigMarshaller::Write(full_sample_config, msg);
- } else {
- DecryptConfigMarshaller::Write(*buffer->decrypt_config(), msg);
- }
- }
+ if (has_decrypt_config)
+ DecryptConfigMarshaller::Write(*buffer->decrypt_config(), msg);
CHECK(msg->WritePod(buffer->data_size()));
CHECK(msg->WriteBuffer(buffer->data(), buffer->data_size()));
diff --git a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc
index 38c9ae362b7..c59b751d01a 100644
--- a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -13,7 +13,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/media/base/decrypt_context_impl.h"
-#include "chromecast/media/cdm/browser_cdm_cast.h"
+#include "chromecast/media/cdm/cast_cdm_context.h"
#include "chromecast/media/cma/base/buffering_frame_provider.h"
#include "chromecast/media/cma/base/buffering_state.h"
#include "chromecast/media/cma/base/cma_logging.h"
@@ -45,10 +45,8 @@ AvPipelineImpl::AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
playable_buffered_time_(::media::kNoTimestamp()),
enable_feeding_(false),
pending_read_(false),
- enable_time_update_(false),
- pending_time_update_task_(false),
- media_keys_(NULL),
- media_keys_callback_id_(kNoCallbackId),
+ cast_cdm_context_(NULL),
+ player_tracker_callback_id_(kNoCallbackId),
weak_factory_(this) {
DCHECK(decoder_);
decoder_->SetDelegate(this);
@@ -59,8 +57,8 @@ AvPipelineImpl::AvPipelineImpl(MediaPipelineBackend::Decoder* decoder,
AvPipelineImpl::~AvPipelineImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
- if (media_keys_ && media_keys_callback_id_ != kNoCallbackId)
- media_keys_->UnregisterPlayer(media_keys_callback_id_);
+ if (cast_cdm_context_ && player_tracker_callback_id_ != kNoCallbackId)
+ cast_cdm_context_->UnregisterPlayer(player_tracker_callback_id_);
}
void AvPipelineImpl::SetCodedFrameProvider(
@@ -152,17 +150,20 @@ void AvPipelineImpl::Stop() {
set_state(kStopped);
}
-void AvPipelineImpl::SetCdm(BrowserCdmCast* media_keys) {
+void AvPipelineImpl::SetCdm(CastCdmContext* cast_cdm_context) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(media_keys);
+ DCHECK(cast_cdm_context);
- if (media_keys_ && media_keys_callback_id_ != kNoCallbackId)
- media_keys_->UnregisterPlayer(media_keys_callback_id_);
+ if (cast_cdm_context_ && player_tracker_callback_id_ != kNoCallbackId)
+ cast_cdm_context_->UnregisterPlayer(player_tracker_callback_id_);
- media_keys_ = media_keys;
- media_keys_callback_id_ = media_keys_->RegisterPlayer(
+ cast_cdm_context_ = cast_cdm_context;
+ player_tracker_callback_id_ = cast_cdm_context_->RegisterPlayer(
base::Bind(&AvPipelineImpl::OnCdmStateChanged, weak_this_),
base::Bind(&AvPipelineImpl::OnCdmDestroyed, weak_this_));
+
+ // We could be waiting for CDM to provide key (see b/29564232).
+ OnCdmStateChanged();
}
void AvPipelineImpl::FetchBuffer() {
@@ -206,19 +207,20 @@ void AvPipelineImpl::ProcessPendingBuffer() {
enable_feeding_ = false;
}
- std::unique_ptr<DecryptContextImpl> decrypt_context;
if (!pending_buffer_->end_of_stream() &&
pending_buffer_->decrypt_config()) {
// Verify that CDM has the key ID.
// Should not send the frame if the key ID is not available yet.
std::string key_id(pending_buffer_->decrypt_config()->key_id());
- if (!media_keys_) {
+ if (!cast_cdm_context_) {
CMALOG(kLogControl) << "No CDM for frame: pts="
<< pending_buffer_->timestamp();
return;
}
- decrypt_context = media_keys_->GetDecryptContext(key_id);
- if (!decrypt_context.get()) {
+
+ std::unique_ptr<DecryptContextImpl> decrypt_context =
+ cast_cdm_context_->GetDecryptContext(key_id);
+ if (!decrypt_context) {
CMALOG(kLogControl) << "frame(pts=" << pending_buffer_->timestamp()
<< "): waiting for key id "
<< base::HexEncode(&key_id[0], key_id.size());
@@ -227,14 +229,30 @@ void AvPipelineImpl::ProcessPendingBuffer() {
return;
}
+ DCHECK_NE(decrypt_context->GetKeySystem(), KEY_SYSTEM_NONE);
+
// If we can get the clear content, decrypt the pending buffer
if (decrypt_context->CanDecryptToBuffer()) {
- pending_buffer_ =
- DecryptDecoderBuffer(pending_buffer_, decrypt_context.get());
- decrypt_context.reset();
+ auto buffer = pending_buffer_;
+ pending_buffer_ = nullptr;
+ DecryptDecoderBuffer(
+ buffer, decrypt_context.get(),
+ base::Bind(&AvPipelineImpl::OnBufferDecrypted, weak_this_,
+ base::Passed(&decrypt_context)));
+
+ return;
}
+
+ pending_buffer_->set_decrypt_context(std::move(decrypt_context));
}
+ PushPendingBuffer();
+}
+
+void AvPipelineImpl::PushPendingBuffer() {
+ DCHECK(pending_buffer_);
+ DCHECK(!pushed_buffer_);
+
if (!pending_buffer_->end_of_stream() && buffering_state_.get()) {
base::TimeDelta timestamp =
base::TimeDelta::FromMicroseconds(pending_buffer_->timestamp());
@@ -242,10 +260,7 @@ void AvPipelineImpl::ProcessPendingBuffer() {
buffering_state_->SetMaxRenderingTime(timestamp);
}
- DCHECK(!pushed_buffer_);
pushed_buffer_ = pending_buffer_;
- if (decrypt_context && decrypt_context->GetKeySystem() != KEY_SYSTEM_NONE)
- pushed_buffer_->set_decrypt_context(std::move(decrypt_context));
pending_buffer_ = nullptr;
MediaPipelineBackend::BufferStatus status =
decoder_->PushBuffer(pushed_buffer_.get());
@@ -254,6 +269,18 @@ void AvPipelineImpl::ProcessPendingBuffer() {
OnPushBufferComplete(status);
}
+void AvPipelineImpl::OnBufferDecrypted(
+ std::unique_ptr<DecryptContextImpl> decrypt_context,
+ scoped_refptr<DecoderBufferBase> buffer,
+ bool success) {
+ if (!success) {
+ LOG(WARNING) << "Can't decrypt with decrypt_context";
+ buffer->set_decrypt_context(std::move(decrypt_context));
+ }
+ pending_buffer_ = buffer;
+ PushPendingBuffer();
+}
+
void AvPipelineImpl::OnPushBufferComplete(BufferStatus status) {
DCHECK(thread_checker_.CalledOnValidThread());
pushed_buffer_ = nullptr;
@@ -287,8 +314,8 @@ void AvPipelineImpl::OnKeyStatusChanged(const std::string& key_id,
uint32_t system_code) {
CMALOG(kLogControl) << __FUNCTION__ << " key_status= " << key_status
<< " system_code=" << system_code;
- DCHECK(media_keys_);
- media_keys_->SetKeyStatus(key_id, key_status, system_code);
+ DCHECK(cast_cdm_context_);
+ cast_cdm_context_->SetKeyStatus(key_id, key_status, system_code);
}
void AvPipelineImpl::OnVideoResolutionChanged(const Size& size) {
@@ -309,7 +336,7 @@ void AvPipelineImpl::OnCdmStateChanged() {
void AvPipelineImpl::OnCdmDestroyed() {
DCHECK(thread_checker_.CalledOnValidThread());
- media_keys_ = NULL;
+ cast_cdm_context_ = NULL;
}
void AvPipelineImpl::OnDataBuffered(
@@ -349,8 +376,9 @@ void AvPipelineImpl::UpdatePlayableFrames() {
const CastDecryptConfig* decrypt_config =
non_playable_frame->decrypt_config();
if (decrypt_config &&
- !(media_keys_ &&
- media_keys_->GetDecryptContext(decrypt_config->key_id()).get())) {
+ !(cast_cdm_context_ &&
+ cast_cdm_context_->GetDecryptContext(decrypt_config->key_id())
+ .get())) {
// The frame is still not playable. All the following are thus not
// playable.
break;
diff --git a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h
index 1ceb0ebb8f1..d8f752263a8 100644
--- a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h
+++ b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h
@@ -29,11 +29,12 @@ class VideoDecoderConfig;
namespace chromecast {
namespace media {
-class BrowserCdmCast;
+class CastCdmContext;
class BufferingFrameProvider;
class BufferingState;
class CodedFrameProvider;
class DecoderBufferBase;
+class DecryptContextImpl;
class AvPipelineImpl : MediaPipelineBackend::Decoder::Delegate {
public:
@@ -41,7 +42,7 @@ class AvPipelineImpl : MediaPipelineBackend::Decoder::Delegate {
const AvPipelineClient& client);
~AvPipelineImpl() override;
- void SetCdm(BrowserCdmCast* media_keys);
+ void SetCdm(CastCdmContext* cast_cdm_context);
// Setup the pipeline and ensure samples are available for the given media
// time, then start rendering samples.
@@ -98,10 +99,6 @@ class AvPipelineImpl : MediaPipelineBackend::Decoder::Delegate {
uint32_t system_code) override;
void OnVideoResolutionChanged(const Size& size) override;
- // Callback invoked when the CDM state has changed in a way that might
- // impact media playback.
- void OnCdmStateChange();
-
// Feed the pipeline, getting the frames from |frame_provider_|.
void FetchBuffer();
@@ -112,12 +109,16 @@ class AvPipelineImpl : MediaPipelineBackend::Decoder::Delegate {
// Process a pending buffer.
void ProcessPendingBuffer();
+ void PushPendingBuffer();
// Callbacks:
// - when BrowserCdm updated its state.
// - when BrowserCdm has been destroyed.
void OnCdmStateChanged();
void OnCdmDestroyed();
+ void OnBufferDecrypted(std::unique_ptr<DecryptContextImpl> decrypt_context,
+ scoped_refptr<DecoderBufferBase> buffer,
+ bool success);
// Callback invoked when a media buffer has been buffered by |frame_provider_|
// which is a BufferingFrameProvider.
@@ -165,14 +166,9 @@ class AvPipelineImpl : MediaPipelineBackend::Decoder::Delegate {
// Buffer that has been pushed to the device but not processed yet.
scoped_refptr<DecoderBufferBase> pushed_buffer_;
- // The media time is retrieved at regular intervals.
- // Indicate whether time update is enabled.
- bool enable_time_update_;
- bool pending_time_update_task_;
-
- // Decryption keys, if available.
- BrowserCdmCast* media_keys_;
- int media_keys_callback_id_;
+ // CdmContext, if available.
+ CastCdmContext* cast_cdm_context_;
+ int player_tracker_callback_id_;
base::WeakPtr<AvPipelineImpl> weak_this_;
base::WeakPtrFactory<AvPipelineImpl> weak_factory_;
diff --git a/chromium/chromecast/media/cma/pipeline/decrypt_util.cc b/chromium/chromecast/media/cma/pipeline/decrypt_util.cc
index 93f1a33e7e1..e45d07ad8c4 100644
--- a/chromium/chromecast/media/cma/pipeline/decrypt_util.cc
+++ b/chromium/chromecast/media/cma/pipeline/decrypt_util.cc
@@ -8,6 +8,8 @@
#include <stdint.h>
#include <string>
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
#include "chromecast/media/base/decrypt_context_impl.h"
@@ -22,7 +24,7 @@ namespace {
class DecoderBufferClear : public DecoderBufferBase {
public:
- explicit DecoderBufferClear(const scoped_refptr<DecoderBufferBase>& buffer);
+ explicit DecoderBufferClear(scoped_refptr<DecoderBufferBase> buffer);
// DecoderBufferBase implementation.
StreamId stream_id() const override;
@@ -43,10 +45,8 @@ class DecoderBufferClear : public DecoderBufferBase {
DISALLOW_COPY_AND_ASSIGN(DecoderBufferClear);
};
-DecoderBufferClear::DecoderBufferClear(
- const scoped_refptr<DecoderBufferBase>& buffer)
- : buffer_(buffer) {
-}
+DecoderBufferClear::DecoderBufferClear(scoped_refptr<DecoderBufferBase> buffer)
+ : buffer_(buffer) {}
DecoderBufferClear::~DecoderBufferClear() {
}
@@ -89,16 +89,21 @@ DecoderBufferClear::ToMediaBuffer() const {
return buffer_->ToMediaBuffer();
}
+void OnBufferDecrypted(scoped_refptr<DecoderBufferBase> buffer,
+ const BufferDecryptedCB& buffer_decrypted_cb,
+ bool success) {
+ scoped_refptr<DecoderBufferBase> out_buffer =
+ success ? new DecoderBufferClear(buffer) : buffer;
+ buffer_decrypted_cb.Run(out_buffer, success);
+}
} // namespace
-scoped_refptr<DecoderBufferBase> DecryptDecoderBuffer(
- const scoped_refptr<DecoderBufferBase>& buffer,
- DecryptContextImpl* decrypt_ctxt) {
- if (decrypt_ctxt->Decrypt(buffer.get(), buffer->writable_data()))
- return scoped_refptr<DecoderBufferBase>(new DecoderBufferClear(buffer));
-
- NOTREACHED();
- return buffer;
+void DecryptDecoderBuffer(scoped_refptr<DecoderBufferBase> buffer,
+ DecryptContextImpl* decrypt_ctxt,
+ const BufferDecryptedCB& buffer_decrypted_cb) {
+ decrypt_ctxt->DecryptAsync(
+ buffer.get(), buffer->writable_data(), 0,
+ base::Bind(&OnBufferDecrypted, buffer, buffer_decrypted_cb));
}
} // namespace media
diff --git a/chromium/chromecast/media/cma/pipeline/decrypt_util.h b/chromium/chromecast/media/cma/pipeline/decrypt_util.h
index f0bc2c8e1da..627068e93fb 100644
--- a/chromium/chromecast/media/cma/pipeline/decrypt_util.h
+++ b/chromium/chromecast/media/cma/pipeline/decrypt_util.h
@@ -5,6 +5,7 @@
#ifndef CHROMECAST_MEDIA_CMA_PIPELINE_DECRYPT_UTIL_H_
#define CHROMECAST_MEDIA_CMA_PIPELINE_DECRYPT_UTIL_H_
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
namespace crypto {
@@ -17,14 +18,18 @@ namespace media {
class DecoderBufferBase;
class DecryptContextImpl;
+using BufferDecryptedCB =
+ base::Callback<void(scoped_refptr<DecoderBufferBase>, bool)>;
+
// Create a new buffer which corresponds to the clear version of |buffer|.
// Note: the memory area corresponding to the ES data of the new buffer
// is the same as the ES data of |buffer| (for efficiency).
-// After the function is called, |buffer| is left in a inconsistent state
-// in the sense it has some decryption info but the ES data is now in clear.
-scoped_refptr<DecoderBufferBase> DecryptDecoderBuffer(
- const scoped_refptr<DecoderBufferBase>& buffer,
- DecryptContextImpl* decrypt_ctxt);
+// After the |buffer_decrypted_cb| is called, |buffer| is left in a inconsistent
+// state in the sense it has some decryption info but the ES data is now in
+// clear.
+void DecryptDecoderBuffer(scoped_refptr<DecoderBufferBase> buffer,
+ DecryptContextImpl* decrypt_ctxt,
+ const BufferDecryptedCB& buffer_decrypted_cb);
} // namespace media
} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index b33305313ec..b6fc997de60 100644
--- a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -15,7 +15,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/base/metrics/cast_metrics_helper.h"
-#include "chromecast/media/cdm/browser_cdm_cast.h"
+#include "chromecast/media/cdm/cast_cdm_context.h"
#include "chromecast/media/cma/base/buffering_controller.h"
#include "chromecast/media/cma/base/buffering_state.h"
#include "chromecast/media/cma/base/cma_logging.h"
@@ -51,6 +51,9 @@ const base::TimeDelta kTimeUpdateInterval(
// kTimeUpdateInterval * kStatisticsUpdatePeriod.
const int kStatisticsUpdatePeriod = 4;
+// Stall duration threshold that triggers a playback stall event.
+constexpr int kPlaybackStallEventThresholdMs = 2500;
+
void LogEstimatedBitrate(int decoded_bytes,
base::TimeDelta elapsed_time,
const char* tag,
@@ -78,15 +81,18 @@ struct MediaPipelineImpl::FlushTask {
};
MediaPipelineImpl::MediaPipelineImpl()
- : cdm_(nullptr),
+ : cdm_context_(nullptr),
backend_state_(BACKEND_STATE_UNINITIALIZED),
playback_rate_(1.0f),
audio_decoder_(nullptr),
video_decoder_(nullptr),
pending_time_update_task_(false),
+ last_media_time_(::media::kNoTimestamp()),
statistics_rolling_counter_(0),
audio_bytes_for_bitrate_estimation_(0),
video_bytes_for_bitrate_estimation_(0),
+ playback_stalled_(false),
+ playback_stalled_notification_sent_(false),
weak_factory_(this) {
CMALOG(kLogControl) << __FUNCTION__;
weak_this_ = weak_factory_.GetWeakPtr();
@@ -154,14 +160,14 @@ void MediaPipelineImpl::SetCdm(int cdm_id) {
// One possibility would be a GetCdmByIdCB that's passed in.
}
-void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) {
+void MediaPipelineImpl::SetCdm(CastCdmContext* cdm_context) {
CMALOG(kLogControl) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
- cdm_ = cdm;
+ cdm_context_ = cdm_context;
if (audio_pipeline_)
- audio_pipeline_->SetCdm(cdm);
+ audio_pipeline_->SetCdm(cdm_context);
if (video_pipeline_)
- video_pipeline_->SetCdm(cdm);
+ video_pipeline_->SetCdm(cdm_context);
}
::media::PipelineStatus MediaPipelineImpl::InitializeAudio(
@@ -178,8 +184,8 @@ void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) {
}
audio_decoder_.reset(new AudioDecoderSoftwareWrapper(backend_audio_decoder));
audio_pipeline_.reset(new AudioPipelineImpl(audio_decoder_.get(), client));
- if (cdm_)
- audio_pipeline_->SetCdm(cdm_);
+ if (cdm_context_)
+ audio_pipeline_->SetCdm(cdm_context_);
return audio_pipeline_->Initialize(config, std::move(frame_provider));
}
@@ -195,8 +201,8 @@ void MediaPipelineImpl::SetCdm(BrowserCdmCast* cdm) {
return ::media::PIPELINE_ERROR_ABORT;
}
video_pipeline_.reset(new VideoPipelineImpl(video_decoder_, client));
- if (cdm_)
- video_pipeline_->SetCdm(cdm_);
+ if (cdm_context_)
+ video_pipeline_->SetCdm(cdm_context_);
return video_pipeline_->Initialize(configs, std::move(frame_provider));
}
@@ -423,6 +429,55 @@ void MediaPipelineImpl::OnBufferingNotification(bool is_buffering) {
}
}
+void MediaPipelineImpl::CheckForPlaybackStall(base::TimeDelta media_time,
+ base::TimeTicks current_stc) {
+ DCHECK(media_time != ::media::kNoTimestamp());
+
+ // A playback stall is defined as a scenario where the underlying media
+ // pipeline has unexpectedly stopped making forward progress. The pipeline is
+ // NOT stalled if:
+ //
+ // 1. Media time is progressing
+ // 2. The backend is paused
+ // 3. We are currently buffering (this is captured in a separate event)
+ if (media_time != last_media_time_ ||
+ backend_state_ != BACKEND_STATE_PLAYING ||
+ (buffering_controller_ && buffering_controller_->IsBuffering())) {
+ if (playback_stalled_) {
+ // Transition out of the stalled condition.
+ base::TimeDelta stall_duration = current_stc - playback_stalled_time_;
+ CMALOG(kLogControl)
+ << "Transitioning out of stalled state. Stall duration was "
+ << stall_duration.InMilliseconds() << " ms";
+ playback_stalled_ = false;
+ playback_stalled_notification_sent_ = false;
+ }
+ return;
+ }
+
+ // Check to see if this is a new stall condition.
+ if (!playback_stalled_) {
+ playback_stalled_ = true;
+ playback_stalled_time_ = current_stc;
+ return;
+ }
+
+ // If we are in an existing stall, check to see if we've been stalled for more
+ // than 2.5 s. If so, send a single notification of the stall event.
+ if (!playback_stalled_notification_sent_) {
+ base::TimeDelta current_stall_duration =
+ current_stc - playback_stalled_time_;
+ if (current_stall_duration.InMilliseconds() >=
+ kPlaybackStallEventThresholdMs) {
+ CMALOG(kLogControl) << "Playback stalled";
+ metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent(
+ "Cast.Platform.PlaybackStall");
+ playback_stalled_notification_sent_ = true;
+ }
+ return;
+ }
+}
+
void MediaPipelineImpl::UpdateMediaTime() {
pending_time_update_task_ = false;
if ((backend_state_ != BACKEND_STATE_PLAYING) &&
@@ -473,6 +528,8 @@ void MediaPipelineImpl::UpdateMediaTime() {
}
base::TimeTicks stc = base::TimeTicks::Now();
+ CheckForPlaybackStall(media_time, stc);
+
base::TimeDelta max_rendering_time = media_time;
if (buffering_controller_) {
buffering_controller_->SetMediaTime(media_time);
@@ -504,8 +561,8 @@ void MediaPipelineImpl::OnError(::media::PipelineStatus error) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(error, ::media::PIPELINE_OK) << "PIPELINE_OK is not an error!";
- metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent(
- "Cast.Platform.Error");
+ metrics::CastMetricsHelper::GetInstance()->RecordApplicationEventWithValue(
+ "Cast.Platform.Error", error);
if (!client_.error_cb.is_null())
client_.error_cb.Run(error);
diff --git a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h
index 753c5ef31f2..87fec0e1bce 100644
--- a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -27,8 +27,8 @@ namespace chromecast {
namespace media {
class AudioDecoderSoftwareWrapper;
class AudioPipelineImpl;
-class BrowserCdmCast;
class BufferingController;
+class CastCdmContext;
class CodedFrameProvider;
class VideoPipelineImpl;
struct AvPipelineClient;
@@ -64,7 +64,7 @@ class MediaPipelineImpl {
bool HasAudio() const;
bool HasVideo() const;
- void SetCdm(BrowserCdmCast* cdm);
+ void SetCdm(CastCdmContext* cdm);
private:
enum BackendState {
@@ -74,6 +74,9 @@ class MediaPipelineImpl {
BACKEND_STATE_PAUSED
};
struct FlushTask;
+ void CheckForPlaybackStall(base::TimeDelta media_time,
+ base::TimeTicks current_stc);
+
void OnFlushDone(bool is_audio_stream);
// Invoked to notify about a change of buffering state.
@@ -88,7 +91,7 @@ class MediaPipelineImpl {
base::ThreadChecker thread_checker_;
MediaPipelineClient client_;
std::unique_ptr<BufferingController> buffering_controller_;
- BrowserCdmCast* cdm_;
+ CastCdmContext* cdm_context_;
// Interface with the underlying hardware media pipeline.
BackendState backend_state_;
@@ -116,6 +119,11 @@ class MediaPipelineImpl {
int audio_bytes_for_bitrate_estimation_;
int video_bytes_for_bitrate_estimation_;
+ // Playback stalled handling.
+ bool playback_stalled_;
+ base::TimeTicks playback_stalled_time_;
+ bool playback_stalled_notification_sent_;
+
base::WeakPtr<MediaPipelineImpl> weak_this_;
base::WeakPtrFactory<MediaPipelineImpl> weak_factory_;
diff --git a/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc
index 84f6f9430ee..8238f76ae8a 100644
--- a/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "chromecast/base/metrics/cast_metrics_helper.h"
-#include "chromecast/media/cdm/browser_cdm_cast.h"
#include "chromecast/media/cma/base/buffering_defs.h"
#include "chromecast/media/cma/base/cma_logging.h"
#include "chromecast/media/cma/base/coded_frame_provider.h"