summaryrefslogtreecommitdiff
path: root/chromium/chromecast
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-08-14 11:38:45 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-08-14 17:16:47 +0000
commit3a97ca8dd9b96b599ae2d33e40df0dd2f7ea5859 (patch)
tree43cc572ba067417c7341db81f71ae7cc6e0fcc3e /chromium/chromecast
parentf61ab1ac7f855cd281809255c0aedbb1895e1823 (diff)
downloadqtwebengine-chromium-3a97ca8dd9b96b599ae2d33e40df0dd2f7ea5859.tar.gz
BASELINE: Update chromium to 45.0.2454.40
Change-Id: Id2121d9f11a8fc633677236c65a3e41feef589e4 Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/chromecast')
-rw-r--r--chromium/chromecast/BUILD.gn12
-rw-r--r--chromium/chromecast/android/AndroidManifest.xml17
-rw-r--r--chromium/chromecast/android/DEPS2
-rw-r--r--chromium/chromecast/android/cast_metrics_helper_android.cc25
-rw-r--r--chromium/chromecast/android/cast_metrics_helper_android.h26
-rw-r--r--chromium/chromecast/android/chromecast_config_android.cc33
-rw-r--r--chromium/chromecast/android/chromecast_config_android_stub.cc15
-rw-r--r--chromium/chromecast/app/BUILD.gn41
-rw-r--r--chromium/chromecast/app/android/DEPS1
-rw-r--r--chromium/chromecast/app/android/cast_crash_reporter_client_android.cc (renamed from chromium/chromecast/crash/android/cast_crash_reporter_client_android.cc)27
-rw-r--r--chromium/chromecast/app/android/cast_crash_reporter_client_android.h (renamed from chromium/chromecast/crash/android/cast_crash_reporter_client_android.h)16
-rw-r--r--chromium/chromecast/app/android/crash_handler.cc105
-rw-r--r--chromium/chromecast/app/android/crash_handler.h (renamed from chromium/chromecast/crash/android/crash_handler.h)23
-rw-r--r--chromium/chromecast/app/cast_main_delegate.cc103
-rw-r--r--chromium/chromecast/app/linux/cast_crash_reporter_client.cc77
-rw-r--r--chromium/chromecast/app/linux/cast_crash_reporter_client.h (renamed from chromium/chromecast/crash/cast_crash_reporter_client.h)11
-rw-r--r--chromium/chromecast/app/linux/cast_crash_reporter_client_unittest.cc116
-rw-r--r--chromium/chromecast/base/BUILD.gn77
-rw-r--r--chromium/chromecast/base/cast_sys_info_android.cc127
-rw-r--r--chromium/chromecast/base/cast_sys_info_android.h57
-rw-r--r--chromium/chromecast/base/chromecast_config_android.cc56
-rw-r--r--chromium/chromecast/base/chromecast_config_android.h (renamed from chromium/chromecast/android/chromecast_config_android.h)7
-rw-r--r--chromium/chromecast/base/chromecast_switches.cc (renamed from chromium/chromecast/common/chromecast_switches.cc)12
-rw-r--r--chromium/chromecast/base/chromecast_switches.h (renamed from chromium/chromecast/common/chromecast_switches.h)10
-rw-r--r--chromium/chromecast/base/error_codes.cc83
-rw-r--r--chromium/chromecast/base/error_codes.h44
-rw-r--r--chromium/chromecast/base/error_codes_unittest.cc65
-rw-r--r--chromium/chromecast/base/metrics/BUILD.gn13
-rw-r--r--chromium/chromecast/base/metrics/cast_metrics_helper.cc38
-rw-r--r--chromium/chromecast/base/metrics/cast_metrics_helper.h19
-rw-r--r--chromium/chromecast/base/metrics/cast_metrics_test_helper.cc4
-rw-r--r--chromium/chromecast/base/path_utils.cc55
-rw-r--r--chromium/chromecast/base/path_utils.h31
-rw-r--r--chromium/chromecast/base/path_utils_unittest.cc56
-rw-r--r--chromium/chromecast/base/process_utils.cc45
-rw-r--r--chromium/chromecast/base/process_utils.h22
-rw-r--r--chromium/chromecast/base/process_utils_unittest.cc52
-rw-r--r--chromium/chromecast/base/version.h.in (renamed from chromium/chromecast/common/version.h.in)7
-rw-r--r--chromium/chromecast/browser/android/apk/AndroidManifest.xml.jinja213
-rw-r--r--chromium/chromecast/browser/android/cast_window_android.cc5
-rw-r--r--chromium/chromecast/browser/android/cast_window_manager.cc6
-rw-r--r--chromium/chromecast/browser/cast_browser_main_parts.cc53
-rw-r--r--chromium/chromecast/browser/cast_browser_main_parts.h5
-rw-r--r--chromium/chromecast/browser/cast_browser_process.cc19
-rw-r--r--chromium/chromecast/browser/cast_browser_process.h18
-rw-r--r--chromium/chromecast/browser/cast_content_browser_client.cc113
-rw-r--r--chromium/chromecast/browser/cast_content_browser_client.h49
-rw-r--r--chromium/chromecast/browser/cast_content_browser_client_simple.cc20
-rw-r--r--chromium/chromecast/browser/cast_content_window.cc46
-rw-r--r--chromium/chromecast/browser/cast_content_window.h1
-rw-r--r--chromium/chromecast/browser/cast_net_log.cc75
-rw-r--r--chromium/chromecast/browser/cast_net_log.h28
-rw-r--r--chromium/chromecast/browser/cast_network_delegate.cc2
-rw-r--r--chromium/chromecast/browser/cast_permission_manager.cc4
-rw-r--r--chromium/chromecast/browser/cast_permission_manager.h4
-rw-r--r--chromium/chromecast/browser/devtools/cast_dev_tools_delegate.h1
-rw-r--r--chromium/chromecast/browser/devtools/remote_debugging_server.cc56
-rw-r--r--chromium/chromecast/browser/devtools/remote_debugging_server.h6
-rw-r--r--chromium/chromecast/browser/media/cast_browser_cdm_factory.cc11
-rw-r--r--chromium/chromecast/browser/media/cma_message_filter_host.cc197
-rw-r--r--chromium/chromecast/browser/media/cma_message_filter_host.h16
-rw-r--r--chromium/chromecast/browser/media/cma_message_loop.h44
-rw-r--r--chromium/chromecast/browser/media/media_pipeline_host.cc11
-rw-r--r--chromium/chromecast/browser/media/media_pipeline_host.h10
-rw-r--r--chromium/chromecast/browser/metrics/BUILD.gn41
-rw-r--r--chromium/chromecast/browser/metrics/cast_metrics_prefs.cc2
-rw-r--r--chromium/chromecast/browser/metrics/cast_metrics_service_client.cc28
-rw-r--r--chromium/chromecast/browser/metrics/cast_metrics_service_client.h6
-rw-r--r--chromium/chromecast/browser/pref_service_helper.cc2
-rw-r--r--chromium/chromecast/browser/service/cast_service_android.cc2
-rw-r--r--chromium/chromecast/browser/url_request_context_factory.cc9
-rw-r--r--chromium/chromecast/browser/url_request_context_factory.h5
-rw-r--r--chromium/chromecast/chromecast.gyp126
-rw-r--r--chromium/chromecast/chromecast_tests.gypi73
-rw-r--r--chromium/chromecast/common/BUILD.gn27
-rw-r--r--chromium/chromecast/common/cast_content_client.cc2
-rw-r--r--chromium/chromecast/common/media/cma_messages.h7
-rw-r--r--chromium/chromecast/common/media/cma_param_traits.cc69
-rw-r--r--chromium/chromecast/common/media/cma_param_traits.h4
-rw-r--r--chromium/chromecast/common/pref_names.cc7
-rw-r--r--chromium/chromecast/common/pref_names.h2
-rw-r--r--chromium/chromecast/crash/BUILD.gn58
-rw-r--r--chromium/chromecast/crash/DEPS1
-rw-r--r--chromium/chromecast/crash/android/DEPS4
-rw-r--r--chromium/chromecast/crash/android/crash_handler.cc143
-rw-r--r--chromium/chromecast/crash/app_state_tracker.cc63
-rw-r--r--chromium/chromecast/crash/app_state_tracker.h32
-rw-r--r--chromium/chromecast/crash/cast_crash_reporter_client.cc58
-rw-r--r--chromium/chromecast/crash/cast_crash_reporter_client_simple.cc17
-rw-r--r--chromium/chromecast/crash/cast_crashdump_uploader.cc123
-rw-r--r--chromium/chromecast/crash/cast_crashdump_uploader.h65
-rw-r--r--chromium/chromecast/crash/cast_crashdump_uploader_unittest.cc190
-rw-r--r--chromium/chromecast/crash/linux/crash_util.cc91
-rw-r--r--chromium/chromecast/crash/linux/crash_util.h37
-rw-r--r--chromium/chromecast/crash/linux/dummy_minidump_generator.cc99
-rw-r--r--chromium/chromecast/crash/linux/dummy_minidump_generator.h47
-rw-r--r--chromium/chromecast/crash/linux/dummy_minidump_generator_unittest.cc157
-rw-r--r--chromium/chromecast/crash/linux/dump_info.cc138
-rw-r--r--chromium/chromecast/crash/linux/dump_info.h66
-rw-r--r--chromium/chromecast/crash/linux/dump_info_unittest.cc131
-rw-r--r--chromium/chromecast/crash/linux/minidump_generator.h23
-rw-r--r--chromium/chromecast/crash/linux/minidump_params.cc35
-rw-r--r--chromium/chromecast/crash/linux/minidump_params.h39
-rw-r--r--chromium/chromecast/crash/linux/minidump_writer.cc135
-rw-r--r--chromium/chromecast/crash/linux/minidump_writer.h85
-rw-r--r--chromium/chromecast/crash/linux/minidump_writer_unittest.cc172
-rw-r--r--chromium/chromecast/crash/linux/synchronized_minidump_manager.cc219
-rw-r--r--chromium/chromecast/crash/linux/synchronized_minidump_manager.h106
-rw-r--r--chromium/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc388
-rw-r--r--chromium/chromecast/graphics/cast_egl_platform_default.cc1
-rw-r--r--chromium/chromecast/graphics/cast_screen.cc88
-rw-r--r--chromium/chromecast/graphics/cast_screen.h54
-rw-r--r--chromium/chromecast/media/BUILD.gn12
-rw-r--r--chromium/chromecast/media/DEPS1
-rw-r--r--chromium/chromecast/media/base/BUILD.gn28
-rw-r--r--chromium/chromecast/media/base/cast_media_default.cc29
-rw-r--r--chromium/chromecast/media/base/media_message_loop.cc (renamed from chromium/chromecast/browser/media/cma_message_loop.cc)17
-rw-r--r--chromium/chromecast/media/base/media_message_loop.h41
-rw-r--r--chromium/chromecast/media/cdm/browser_cdm_cast.cc40
-rw-r--r--chromium/chromecast/media/cdm/browser_cdm_cast.h12
-rw-r--r--chromium/chromecast/media/cdm/chromecast_init_data.cc68
-rw-r--r--chromium/chromecast/media/cdm/chromecast_init_data.h41
-rw-r--r--chromium/chromecast/media/cdm/chromecast_init_data_unittest.cc99
-rw-r--r--chromium/chromecast/media/cdm/playready_drm_delegate_android.cc54
-rw-r--r--chromium/chromecast/media/cma/backend/BUILD.gn20
-rw-r--r--chromium/chromecast/media/cma/backend/audio_pipeline_device_default.cc84
-rw-r--r--chromium/chromecast/media/cma/backend/audio_pipeline_device_default.h52
-rw-r--r--chromium/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc43
-rw-r--r--chromium/chromecast/media/cma/backend/media_clock_device_default.cc84
-rw-r--r--chromium/chromecast/media/cma/backend/media_clock_device_default.h41
-rw-r--r--chromium/chromecast/media/cma/backend/media_component_device_default.cc189
-rw-r--r--chromium/chromecast/media/cma/backend/media_component_device_default.h84
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device.cc20
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device.h41
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_factory.h41
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.cc38
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.h36
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_factory_simple.cc17
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_fake.cc583
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_fake.h40
-rw-r--r--chromium/chromecast/media/cma/backend/media_pipeline_device_fake_factory.cc18
-rw-r--r--chromium/chromecast/media/cma/backend/video_pipeline_device_default.cc83
-rw-r--r--chromium/chromecast/media/cma/backend/video_pipeline_device_default.h53
-rw-r--r--chromium/chromecast/media/cma/backend/video_plane.cc54
-rw-r--r--chromium/chromecast/media/cma/backend/video_plane.h62
-rw-r--r--chromium/chromecast/media/cma/backend/video_plane_fake.cc33
-rw-r--r--chromium/chromecast/media/cma/backend/video_plane_fake.h31
-rw-r--r--chromium/chromecast/media/cma/backend/video_plane_fake_factory.cc15
-rw-r--r--chromium/chromecast/media/cma/base/BUILD.gn10
-rw-r--r--chromium/chromecast/media/cma/base/balanced_media_task_runner_factory.cc10
-rw-r--r--chromium/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc48
-rw-r--r--chromium/chromecast/media/cma/base/buffering_controller.cc2
-rw-r--r--chromium/chromecast/media/cma/base/buffering_frame_provider.cc2
-rw-r--r--chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc18
-rw-r--r--chromium/chromecast/media/cma/base/decoder_buffer_adapter.h11
-rw-r--r--chromium/chromecast/media/cma/base/decoder_buffer_base.h8
-rw-r--r--chromium/chromecast/media/cma/base/decoder_config_adapter.cc101
-rw-r--r--chromium/chromecast/media/cma/base/decoder_config_adapter.h6
-rw-r--r--chromium/chromecast/media/cma/base/simple_media_task_runner.cc28
-rw-r--r--chromium/chromecast/media/cma/base/simple_media_task_runner.h42
-rw-r--r--chromium/chromecast/media/cma/filters/BUILD.gn11
-rw-r--r--chromium/chromecast/media/cma/filters/cma_renderer.cc74
-rw-r--r--chromium/chromecast/media/cma/filters/cma_renderer.h18
-rw-r--r--chromium/chromecast/media/cma/filters/demuxer_stream_adapter.cc46
-rw-r--r--chromium/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc156
-rw-r--r--chromium/chromecast/media/cma/filters/hole_frame_factory.cc79
-rw-r--r--chromium/chromecast/media/cma/filters/hole_frame_factory.h51
-rw-r--r--chromium/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc162
-rw-r--r--chromium/chromecast/media/cma/ipc/BUILD.gn5
-rw-r--r--chromium/chromecast/media/cma/ipc/media_message_fifo.cc21
-rw-r--r--chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc27
-rw-r--r--chromium/chromecast/media/cma/ipc_streamer/BUILD.gn6
-rw-r--r--chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc30
-rw-r--r--chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.h7
-rw-r--r--chromium/chromecast/media/cma/ipc_streamer/av_streamer_unittest.cc147
-rw-r--r--chromium/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc17
-rw-r--r--chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.cc8
-rw-r--r--chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.h4
-rw-r--r--chromium/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc25
-rw-r--r--chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc22
-rw-r--r--chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h4
-rw-r--r--chromium/chromecast/media/cma/pipeline/decrypt_util.cc10
-rw-r--r--chromium/chromecast/media/cma/pipeline/media_pipeline.h2
-rw-r--r--chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc36
-rw-r--r--chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h4
-rw-r--r--chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc29
-rw-r--r--chromium/chromecast/media/cma/pipeline/video_pipeline_impl.h6
-rw-r--r--chromium/chromecast/media/empty.cc0
-rw-r--r--chromium/chromecast/media/media.gyp54
-rw-r--r--chromium/chromecast/net/BUILD.gn32
-rw-r--r--chromium/chromecast/net/connectivity_checker.cc161
-rw-r--r--chromium/chromecast/net/connectivity_checker.h67
-rw-r--r--chromium/chromecast/net/connectivity_checker_impl.cc195
-rw-r--r--chromium/chromecast/net/connectivity_checker_impl.h85
-rw-r--r--chromium/chromecast/net/fake_connectivity_checker.cc31
-rw-r--r--chromium/chromecast/net/fake_connectivity_checker.h32
-rw-r--r--chromium/chromecast/public/BUILD.gn19
-rw-r--r--chromium/chromecast/public/cast_egl_platform.h5
-rw-r--r--chromium/chromecast/public/cast_media_shlib.h7
-rw-r--r--chromium/chromecast/public/graphics_types.h11
-rw-r--r--chromium/chromecast/public/media/decoder_config.h79
-rw-r--r--chromium/chromecast/public/media/stream_id.h19
-rw-r--r--chromium/chromecast/public/video_plane.h55
-rw-r--r--chromium/chromecast/renderer/cast_content_renderer_client.cc45
-rw-r--r--chromium/chromecast/renderer/cast_content_renderer_client.h23
-rw-r--r--chromium/chromecast/renderer/cast_content_renderer_client_simple.cc10
-rw-r--r--chromium/chromecast/renderer/key_systems_cast.cc6
-rw-r--r--chromium/chromecast/renderer/key_systems_cast.h4
-rw-r--r--chromium/chromecast/renderer/key_systems_cast_simple.cc16
-rw-r--r--chromium/chromecast/renderer/media/audio_pipeline_proxy.cc20
-rw-r--r--chromium/chromecast/renderer/media/audio_pipeline_proxy.h9
-rw-r--r--chromium/chromecast/renderer/media/chromecast_media_renderer_factory.cc13
-rw-r--r--chromium/chromecast/renderer/media/chromecast_media_renderer_factory.h7
-rw-r--r--chromium/chromecast/renderer/media/cma_message_filter_proxy.cc21
-rw-r--r--chromium/chromecast/renderer/media/cma_message_filter_proxy.h6
-rw-r--r--chromium/chromecast/renderer/media/cma_renderer_unittest.cc125
-rw-r--r--chromium/chromecast/renderer/media/media_pipeline_proxy.cc53
-rw-r--r--chromium/chromecast/renderer/media/media_pipeline_proxy.h17
-rw-r--r--chromium/chromecast/renderer/media/video_pipeline_proxy.cc34
-rw-r--r--chromium/chromecast/renderer/media/video_pipeline_proxy.h13
220 files changed, 7772 insertions, 2619 deletions
diff --git a/chromium/chromecast/BUILD.gn b/chromium/chromecast/BUILD.gn
index 6169cf86808..e5f3b89ee80 100644
--- a/chromium/chromecast/BUILD.gn
+++ b/chromium/chromecast/BUILD.gn
@@ -16,6 +16,18 @@ component("chromecast") {
deps = [
"//chromecast/base",
"//chromecast/base/metrics",
+ "//chromecast/crash",
"//chromecast/media",
]
}
+
+group("chromecast_unittests") {
+ testonly = true
+
+ deps = [
+ "//chromecast/app:cast_shell_unittests",
+ "//chromecast/base:cast_base_unittests",
+ "//chromecast/crash:cast_crash_unittests",
+ "//chromecast/media:cast_media_unittests",
+ ]
+}
diff --git a/chromium/chromecast/android/AndroidManifest.xml b/chromium/chromecast/android/AndroidManifest.xml
new file mode 100644
index 00000000000..bd6061880c7
--- /dev/null
+++ b/chromium/chromecast/android/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2015 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.
+-->
+
+<!--
+ This is a dummy manifest which is required by lint for determining min/target
+ SDK version.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="dummy.package">
+
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="22" />
+
+</manifest>
diff --git a/chromium/chromecast/android/DEPS b/chromium/chromecast/android/DEPS
index df718c8e423..941b823e6ed 100644
--- a/chromium/chromecast/android/DEPS
+++ b/chromium/chromecast/android/DEPS
@@ -1,7 +1,7 @@
include_rules = [
# Includes for JNI.
"+chromecast/android",
+ "+chromecast/app/android",
"+chromecast/browser/android",
- "+chromecast/crash/android",
"+components/external_video_surface",
]
diff --git a/chromium/chromecast/android/cast_metrics_helper_android.cc b/chromium/chromecast/android/cast_metrics_helper_android.cc
new file mode 100644
index 00000000000..62530bd0224
--- /dev/null
+++ b/chromium/chromecast/android/cast_metrics_helper_android.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 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/android/cast_metrics_helper_android.h"
+
+#include "chromecast/base/metrics/cast_metrics_helper.h"
+#include "jni/CastMetricsHelper_jni.h"
+
+namespace chromecast {
+
+// static
+bool CastMetricsHelperAndroid::RegisterJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void LogMediaPlay(JNIEnv* env, jclass clazz) {
+ metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
+}
+
+void LogMediaPause(JNIEnv* env, jclass clazz) {
+ metrics::CastMetricsHelper::GetInstance()->LogMediaPause();
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/android/cast_metrics_helper_android.h b/chromium/chromecast/android/cast_metrics_helper_android.h
new file mode 100644
index 00000000000..23e0f470d70
--- /dev/null
+++ b/chromium/chromecast/android/cast_metrics_helper_android.h
@@ -0,0 +1,26 @@
+// Copyright 2015 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_ANDROID_CAST_METRICS_HELPER_ANDROID_H_
+#define CHROMECAST_ANDROID_CAST_METRICS_HELPER_ANDROID_H_
+
+#include <jni.h>
+#include <vector>
+
+#include "base/macros.h"
+
+namespace chromecast {
+
+class CastMetricsHelperAndroid {
+ public:
+ // Registers the JNI methods for CastMetricsHelperAndroid.
+ static bool RegisterJni(JNIEnv* env);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CastMetricsHelperAndroid);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_ANDROID_CAST_METRICS_HELPER_ANDROID_H_
diff --git a/chromium/chromecast/android/chromecast_config_android.cc b/chromium/chromecast/android/chromecast_config_android.cc
deleted file mode 100644
index d698b70a18b..00000000000
--- a/chromium/chromecast/android/chromecast_config_android.cc
+++ /dev/null
@@ -1,33 +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/android/chromecast_config_android.h"
-
-namespace chromecast {
-namespace android {
-
-namespace {
-base::LazyInstance<ChromecastConfigAndroid> g_instance =
- LAZY_INSTANCE_INITIALIZER;
-} // namespace
-
-// static
-ChromecastConfigAndroid* ChromecastConfigAndroid::GetInstance() {
- return g_instance.Pointer();
-}
-
-ChromecastConfigAndroid::ChromecastConfigAndroid() {
-}
-
-ChromecastConfigAndroid::~ChromecastConfigAndroid() {
-}
-
-// Registers a handler to be notified when SendUsageStats is changed.
-void ChromecastConfigAndroid::SetSendUsageStatsChangedCallback(
- const base::Callback<void(bool)>& callback) {
- send_usage_stats_changed_callback_ = callback;
-}
-
-} // namespace android
-} // namespace chromecast
diff --git a/chromium/chromecast/android/chromecast_config_android_stub.cc b/chromium/chromecast/android/chromecast_config_android_stub.cc
deleted file mode 100644
index dc8bdca2d6a..00000000000
--- a/chromium/chromecast/android/chromecast_config_android_stub.cc
+++ /dev/null
@@ -1,15 +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/android/chromecast_config_android.h"
-
-namespace chromecast {
-namespace android {
-
-bool ChromecastConfigAndroid::CanSendUsageStats() {
- return false;
-}
-
-} // namespace android
-} // namespace chromecast
diff --git a/chromium/chromecast/app/BUILD.gn b/chromium/chromecast/app/BUILD.gn
new file mode 100644
index 00000000000..51cf158402f
--- /dev/null
+++ b/chromium/chromecast/app/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2015 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.
+
+import("//testing/test.gni")
+
+source_set("cast_crash_client") {
+ sources = [
+ "android/cast_crash_reporter_client_android.cc",
+ "android/cast_crash_reporter_client_android.h",
+ "linux/cast_crash_reporter_client.cc",
+ "linux/cast_crash_reporter_client.h",
+ ]
+
+ configs += [ "//chromecast:config" ]
+
+ deps = [
+ "//base",
+ "//chromecast/base",
+ "//chromecast/crash",
+ "//components/crash/app",
+ "//components/crash/app:lib",
+ "//content/public/common",
+ ]
+}
+
+# TODO(kmackay) Consider renaming this.
+test("cast_shell_unittests") {
+ sources = [
+ "linux/cast_crash_reporter_client_unittest.cc",
+ ]
+
+ deps = [
+ ":cast_crash_client",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//chromecast/crash",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/chromecast/app/android/DEPS b/chromium/chromecast/app/android/DEPS
index 5021862892e..c31bf9fbce2 100644
--- a/chromium/chromecast/app/android/DEPS
+++ b/chromium/chromecast/app/android/DEPS
@@ -1,3 +1,4 @@
include_rules = [
+ "+breakpad",
"+chromecast/android",
]
diff --git a/chromium/chromecast/crash/android/cast_crash_reporter_client_android.cc b/chromium/chromecast/app/android/cast_crash_reporter_client_android.cc
index ae4063745e5..5bc66ab9e3c 100644
--- a/chromium/chromecast/crash/android/cast_crash_reporter_client_android.cc
+++ b/chromium/chromecast/app/android/cast_crash_reporter_client_android.cc
@@ -2,21 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chromecast/crash/android/cast_crash_reporter_client_android.h"
+#include "chromecast/app/android/cast_crash_reporter_client_android.h"
#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
-#include "chromecast/android/chromecast_config_android.h"
+#include "chromecast/base/chromecast_config_android.h"
+#include "chromecast/base/version.h"
#include "chromecast/common/global_descriptors.h"
-#include "chromecast/common/version.h"
#include "chromecast/crash/cast_crash_keys.h"
#include "content/public/common/content_switches.h"
namespace chromecast {
-CastCrashReporterClientAndroid::CastCrashReporterClientAndroid() {
+CastCrashReporterClientAndroid::CastCrashReporterClientAndroid(
+ const std::string& process_type)
+ : process_type_(process_type) {
}
CastCrashReporterClientAndroid::~CastCrashReporterClientAndroid() {
@@ -37,7 +39,9 @@ base::FilePath CastCrashReporterClientAndroid::GetReporterLogFilename() {
return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
}
+// static
bool CastCrashReporterClientAndroid::GetCrashDumpLocation(
+ const std::string& process_type,
base::FilePath* crash_dir) {
base::FilePath crash_dir_local;
if (!PathService::Get(base::DIR_ANDROID_APP_DATA, &crash_dir_local)) {
@@ -45,9 +49,12 @@ bool CastCrashReporterClientAndroid::GetCrashDumpLocation(
}
crash_dir_local = crash_dir_local.Append("crashes");
- if (!base::DirectoryExists(crash_dir_local)) {
- if (!base::CreateDirectory(crash_dir_local)) {
- return false;
+ // Only try to create the directory in the browser process (empty value).
+ if (process_type.empty()) {
+ if (!base::DirectoryExists(crash_dir_local)) {
+ if (!base::CreateDirectory(crash_dir_local)) {
+ return false;
+ }
}
}
@@ -56,6 +63,12 @@ bool CastCrashReporterClientAndroid::GetCrashDumpLocation(
return true;
}
+bool CastCrashReporterClientAndroid::GetCrashDumpLocation(
+ base::FilePath* crash_dir) {
+ return CastCrashReporterClientAndroid::GetCrashDumpLocation(process_type_,
+ crash_dir);
+}
+
size_t CastCrashReporterClientAndroid::RegisterCrashKeys() {
return crash_keys::RegisterCastCrashKeys();
}
diff --git a/chromium/chromecast/crash/android/cast_crash_reporter_client_android.h b/chromium/chromecast/app/android/cast_crash_reporter_client_android.h
index e98eef72605..a87d1670079 100644
--- a/chromium/chromecast/crash/android/cast_crash_reporter_client_android.h
+++ b/chromium/chromecast/app/android/cast_crash_reporter_client_android.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_CRASH_ANDROID_CAST_CRASH_REPORTER_CLIENT_ANDROID_H_
-#define CHROMECAST_CRASH_ANDROID_CAST_CRASH_REPORTER_CLIENT_ANDROID_H_
+#ifndef CHROMECAST_APP_ANDROID_CAST_CRASH_REPORTER_CLIENT_ANDROID_H_
+#define CHROMECAST_APP_ANDROID_CAST_CRASH_REPORTER_CLIENT_ANDROID_H_
#include "base/compiler_specific.h"
#include "components/crash/app/crash_reporter_client.h"
@@ -13,9 +13,12 @@ namespace chromecast {
class CastCrashReporterClientAndroid
: public crash_reporter::CrashReporterClient {
public:
- CastCrashReporterClientAndroid();
+ explicit CastCrashReporterClientAndroid(const std::string& process_type);
~CastCrashReporterClientAndroid() override;
+ static bool GetCrashDumpLocation(const std::string& process_type,
+ base::FilePath* crash_dir);
+
// crash_reporter::CrashReporterClient implementation:
void GetProductNameAndVersion(const char** product_name,
const char** version) override;
@@ -23,14 +26,15 @@ class CastCrashReporterClientAndroid
bool GetCrashDumpLocation(base::FilePath* crash_dir) override;
int GetAndroidMinidumpDescriptor() override;
bool GetCollectStatsConsent() override;
- bool EnableBreakpadForProcess(
- const std::string& process_type) override;
+ bool EnableBreakpadForProcess(const std::string& process_type) override;
size_t RegisterCrashKeys() override;
private:
+ std::string process_type_;
+
DISALLOW_COPY_AND_ASSIGN(CastCrashReporterClientAndroid);
};
} // namespace chromecast
-#endif // CHROMECAST_CRASH_ANDROID_CAST_CRASH_REPORTER_CLIENT_ANDROID_H_
+#endif // CHROMECAST_APP_ANDROID_CAST_CRASH_REPORTER_CLIENT_ANDROID_H_
diff --git a/chromium/chromecast/app/android/crash_handler.cc b/chromium/chromecast/app/android/crash_handler.cc
new file mode 100644
index 00000000000..8a2dc7ac657
--- /dev/null
+++ b/chromium/chromecast/app/android/crash_handler.cc
@@ -0,0 +1,105 @@
+// 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/app/android/crash_handler.h"
+
+#include <jni.h>
+#include <stdlib.h>
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "breakpad/src/client/linux/handler/exception_handler.h"
+#include "breakpad/src/client/linux/handler/minidump_descriptor.h"
+#include "chromecast/app/android/cast_crash_reporter_client_android.h"
+#include "chromecast/base/version.h"
+#include "components/crash/app/breakpad_linux.h"
+#include "components/crash/app/crash_reporter_client.h"
+#include "content/public/common/content_switches.h"
+#include "jni/CastCrashHandler_jni.h"
+
+namespace {
+
+chromecast::CrashHandler* g_crash_handler = NULL;
+
+// Debug builds: always to crash-staging
+// Release builds: only to crash-staging for local/invalid build numbers
+bool UploadCrashToStaging() {
+#if CAST_IS_DEBUG_BUILD()
+ return true;
+#else
+ int build_number;
+ if (base::StringToInt(CAST_BUILD_INCREMENTAL, &build_number))
+ return build_number == 0;
+ return true;
+#endif
+}
+
+} // namespace
+
+namespace chromecast {
+
+// static
+void CrashHandler::Initialize(const std::string& process_type,
+ const base::FilePath& log_file_path) {
+ DCHECK(!g_crash_handler);
+ g_crash_handler = new CrashHandler(process_type, log_file_path);
+ g_crash_handler->Initialize();
+}
+
+// static
+bool CrashHandler::GetCrashDumpLocation(base::FilePath* crash_dir) {
+ DCHECK(g_crash_handler);
+ return g_crash_handler->crash_reporter_client_->GetCrashDumpLocation(
+ crash_dir);
+}
+
+// static
+bool CrashHandler::RegisterCastCrashJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+CrashHandler::CrashHandler(const std::string& process_type,
+ const base::FilePath& log_file_path)
+ : log_file_path_(log_file_path),
+ process_type_(process_type),
+ crash_reporter_client_(new CastCrashReporterClientAndroid(process_type)) {
+ if (!crash_reporter_client_->GetCrashDumpLocation(&crash_dump_path_)) {
+ LOG(ERROR) << "Could not get crash dump location";
+ }
+ SetCrashReporterClient(crash_reporter_client_.get());
+}
+
+CrashHandler::~CrashHandler() {
+ DCHECK(g_crash_handler);
+ g_crash_handler = NULL;
+}
+
+void CrashHandler::Initialize() {
+ if (process_type_.empty()) {
+ InitializeUploader();
+ breakpad::InitCrashReporter(process_type_);
+ return;
+ }
+
+ if (process_type_ != switches::kZygoteProcess) {
+ breakpad::InitNonBrowserCrashReporterForAndroid(process_type_);
+ }
+}
+
+void CrashHandler::InitializeUploader() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jstring> crash_dump_path_java =
+ base::android::ConvertUTF8ToJavaString(env, crash_dump_path_.value());
+ Java_CastCrashHandler_initializeUploader(
+ env,
+ base::android::GetApplicationContext(),
+ crash_dump_path_java.obj(),
+ UploadCrashToStaging());
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/android/crash_handler.h b/chromium/chromecast/app/android/crash_handler.h
index 853e7f50973..d4a79754d07 100644
--- a/chromium/chromecast/crash/android/crash_handler.h
+++ b/chromium/chromecast/app/android/crash_handler.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_CRASH_ANDROID_CRASH_HANDLER_H_
-#define CHROMECAST_CRASH_ANDROID_CRASH_HANDLER_H_
+#ifndef CHROMECAST_APP_ANDROID_CRASH_HANDLER_H_
+#define CHROMECAST_APP_ANDROID_CRASH_HANDLER_H_
#include <jni.h>
#include <string>
@@ -12,10 +12,6 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
-namespace google_breakpad {
-class ExceptionHandler;
-}
-
namespace chromecast {
class CastCrashReporterClientAndroid;
@@ -33,16 +29,12 @@ class CrashHandler {
// Registers JNI methods for this module.
static bool RegisterCastCrashJni(JNIEnv* env);
- // Returns whether or not the user has allowed for uploading crash dumps.
- bool CanUploadCrashDump();
-
- void UploadCrashDumps();
-
private:
- CrashHandler(const base::FilePath& log_file_path);
+ CrashHandler(const std::string& process_type,
+ const base::FilePath& log_file_path);
~CrashHandler();
- void Initialize(const std::string& process_type);
+ void Initialize();
// Starts a thread to periodically check for uploads
void InitializeUploader();
@@ -53,12 +45,13 @@ class CrashHandler {
// Location to which crash dumps should be written.
base::FilePath crash_dump_path_;
+ std::string process_type_;
+
scoped_ptr<CastCrashReporterClientAndroid> crash_reporter_client_;
- scoped_ptr<google_breakpad::ExceptionHandler> crash_uploader_;
DISALLOW_COPY_AND_ASSIGN(CrashHandler);
};
} // namespace chromecast
-#endif // CHROMECAST_CRASH_ANDROID_CRASH_HANDLER_H_
+#endif // CHROMECAST_APP_ANDROID_CRASH_HANDLER_H_
diff --git a/chromium/chromecast/app/cast_main_delegate.cc b/chromium/chromecast/app/cast_main_delegate.cc
index 58c7507eaf3..88764598541 100644
--- a/chromium/chromecast/app/cast_main_delegate.cc
+++ b/chromium/chromecast/app/cast_main_delegate.cc
@@ -4,10 +4,15 @@
#include "chromecast/app/cast_main_delegate.h"
+#include <algorithm>
#include <string>
+#include <vector>
#include "base/command_line.h"
#include "base/cpu.h"
+#include "base/files/file.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/path_service.h"
@@ -16,7 +21,6 @@
#include "chromecast/browser/cast_content_browser_client.h"
#include "chromecast/common/cast_resource_delegate.h"
#include "chromecast/common/global_descriptors.h"
-#include "chromecast/crash/cast_crash_reporter_client.h"
#include "chromecast/renderer/cast_content_renderer_client.h"
#include "components/crash/app/crash_reporter_client.h"
#include "content/public/browser/browser_main_runner.h"
@@ -24,7 +28,11 @@
#include "ui/base/resource/resource_bundle.h"
#if defined(OS_ANDROID)
-#include "chromecast/crash/android/crash_handler.h"
+#include "base/android/apk_assets.h"
+#include "chromecast/app/android/cast_crash_reporter_client_android.h"
+#include "chromecast/app/android/crash_handler.h"
+#else
+#include "chromecast/app/linux/cast_crash_reporter_client.h"
#endif // defined(OS_ANDROID)
namespace {
@@ -34,6 +42,10 @@ base::LazyInstance<chromecast::CastCrashReporterClient>::Leaky
g_crash_reporter_client = LAZY_INSTANCE_INITIALIZER;
#endif // !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+const int kMaxCrashFiles = 10;
+#endif // defined(OS_ANDROID)
+
} // namespace
namespace chromecast {
@@ -54,7 +66,13 @@ bool CastMainDelegate::BasicStartupComplete(int* exit_code) {
PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = log_file.value().c_str();
- settings.delete_old = logging::DELETE_OLD_LOG_FILE;
+ const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
+ std::string process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ // Only delete the old logs if the current process is the browser process.
+ // Empty process_type signifies browser process.
+ settings.delete_old = process_type.empty() ? logging::DELETE_OLD_LOG_FILE
+ : logging::APPEND_TO_OLD_LOG_FILE;
#else
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif // defined(OS_ANDROID)
@@ -62,6 +80,42 @@ bool CastMainDelegate::BasicStartupComplete(int* exit_code) {
// Time, process, and thread ID are available through logcat.
logging::SetLogItems(true, true, false, false);
+#if defined(OS_ANDROID)
+ // Only delete the old crash dumps if the current process is the browser
+ // process. Empty |process_type| signifies browser process.
+ if (process_type.empty()) {
+ // Get a listing of all of the crash dump files.
+ base::FilePath crash_directory;
+ if (CastCrashReporterClientAndroid::GetCrashDumpLocation(
+ process_type, &crash_directory)) {
+ base::FileEnumerator crash_directory_list(crash_directory, false,
+ base::FileEnumerator::FILES);
+ std::vector<base::FilePath> crash_files;
+ for (base::FilePath file = crash_directory_list.Next(); !file.empty();
+ file = crash_directory_list.Next()) {
+ crash_files.push_back(file);
+ }
+ // Delete crash dumps except for the |kMaxCrashFiles| most recent ones.
+ if (crash_files.size() > kMaxCrashFiles) {
+ auto newest_first =
+ [](const base::FilePath& l, const base::FilePath& r) -> bool {
+ base::File::Info l_info, r_info;
+ base::GetFileInfo(l, &l_info);
+ base::GetFileInfo(r, &r_info);
+ return l_info.last_modified > r_info.last_modified;
+ };
+ std::partial_sort(crash_files.begin(),
+ crash_files.begin() + kMaxCrashFiles,
+ crash_files.end(), newest_first);
+ for (auto file = crash_files.begin() + kMaxCrashFiles;
+ file != crash_files.end(); ++file) {
+ base::DeleteFile(*file, false);
+ }
+ }
+ }
+ }
+#endif // defined(OS_ANDROID)
+
content::SetContentClient(&content_client_);
return false;
}
@@ -120,17 +174,31 @@ void CastMainDelegate::ZygoteForked() {
#endif // !defined(OS_ANDROID)
void CastMainDelegate::InitializeResourceBundle() {
+ base::FilePath pak_file;
+ CHECK(PathService::Get(FILE_CAST_PAK, &pak_file));
#if defined(OS_ANDROID)
// On Android, the renderer runs with a different UID and can never access
// the file system. Use the file descriptor passed in at launch time.
- int pak_fd =
- base::GlobalDescriptors::GetInstance()->MaybeGet(kAndroidPakDescriptor);
+ auto global_descriptors = base::GlobalDescriptors::GetInstance();
+ int pak_fd = global_descriptors->MaybeGet(kAndroidPakDescriptor);
+ base::MemoryMappedFile::Region pak_region;
if (pak_fd >= 0) {
- ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
- base::File(pak_fd), base::MemoryMappedFile::Region::kWholeFile);
- ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
- base::File(pak_fd), ui::SCALE_FACTOR_100P);
+ pak_region = global_descriptors->GetRegion(kAndroidPakDescriptor);
+ ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(base::File(pak_fd),
+ pak_region);
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
+ base::File(pak_fd), pak_region, ui::SCALE_FACTOR_100P);
return;
+ } else {
+ pak_fd = base::android::OpenApkAsset("assets/cast_shell.pak", &pak_region);
+ // Loaded from disk for browsertests.
+ if (pak_fd < 0) {
+ int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
+ pak_fd = base::File(pak_file, flags).TakePlatformFile();
+ pak_region = base::MemoryMappedFile::Region::kWholeFile;
+ }
+ DCHECK_GE(pak_fd, 0);
+ global_descriptors->Set(kAndroidPakDescriptor, pak_fd, pak_region);
}
#endif // defined(OS_ANDROID)
@@ -138,25 +206,26 @@ void CastMainDelegate::InitializeResourceBundle() {
// TODO(gunsch): Use LOAD_COMMON_RESOURCES once ResourceBundle no longer
// hardcodes resource file names.
ui::ResourceBundle::InitSharedInstanceWithLocale(
- "en-US",
- resource_delegate_.get(),
+ "en-US", resource_delegate_.get(),
ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
- base::FilePath pak_file;
- CHECK(PathService::Get(FILE_CAST_PAK, &pak_file));
+#if defined(OS_ANDROID)
+ ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
+ base::File(pak_fd), pak_region, ui::SCALE_FACTOR_NONE);
+#else
ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
- pak_file,
- ui::SCALE_FACTOR_NONE);
+ pak_file, ui::SCALE_FACTOR_NONE);
+#endif // defined(OS_ANDROID)
}
content::ContentBrowserClient* CastMainDelegate::CreateContentBrowserClient() {
- browser_client_.reset(new CastContentBrowserClient);
+ browser_client_ = CastContentBrowserClient::Create();
return browser_client_.get();
}
content::ContentRendererClient*
CastMainDelegate::CreateContentRendererClient() {
- renderer_client_.reset(new CastContentRendererClient);
+ renderer_client_ = CastContentRendererClient::Create();
return renderer_client_.get();
}
diff --git a/chromium/chromecast/app/linux/cast_crash_reporter_client.cc b/chromium/chromecast/app/linux/cast_crash_reporter_client.cc
new file mode 100644
index 00000000000..0bf2877057e
--- /dev/null
+++ b/chromium/chromecast/app/linux/cast_crash_reporter_client.cc
@@ -0,0 +1,77 @@
+// 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/app/linux/cast_crash_reporter_client.h"
+
+#include "base/time/time.h"
+#include "chromecast/base/error_codes.h"
+#include "chromecast/crash/linux/crash_util.h"
+#include "components/crash/app/breakpad_linux.h"
+#include "content/public/common/content_switches.h"
+
+namespace chromecast {
+
+namespace {
+
+std::string* g_process_type = nullptr;
+uint64_t g_process_start_time_ms = 0u;
+
+} // namespace
+
+// static
+void CastCrashReporterClient::InitCrashReporter(
+ const std::string& process_type) {
+ DCHECK(!g_process_type);
+ g_process_start_time_ms =
+ (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
+
+ // Save the process type (leaked).
+ g_process_type = new std::string(process_type);
+
+ // Start up breakpad for this process, if applicable.
+ breakpad::InitCrashReporter(process_type);
+}
+
+// static
+const char* CastCrashReporterClient::GetProcessType() {
+ return g_process_type ? g_process_type->c_str() : nullptr;
+}
+
+// static
+uint64_t CastCrashReporterClient::GetProcessStartTime() {
+ return g_process_start_time_ms;
+}
+
+CastCrashReporterClient::CastCrashReporterClient() {
+}
+CastCrashReporterClient::~CastCrashReporterClient() {
+}
+
+bool CastCrashReporterClient::EnableBreakpadForProcess(
+ const std::string& process_type) {
+ return process_type == switches::kRendererProcess ||
+ process_type == switches::kZygoteProcess ||
+ process_type == switches::kGpuProcess;
+}
+
+bool CastCrashReporterClient::HandleCrashDump(const char* crashdump_filename) {
+ // Set the initial error code to ERROR_WEB_CONTENT_RENDER_VIEW_GONE to show
+ // an error message on next cast_shell run. Though the error code is for
+ // renderer process crash, the actual messages can be used for browser process
+ // as well.
+ if (!GetProcessType() || !strcmp(GetProcessType(), ""))
+ SetInitialErrorCode(ERROR_WEB_CONTENT_RENDER_VIEW_GONE);
+
+ // Upload crash dump. If user didn't opt-in crash report, minidump writer
+ // instantiated within CrashUtil::RequestUploadCrashDump() does nothing.
+ CrashUtil::RequestUploadCrashDump(crashdump_filename,
+ GetProcessType() ? GetProcessType() : "",
+ GetProcessStartTime());
+
+ // Always return true to indicate that this crash dump has been processed,
+ // so that it won't fallback to use chrome's default uploader.
+ return true;
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/cast_crash_reporter_client.h b/chromium/chromecast/app/linux/cast_crash_reporter_client.h
index a0916a041ea..07712af233d 100644
--- a/chromium/chromecast/crash/cast_crash_reporter_client.h
+++ b/chromium/chromecast/app/linux/cast_crash_reporter_client.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_CRASH_CAST_CRASH_REPORTER_CLIENT_H_
-#define CHROMECAST_CRASH_CAST_CRASH_REPORTER_CLIENT_H_
+#ifndef CHROMECAST_APP_LINUX_CAST_CRASH_REPORTER_CLIENT_H_
+#define CHROMECAST_APP_LINUX_CAST_CRASH_REPORTER_CLIENT_H_
#include <string>
@@ -20,12 +20,11 @@ class CastCrashReporterClient : public crash_reporter::CrashReporterClient {
~CastCrashReporterClient() override;
// crash_reporter::CrashReporterClient implementation:
- bool EnableBreakpadForProcess(
- const std::string& process_type) override;
+ bool EnableBreakpadForProcess(const std::string& process_type) override;
bool HandleCrashDump(const char* crashdump_filename) override;
private:
- static char* GetProcessType();
+ static const char* GetProcessType();
static uint64_t GetProcessStartTime();
DISALLOW_COPY_AND_ASSIGN(CastCrashReporterClient);
@@ -33,4 +32,4 @@ class CastCrashReporterClient : public crash_reporter::CrashReporterClient {
} // namespace chromecast
-#endif // CHROMECAST_CRASH_CAST_CRASH_REPORTER_CLIENT_H_
+#endif // CHROMECAST_APP_LINUX_CAST_CRASH_REPORTER_CLIENT_H_
diff --git a/chromium/chromecast/app/linux/cast_crash_reporter_client_unittest.cc b/chromium/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
new file mode 100644
index 00000000000..88cbad9c50c
--- /dev/null
+++ b/chromium/chromecast/app/linux/cast_crash_reporter_client_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright 2015 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 <fstream>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_vector.h"
+#include "base/test/scoped_path_override.h"
+#include "chromecast/app/linux/cast_crash_reporter_client.h"
+#include "chromecast/crash/app_state_tracker.h"
+#include "chromecast/crash/linux/crash_util.h"
+#include "chromecast/crash/linux/dump_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace {
+
+const char kFakeDumpstateContents[] = "Dumpstate Contents\nDumpdumpdumpdump\n";
+const char kFakeMinidumpContents[] = "Minidump Contents\nLine1\nLine2\n";
+
+int WriteFakeDumpStateFile(const std::string& path) {
+ // Append the correct extension and write the data to file.
+ base::File dumpstate(base::FilePath(path).AddExtension(".txt.gz"),
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ dumpstate.Write(
+ 0, kFakeDumpstateContents, sizeof(kFakeDumpstateContents) - 1);
+ return 0;
+}
+
+ScopedVector<DumpInfo> GetCurrentDumps(const std::string& logfile_path) {
+ ScopedVector<DumpInfo> dumps;
+ std::string entry;
+
+ std::ifstream in(logfile_path);
+ DCHECK(in.is_open());
+ while (std::getline(in, entry)) {
+ scoped_ptr<DumpInfo> info(new DumpInfo(entry));
+ dumps.push_back(info.Pass());
+ }
+ return dumps.Pass();
+}
+
+} // namespace
+
+TEST(CastCrashReporterClientTest, EndToEnd) {
+ // Set up a temporary directory which will be used as our fake home dir.
+ base::FilePath fake_home_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir));
+ base::ScopedPathOverride home(base::DIR_HOME, fake_home_dir);
+
+ // Set a callback to be used in place of the |dumpstate| executable.
+ CrashUtil::SetDumpStateCbForTest(base::Bind(&WriteFakeDumpStateFile));
+
+ // "Launch" YouTube.
+ AppStateTracker::SetLastLaunchedApp("youtube");
+ AppStateTracker::SetCurrentApp("youtube");
+
+ // "Launch" and switch to Pandora.
+ AppStateTracker::SetLastLaunchedApp("pandora");
+ AppStateTracker::SetCurrentApp("pandora");
+
+ // "Launch" Netflix.
+ AppStateTracker::SetLastLaunchedApp("netflix");
+ // Netflix crashed.
+
+ // A minidump file is created.
+ base::FilePath minidump_path;
+ base::CreateTemporaryFile(&minidump_path);
+ base::File minidump(minidump_path,
+ base::File::FLAG_OPEN | base::File::FLAG_APPEND);
+ minidump.Write(0, kFakeMinidumpContents, sizeof(kFakeMinidumpContents) - 1);
+ minidump.Close();
+
+ // Handle the crash.
+ CastCrashReporterClient client;
+ ASSERT_TRUE(client.HandleCrashDump(minidump_path.value().c_str()));
+
+ // Assert that the original file has been moved.
+ ASSERT_FALSE(base::PathExists(minidump_path));
+
+ // Assert that the file has been moved to "minidumps", with the expected
+ // contents.
+ std::string contents;
+ base::FilePath new_minidump =
+ fake_home_dir.Append("minidumps").Append(minidump_path.BaseName());
+ ASSERT_TRUE(base::PathExists(new_minidump));
+ ASSERT_TRUE(base::ReadFileToString(new_minidump, &contents));
+ ASSERT_EQ(kFakeMinidumpContents, contents);
+
+ // Assert that the dumpstate file has been written with the expected contents.
+ base::FilePath dumpstate = new_minidump.AddExtension(".txt.gz");
+ ASSERT_TRUE(base::PathExists(dumpstate));
+ ASSERT_TRUE(base::ReadFileToString(dumpstate, &contents));
+ ASSERT_EQ(kFakeDumpstateContents, contents);
+
+ // Assert that the lockfile has logged the correct information.
+ base::FilePath lockfile =
+ fake_home_dir.Append("minidumps").Append("lockfile");
+ ASSERT_TRUE(base::PathExists(lockfile));
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile.value());
+ ASSERT_EQ(1u, dumps.size());
+
+ const DumpInfo& dump_info = *(dumps[0]);
+ ASSERT_TRUE(dump_info.valid());
+ EXPECT_EQ(new_minidump.value(), dump_info.crashed_process_dump());
+ EXPECT_EQ(dumpstate.value(), dump_info.logfile());
+ EXPECT_EQ("youtube", dump_info.params().previous_app_name);
+ EXPECT_EQ("pandora", dump_info.params().current_app_name);
+ EXPECT_EQ("netflix", dump_info.params().last_app_name);
+}
+
+} // namespace chromecast \ No newline at end of file
diff --git a/chromium/chromecast/base/BUILD.gn b/chromium/chromecast/base/BUILD.gn
index b105a71926a..c27a4c5eccf 100644
--- a/chromium/chromecast/base/BUILD.gn
+++ b/chromium/chromecast/base/BUILD.gn
@@ -2,11 +2,88 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//chrome/version.gni") # TODO layering violation!
+import("//chromecast/chromecast.gni")
+import("//testing/test.gni")
+
source_set("base") {
sources = [
"cast_paths.cc",
"cast_paths.h",
+ "chromecast_switches.cc",
+ "chromecast_switches.h",
+ "error_codes.cc",
+ "error_codes.h",
+ "path_utils.cc",
+ "path_utils.h",
+ "process_utils.cc",
+ "process_utils.h",
+ "serializers.cc",
+ "serializers.h",
]
configs += [ "//chromecast:config" ]
+
+ public_deps = [
+ "//chromecast/base/metrics",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
+
+test("cast_base_unittests") {
+ sources = [
+ "error_codes_unittest.cc",
+ "path_utils_unittest.cc",
+ "process_utils_unittest.cc",
+ "serializers_unittest.cc",
+ ]
+
+ deps = [
+ ":base",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+}
+
+source_set("cast_sys_info") {
+ sources = [
+ "cast_sys_info_dummy.cc",
+ "cast_sys_info_dummy.h",
+ "cast_sys_info_util.h",
+ ]
+
+ if (!is_chromecast_chrome_branded && !is_android) {
+ sources += [ "cast_sys_info_util_simple.cc" ]
+ }
+
+ # TODO(mbjorge): put cast_sys_info_android in here
+
+ deps = [
+ "//base",
+ "//chromecast/public",
+ ]
+}
+
+process_version("cast_version") {
+ template_file = "version.h.in"
+ output = "$target_gen_dir/version.h"
+ extra_args = [
+ "-e",
+ "VERSION_FULL=\"%s.%s.%s.%s\"%(MAJOR,MINOR,BUILD,PATCH)",
+
+ # TODO(slan): Populate the fields below with real values
+ "-e",
+ "CAST_BUILD_INCREMENTAL=20150608.181153",
+ "-e",
+ "CAST_BUILD_RELEASE=1.15",
+ "-e",
+ "CAST_IS_DEBUG_BUILD=1",
+ "-e",
+ "CAST_PRODUCT_TYPE=0",
+ ]
}
diff --git a/chromium/chromecast/base/cast_sys_info_android.cc b/chromium/chromecast/base/cast_sys_info_android.cc
new file mode 100644
index 00000000000..0d85a06ad82
--- /dev/null
+++ b/chromium/chromecast/base/cast_sys_info_android.cc
@@ -0,0 +1,127 @@
+// Copyright 2015 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/base/cast_sys_info_android.h"
+
+#include "base/android/build_info.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
+#include "chromecast/base/cast_sys_info_util.h"
+#include "chromecast/base/version.h"
+#include "jni/CastSysInfoAndroid_jni.h"
+
+namespace chromecast {
+
+namespace {
+const char kBuildTypeUser[] = "user";
+} // namespace
+
+// static
+bool CastSysInfoAndroid::RegisterJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// static
+scoped_ptr<CastSysInfo> CreateSysInfo() {
+ return make_scoped_ptr(new CastSysInfoAndroid());
+}
+
+CastSysInfoAndroid::CastSysInfoAndroid()
+ : build_info_(base::android::BuildInfo::GetInstance()) {
+}
+
+CastSysInfoAndroid::~CastSysInfoAndroid() {
+}
+
+CastSysInfo::BuildType CastSysInfoAndroid::GetBuildType() {
+ if (CAST_IS_DEBUG_BUILD())
+ return BUILD_ENG;
+
+ int build_number;
+ if (!base::StringToInt(CAST_BUILD_INCREMENTAL, &build_number))
+ build_number = 0;
+
+ // Note: no way to determine which channel was used on play store.
+ if (strcmp(build_info_->build_type(), kBuildTypeUser) == 0 &&
+ build_number > 0) {
+ return BUILD_PRODUCTION;
+ }
+
+ // Dogfooders without a user system build should all still have non-Debug
+ // builds of the cast receiver APK, but with valid build numbers.
+ if (build_number > 0)
+ return BUILD_BETA;
+
+ // Default to ENG build.
+ return BUILD_ENG;
+}
+
+std::string CastSysInfoAndroid::GetSerialNumber() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return base::android::ConvertJavaStringToUTF8(
+ Java_CastSysInfoAndroid_getSerialNumber(env));
+}
+
+std::string CastSysInfoAndroid::GetProductName() {
+ return build_info_->device();
+}
+
+std::string CastSysInfoAndroid::GetDeviceModel() {
+ return build_info_->model();
+}
+
+std::string CastSysInfoAndroid::GetManufacturer() {
+ return build_info_->manufacturer();
+}
+
+std::string CastSysInfoAndroid::GetSystemBuildNumber() {
+ return base::SysInfo::GetAndroidBuildID();
+}
+
+std::string CastSysInfoAndroid::GetSystemReleaseChannel() {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetBoardName() {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetBoardRevision() {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetFactoryCountry() {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetFactoryLocale(std::string* second_locale) {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetWifiInterface() {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetApInterface() {
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetGlVendor() {
+ NOTREACHED() << "GL information shouldn't be requested on Android.";
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetGlRenderer() {
+ NOTREACHED() << "GL information shouldn't be requested on Android.";
+ return "";
+}
+
+std::string CastSysInfoAndroid::GetGlVersion() {
+ NOTREACHED() << "GL information shouldn't be requested on Android.";
+ return "";
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/base/cast_sys_info_android.h b/chromium/chromecast/base/cast_sys_info_android.h
new file mode 100644
index 00000000000..0cc4b55ea04
--- /dev/null
+++ b/chromium/chromecast/base/cast_sys_info_android.h
@@ -0,0 +1,57 @@
+// Copyright 2015 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_BASE_CAST_SYS_INFO_ANDROID_H_
+#define CHROMECAST_BASE_CAST_SYS_INFO_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/macros.h"
+#include "chromecast/public/cast_sys_info.h"
+
+namespace base {
+namespace android {
+class BuildInfo;
+}
+}
+
+namespace chromecast {
+
+class CastSysInfoAndroid : public CastSysInfo {
+ public:
+ static bool RegisterJni(JNIEnv* env);
+
+ CastSysInfoAndroid();
+ ~CastSysInfoAndroid() override;
+
+ // CastSysInfo implementation:
+ BuildType GetBuildType() override;
+ std::string GetSerialNumber() override;
+ std::string GetProductName() override;
+ std::string GetDeviceModel() override;
+ std::string GetManufacturer() override;
+ std::string GetSystemBuildNumber() override;
+ std::string GetSystemReleaseChannel() override;
+ std::string GetBoardName() override;
+ std::string GetBoardRevision() override;
+ std::string GetFactoryCountry() override;
+ std::string GetFactoryLocale(std::string* second_locale) override;
+ std::string GetWifiInterface() override;
+ std::string GetApInterface() override;
+ std::string GetGlVendor() override;
+ std::string GetGlRenderer() override;
+ std::string GetGlVersion() override;
+
+ // Native implementation of Java methods.
+ void DeviceNameChanged(JNIEnv* env, jobject obj, jstring device_name);
+
+ private:
+ const base::android::BuildInfo* const build_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastSysInfoAndroid);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_BASE_CAST_SYS_INFO_ANDROID_H_
diff --git a/chromium/chromecast/base/chromecast_config_android.cc b/chromium/chromecast/base/chromecast_config_android.cc
new file mode 100644
index 00000000000..f16b4733069
--- /dev/null
+++ b/chromium/chromecast/base/chromecast_config_android.cc
@@ -0,0 +1,56 @@
+// 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/base/chromecast_config_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/lazy_instance.h"
+#include "jni/ChromecastConfigAndroid_jni.h"
+
+namespace chromecast {
+namespace android {
+
+namespace {
+base::LazyInstance<ChromecastConfigAndroid> g_instance =
+ LAZY_INSTANCE_INITIALIZER;
+} // namespace
+
+// static
+ChromecastConfigAndroid* ChromecastConfigAndroid::GetInstance() {
+ return g_instance.Pointer();
+}
+
+// static
+bool ChromecastConfigAndroid::RegisterJni(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+ChromecastConfigAndroid::ChromecastConfigAndroid() {
+}
+
+ChromecastConfigAndroid::~ChromecastConfigAndroid() {
+}
+
+bool ChromecastConfigAndroid::CanSendUsageStats() {
+ // TODO(gunsch): make opt-in.stats pref the source of truth for this data,
+ // instead of Android prefs, then delete ChromecastConfigAndroid.
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_ChromecastConfigAndroid_canSendUsageStats(
+ env, base::android::GetApplicationContext());
+}
+
+// Registers a handler to be notified when SendUsageStats is changed.
+void ChromecastConfigAndroid::SetSendUsageStatsChangedCallback(
+ const base::Callback<void(bool)>& callback) {
+ send_usage_stats_changed_callback_ = callback;
+}
+
+// Called from Java.
+void SetSendUsageStatsEnabled(JNIEnv* env, jclass caller, jboolean enabled) {
+ ChromecastConfigAndroid::GetInstance()->
+ send_usage_stats_changed_callback().Run(enabled);
+}
+
+} // namespace android
+} // namespace chromecast
diff --git a/chromium/chromecast/android/chromecast_config_android.h b/chromium/chromecast/base/chromecast_config_android.h
index e09d657acc9..1d9082f51c2 100644
--- a/chromium/chromecast/android/chromecast_config_android.h
+++ b/chromium/chromecast/base/chromecast_config_android.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_ANDROID_CHROMECAST_CONFIG_ANDROID_H_
-#define CHROMECAST_ANDROID_CHROMECAST_CONFIG_ANDROID_H_
+#ifndef CHROMECAST_BASE_CHROMECAST_CONFIG_ANDROID_H_
+#define CHROMECAST_BASE_CHROMECAST_CONFIG_ANDROID_H_
#include <jni.h>
@@ -17,6 +17,7 @@ namespace android {
class ChromecastConfigAndroid {
public:
static ChromecastConfigAndroid* GetInstance();
+ static bool RegisterJni(JNIEnv* env);
// Returns whether or not the user has allowed sending usage stats and
// crash reports.
@@ -44,4 +45,4 @@ class ChromecastConfigAndroid {
} // namespace android
} // namespace chromecast
-#endif // CHROMECAST_ANDROID_CHROMECAST_CONFIG_ANDROID_H_
+#endif // CHROMECAST_BASE_CHROMECAST_CONFIG_ANDROID_H_
diff --git a/chromium/chromecast/common/chromecast_switches.cc b/chromium/chromecast/base/chromecast_switches.cc
index 435a35abdf9..5f97eba504d 100644
--- a/chromium/chromecast/common/chromecast_switches.cc
+++ b/chromium/chromecast/base/chromecast_switches.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chromecast/common/chromecast_switches.h"
+#include "chromecast/base/chromecast_switches.h"
namespace switches {
@@ -12,6 +12,11 @@ const char kEnableCmaMediaPipeline[] = "enable-cma-media-pipeline";
// The bitmask of codecs (media_caps.h) supported by the current HDMI sink.
const char kHdmiSinkSupportedCodecs[] = "hdmi-sink-supported-codecs";
+// Enables old (VIDEO_HOLE) hole punching codepath for video plane.
+// TODO(halliwell): remove switch and old codepath once overlays
+// are well established.
+const char kEnableLegacyHolePunching[] = "enable-legacy-hole-punching";
+
// Enable file accesses. It should not be enabled for most Cast devices.
const char kEnableLocalFileAccesses[] = "enable-local-file-accesses";
@@ -29,4 +34,9 @@ const char kLastLaunchedApp[] = "last-launched-app";
// started.
const char kPreviousApp[] = "previous-app";
+// Enables applications to output transparent pixels to final framebuffer
+// (e.g. using transparent body background), to be composited with other
+// externally-populated hardware planes.
+const char kEnableTransparentBackground[] = "enable-transparent-background";
+
} // namespace switches
diff --git a/chromium/chromecast/common/chromecast_switches.h b/chromium/chromecast/base/chromecast_switches.h
index 697a8a15763..c7ac0143534 100644
--- a/chromium/chromecast/common/chromecast_switches.h
+++ b/chromium/chromecast/base/chromecast_switches.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_COMMON_CHROMECAST_SWITCHES_H_
-#define CHROMECAST_COMMON_CHROMECAST_SWITCHES_H_
+#ifndef CHROMECAST_BASE_CHROMECAST_SWITCHES_H_
+#define CHROMECAST_BASE_CHROMECAST_SWITCHES_H_
#include "build/build_config.h"
@@ -12,6 +12,7 @@ namespace switches {
// Media switches
extern const char kEnableCmaMediaPipeline[];
extern const char kHdmiSinkSupportedCodecs[];
+extern const char kEnableLegacyHolePunching[];
// Content-implementation switches
extern const char kEnableLocalFileAccesses[];
@@ -26,6 +27,9 @@ extern const char kNoWifi[];
extern const char kLastLaunchedApp[];
extern const char kPreviousApp[];
+// Graphics switches
+extern const char kEnableTransparentBackground[];
+
} // namespace switches
-#endif // CHROMECAST_COMMON_CHROMECAST_SWITCHES_H_
+#endif // CHROMECAST_BASE_CHROMECAST_SWITCHES_H_
diff --git a/chromium/chromecast/base/error_codes.cc b/chromium/chromecast/base/error_codes.cc
new file mode 100644
index 00000000000..e26a82009cc
--- /dev/null
+++ b/chromium/chromecast/base/error_codes.cc
@@ -0,0 +1,83 @@
+// Copyright 2015 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/base/error_codes.h"
+
+#include <fcntl.h>
+
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "chromecast/base/path_utils.h"
+
+namespace chromecast {
+
+namespace {
+
+const char kInitialErrorFile[] = "initial_error";
+
+base::FilePath GetInitialErrorFilePath() {
+ return GetHomePathASCII(kInitialErrorFile);
+}
+
+} // namespace
+
+ErrorCode GetInitialErrorCode() {
+ std::string initial_error_code_str;
+ if (!base::ReadFileToString(GetInitialErrorFilePath(),
+ &initial_error_code_str)) {
+ return NO_ERROR;
+ }
+
+ int initial_error_code = 0;
+ if (base::StringToInt(initial_error_code_str, &initial_error_code) &&
+ initial_error_code >= NO_ERROR && initial_error_code <= ERROR_UNKNOWN) {
+ VLOG(1) << "Initial error from " << GetInitialErrorFilePath().value()
+ << ": " << initial_error_code;
+ return static_cast<ErrorCode>(initial_error_code);
+ }
+
+ LOG(ERROR) << "Unknown initial error code: " << initial_error_code_str;
+ return NO_ERROR;
+}
+
+bool SetInitialErrorCode(ErrorCode initial_error_code) {
+ // Note: Do not use Chromium IO methods in this function. When cast_shell
+ // crashes, this function can be called by any thread.
+ const std::string error_file_path = GetInitialErrorFilePath().value();
+
+ if (initial_error_code > NO_ERROR && initial_error_code <= ERROR_UNKNOWN) {
+ const std::string initial_error_code_str(
+ base::IntToString(initial_error_code));
+ int fd = creat(error_file_path.c_str(), 0640);
+ if (fd < 0) {
+ PLOG(ERROR) << "Could not open error code file";
+ return false;
+ }
+
+ int written =
+ write(fd, initial_error_code_str.data(), initial_error_code_str.size());
+
+ if (written != static_cast<int>(initial_error_code_str.size())) {
+ PLOG(ERROR) << "Could not write error code to file: written=" << written
+ << ", expected=" << initial_error_code_str.size();
+ close(fd);
+ return false;
+ }
+
+ close(fd);
+ return true;
+ }
+
+ // Remove initial error file if no error.
+ if (unlink(error_file_path.c_str()) == 0 || errno == ENOENT)
+ return true;
+
+ PLOG(ERROR) << "Failed to remove error file";
+ return false;
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/base/error_codes.h b/chromium/chromecast/base/error_codes.h
new file mode 100644
index 00000000000..80d430f2046
--- /dev/null
+++ b/chromium/chromecast/base/error_codes.h
@@ -0,0 +1,44 @@
+// Copyright 2015 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_BASE_ERROR_CODES_H_
+#define CHROMECAST_BASE_ERROR_CODES_H_
+
+namespace chromecast {
+
+enum ErrorCode {
+ NO_ERROR = 0,
+
+ // web_content [1, 9999]
+ ERROR_WEB_CONTENT_RENDER_VIEW_GONE = 1,
+ ERROR_WEB_CONTENT_NAME_NOT_RESOLVED,
+ ERROR_WEB_CONTENT_INTERNET_DISCONNECTED,
+
+ // reboot [10000, 19999]
+ // The following error codes do not reset the volume when the page is
+ // launched. Add codes that do not reset the volume before ERROR_REBOOT_NOW.
+ ERROR_REBOOT_NOW = 10000,
+ ERROR_REBOOT_FDR,
+ ERROR_REBOOT_OTA,
+ ERROR_REBOOT_IDLE,
+ // Chromecast WebUI uses 19999 for END_OF_REBOOT_SECTION, so reserve it here.
+ END_OF_REBOOT_SECTION = 19999,
+
+ // misc [20000, 29999]
+ ERROR_ABORTED = 20000,
+ ERROR_LOST_PEER_CONNECTION = 20001,
+
+ ERROR_UNKNOWN = 30000,
+};
+
+// Gets the error code for the first idle screen.
+ErrorCode GetInitialErrorCode();
+
+// Sets the error code for the first idle screen. Returns true if set
+// successfully.
+bool SetInitialErrorCode(ErrorCode initial_error_code);
+
+} // namespace chromecast
+
+#endif // CHROMECAST_BASE_ERROR_CODES_H_
diff --git a/chromium/chromecast/base/error_codes_unittest.cc b/chromium/chromecast/base/error_codes_unittest.cc
new file mode 100644
index 00000000000..293d8952f77
--- /dev/null
+++ b/chromium/chromecast/base/error_codes_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2015 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 "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/scoped_path_override.h"
+#include "chromecast/base/error_codes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+
+class ErrorCodesTest : public testing::Test {
+ protected:
+ ErrorCodesTest() {}
+ ~ErrorCodesTest() override {}
+
+ void SetUp() override {
+ // Set up a temporary directory which will be used as our fake home dir.
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_));
+ path_override_.reset(
+ new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_));
+ }
+
+ base::FilePath fake_home_dir_;
+ scoped_ptr<base::ScopedPathOverride> path_override_;
+};
+
+TEST_F(ErrorCodesTest, GetInitialErrorCodeReturnsNoErrorIfMissingFile) {
+ EXPECT_EQ(NO_ERROR, GetInitialErrorCode());
+}
+
+TEST_F(ErrorCodesTest, SetInitialErrorCodeSucceedsWithNoError) {
+ ASSERT_TRUE(SetInitialErrorCode(NO_ERROR));
+
+ // File should not be written.
+ ASSERT_FALSE(base::PathExists(fake_home_dir_.Append("initial_error")));
+ EXPECT_EQ(NO_ERROR, GetInitialErrorCode());
+}
+
+TEST_F(ErrorCodesTest, SetInitialErrorCodeSucceedsWithValidErrors) {
+ // Write initial error and read it from the file.
+ EXPECT_TRUE(SetInitialErrorCode(ERROR_WEB_CONTENT_RENDER_VIEW_GONE));
+ EXPECT_TRUE(base::PathExists(fake_home_dir_.Append("initial_error")));
+ EXPECT_EQ(ERROR_WEB_CONTENT_RENDER_VIEW_GONE, GetInitialErrorCode());
+
+ // File should be updated with most recent error.
+ EXPECT_TRUE(SetInitialErrorCode(ERROR_UNKNOWN));
+ EXPECT_TRUE(base::PathExists(fake_home_dir_.Append("initial_error")));
+ EXPECT_EQ(ERROR_UNKNOWN, GetInitialErrorCode());
+
+ // File should be updated with most recent error.
+ EXPECT_TRUE(SetInitialErrorCode(ERROR_WEB_CONTENT_NAME_NOT_RESOLVED));
+ EXPECT_TRUE(base::PathExists(fake_home_dir_.Append("initial_error")));
+ EXPECT_EQ(ERROR_WEB_CONTENT_NAME_NOT_RESOLVED, GetInitialErrorCode());
+
+ // File should be removed after writing NO_ERROR.
+ EXPECT_TRUE(SetInitialErrorCode(NO_ERROR));
+ EXPECT_FALSE(base::PathExists(fake_home_dir_.Append("initial_error")));
+ EXPECT_EQ(NO_ERROR, GetInitialErrorCode());
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/base/metrics/BUILD.gn b/chromium/chromecast/base/metrics/BUILD.gn
index 7ed81a562fe..191b30413c1 100644
--- a/chromium/chromecast/base/metrics/BUILD.gn
+++ b/chromium/chromecast/base/metrics/BUILD.gn
@@ -11,11 +11,11 @@ source_set("metrics") {
"grouped_histogram.h",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
- "//chromecast/base",
+ "//base",
]
-
- configs += [ "//chromecast:config" ]
}
source_set("test_support") {
@@ -26,9 +26,12 @@ source_set("test_support") {
"cast_metrics_test_helper.h",
]
- deps = [
+ public_deps = [
":metrics",
- "//chromecast/base",
+ ]
+
+ deps = [
+ "//base",
]
configs += [ "//chromecast:config" ]
diff --git a/chromium/chromecast/base/metrics/cast_metrics_helper.cc b/chromium/chromecast/base/metrics/cast_metrics_helper.cc
index 85cdfe8931e..6d07b4a9341 100644
--- a/chromium/chromecast/base/metrics/cast_metrics_helper.cc
+++ b/chromium/chromecast/base/metrics/cast_metrics_helper.cc
@@ -7,9 +7,9 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
#include "base/metrics/user_metrics.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "chromecast/base/metrics/cast_histograms.h"
@@ -19,12 +19,12 @@ namespace chromecast {
namespace metrics {
// A useful macro to make sure current member function runs on the valid thread.
-#define MAKE_SURE_THREAD(callback, ...) \
- if (!message_loop_proxy_->BelongsToCurrentThread()) { \
- message_loop_proxy_->PostTask(FROM_HERE, base::Bind( \
- &CastMetricsHelper::callback, \
- base::Unretained(this), ##__VA_ARGS__)); \
- return; \
+#define MAKE_SURE_THREAD(callback, ...) \
+ if (!task_runner_->BelongsToCurrentThread()) { \
+ task_runner_->PostTask(FROM_HERE, \
+ base::Bind(&CastMetricsHelper::callback, \
+ base::Unretained(this), ##__VA_ARGS__)); \
+ return; \
}
namespace {
@@ -93,11 +93,11 @@ CastMetricsHelper* CastMetricsHelper::GetInstance() {
}
CastMetricsHelper::CastMetricsHelper(
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
- : message_loop_proxy_(message_loop_proxy),
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(task_runner),
metrics_sink_(NULL),
record_action_callback_(base::Bind(&base::RecordComputedAction)) {
- DCHECK(message_loop_proxy_.get());
+ DCHECK(task_runner_.get());
DCHECK(!g_instance);
g_instance = this;
}
@@ -119,7 +119,6 @@ void CastMetricsHelper::UpdateCurrentAppInfo(const std::string& app_id,
app_id_ = app_id;
session_id_ = session_id;
app_start_time_ = base::TimeTicks::Now();
- new_startup_time_ = true;
TagAppStartForGroupedHistograms(app_id_);
sdk_version_.clear();
}
@@ -158,19 +157,6 @@ void CastMetricsHelper::LogTimeToFirstPaint() {
LOG(INFO) << uma_name << " is " << launch_time.InSecondsF() << " seconds.";
}
-void CastMetricsHelper::LogTimeToDisplayVideo() {
- if (!new_startup_time_) { // For faster check.
- return;
- }
- MAKE_SURE_THREAD(LogTimeToDisplayVideo);
- new_startup_time_ = false;
- base::TimeDelta launch_time = base::TimeTicks::Now() - app_start_time_;
- const std::string uma_name(GetMetricsNameWithAppName("Startup",
- "TimeToDisplayVideo"));
- LogMediumTimeHistogramEvent(uma_name, launch_time);
- LOG(INFO) << uma_name << " is " << launch_time.InSecondsF() << " seconds.";
-}
-
void CastMetricsHelper::LogTimeToBufferAv(BufferingType buffering_type,
base::TimeDelta time) {
MAKE_SURE_THREAD(LogTimeToBufferAv, buffering_type, time);
@@ -251,7 +237,7 @@ void CastMetricsHelper::LogFramesPer5Seconds(int displayed_frames,
std::string CastMetricsHelper::GetMetricsNameWithAppName(
const std::string& prefix,
const std::string& suffix) const {
- DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
std::string metrics_name(prefix);
if (!app_id_.empty()) {
if (!metrics_name.empty())
@@ -273,7 +259,7 @@ void CastMetricsHelper::SetMetricsSink(MetricsSink* delegate) {
void CastMetricsHelper::SetRecordActionCallback(
const RecordActionCallback& callback) {
- DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
record_action_callback_ = callback;
}
diff --git a/chromium/chromecast/base/metrics/cast_metrics_helper.h b/chromium/chromecast/base/metrics/cast_metrics_helper.h
index 144d9dc3b32..6f5c3425df0 100644
--- a/chromium/chromecast/base/metrics/cast_metrics_helper.h
+++ b/chromium/chromecast/base/metrics/cast_metrics_helper.h
@@ -12,7 +12,7 @@
#include "base/time/time.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace chromecast {
@@ -58,7 +58,7 @@ class CastMetricsHelper {
static CastMetricsHelper* GetInstance();
explicit CastMetricsHelper(
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy);
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
virtual ~CastMetricsHelper();
// This function updates the info and stores the startup time of the current
@@ -79,10 +79,6 @@ class CastMetricsHelper {
// Logs UMA record of the time the app made its first paint.
virtual void LogTimeToFirstPaint();
- // Logs UMA record of the elapsed time from the app launch
- // to the time first video frame is displayed.
- virtual void LogTimeToDisplayVideo();
-
// Logs UMA record of the time needed to re-buffer A/V.
virtual void LogTimeToBufferAv(BufferingType buffering_type,
base::TimeDelta time);
@@ -112,8 +108,8 @@ class CastMetricsHelper {
virtual void SetRecordActionCallback(const RecordActionCallback& callback);
protected:
- // Creates a CastMetricsHelper instance with no MessageLoopProxy. This should
- // only be used by tests, since invoking any non-overridden methods on this
+ // Creates a CastMetricsHelper instance with no task runner. This should only
+ // be used by tests, since invoking any non-overridden methods on this
// instance will cause a failure.
CastMetricsHelper();
@@ -134,7 +130,7 @@ class CastMetricsHelper {
void LogMediumTimeHistogramEvent(const std::string& name,
const base::TimeDelta& value);
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Start time of the most recent app.
base::TimeTicks app_start_time_;
@@ -144,11 +140,6 @@ class CastMetricsHelper {
std::string session_id_;
std::string sdk_version_;
- // Whether a new app start time has been stored but not recorded.
- // After the startup time has been used to generate an UMA event,
- // this is set to false.
- bool new_startup_time_;
-
base::TimeTicks previous_video_stat_sample_time_;
MetricsSink* metrics_sink_;
diff --git a/chromium/chromecast/base/metrics/cast_metrics_test_helper.cc b/chromium/chromecast/base/metrics/cast_metrics_test_helper.cc
index c78abe10409..2e4f0749d3f 100644
--- a/chromium/chromecast/base/metrics/cast_metrics_test_helper.cc
+++ b/chromium/chromecast/base/metrics/cast_metrics_test_helper.cc
@@ -23,7 +23,6 @@ class CastMetricsHelperStub : public CastMetricsHelper {
void UpdateSDKInfo(const std::string& sdk_version) override;
void LogMediaPlay() override;
void LogMediaPause() override;
- void LogTimeToDisplayVideo() override;
void LogTimeToBufferAv(BufferingType buffering_type,
base::TimeDelta time) override;
void ResetVideoFrameSampling() override;
@@ -65,9 +64,6 @@ void CastMetricsHelperStub::LogMediaPlay() {
void CastMetricsHelperStub::LogMediaPause() {
}
-void CastMetricsHelperStub::LogTimeToDisplayVideo() {
-}
-
void CastMetricsHelperStub::LogTimeToBufferAv(BufferingType buffering_type,
base::TimeDelta time) {
}
diff --git a/chromium/chromecast/base/path_utils.cc b/chromium/chromecast/base/path_utils.cc
new file mode 100644
index 00000000000..4f5b27b7e02
--- /dev/null
+++ b/chromium/chromecast/base/path_utils.cc
@@ -0,0 +1,55 @@
+// Copyright 2015 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/base/path_utils.h"
+
+#include "base/logging.h"
+#include "base/path_service.h"
+
+namespace chromecast {
+
+namespace {
+
+base::FilePath GetPath(base::BasePathKey default_dir_key,
+ const base::FilePath& path) {
+ if (path.IsAbsolute())
+ return path;
+
+ base::FilePath default_dir;
+ if (!PathService::Get(default_dir_key, &default_dir))
+ LOG(DFATAL) << "Cannot get default dir: " << default_dir_key;
+
+ base::FilePath adjusted_path(default_dir.Append(path));
+ VLOG(1) << "Path adjusted from " << path.value() << " to "
+ << adjusted_path.value();
+ return adjusted_path;
+}
+
+} // namespace
+
+base::FilePath GetHomePath(const base::FilePath& path) {
+ return GetPath(base::DIR_HOME, path);
+}
+
+base::FilePath GetHomePathASCII(const std::string& path) {
+ return GetHomePath(base::FilePath(path));
+}
+
+base::FilePath GetBinPath(const base::FilePath& path) {
+ return GetPath(base::DIR_EXE, path);
+}
+
+base::FilePath GetBinPathASCII(const std::string& path) {
+ return GetBinPath(base::FilePath(path));
+}
+
+base::FilePath GetTmpPath(const base::FilePath& path) {
+ return GetPath(base::DIR_TEMP, path);
+}
+
+base::FilePath GetTmpPathASCII(const std::string& path) {
+ return GetTmpPath(base::FilePath(path));
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/base/path_utils.h b/chromium/chromecast/base/path_utils.h
new file mode 100644
index 00000000000..5c1e205c2c3
--- /dev/null
+++ b/chromium/chromecast/base/path_utils.h
@@ -0,0 +1,31 @@
+// Copyright 2015 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_BASE_PATH_UTILS_H_
+#define CHROMECAST_BASE_PATH_UTILS_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+
+namespace chromecast {
+
+// If |path| is relative, returns the path created by prepending HOME directory
+// to |path| (e.g. {HOME}/|path|). If |path| is absolute, returns |path|.
+base::FilePath GetHomePath(const base::FilePath& path);
+base::FilePath GetHomePathASCII(const std::string& path);
+
+// If |path| is relative, returns the path created by prepending BIN directory
+// to |path| (e.g. {BIN}/|path|). If |path| is absolute, returns |path|.
+base::FilePath GetBinPath(const base::FilePath& path);
+base::FilePath GetBinPathASCII(const std::string& path);
+
+// If |path| is relative, returns the path created by prepending TMP directory
+// to |path| (e.g. {TMP}/|path|). If |path| is absolute, returns |path|.
+base::FilePath GetTmpPath(const base::FilePath& path);
+base::FilePath GetTmpPathASCII(const std::string& path);
+
+} // namespace chromecast
+
+#endif // CHROMECAST_BASE_PATH_UTILS_H_
diff --git a/chromium/chromecast/base/path_utils_unittest.cc b/chromium/chromecast/base/path_utils_unittest.cc
new file mode 100644
index 00000000000..618bb0f3e4b
--- /dev/null
+++ b/chromium/chromecast/base/path_utils_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2015 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 "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chromecast/base/path_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace {
+const char kTestRelPath[] = "rel/path";
+const char kTestAbsPath[] = "/abs/path/to/dir";
+
+std::string GetTestString(int base_dir_key) {
+ base::FilePath basedir;
+ EXPECT_TRUE(PathService::Get(base_dir_key, &basedir));
+ return basedir.value() + "/" + kTestRelPath;
+}
+
+} // namespace
+
+TEST(PathUtilsTest, GetHomePath) {
+ // Test with relative path.
+ std::string expected = GetTestString(base::DIR_HOME);
+ base::FilePath actual = GetHomePath(base::FilePath(kTestRelPath));
+ EXPECT_EQ(expected, actual.value());
+
+ // Test with absolute path.
+ actual = GetHomePath(base::FilePath(kTestAbsPath));
+ EXPECT_EQ(kTestAbsPath, actual.value());
+}
+
+TEST(PathUtilsTest, GetBinPath) {
+ // Test with relative path.
+ std::string expected = GetTestString(base::DIR_EXE);
+ base::FilePath actual = GetBinPath(base::FilePath(kTestRelPath));
+ EXPECT_EQ(expected, actual.value());
+
+ // Test with absolute path.
+ actual = GetBinPath(base::FilePath(kTestAbsPath));
+ EXPECT_EQ(kTestAbsPath, actual.value());
+}
+
+TEST(PathUtilsTest, GetTmpPath) {
+ // Test with relative path.
+ std::string expected = GetTestString(base::DIR_TEMP);
+ base::FilePath actual = GetTmpPath(base::FilePath(kTestRelPath));
+ EXPECT_EQ(expected, actual.value());
+
+ // Test with absolute path.
+ actual = GetTmpPath(base::FilePath(kTestAbsPath));
+ EXPECT_EQ(kTestAbsPath, actual.value());
+}
+
+} // chromecast \ No newline at end of file
diff --git a/chromium/chromecast/base/process_utils.cc b/chromium/chromecast/base/process_utils.cc
new file mode 100644
index 00000000000..523fb1c697f
--- /dev/null
+++ b/chromium/chromecast/base/process_utils.cc
@@ -0,0 +1,45 @@
+// Copyright 2015 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/base/process_utils.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "base/logging.h"
+#include "base/posix/safe_strerror.h"
+#include "base/strings/string_util.h"
+
+namespace chromecast {
+
+bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
+ DCHECK(output);
+
+ // Join the args into one string, creating the command.
+ std::string command = JoinString(argv, ' ');
+
+ // Open the process.
+ FILE* fp = popen(command.c_str(), "r");
+ if (!fp) {
+ LOG(ERROR) << "popen (" << command << ") failed: "
+ << base::safe_strerror(errno);
+ return false;
+ }
+
+ // Fill |output| with the stdout from the process.
+ output->clear();
+ while (!feof(fp)) {
+ char buffer[256];
+ size_t bytes_read = fread(buffer, 1, sizeof(buffer), fp);
+ if (bytes_read <= 0)
+ break;
+ output->append(buffer, bytes_read);
+ }
+
+ // pclose() function waits for the associated process to terminate and returns
+ // the exit status.
+ return (pclose(fp) == 0);
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/base/process_utils.h b/chromium/chromecast/base/process_utils.h
new file mode 100644
index 00000000000..c79da17c037
--- /dev/null
+++ b/chromium/chromecast/base/process_utils.h
@@ -0,0 +1,22 @@
+// Copyright 2015 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_BASE_PROCESS_UTILS_H_
+#define CHROMECAST_BASE_PROCESS_UTILS_H_
+
+#include <string>
+#include <vector>
+
+namespace chromecast {
+
+// Executes application, for which arguments are specified by |argv| and wait
+// for it to exit. Stores the output (stdout) in |output|. Returns true on
+// success.
+// TODO(slan): Replace uses of this with base::GetAppOutput when crbug/493711 is
+// resolved.
+bool GetAppOutput(const std::vector<std::string>& argv, std::string* output);
+
+} // namespace chromecast
+
+#endif // CHROMECAST_BASE_PROCESS_UTILS_H_
diff --git a/chromium/chromecast/base/process_utils_unittest.cc b/chromium/chromecast/base/process_utils_unittest.cc
new file mode 100644
index 00000000000..f9c2a0d7d8c
--- /dev/null
+++ b/chromium/chromecast/base/process_utils_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright 2015 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/base/process_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+
+// Verify that a simple process works as expected.
+TEST(ProcessUtilsTest, SimpleProcess) {
+ // Create a simple command.
+ std::vector<std::string> args;
+ args.push_back("echo");
+ args.push_back("Hello World");
+
+ // Execute the command and collect the output.
+ std::string stdout_result;
+ ASSERT_TRUE(GetAppOutput(args, &stdout_result));
+
+ // Echo will append a newline to the stdout.
+ EXPECT_EQ("Hello World\n", stdout_result);
+}
+
+// Verify that false is returned for an invalid command.
+TEST(ProcessUtilsTest, InvalidCommand) {
+ // Create a command which is not valid.
+ std::vector<std::string> args;
+ args.push_back("invalid_command");
+
+ // The command should not run.
+ std::string stdout_result;
+ ASSERT_FALSE(GetAppOutput(args, &stdout_result));
+ ASSERT_TRUE(stdout_result.empty());
+}
+
+// Verify that false is returned when a command an error code.
+TEST(ProcessUtilsTest, ProcessReturnsError) {
+ // Create a simple command.
+ std::vector<std::string> args;
+ args.push_back("cd");
+ args.push_back("path/to/invalid/directory");
+ args.push_back("2>&1"); // Pipe the stderr into stdout.
+
+ // Execute the command and collect the output. Verify that the output of the
+ // process is collected, even when the process returns an error code.
+ std::string stderr_result;
+ ASSERT_FALSE(GetAppOutput(args, &stderr_result));
+ ASSERT_FALSE(stderr_result.empty());
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/common/version.h.in b/chromium/chromecast/base/version.h.in
index 918401f42ae..62b01d31929 100644
--- a/chromium/chromecast/common/version.h.in
+++ b/chromium/chromecast/base/version.h.in
@@ -4,13 +4,14 @@
// version.h is generated from version.h.in. Edit the source!
-#ifndef CHROMECAST_COMMON_VERSION_INFO_H_
-#define CHROMECAST_COMMON_VERSION_INFO_H_
+#ifndef CHROMECAST_BASE_VERSION_INFO_H_
+#define CHROMECAST_BASE_VERSION_INFO_H_
#define PRODUCT_VERSION "@VERSION_FULL@"
#define CAST_BUILD_INCREMENTAL "@CAST_BUILD_INCREMENTAL@"
+#define CAST_BUILD_RELEASE "@CAST_BUILD_RELEASE@"
#define CAST_BUILD_REVISION "@CAST_BUILD_RELEASE@.@CAST_BUILD_INCREMENTAL@"
#define CAST_IS_DEBUG_BUILD() @CAST_IS_DEBUG_BUILD@
#define CAST_PRODUCT_TYPE @CAST_PRODUCT_TYPE@
-#endif // CHROMECAST_COMMON_VERSION_INFO_H_
+#endif // CHROMECAST_BASE_VERSION_INFO_H_
diff --git a/chromium/chromecast/browser/android/apk/AndroidManifest.xml.jinja2 b/chromium/chromecast/browser/android/apk/AndroidManifest.xml.jinja2
index 7b02275ffcf..b977a9ddaeb 100644
--- a/chromium/chromecast/browser/android/apk/AndroidManifest.xml.jinja2
+++ b/chromium/chromecast/browser/android/apk/AndroidManifest.xml.jinja2
@@ -8,6 +8,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.chromium.chromecast.shell">
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="22" />
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+
<application android:name="org.chromium.chromecast.shell.CastApplication"
android:icon="@mipmap/app_icon"
android:label="@string/app_name">
@@ -48,10 +55,4 @@
{% endfor %}
</application>
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <uses-permission android:name="android.permission.WAKE_LOCK"/>
-
</manifest>
diff --git a/chromium/chromecast/browser/android/cast_window_android.cc b/chromium/chromecast/browser/android/cast_window_android.cc
index 7c2e3547b30..9e8b1d52cd0 100644
--- a/chromium/chromecast/browser/android/cast_window_android.cc
+++ b/chromium/chromecast/browser/android/cast_window_android.cc
@@ -4,7 +4,8 @@
#include "chromecast/browser/android/cast_window_android.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "chromecast/browser/android/cast_window_manager.h"
#include "chromecast/browser/cast_content_window.h"
#include "content/public/browser/devtools_agent_host.h"
@@ -125,7 +126,7 @@ void CastWindowAndroid::CloseContents(content::WebContents* source) {
// give (and guarantee) the renderer enough time to finish 'onunload'
// handler (but we don't want to wait any longer than that to delay the
// starting of next app).
- base::MessageLoopProxy::current()->PostDelayedTask(
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::Bind(&CastWindowAndroid::Destroy, weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kWebContentsDestructionDelayInMs));
diff --git a/chromium/chromecast/browser/android/cast_window_manager.cc b/chromium/chromecast/browser/android/cast_window_manager.cc
index 01fe689b3d5..05950d257ff 100644
--- a/chromium/chromecast/browser/android/cast_window_manager.cc
+++ b/chromium/chromecast/browser/android/cast_window_manager.cc
@@ -78,10 +78,8 @@ void StopCastWindow(JNIEnv* env, jclass clazz,
void EnableDevTools(JNIEnv* env, jclass clazz, jboolean enable) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- // The specific port value doesn't matter since Android uses Unix domain
- // sockets, only whether or not it is zero.
- CastBrowserProcess::GetInstance()->pref_service()->
- SetInteger(prefs::kRemoteDebuggingPort, enable ? 1 : 0);
+ CastBrowserProcess::GetInstance()->pref_service()->SetBoolean(
+ prefs::kEnableRemoteDebugging, enable);
}
} // namespace shell
diff --git a/chromium/chromecast/browser/cast_browser_main_parts.cc b/chromium/chromecast/browser/cast_browser_main_parts.cc
index 91b13cef9f7..81701cb2d98 100644
--- a/chromium/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromium/chromecast/browser/cast_browser_main_parts.cc
@@ -16,22 +16,25 @@
#include "base/path_service.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/base/switches.h"
#include "chromecast/base/cast_paths.h"
#include "chromecast/base/cast_sys_info_util.h"
+#include "chromecast/base/chromecast_switches.h"
#include "chromecast/base/metrics/cast_metrics_helper.h"
#include "chromecast/base/metrics/grouped_histogram.h"
#include "chromecast/browser/cast_browser_context.h"
#include "chromecast/browser/cast_browser_process.h"
+#include "chromecast/browser/cast_net_log.h"
#include "chromecast/browser/devtools/remote_debugging_server.h"
#include "chromecast/browser/metrics/cast_metrics_prefs.h"
#include "chromecast/browser/metrics/cast_metrics_service_client.h"
#include "chromecast/browser/pref_service_helper.h"
#include "chromecast/browser/service/cast_service.h"
#include "chromecast/browser/url_request_context_factory.h"
-#include "chromecast/common/chromecast_switches.h"
#include "chromecast/common/platform_client_auth.h"
#include "chromecast/media/base/key_systems_common.h"
+#include "chromecast/media/base/media_message_loop.h"
#include "chromecast/net/connectivity_checker.h"
#include "chromecast/public/cast_media_shlib.h"
#include "chromecast/public/cast_sys_info.h"
@@ -41,11 +44,12 @@
#include "media/audio/audio_manager.h"
#include "media/audio/audio_manager_factory.h"
#include "media/base/browser_cdm_factory.h"
-#include "media/base/media_switches.h"
+#include "media/base/media.h"
+#include "ui/compositor/compositor_switches.h"
#if defined(OS_ANDROID)
+#include "chromecast/app/android/crash_handler.h"
#include "chromecast/browser/media/cast_media_client_android.h"
-#include "chromecast/crash/android/crash_handler.h"
#include "components/crash/browser/crash_dump_manager_android.h"
#include "media/base/android/media_client_android.h"
#include "net/android/network_change_notifier_factory_android.h"
@@ -55,8 +59,8 @@
#endif
#if defined(USE_AURA)
+#include "chromecast/graphics/cast_screen.h"
#include "ui/aura/env.h"
-#include "ui/aura/test/test_screen.h"
#include "ui/gfx/screen.h"
#endif
@@ -163,7 +167,6 @@ DefaultCommandLineSwitch g_default_switches[] = {
// Disables Chromecast-specific WiFi-related features on ATV for now.
{ switches::kNoWifi, "" },
{ switches::kEnableOverlayFullscreenVideo, ""},
- { switches::kDisableInfobarForProtectedMediaIdentifier, ""},
{ switches::kDisableGestureRequirementForMediaPlayback, ""},
#endif
// Always enable HTMLMediaElement logs.
@@ -176,9 +179,12 @@ DefaultCommandLineSwitch g_default_switches[] = {
// This is needed for now to enable the egltest Ozone platform to work with
// current Linux/NVidia OpenGL drivers.
{ switches::kIgnoreGpuBlacklist, ""},
-#elif defined(ARCH_CPU_ARM_FAMILY) && !defined(DISABLE_DISPLAY)
+#elif defined(ARCH_CPU_ARM_FAMILY)
// On Linux arm, enable CMA pipeline by default.
{ switches::kEnableCmaMediaPipeline, "" },
+#if !defined(DISABLE_DISPLAY)
+ { switches::kEnableHardwareOverlays, "" },
+#endif
#endif
#endif // defined(OS_LINUX)
// Needed to fix a bug where the raster thread doesn't get scheduled for a
@@ -207,7 +213,8 @@ CastBrowserMainParts::CastBrowserMainParts(
cast_browser_process_(new CastBrowserProcess()),
parameters_(parameters),
url_request_context_factory_(url_request_context_factory),
- audio_manager_factory_(audio_manager_factory.Pass()) {
+ audio_manager_factory_(audio_manager_factory.Pass()),
+ net_log_(new CastNetLog()) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
AddDefaultCommandLineSwitches(command_line);
}
@@ -238,7 +245,7 @@ void CastBrowserMainParts::PreMainMessageLoopStart() {
void CastBrowserMainParts::PostMainMessageLoopStart() {
cast_browser_process_->SetMetricsHelper(make_scoped_ptr(
- new metrics::CastMetricsHelper(base::MessageLoopProxy::current())));
+ new metrics::CastMetricsHelper(base::ThreadTaskRunnerHandle::Get())));
#if defined(OS_ANDROID)
base::MessageLoopForUI::current()->Start();
@@ -267,14 +274,13 @@ int CastBrowserMainParts::PreCreateThreads() {
// is assumed as an interface to access display information, e.g. from metrics
// code. See CastContentWindow::CreateWindowTree for update when resolution
// is available.
+ cast_browser_process_->SetCastScreen(make_scoped_ptr(new CastScreen));
DCHECK(!gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE));
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
- aura::TestScreen::Create(gfx::Size(0, 0)));
+ cast_browser_process_->cast_screen());
#endif
- return 0;
-}
-void CastBrowserMainParts::PreMainMessageLoopRun() {
+#if !defined(OS_ANDROID)
// Set GL strings so GPU config code can make correct feature blacklisting/
// whitelisting decisions.
// Note: SetGLStrings MUST be called after GpuDataManager::Initialize.
@@ -282,7 +288,12 @@ void CastBrowserMainParts::PreMainMessageLoopRun() {
content::GpuDataManager::GetInstance()->SetGLStrings(
sys_info->GetGlVendor(), sys_info->GetGlRenderer(),
sys_info->GetGlVersion());
+#endif // !defined(OS_ANDROID)
+ return 0;
+}
+
+void CastBrowserMainParts::PreMainMessageLoopRun() {
scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple());
metrics::RegisterPrefs(pref_registry.get());
cast_browser_process_->SetPrefService(
@@ -297,11 +308,13 @@ void CastBrowserMainParts::PreMainMessageLoopRun() {
#endif // defined(OS_ANDROID)
cast_browser_process_->SetConnectivityChecker(
- make_scoped_refptr(new ConnectivityChecker(
+ ConnectivityChecker::Create(
content::BrowserThread::GetMessageLoopProxyForThread(
- content::BrowserThread::IO))));
+ content::BrowserThread::IO)));
+
+ cast_browser_process_->SetNetLog(net_log_.get());
- url_request_context_factory_->InitializeOnUIThread();
+ url_request_context_factory_->InitializeOnUIThread(net_log_.get());
cast_browser_process_->SetBrowserContext(
make_scoped_ptr(new CastBrowserContext(url_request_context_factory_)));
@@ -317,7 +330,10 @@ void CastBrowserMainParts::PreMainMessageLoopRun() {
cast_browser_process_->SetRemoteDebuggingServer(
make_scoped_ptr(new RemoteDebuggingServer()));
- media::CastMediaShlib::Initialize(cmd_line->argv());
+ media::MediaMessageLoop::GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&media::CastMediaShlib::Initialize, cmd_line->argv()));
+ ::media::InitializeMediaLibrary();
cast_browser_process_->SetCastService(CastService::Create(
cast_browser_process_->browser_context(),
@@ -382,7 +398,10 @@ void CastBrowserMainParts::PostMainMessageLoopRun() {
DeregisterKillOnAlarm();
#endif
- media::CastMediaShlib::Finalize();
+ // Finalize CastMediaShlib on media thread to ensure it's not accessed
+ // after Finalize.
+ media::MediaMessageLoop::GetTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&media::CastMediaShlib::Finalize));
}
} // namespace shell
diff --git a/chromium/chromecast/browser/cast_browser_main_parts.h b/chromium/chromecast/browser/cast_browser_main_parts.h
index 49954cef55d..4b5b5d8dfb9 100644
--- a/chromium/chromecast/browser/cast_browser_main_parts.h
+++ b/chromium/chromecast/browser/cast_browser_main_parts.h
@@ -15,6 +15,10 @@ namespace media {
class AudioManagerFactory;
}
+namespace net {
+class NetLog;
+}
+
namespace chromecast {
namespace shell {
class CastBrowserProcess;
@@ -42,6 +46,7 @@ class CastBrowserMainParts : public content::BrowserMainParts {
const content::MainFunctionParams parameters_; // For running browser tests.
URLRequestContextFactory* const url_request_context_factory_;
scoped_ptr<::media::AudioManagerFactory> audio_manager_factory_;
+ scoped_ptr<net::NetLog> net_log_;
DISALLOW_COPY_AND_ASSIGN(CastBrowserMainParts);
};
diff --git a/chromium/chromecast/browser/cast_browser_process.cc b/chromium/chromecast/browser/cast_browser_process.cc
index 25fcd44ff4a..d3cfbfa9ead 100644
--- a/chromium/chromecast/browser/cast_browser_process.cc
+++ b/chromium/chromecast/browser/cast_browser_process.cc
@@ -18,6 +18,10 @@
#include "components/crash/browser/crash_dump_manager_android.h"
#endif // defined(OS_ANDROID)
+#if defined(USE_AURA)
+#include "chromecast/graphics/cast_screen.h"
+#endif // defined(USE_AURA)
+
namespace chromecast {
namespace shell {
@@ -31,7 +35,8 @@ CastBrowserProcess* CastBrowserProcess::GetInstance() {
return g_instance;
}
-CastBrowserProcess::CastBrowserProcess() {
+CastBrowserProcess::CastBrowserProcess()
+ : net_log_(nullptr) {
DCHECK(!g_instance);
g_instance = this;
}
@@ -54,6 +59,13 @@ void CastBrowserProcess::SetCastService(scoped_ptr<CastService> cast_service) {
cast_service_.swap(cast_service);
}
+#if defined(USE_AURA)
+void CastBrowserProcess::SetCastScreen(scoped_ptr<CastScreen> cast_screen) {
+ DCHECK(!cast_screen_);
+ cast_screen_ = cast_screen.Pass();
+}
+#endif // defined(USE_AURA)
+
void CastBrowserProcess::SetMetricsHelper(
scoped_ptr<metrics::CastMetricsHelper> metrics_helper) {
DCHECK(!metrics_helper_);
@@ -97,5 +109,10 @@ void CastBrowserProcess::SetConnectivityChecker(
connectivity_checker_.swap(connectivity_checker);
}
+void CastBrowserProcess::SetNetLog(net::NetLog* net_log) {
+ DCHECK(!net_log_);
+ net_log_ = net_log;
+}
+
} // namespace shell
} // namespace chromecast
diff --git a/chromium/chromecast/browser/cast_browser_process.h b/chromium/chromecast/browser/cast_browser_process.h
index f4bec89e7a1..2af917a2493 100644
--- a/chromium/chromecast/browser/cast_browser_process.h
+++ b/chromium/chromecast/browser/cast_browser_process.h
@@ -15,8 +15,13 @@ namespace breakpad {
class CrashDumpManager;
} // namespace breakpad
+namespace net {
+class NetLog;
+} // namespace net
+
namespace chromecast {
class CastService;
+class CastScreen;
class ConnectivityChecker;
namespace metrics {
@@ -40,6 +45,9 @@ class CastBrowserProcess {
void SetBrowserContext(scoped_ptr<CastBrowserContext> browser_context);
void SetCastService(scoped_ptr<CastService> cast_service);
+#if defined(USE_AURA)
+ void SetCastScreen(scoped_ptr<CastScreen> cast_screen);
+#endif // defined(USE_AURA)
void SetMetricsHelper(scoped_ptr<metrics::CastMetricsHelper> metrics_helper);
void SetMetricsServiceClient(
scoped_ptr<metrics::CastMetricsServiceClient> metrics_service_client);
@@ -54,9 +62,13 @@ class CastBrowserProcess {
#endif // defined(OS_ANDROID)
void SetConnectivityChecker(
scoped_refptr<ConnectivityChecker> connectivity_checker);
+ void SetNetLog(net::NetLog* net_log);
CastBrowserContext* browser_context() const { return browser_context_.get(); }
CastService* cast_service() const { return cast_service_.get(); }
+#if defined(USE_AURA)
+ CastScreen* cast_screen() const { return cast_screen_.get(); }
+#endif // defined(USE_AURA)
metrics::CastMetricsServiceClient* metrics_service_client() const {
return metrics_service_client_.get();
}
@@ -68,11 +80,15 @@ class CastBrowserProcess {
ConnectivityChecker* connectivity_checker() const {
return connectivity_checker_.get();
}
+ net::NetLog* net_log() const { return net_log_; }
private:
// Note: The following order should match the order they are set in
// CastBrowserMainParts.
scoped_ptr<metrics::CastMetricsHelper> metrics_helper_;
+#if defined(USE_AURA)
+ scoped_ptr<CastScreen> cast_screen_;
+#endif // defined(USE_AURA)
scoped_ptr<PrefService> pref_service_;
scoped_refptr<ConnectivityChecker> connectivity_checker_;
scoped_ptr<CastBrowserContext> browser_context_;
@@ -84,6 +100,8 @@ class CastBrowserProcess {
#endif // defined(OS_ANDROID)
scoped_ptr<RemoteDebuggingServer> remote_debugging_server_;
+ net::NetLog* net_log_;
+
// Note: CastService must be destroyed before others.
scoped_ptr<CastService> cast_service_;
diff --git a/chromium/chromecast/browser/cast_content_browser_client.cc b/chromium/chromecast/browser/cast_content_browser_client.cc
index 3e075faadf7..5b2c0540649 100644
--- a/chromium/chromecast/browser/cast_content_browser_client.cc
+++ b/chromium/chromecast/browser/cast_content_browser_client.cc
@@ -9,10 +9,10 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/scoped_file.h"
-#include "base/i18n/icu_util.h"
#include "base/i18n/rtl.h"
#include "base/path_service.h"
#include "chromecast/base/cast_paths.h"
+#include "chromecast/base/chromecast_switches.h"
#include "chromecast/browser/cast_browser_context.h"
#include "chromecast/browser/cast_browser_main_parts.h"
#include "chromecast/browser/cast_browser_process.h"
@@ -22,8 +22,9 @@
#include "chromecast/browser/geolocation/cast_access_token_store.h"
#include "chromecast/browser/media/cma_message_filter_host.h"
#include "chromecast/browser/url_request_context_factory.h"
-#include "chromecast/common/chromecast_switches.h"
#include "chromecast/common/global_descriptors.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
+#include "chromecast/media/cma/backend/media_pipeline_device_factory.h"
#include "components/crash/app/breakpad_linux.h"
#include "components/crash/browser/crash_handler_host_linux.h"
#include "components/network_hints/browser/network_hints_message_filter.h"
@@ -37,7 +38,6 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/web_preferences.h"
-#include "gin/v8_initializer.h"
#include "media/audio/audio_manager_factory.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/url_request/url_request_context_getter.h"
@@ -52,9 +52,7 @@ namespace chromecast {
namespace shell {
CastContentBrowserClient::CastContentBrowserClient()
- : v8_natives_fd_(-1),
- v8_snapshot_fd_(-1),
- url_request_context_factory_(new URLRequestContextFactory()) {
+ : url_request_context_factory_(new URLRequestContextFactory()) {
}
CastContentBrowserClient::~CastContentBrowserClient() {
@@ -64,18 +62,48 @@ CastContentBrowserClient::~CastContentBrowserClient() {
url_request_context_factory_.release());
}
+void CastContentBrowserClient::AppendExtraCommandLineSwitches(
+ base::CommandLine* command_line) {
+}
+
+std::vector<scoped_refptr<content::BrowserMessageFilter>>
+CastContentBrowserClient::GetBrowserMessageFilters() {
+ return std::vector<scoped_refptr<content::BrowserMessageFilter>>();
+}
+
+scoped_ptr<::media::AudioManagerFactory>
+CastContentBrowserClient::CreateAudioManagerFactory() {
+ // Return nullptr. The factory will not be set, and the statically linked
+ // implementation of AudioManager will be used.
+ return scoped_ptr<::media::AudioManagerFactory>();
+}
+
+#if !defined(OS_ANDROID)
+scoped_ptr<media::MediaPipelineDevice>
+CastContentBrowserClient::CreateMediaPipelineDevice(
+ const media::MediaPipelineDeviceParams& params) {
+ scoped_ptr<media::MediaPipelineDeviceFactory> factory =
+ GetMediaPipelineDeviceFactory(params);
+ return make_scoped_ptr(new media::MediaPipelineDevice(factory.Pass()));
+}
+#endif
+
content::BrowserMainParts* CastContentBrowserClient::CreateBrowserMainParts(
const content::MainFunctionParams& parameters) {
return new CastBrowserMainParts(parameters,
url_request_context_factory_.get(),
- PlatformCreateAudioManagerFactory());
+ CreateAudioManagerFactory());
}
void CastContentBrowserClient::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
#if !defined(OS_ANDROID)
scoped_refptr<media::CmaMessageFilterHost> cma_message_filter(
- new media::CmaMessageFilterHost(host->GetID()));
+ new media::CmaMessageFilterHost(
+ host->GetID(),
+ base::Bind(
+ &CastContentBrowserClient::CreateMediaPipelineDevice,
+ base::Unretained(this))));
host->AddFilter(cma_message_filter.get());
#endif // !defined(OS_ANDROID)
@@ -89,7 +117,7 @@ void CastContentBrowserClient::RenderProcessWillLaunch(
base::Bind(&CastContentBrowserClient::AddNetworkHintsMessageFilter,
base::Unretained(this), host->GetID()));
- auto extra_filters = PlatformGetBrowserMessageFilters();
+ auto extra_filters = GetBrowserMessageFilters();
for (auto const& filter : extra_filters) {
host->AddFilter(filter.get());
}
@@ -149,19 +177,11 @@ bool CastContentBrowserClient::IsHandledURL(const GURL& url) {
void CastContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int child_process_id) {
-
std::string process_type =
command_line->GetSwitchValueNative(switches::kProcessType);
base::CommandLine* browser_command_line =
base::CommandLine::ForCurrentProcess();
-#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
- if (process_type != switches::kZygoteProcess) {
- command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
- command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
- }
-#endif // V8_USE_EXTERNAL_STARTUP_DATA
-
// IsCrashReporterEnabled() is set when InitCrashReporter() is called, and
// controlled by GetBreakpadClient()->EnableBreakpadForProcess(), therefore
// it's ok to add switch to every process here.
@@ -176,6 +196,8 @@ void CastContentBrowserClient::AppendExtraCommandLineSwitches(
if (browser_command_line->HasSwitch(switches::kEnableCmaMediaPipeline))
command_line->AppendSwitch(switches::kEnableCmaMediaPipeline);
+ if (browser_command_line->HasSwitch(switches::kEnableLegacyHolePunching))
+ command_line->AppendSwitch(switches::kEnableLegacyHolePunching);
}
#if defined(OS_LINUX)
@@ -187,7 +209,7 @@ void CastContentBrowserClient::AppendExtraCommandLineSwitches(
}
#endif
- PlatformAppendExtraCommandLineSwitches(command_line);
+ AppendExtraCommandLineSwitches(command_line);
}
content::AccessTokenStore* CastContentBrowserClient::CreateAccessTokenStore() {
@@ -305,41 +327,25 @@ bool CastContentBrowserClient::CanCreateWindow(
bool opener_suppressed,
content::ResourceContext* context,
int render_process_id,
- int opener_id,
+ int opener_render_view_id,
+ int opener_render_frame_id,
bool* no_javascript_access) {
*no_javascript_access = true;
return false;
}
+#if defined(OS_ANDROID)
void CastContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
- content::FileDescriptorInfo* mappings) {
-#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
- if (v8_natives_fd_.get() == -1 || v8_snapshot_fd_.get() == -1) {
- int v8_natives_fd = -1;
- int v8_snapshot_fd = -1;
- if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
- &v8_snapshot_fd)) {
- v8_natives_fd_.reset(v8_natives_fd);
- v8_snapshot_fd_.reset(v8_snapshot_fd);
- }
- }
- DCHECK(v8_natives_fd_.get() != -1 && v8_snapshot_fd_.get() != -1);
- mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
- mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
-#endif // V8_USE_EXTERNAL_STARTUP_DATA
-#if defined(OS_ANDROID)
- const int flags_open_read = base::File::FLAG_OPEN | base::File::FLAG_READ;
- base::FilePath pak_file_path;
- CHECK(PathService::Get(FILE_CAST_PAK, &pak_file_path));
- base::File pak_file(pak_file_path, flags_open_read);
- if (!pak_file.IsValid()) {
- NOTREACHED() << "Failed to open file when creating renderer process: "
- << "cast_shell.pak";
- }
- mappings->Transfer(kAndroidPakDescriptor,
- base::ScopedFD(pak_file.TakePlatformFile()));
+ content::FileDescriptorInfo* mappings,
+ std::map<int, base::MemoryMappedFile::Region>* regions) {
+ mappings->Share(
+ kAndroidPakDescriptor,
+ base::GlobalDescriptors::GetInstance()->Get(kAndroidPakDescriptor));
+ regions->insert(std::make_pair(
+ kAndroidPakDescriptor, base::GlobalDescriptors::GetInstance()->GetRegion(
+ kAndroidPakDescriptor)));
if (breakpad::IsCrashReporterEnabled()) {
base::File minidump_file(
@@ -353,23 +359,18 @@ void CastContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
base::ScopedFD(minidump_file.TakePlatformFile()));
}
}
-
- base::FilePath app_data_path;
- CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &app_data_path));
- base::FilePath icudata_path =
- app_data_path.AppendASCII(base::i18n::kIcuDataFileName);
- base::File icudata_file(icudata_path, flags_open_read);
- if (!icudata_file.IsValid())
- NOTREACHED() << "Failed to open ICU file when creating renderer process";
- mappings->Transfer(kAndroidICUDataDescriptor,
- base::ScopedFD(icudata_file.TakePlatformFile()));
+}
#else
+void CastContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
+ const base::CommandLine& command_line,
+ int child_process_id,
+ content::FileDescriptorInfo* mappings) {
int crash_signal_fd = GetCrashSignalFD(command_line);
if (crash_signal_fd >= 0) {
mappings->Share(kCrashDumpSignal, crash_signal_fd);
}
-#endif // defined(OS_ANDROID)
}
+#endif // defined(OS_ANDROID)
#if defined(OS_ANDROID) && defined(VIDEO_HOLE)
content::ExternalVideoSurfaceContainer*
diff --git a/chromium/chromecast/browser/cast_content_browser_client.h b/chromium/chromecast/browser/cast_content_browser_client.h
index 5e5c262f92a..1db6ba38ae0 100644
--- a/chromium/chromecast/browser/cast_content_browser_client.h
+++ b/chromium/chromecast/browser/cast_content_browser_client.h
@@ -30,6 +30,11 @@ class HostResolver;
}
namespace chromecast {
+namespace media {
+class MediaPipelineDevice;
+class MediaPipelineDeviceParams;
+}
+
namespace shell {
class CastBrowserMainParts;
@@ -37,16 +42,29 @@ class URLRequestContextFactory;
class CastContentBrowserClient: public content::ContentBrowserClient {
public:
- CastContentBrowserClient();
+ // Creates an implementation of CastContentBrowserClient. Platform should
+ // link in an implementation as needed.
+ static scoped_ptr<CastContentBrowserClient> Create();
+
~CastContentBrowserClient() override;
// Appends extra command line arguments before launching a new process.
- void PlatformAppendExtraCommandLineSwitches(base::CommandLine* command_line);
+ virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line);
+
+ // Returns any BrowserMessageFilters that should be added when launching a
+ // new render process.
+ virtual std::vector<scoped_refptr<content::BrowserMessageFilter>>
+ GetBrowserMessageFilters();
- // Returns any BrowserMessageFilters from the platform implementation that
- // should be added when launching a new render process.
- std::vector<scoped_refptr<content::BrowserMessageFilter>>
- PlatformGetBrowserMessageFilters();
+ // Provide an AudioManagerFactory instance for WebAudio playback.
+ virtual scoped_ptr<::media::AudioManagerFactory> CreateAudioManagerFactory();
+
+#if !defined(OS_ANDROID)
+ // Creates a MediaPipelineDevice (CMA backend) for media playback, called
+ // once per media player instance.
+ virtual scoped_ptr<media::MediaPipelineDevice> CreateMediaPipelineDevice(
+ const media::MediaPipelineDeviceParams& params);
+#endif
// content::ContentBrowserClient implementation:
content::BrowserMainParts* CreateBrowserMainParts(
@@ -95,18 +113,30 @@ class CastContentBrowserClient: public content::ContentBrowserClient {
bool opener_suppressed,
content::ResourceContext* context,
int render_process_id,
- int opener_id,
+ int opener_render_view_id,
+ int opener_render_frame_id,
bool* no_javascript_access) override;
+#if defined(OS_ANDROID)
+ void GetAdditionalMappedFilesForChildProcess(
+ const base::CommandLine& command_line,
+ int child_process_id,
+ content::FileDescriptorInfo* mappings,
+ std::map<int, base::MemoryMappedFile::Region>* regions) override;
+#else
void GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
content::FileDescriptorInfo* mappings) override;
+#endif // defined(OS_ANDROID)
#if defined(OS_ANDROID) && defined(VIDEO_HOLE)
content::ExternalVideoSurfaceContainer*
OverrideCreateExternalVideoSurfaceContainer(
content::WebContents* web_contents) override;
#endif // defined(OS_ANDROID) && defined(VIDEO_HOLE)
+ protected:
+ CastContentBrowserClient();
+
private:
void AddNetworkHintsMessageFilter(int render_process_id,
net::URLRequestContext* context);
@@ -115,8 +145,6 @@ class CastContentBrowserClient: public content::ContentBrowserClient {
GURL requesting_url,
int render_process_id);
- scoped_ptr<::media::AudioManagerFactory> PlatformCreateAudioManagerFactory();
-
#if !defined(OS_ANDROID)
// Returns the crash signal FD corresponding to the current process type.
int GetCrashSignalFD(const base::CommandLine& command_line);
@@ -129,9 +157,6 @@ class CastContentBrowserClient: public content::ContentBrowserClient {
std::map<std::string, breakpad::CrashHandlerHostLinux*> crash_handlers_;
#endif
- base::ScopedFD v8_natives_fd_;
- base::ScopedFD v8_snapshot_fd_;
-
scoped_ptr<URLRequestContextFactory> url_request_context_factory_;
DISALLOW_COPY_AND_ASSIGN(CastContentBrowserClient);
diff --git a/chromium/chromecast/browser/cast_content_browser_client_simple.cc b/chromium/chromecast/browser/cast_content_browser_client_simple.cc
index bde5a71d028..2b27e60db0d 100644
--- a/chromium/chromecast/browser/cast_content_browser_client_simple.cc
+++ b/chromium/chromecast/browser/cast_content_browser_client_simple.cc
@@ -4,26 +4,14 @@
#include "chromecast/browser/cast_content_browser_client.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "media/audio/audio_manager_factory.h"
+#include "base/memory/scoped_ptr.h"
namespace chromecast {
namespace shell {
-void CastContentBrowserClient::PlatformAppendExtraCommandLineSwitches(
- base::CommandLine* command_line) {
-}
-
-std::vector<scoped_refptr<content::BrowserMessageFilter>>
-CastContentBrowserClient::PlatformGetBrowserMessageFilters() {
- return std::vector<scoped_refptr<content::BrowserMessageFilter>>();
-}
-
-scoped_ptr<::media::AudioManagerFactory>
-CastContentBrowserClient::PlatformCreateAudioManagerFactory() {
- // Return nullptr. The factory will not be set, and the statically linked
- // implementation of AudioManager will be used.
- return scoped_ptr<::media::AudioManagerFactory>();
+// static
+scoped_ptr<CastContentBrowserClient> CastContentBrowserClient::Create() {
+ return make_scoped_ptr(new CastContentBrowserClient());
}
} // namespace shell
diff --git a/chromium/chromecast/browser/cast_content_window.cc b/chromium/chromecast/browser/cast_content_window.cc
index 27c91b74cb4..8ca03391915 100644
--- a/chromium/chromecast/browser/cast_content_window.cc
+++ b/chromium/chromecast/browser/cast_content_window.cc
@@ -4,16 +4,21 @@
#include "chromecast/browser/cast_content_window.h"
+#include "base/command_line.h"
#include "base/threading/thread_restrictions.h"
+#include "chromecast/base/chromecast_switches.h"
#include "chromecast/base/metrics/cast_metrics_helper.h"
+#include "chromecast/browser/cast_browser_process.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message.h"
#if defined(USE_AURA)
+#include "chromecast/graphics/cast_screen.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/test/test_focus_client.h"
-#include "ui/aura/test/test_screen.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#endif
@@ -66,26 +71,27 @@ void CastContentWindow::CreateWindowTree(
content::WebContents* web_contents) {
#if defined(USE_AURA)
// Aura initialization
- // TODO(lcwu): We only need a minimal implementation of gfx::Screen
- // and aura's TestScreen will do for us now. We should change to use
- // ozone's screen implementation when it is ready.
- gfx::Screen* old_screen =
- gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
- if (!old_screen || old_screen->GetPrimaryDisplay().size() != initial_size) {
- gfx::Screen* new_screen = aura::TestScreen::Create(initial_size);
- DCHECK(new_screen) << "New screen not created.";
- gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, new_screen);
- if (old_screen) {
- delete old_screen;
- }
- }
+ CastScreen* cast_screen =
+ shell::CastBrowserProcess::GetInstance()->cast_screen();
+ if (!gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE))
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, cast_screen);
+ if (cast_screen->GetPrimaryDisplay().size() != initial_size)
+ cast_screen->UpdateDisplaySize(initial_size);
+
CHECK(aura::Env::GetInstance());
window_tree_host_.reset(
aura::WindowTreeHost::Create(gfx::Rect(initial_size)));
window_tree_host_->InitHost();
window_tree_host_->window()->SetLayoutManager(
new CastFillLayout(window_tree_host_->window()));
- window_tree_host_->compositor()->SetBackgroundColor(SK_ColorBLACK);
+
+ const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableTransparentBackground)) {
+ window_tree_host_->compositor()->SetBackgroundColor(SK_ColorTRANSPARENT);
+ window_tree_host_->compositor()->SetHostHasTransparentBackground(true);
+ } else {
+ window_tree_host_->compositor()->SetBackgroundColor(SK_ColorBLACK);
+ }
focus_client_.reset(new aura::test::TestFocusClient());
aura::client::SetFocusClient(
@@ -127,4 +133,14 @@ void CastContentWindow::MediaStartedPlaying() {
metrics::CastMetricsHelper::GetInstance()->LogMediaPlay();
}
+void CastContentWindow::RenderViewCreated(
+ content::RenderViewHost* render_view_host) {
+ const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
+ if (command_line->HasSwitch(switches::kEnableTransparentBackground)) {
+ content::RenderWidgetHostView* view = render_view_host->GetView();
+ if (view)
+ view->SetBackgroundColor(SK_ColorTRANSPARENT);
+ }
+}
+
} // namespace chromecast
diff --git a/chromium/chromecast/browser/cast_content_window.h b/chromium/chromecast/browser/cast_content_window.h
index 1360a5e0ca4..9d76426e667 100644
--- a/chromium/chromecast/browser/cast_content_window.h
+++ b/chromium/chromecast/browser/cast_content_window.h
@@ -46,6 +46,7 @@ class CastContentWindow : public content::WebContentsObserver {
void DidFirstVisuallyNonEmptyPaint() override;
void MediaPaused() override;
void MediaStartedPlaying() override;
+ void RenderViewCreated(content::RenderViewHost* render_view_host) override;
private:
#if defined(USE_AURA)
diff --git a/chromium/chromecast/browser/cast_net_log.cc b/chromium/chromecast/browser/cast_net_log.cc
new file mode 100644
index 00000000000..d1c62d4b5f8
--- /dev/null
+++ b/chromium/chromecast/browser/cast_net_log.cc
@@ -0,0 +1,75 @@
+// Copyright 2015 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/browser/cast_net_log.h"
+
+#include <stdio.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/values.h"
+#include "content/public/common/content_switches.h"
+#include "net/log/net_log_util.h"
+#include "net/log/write_to_file_net_log_observer.h"
+
+namespace chromecast {
+
+namespace {
+
+base::DictionaryValue* GetShellConstants() {
+ scoped_ptr<base::DictionaryValue> constants_dict = net::GetNetConstants();
+
+ // Add a dictionary with client information
+ base::DictionaryValue* dict = new base::DictionaryValue();
+
+ dict->SetString("name", "cast_shell");
+ dict->SetString(
+ "command_line",
+ base::CommandLine::ForCurrentProcess()->GetCommandLineString());
+
+ constants_dict->Set("clientInfo", dict);
+
+ return constants_dict.release();
+}
+
+} // namespace
+
+CastNetLog::CastNetLog() {
+ // TODO(derekjchow): This code is virtually identical to ShellNetLog which is
+ // nearly identical to code in ChromeNetLog. Consider merging the code.
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ if (command_line->HasSwitch(switches::kLogNetLog)) {
+ base::FilePath log_path =
+ command_line->GetSwitchValuePath(switches::kLogNetLog);
+ // Much like logging.h, bypass threading restrictions by using fopen
+ // directly. Have to write on a thread that's shutdown to handle events on
+ // shutdown properly, and posting events to another thread as they occur
+ // would result in an unbounded buffer size, so not much can be gained by
+ // doing this on another thread. It's only used when debugging, so
+ // performance is not a big concern.
+ base::ScopedFILE file;
+ file.reset(fopen(log_path.value().c_str(), "w"));
+
+ if (!file) {
+ LOG(ERROR) << "Could not open file " << log_path.value()
+ << " for net logging";
+ } else {
+ scoped_ptr<base::Value> constants(GetShellConstants());
+ write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
+ write_to_file_observer_->StartObserving(this, file.Pass(),
+ constants.get(), nullptr);
+ }
+ }
+}
+
+CastNetLog::~CastNetLog() {
+ // Remove the observer we own before we're destroyed.
+ if (write_to_file_observer_)
+ write_to_file_observer_->StopObserving(nullptr);
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/browser/cast_net_log.h b/chromium/chromecast/browser/cast_net_log.h
new file mode 100644
index 00000000000..6be2b5b34c6
--- /dev/null
+++ b/chromium/chromecast/browser/cast_net_log.h
@@ -0,0 +1,28 @@
+// Copyright 2015 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_BROWSER_CAST_NET_LOG_H_
+#define CHROMECAST_BROWSER_CAST_NET_LOG_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "net/log/write_to_file_net_log_observer.h"
+
+namespace chromecast {
+
+class CastNetLog : public net::NetLog {
+ public:
+ CastNetLog();
+ ~CastNetLog() override;
+
+ private:
+ scoped_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastNetLog);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_BROWSER_CAST_NET_LOG_H_
diff --git a/chromium/chromecast/browser/cast_network_delegate.cc b/chromium/chromecast/browser/cast_network_delegate.cc
index 51d9fd4aa5b..3e004a0a539 100644
--- a/chromium/chromecast/browser/cast_network_delegate.cc
+++ b/chromium/chromecast/browser/cast_network_delegate.cc
@@ -6,7 +6,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
-#include "chromecast/common/chromecast_switches.h"
+#include "chromecast/base/chromecast_switches.h"
namespace chromecast {
namespace shell {
diff --git a/chromium/chromecast/browser/cast_permission_manager.cc b/chromium/chromecast/browser/cast_permission_manager.cc
index 54352c0db79..047a6ff5a90 100644
--- a/chromium/chromecast/browser/cast_permission_manager.cc
+++ b/chromium/chromecast/browser/cast_permission_manager.cc
@@ -20,7 +20,7 @@ CastPermissionManager::~CastPermissionManager() {
void CastPermissionManager::RequestPermission(
content::PermissionType permission,
- content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
int request_id,
const GURL& origin,
bool user_gesture,
@@ -31,7 +31,7 @@ void CastPermissionManager::RequestPermission(
void CastPermissionManager::CancelPermissionRequest(
content::PermissionType permission,
- content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
int request_id,
const GURL& origin) {
}
diff --git a/chromium/chromecast/browser/cast_permission_manager.h b/chromium/chromecast/browser/cast_permission_manager.h
index c82f08a4be2..237eff99306 100644
--- a/chromium/chromecast/browser/cast_permission_manager.h
+++ b/chromium/chromecast/browser/cast_permission_manager.h
@@ -20,13 +20,13 @@ class CastPermissionManager : public content::PermissionManager {
// content::PermissionManager implementation:
void RequestPermission(
content::PermissionType permission,
- content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
int request_id,
const GURL& requesting_origin,
bool user_gesture,
const base::Callback<void(content::PermissionStatus)>& callback) override;
void CancelPermissionRequest(content::PermissionType permission,
- content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
int request_id,
const GURL& requesting_origin) override;
void ResetPermission(content::PermissionType permission,
diff --git a/chromium/chromecast/browser/devtools/cast_dev_tools_delegate.h b/chromium/chromecast/browser/devtools/cast_dev_tools_delegate.h
index 190abec1244..1726af230cf 100644
--- a/chromium/chromecast/browser/devtools/cast_dev_tools_delegate.h
+++ b/chromium/chromecast/browser/devtools/cast_dev_tools_delegate.h
@@ -6,7 +6,6 @@
#define CHROMECAST_BROWSER_DEVTOOLS_CAST_DEV_TOOLS_DELEGATE_H_
#include "components/devtools_http_handler/devtools_http_handler_delegate.h"
-#include "net/socket/stream_listen_socket.h"
namespace chromecast {
namespace shell {
diff --git a/chromium/chromecast/browser/devtools/remote_debugging_server.cc b/chromium/chromecast/browser/devtools/remote_debugging_server.cc
index 6391b6d6303..dda2123e1ea 100644
--- a/chromium/chromecast/browser/devtools/remote_debugging_server.cc
+++ b/chromium/chromecast/browser/devtools/remote_debugging_server.cc
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "chromecast/browser/cast_browser_process.h"
#include "chromecast/browser/devtools/cast_dev_tools_delegate.h"
@@ -112,42 +113,40 @@ std::string GetFrontendUrl() {
} // namespace
-RemoteDebuggingServer::RemoteDebuggingServer() : port_(0) {
+RemoteDebuggingServer::RemoteDebuggingServer()
+ : port_(kDefaultRemoteDebuggingPort) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- pref_port_.Init(prefs::kRemoteDebuggingPort,
- CastBrowserProcess::GetInstance()->pref_service(),
- base::Bind(&RemoteDebuggingServer::OnPortChanged,
- base::Unretained(this)));
+ pref_enabled_.Init(prefs::kEnableRemoteDebugging,
+ CastBrowserProcess::GetInstance()->pref_service(),
+ base::Bind(&RemoteDebuggingServer::OnEnabledChanged,
+ base::Unretained(this)));
+
+ std::string port_str =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kRemoteDebuggingPort);
+ if (!port_str.empty()) {
+ int port = kDefaultRemoteDebuggingPort;
+ if (base::StringToInt(port_str, &port)) {
+ port_ = static_cast<uint16>(port);
+ } else {
+ port_ = kDefaultRemoteDebuggingPort;
+ }
+ }
// Starts new dev tools, clearing port number saved in config.
// Remote debugging in production must be triggered only by config server.
- pref_port_.SetValue(ShouldStartImmediately() ?
- kDefaultRemoteDebuggingPort : 0);
- OnPortChanged();
+ pref_enabled_.SetValue(ShouldStartImmediately() && port_ != 0);
+ OnEnabledChanged();
}
RemoteDebuggingServer::~RemoteDebuggingServer() {
- pref_port_.SetValue(0);
- OnPortChanged();
+ pref_enabled_.SetValue(false);
+ OnEnabledChanged();
}
-void RemoteDebuggingServer::OnPortChanged() {
- uint16 new_port = static_cast<uint16>(std::max(*pref_port_, 0));
- VLOG(1) << "OnPortChanged called: old_port=" << port_
- << ", new_port=" << new_port;
-
- if (new_port == port_) {
- VLOG(1) << "Port has not been changed. Ignore silently.";
- return;
- }
-
- if (devtools_http_handler_) {
- LOG(INFO) << "Stop old devtools: port=" << port_;
- devtools_http_handler_.reset();
- }
-
- port_ = new_port;
- if (port_ > 0) {
+void RemoteDebuggingServer::OnEnabledChanged() {
+ bool enabled = *pref_enabled_ && port_ != 0;
+ if (enabled && !devtools_http_handler_) {
devtools_http_handler_.reset(new DevToolsHttpHandler(
CreateSocketFactory(port_),
GetFrontendUrl(),
@@ -157,6 +156,9 @@ void RemoteDebuggingServer::OnPortChanged() {
std::string(),
GetUserAgent()));
LOG(INFO) << "Devtools started: port=" << port_;
+ } else if (!enabled && devtools_http_handler_) {
+ LOG(INFO) << "Stop devtools: port=" << port_;
+ devtools_http_handler_.reset();
}
}
diff --git a/chromium/chromecast/browser/devtools/remote_debugging_server.h b/chromium/chromecast/browser/devtools/remote_debugging_server.h
index 399b34449f9..146f137fc2a 100644
--- a/chromium/chromecast/browser/devtools/remote_debugging_server.h
+++ b/chromium/chromecast/browser/devtools/remote_debugging_server.h
@@ -23,8 +23,8 @@ class RemoteDebuggingServer {
~RemoteDebuggingServer();
private:
- // Called on port number changed.
- void OnPortChanged();
+ // Called when pref_enabled_ is changed.
+ void OnEnabledChanged();
// Returns whether or not the remote debugging server should be available
// on device startup.
@@ -32,7 +32,7 @@ class RemoteDebuggingServer {
scoped_ptr<devtools_http_handler::DevToolsHttpHandler> devtools_http_handler_;
- IntegerPrefMember pref_port_;
+ BooleanPrefMember pref_enabled_;
uint16 port_;
DISALLOW_COPY_AND_ASSIGN(RemoteDebuggingServer);
diff --git a/chromium/chromecast/browser/media/cast_browser_cdm_factory.cc b/chromium/chromecast/browser/media/cast_browser_cdm_factory.cc
index 61d80019090..67a0891070f 100644
--- a/chromium/chromecast/browser/media/cast_browser_cdm_factory.cc
+++ b/chromium/chromecast/browser/media/cast_browser_cdm_factory.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "chromecast/browser/media/cma_message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "chromecast/media/base/media_message_loop.h"
#include "chromecast/media/cdm/browser_cdm_cast.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/cdm_key_information.h"
@@ -36,7 +36,7 @@ scoped_ptr<::media::BrowserCdm> CastBrowserCdmFactory::CreateBrowserCdm(
}
if (browser_cdm) {
- CmaMessageLoop::GetMessageLoopProxy()->PostTask(
+ MediaMessageLoop::GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&BrowserCdmCast::Initialize,
base::Unretained(browser_cdm.get()),
@@ -45,9 +45,8 @@ scoped_ptr<::media::BrowserCdm> CastBrowserCdmFactory::CreateBrowserCdm(
::media::BindToCurrentLoop(legacy_session_error_cb),
::media::BindToCurrentLoop(session_keys_change_cb),
::media::BindToCurrentLoop(session_expiration_update_cb)));
- return make_scoped_ptr(
- new BrowserCdmCastUi(browser_cdm.Pass(),
- CmaMessageLoop::GetMessageLoopProxy()));
+ return make_scoped_ptr(new BrowserCdmCastUi(
+ browser_cdm.Pass(), MediaMessageLoop::GetTaskRunner()));
}
LOG(INFO) << "No matching key system found.";
diff --git a/chromium/chromecast/browser/media/cma_message_filter_host.cc b/chromium/chromecast/browser/media/cma_message_filter_host.cc
index d3664c915a6..226d5744b39 100644
--- a/chromium/chromecast/browser/media/cma_message_filter_host.cc
+++ b/chromium/chromecast/browser/media/cma_message_filter_host.cc
@@ -10,14 +10,16 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/sync_socket.h"
-#include "chromecast/browser/media/cma_message_loop.h"
#include "chromecast/browser/media/media_pipeline_host.h"
#include "chromecast/common/media/cma_messages.h"
+#include "chromecast/media/base/media_message_loop.h"
#include "chromecast/media/cdm/browser_cdm_cast.h"
-#include "chromecast/media/cma/backend/video_plane.h"
#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
#include "chromecast/media/cma/pipeline/media_pipeline_client.h"
#include "chromecast/media/cma/pipeline/video_pipeline_client.h"
+#include "chromecast/public/cast_media_shlib.h"
+#include "chromecast/public/graphics_types.h"
+#include "chromecast/public/video_plane.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "media/base/bind_to_current_loop.h"
@@ -52,7 +54,7 @@ uint64_t GetPipelineCmaId(int process_id, int media_id) {
}
MediaPipelineHost* GetMediaPipeline(int process_id, int media_id) {
- DCHECK(CmaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
+ DCHECK(MediaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
MediaPipelineCmaMap::iterator it =
g_pipeline_map_cma.Get().find(GetPipelineCmaId(process_id, media_id));
if (it == g_pipeline_map_cma.Get().end())
@@ -61,7 +63,7 @@ MediaPipelineHost* GetMediaPipeline(int process_id, int media_id) {
}
void SetMediaPipeline(int process_id, int media_id, MediaPipelineHost* host) {
- DCHECK(CmaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
+ DCHECK(MediaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
std::pair<MediaPipelineCmaMap::iterator, bool> ret =
g_pipeline_map_cma.Get().insert(
std::make_pair(GetPipelineCmaId(process_id, media_id), host));
@@ -73,7 +75,7 @@ void SetMediaPipeline(int process_id, int media_id, MediaPipelineHost* host) {
void DestroyMediaPipeline(int process_id,
int media_id,
scoped_ptr<MediaPipelineHost> media_pipeline) {
- DCHECK(CmaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
+ DCHECK(MediaMessageLoop::GetTaskRunner()->BelongsToCurrentThread());
MediaPipelineCmaMap::iterator it =
g_pipeline_map_cma.Get().find(GetPipelineCmaId(process_id, media_id));
if (it != g_pipeline_map_cma.Get().end())
@@ -117,7 +119,7 @@ void SetCdmOnUiThread(
BrowserCdmCast* browser_cdm_cast =
static_cast<BrowserCdmCastUi*>(cdm)->browser_cdm_cast();
- CmaMessageLoop::GetTaskRunner()->PostTask(
+ MediaMessageLoop::GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&SetCdmOnCmaThread,
render_process_id,
@@ -125,22 +127,183 @@ void SetCdmOnUiThread(
browser_cdm_cast));
}
+// TODO(halliwell): remove this and the NotifyExternalSurface path once
+// VIDEO_HOLE is no longer required.
+void EstimateVideoPlaneRect(const gfx::QuadF& quad,
+ VideoPlane::Transform* transform,
+ RectF* rect) {
+ const gfx::PointF& p0 = quad.p1();
+ const gfx::PointF& p1 = quad.p2();
+ const gfx::PointF& p2 = quad.p3();
+ const gfx::PointF& p3 = quad.p4();
+
+ float det0 = p0.x() * p1.y() - p1.x() * p0.y();
+ float det1 = p1.x() * p2.y() - p2.x() * p1.y();
+ float det2 = p2.x() * p3.y() - p3.x() * p2.y();
+ float det3 = p3.x() * p0.y() - p0.x() * p3.y();
+
+ // Calculate the area of the quad (i.e. moment 0 of the polygon).
+ // Note: the area can here be either positive or negative
+ // depending on whether the quad is clock wise or counter clock wise.
+ float area = 0.5 * (det0 + det1 + det2 + det3);
+ if (area == 0.0) {
+ // Empty rectangle in that case.
+ *transform = VideoPlane::TRANSFORM_NONE;
+ *rect = RectF(p0.x(), p0.y(), 0.0, 0.0);
+ return;
+ }
+
+ // Calculate the center of gravity of the polygon
+ // (i.e. moment 1 of the polygon).
+ float cx = (1.0 / (6.0 * area)) *
+ ((p0.x() + p1.x()) * det0 +
+ (p1.x() + p2.x()) * det1 +
+ (p2.x() + p3.x()) * det2 +
+ (p3.x() + p0.x()) * det3);
+ float cy = (1.0 / (6.0 * area)) *
+ ((p0.y() + p1.y()) * det0 +
+ (p1.y() + p2.y()) * det1 +
+ (p2.y() + p3.y()) * det2 +
+ (p3.y() + p0.y()) * det3);
+
+ // For numerical stability, subtract the center of gravity now instead of
+ // later doing:
+ // mxx -= cx * cx;
+ // myy -= cy * cy;
+ // mxy -= cx * cy;
+ // to get the centered 2nd moments.
+ gfx::PointF p0c(p0.x() - cx, p0.y() - cy);
+ gfx::PointF p1c(p1.x() - cx, p1.y() - cy);
+ gfx::PointF p2c(p2.x() - cx, p2.y() - cy);
+ gfx::PointF p3c(p3.x() - cx, p3.y() - cy);
+
+ // Calculate the second moments of the polygon.
+ float det0c = p0c.x() * p1c.y() - p1c.x() * p0c.y();
+ float det1c = p1c.x() * p2c.y() - p2c.x() * p1c.y();
+ float det2c = p2c.x() * p3c.y() - p3c.x() * p2c.y();
+ float det3c = p3c.x() * p0c.y() - p0c.x() * p3c.y();
+ float mxx = (1.0 / (12.0 * area)) *
+ ((p0c.x() * p0c.x() + p0c.x() * p1c.x() + p1c.x() * p1c.x()) * det0c +
+ (p1c.x() * p1c.x() + p1c.x() * p2c.x() + p2c.x() * p2c.x()) * det1c +
+ (p2c.x() * p2c.x() + p2c.x() * p3c.x() + p3c.x() * p3c.x()) * det2c +
+ (p3c.x() * p3c.x() + p3c.x() * p0c.x() + p0c.x() * p0c.x()) * det3c);
+ float myy = (1.0 / (12.0 * area)) *
+ ((p0c.y() * p0c.y() + p0c.y() * p1c.y() + p1c.y() * p1c.y()) * det0c +
+ (p1c.y() * p1c.y() + p1c.y() * p2c.y() + p2c.y() * p2c.y()) * det1c +
+ (p2c.y() * p2c.y() + p2c.y() * p3c.y() + p3c.y() * p3c.y()) * det2c +
+ (p3c.y() * p3c.y() + p3c.y() * p0c.y() + p0c.y() * p0c.y()) * det3c);
+
+ // Remark: the 2nd moments of a rotated & centered rectangle are given by:
+ // mxx = (1/12) * (h^2 * s^2 + w^2 * c^2)
+ // myy = (1/12) * (h^2 * c^2 + w^2 * s^2)
+ // mxy = (1/12) * (w^2 - h^2) * c * s
+ // where w = width of the original rectangle,
+ // h = height of the original rectangle,
+ // c = cos(teta) with teta the angle of the rotation,
+ // s = sin(teta)
+ //
+ // For reference, mxy can be calculated from the quad using:
+ // float mxy = (1.0 / (24.0 * area)) *
+ // ((2.0 * p0c.x() * p0c.y() + p0c.x() * p1c.y() + p1c.x() * p0c.y() +
+ // 2.0 * p1c.x() * p1c.y()) * det0c +
+ // (2.0 * p1c.x() * p1c.y() + p1c.x() * p2c.y() + p2c.x() * p1c.y() +
+ // 2.0 * p2c.x() * p2c.y()) * det1c +
+ // (2.0 * p2c.x() * p2c.y() + p2c.x() * p3c.y() + p3c.x() * p2c.y() +
+ // 2.0 * p3c.x() * p3c.y()) * det2c +
+ // (2.0 * p3c.x() * p3c.y() + p3c.x() * p0c.y() + p0c.x() * p3c.y() +
+ // 2.0 * p0c.x() * p0c.y()) * det3c);
+
+ // The rotation is assumed to be 0, 90, 180 or 270 degrees, so mxy = 0.0
+ // Using this assumption: mxx = (1/12) h^2 or (1/12) w^2 depending on the
+ // rotation. Same for myy.
+ if (mxx < 0 || myy < 0) {
+ // mxx and myy should be positive, only numerical errors can lead to a
+ // negative value.
+ LOG(WARNING) << "Numerical errors: " << mxx << " " << myy;
+ *transform = VideoPlane::TRANSFORM_NONE;
+ *rect = RectF(p0.x(), p0.y(), 0.0, 0.0);
+ return;
+ }
+ float size_x = sqrt(12.0 * mxx);
+ float size_y = sqrt(12.0 * myy);
+
+ // Estimate the parameters of the rotation since teta can only be known
+ // modulo 90 degrees. In previous equations, you can always swap w and h
+ // and subtract 90 degrees to teta to get the exact same second moment.
+ int idx_best = -1;
+ float err_best = 0.0;
+
+ // First, estimate the rotation angle assuming
+ // dist(p0,p1) is equal to |size_x|,
+ // dist(p0,p3) is equal to |size_y|.
+ gfx::PointF r1(size_x, 0);
+ gfx::PointF r2(size_x, size_y);
+ gfx::PointF r3(0, size_y);
+ for (int k = 0; k < 4; k++) {
+ float cur_err =
+ fabs((p1.x() - p0.x()) - r1.x()) + fabs((p1.y() - p0.y()) - r1.y()) +
+ fabs((p2.x() - p0.x()) - r2.x()) + fabs((p2.y() - p0.y()) - r2.y()) +
+ fabs((p3.x() - p0.x()) - r3.x()) + fabs((p3.y() - p0.y()) - r3.y());
+ if (idx_best < 0 || cur_err < err_best) {
+ idx_best = k;
+ err_best = cur_err;
+ }
+ // 90 degree rotation.
+ r1 = gfx::PointF(-r1.y(), r1.x());
+ r2 = gfx::PointF(-r2.y(), r2.x());
+ r3 = gfx::PointF(-r3.y(), r3.x());
+ }
+
+ // Then, estimate the rotation angle assuming:
+ // dist(p0,p1) is equal to |size_y|,
+ // dist(p0,p3) is equal to |size_x|.
+ r1 = gfx::PointF(size_y, 0);
+ r2 = gfx::PointF(size_y, size_x);
+ r3 = gfx::PointF(0, size_x);
+ for (int k = 0; k < 4; k++) {
+ float cur_err =
+ fabs((p1.x() - p0.x()) - r1.x()) + fabs((p1.y() - p0.y()) - r1.y()) +
+ fabs((p2.x() - p0.x()) - r2.x()) + fabs((p2.y() - p0.y()) - r2.y()) +
+ fabs((p3.x() - p0.x()) - r3.x()) + fabs((p3.y() - p0.y()) - r3.y());
+ if (idx_best < 0 || cur_err < err_best) {
+ idx_best = k;
+ err_best = cur_err;
+ }
+ // 90 degree rotation.
+ r1 = gfx::PointF(-r1.y(), r1.x());
+ r2 = gfx::PointF(-r2.y(), r2.x());
+ r3 = gfx::PointF(-r3.y(), r3.x());
+ }
+
+ *transform = static_cast<VideoPlane::Transform>(idx_best);
+ *rect = RectF(cx - size_x / 2.0, cy - size_y / 2.0, size_x, size_y);
+}
+
void UpdateVideoSurfaceHost(int surface_id, const gfx::QuadF& quad) {
// Currently supports only one video plane.
CHECK_EQ(surface_id, 0);
- VideoPlane* video_plane = GetVideoPlane();
+ // Convert quad into rect + transform
+ VideoPlane::Transform transform = VideoPlane::TRANSFORM_NONE;
+ RectF rect(0, 0, 0, 0);
+ EstimateVideoPlaneRect(quad, &transform, &rect);
+
+ VideoPlane* video_plane = CastMediaShlib::GetVideoPlane();
video_plane->SetGeometry(
- quad,
- VideoPlane::COORDINATE_TYPE_GRAPHICS_PLANE);
+ rect,
+ VideoPlane::COORDINATE_TYPE_GRAPHICS_PLANE,
+ transform);
}
} // namespace
-CmaMessageFilterHost::CmaMessageFilterHost(int render_process_id)
+CmaMessageFilterHost::CmaMessageFilterHost(
+ int render_process_id,
+ const media::CreatePipelineDeviceCB& create_pipeline_device_cb)
: content::BrowserMessageFilter(CastMediaMsgStart),
process_id_(render_process_id),
- task_runner_(CmaMessageLoop::GetMessageLoopProxy()),
+ create_pipeline_device_cb_(create_pipeline_device_cb),
+ task_runner_(MediaMessageLoop::GetTaskRunner()),
weak_factory_(this) {
weak_this_ = weak_factory_.GetWeakPtr();
}
@@ -222,10 +385,9 @@ void CmaMessageFilterHost::CreateMedia(int media_id, LoadType load_type) {
base::Bind(&SetMediaPipeline,
process_id_, media_id, media_pipeline_host.get()));
task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&MediaPipelineHost::Initialize,
- base::Unretained(media_pipeline_host.get()),
- load_type, client));
+ FROM_HERE, base::Bind(&MediaPipelineHost::Initialize,
+ base::Unretained(media_pipeline_host.get()),
+ load_type, client, create_pipeline_device_cb_));
std::pair<MediaPipelineMap::iterator, bool> ret =
media_pipelines_.insert(
std::make_pair(media_id, media_pipeline_host.release()));
@@ -374,7 +536,8 @@ void CmaMessageFilterHost::AudioInitialize(
}
void CmaMessageFilterHost::VideoInitialize(
- int media_id, TrackId track_id, const ::media::VideoDecoderConfig& config) {
+ int media_id, TrackId track_id,
+ const std::vector<::media::VideoDecoderConfig>& configs) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
MediaPipelineHost* media_pipeline = LookupById(media_id);
if (!media_pipeline) {
@@ -404,7 +567,7 @@ void CmaMessageFilterHost::VideoInitialize(
FROM_HERE,
base::Bind(&MediaPipelineHost::VideoInitialize,
base::Unretained(media_pipeline),
- track_id, client, config, pipeline_status_cb));
+ track_id, client, configs, pipeline_status_cb));
}
void CmaMessageFilterHost::StartPlayingFrom(
diff --git a/chromium/chromecast/browser/media/cma_message_filter_host.h b/chromium/chromecast/browser/media/cma_message_filter_host.h
index e00057466f5..9b1620516ff 100644
--- a/chromium/chromecast/browser/media/cma_message_filter_host.h
+++ b/chromium/chromecast/browser/media/cma_message_filter_host.h
@@ -12,6 +12,7 @@
#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
#include "chromecast/common/media/cma_ipc_common.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
#include "chromecast/media/cma/pipeline/load_type.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
@@ -42,7 +43,9 @@ class MediaPipelineHost;
class CmaMessageFilterHost
: public content::BrowserMessageFilter {
public:
- explicit CmaMessageFilterHost(int render_process_id);
+ CmaMessageFilterHost(
+ int render_process_id,
+ const media::CreatePipelineDeviceCB& create_pipeline_device_cb);
// content::BrowserMessageFilter implementation.
void OnChannelClosing() override;
@@ -71,9 +74,10 @@ class CmaMessageFilterHost
void AudioInitialize(int media_id,
TrackId track_id,
const ::media::AudioDecoderConfig& config);
- void VideoInitialize(int media_id,
- TrackId track_id,
- const ::media::VideoDecoderConfig& config);
+ void VideoInitialize(
+ int media_id,
+ TrackId track_id,
+ const std::vector<::media::VideoDecoderConfig>& configs);
void StartPlayingFrom(int media_id, base::TimeDelta time);
void Flush(int media_id);
void Stop(int media_id);
@@ -109,6 +113,9 @@ class CmaMessageFilterHost
// Render process ID correponding to this message filter.
const int process_id_;
+ // Factory function for device-specific part of media pipeline creation
+ media::CreatePipelineDeviceCB create_pipeline_device_cb_;
+
// List of media pipeline and message loop media pipelines are running on.
MediaPipelineMap media_pipelines_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
@@ -123,4 +130,3 @@ class CmaMessageFilterHost
} // namespace chromecast
#endif // CHROMECAST_BROWSER_MEDIA_CMA_MESSAGE_FILTER_HOST_H_
-
diff --git a/chromium/chromecast/browser/media/cma_message_loop.h b/chromium/chromecast/browser/media/cma_message_loop.h
deleted file mode 100644
index 5ce2cd40c83..00000000000
--- a/chromium/chromecast/browser/media/cma_message_loop.h
+++ /dev/null
@@ -1,44 +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.
-
-#ifndef CHROMECAST_BROWSER_MEDIA_CMA_MESSAGE_LOOP_H_
-#define CHROMECAST_BROWSER_MEDIA_CMA_MESSAGE_LOOP_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-
-namespace base {
-class MessageLoopProxy;
-class SingleThreadTaskRunner;
-class Thread;
-}
-
-namespace chromecast {
-namespace media {
-
-class CmaMessageLoop {
- public:
- // TODO(gunsch): clean up references to deprecated Message*Loop*Proxy.
- static scoped_refptr<base::MessageLoopProxy> GetMessageLoopProxy();
- static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner();
-
- private:
- friend struct DefaultSingletonTraits<CmaMessageLoop>;
- friend class Singleton<CmaMessageLoop>;
-
- static CmaMessageLoop* GetInstance();
-
- CmaMessageLoop();
- ~CmaMessageLoop();
-
- scoped_ptr<base::Thread> thread_;
-
- DISALLOW_COPY_AND_ASSIGN(CmaMessageLoop);
-};
-
-} // namespace media
-} // namespace chromecast
-
-#endif // CHROMECAST_BROWSER_MEDIA_CMA_MESSAGE_LOOP_H_
diff --git a/chromium/chromecast/browser/media/media_pipeline_host.cc b/chromium/chromecast/browser/media/media_pipeline_host.cc
index ff3eb6926f9..087077d044b 100644
--- a/chromium/chromecast/browser/media/media_pipeline_host.cc
+++ b/chromium/chromecast/browser/media/media_pipeline_host.cc
@@ -52,15 +52,15 @@ MediaPipelineHost::~MediaPipelineHost() {
void MediaPipelineHost::Initialize(
LoadType load_type,
- const MediaPipelineClient& client) {
+ const MediaPipelineClient& client,
+ const media::CreatePipelineDeviceCB& create_pipeline_device_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
media_pipeline_.reset(new MediaPipelineImpl());
MediaPipelineDeviceParams default_parameters;
if (load_type == kLoadTypeMediaStream)
default_parameters.sync_type = MediaPipelineDeviceParams::kModeIgnorePts;
media_pipeline_->Initialize(
- load_type,
- CreateMediaPipelineDevice(default_parameters).Pass());
+ load_type, create_pipeline_device_cb.Run(default_parameters).Pass());
media_pipeline_->SetClient(client);
}
@@ -118,13 +118,13 @@ void MediaPipelineHost::AudioInitialize(
void MediaPipelineHost::VideoInitialize(
TrackId track_id,
const VideoPipelineClient& client,
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
const ::media::PipelineStatusCB& status_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(track_id == kVideoTrackId);
media_pipeline_->GetVideoPipeline()->SetClient(client);
media_pipeline_->InitializeVideo(
- config, scoped_ptr<CodedFrameProvider>(), status_cb);
+ configs, scoped_ptr<CodedFrameProvider>(), status_cb);
}
void MediaPipelineHost::StartPlayingFrom(base::TimeDelta time) {
@@ -171,4 +171,3 @@ void MediaPipelineHost::NotifyPipeWrite(TrackId track_id) {
} // namespace media
} // namespace chromecast
-
diff --git a/chromium/chromecast/browser/media/media_pipeline_host.h b/chromium/chromecast/browser/media/media_pipeline_host.h
index dc15db94240..d53ba3f9c69 100644
--- a/chromium/chromecast/browser/media/media_pipeline_host.h
+++ b/chromium/chromecast/browser/media/media_pipeline_host.h
@@ -14,6 +14,7 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "chromecast/common/media/cma_ipc_common.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
#include "chromecast/media/cma/pipeline/load_type.h"
#include "media/base/pipeline_status.h"
@@ -40,8 +41,10 @@ class MediaPipelineHost {
MediaPipelineHost();
~MediaPipelineHost();
- void Initialize(LoadType load_type,
- const MediaPipelineClient& client);
+ void Initialize(
+ LoadType load_type,
+ const MediaPipelineClient& client,
+ const media::CreatePipelineDeviceCB& create_pipeline_device_cb);
void SetAvPipe(TrackId track_id,
scoped_ptr<base::SharedMemory> shared_mem,
@@ -53,7 +56,7 @@ class MediaPipelineHost {
const ::media::PipelineStatusCB& status_cb);
void VideoInitialize(TrackId track_id,
const VideoPipelineClient& client,
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
const ::media::PipelineStatusCB& status_cb);
void StartPlayingFrom(base::TimeDelta time);
void Flush(const ::media::PipelineStatusCB& status_cb);
@@ -83,4 +86,3 @@ class MediaPipelineHost {
} // namespace chromecast
#endif // CHROMECAST_BROWSER_MEDIA_MEDIA_PIPELINE_HOST_H_
-
diff --git a/chromium/chromecast/browser/metrics/BUILD.gn b/chromium/chromecast/browser/metrics/BUILD.gn
new file mode 100644
index 00000000000..a07fbdfc5ee
--- /dev/null
+++ b/chromium/chromecast/browser/metrics/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2015 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.
+
+source_set("metrics") {
+ sources = [
+ "cast_metrics_prefs.cc",
+ "cast_metrics_prefs.h",
+ "cast_metrics_service_client.cc",
+ "cast_metrics_service_client.h",
+ "cast_stability_metrics_provider.cc",
+ "cast_stability_metrics_provider.h",
+ "platform_metrics_providers.h",
+ ]
+
+ deps = [
+ "//base",
+ "//base:i18n",
+ "//base:prefs",
+ "//chromecast/base",
+ "//chromecast/common",
+ "//components/metrics",
+ "//components/metrics:gpu",
+ "//components/metrics:net",
+ "//components/metrics:profiler",
+ "//content/public/common",
+ "//content/public/browser",
+ ]
+
+ if (is_linux) {
+ sources += [
+ "external_metrics.cc",
+ "external_metrics.h",
+ ]
+
+ deps += [ "//components/metrics:serialization" ]
+ }
+
+ # TODO(kmackay) add source "platform_metrics_providers_simple.cc"
+ # according to condition (chromecast_branding != "Chrome")
+}
diff --git a/chromium/chromecast/browser/metrics/cast_metrics_prefs.cc b/chromium/chromecast/browser/metrics/cast_metrics_prefs.cc
index b53ed807243..2755ccaca42 100644
--- a/chromium/chromecast/browser/metrics/cast_metrics_prefs.cc
+++ b/chromium/chromecast/browser/metrics/cast_metrics_prefs.cc
@@ -4,6 +4,7 @@
#include "chromecast/browser/metrics/cast_metrics_prefs.h"
+#include "chromecast/browser/metrics/cast_metrics_service_client.h"
#include "chromecast/browser/metrics/cast_stability_metrics_provider.h"
#include "components/metrics/metrics_service.h"
@@ -12,6 +13,7 @@ namespace metrics {
void RegisterPrefs(PrefRegistrySimple* registry) {
::metrics::MetricsService::RegisterPrefs(registry);
+ CastMetricsServiceClient::RegisterPrefs(registry);
CastStabilityMetricsProvider::RegisterPrefs(registry);
}
diff --git a/chromium/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromium/chromecast/browser/metrics/cast_metrics_service_client.cc
index a367322da4e..daa5216c64b 100644
--- a/chromium/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromium/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -7,14 +7,15 @@
#include "base/command_line.h"
#include "base/guid.h"
#include "base/i18n/rtl.h"
+#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
+#include "base/thread_task_runner_handle.h"
+#include "chromecast/base/chromecast_switches.h"
#include "chromecast/browser/metrics/cast_stability_metrics_provider.h"
#include "chromecast/browser/metrics/platform_metrics_providers.h"
-#include "chromecast/common/chromecast_switches.h"
#include "chromecast/common/pref_names.h"
#include "components/metrics/client_info.h"
#include "components/metrics/gpu/gpu_metrics_provider.h"
-#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_state_manager.h"
@@ -32,7 +33,11 @@ namespace chromecast {
namespace metrics {
namespace {
+
const int kStandardUploadIntervalMinutes = 5;
+
+const char kMetricsOldClientID[] = "user_experience_metrics.client_id";
+
} // namespace
// static
@@ -45,6 +50,10 @@ scoped_ptr<CastMetricsServiceClient> CastMetricsServiceClient::Create(
request_context));
}
+void CastMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterStringPref(kMetricsOldClientID, std::string());
+}
+
void CastMetricsServiceClient::SetMetricsClientId(
const std::string& client_id) {
client_id_ = client_id;
@@ -71,8 +80,7 @@ scoped_ptr< ::metrics::ClientInfo> CastMetricsServiceClient::LoadClientInfo() {
if (!pref_service_->GetBoolean(prefs::kMetricsIsNewClientID)) {
// If the old client id exists, the device must be on pre-v1.2 build,
// instead of just being FDR'ed.
- if (!pref_service_->GetString(::metrics::prefs::kMetricsOldClientID)
- .empty()) {
+ if (!pref_service_->GetString(kMetricsOldClientID).empty()) {
// Force old client id to be regenerated. See b/9487011.
client_info->client_id = base::GenerateGUID();
pref_service_->SetBoolean(prefs::kMetricsIsNewClientID, true);
@@ -162,12 +170,10 @@ base::TimeDelta CastMetricsServiceClient::GetStandardUploadInterval() {
}
void CastMetricsServiceClient::EnableMetricsService(bool enabled) {
- if (!metrics_service_loop_->BelongsToCurrentThread()) {
- metrics_service_loop_->PostTask(
- FROM_HERE,
- base::Bind(&CastMetricsServiceClient::EnableMetricsService,
- base::Unretained(this),
- enabled));
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&CastMetricsServiceClient::EnableMetricsService,
+ base::Unretained(this), enabled));
return;
}
@@ -188,7 +194,7 @@ CastMetricsServiceClient::CastMetricsServiceClient(
#if !defined(OS_ANDROID)
external_metrics_(NULL),
#endif // !defined(OS_ANDROID)
- metrics_service_loop_(base::MessageLoopProxy::current()),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()),
request_context_(request_context) {
}
diff --git a/chromium/chromecast/browser/metrics/cast_metrics_service_client.h b/chromium/chromecast/browser/metrics/cast_metrics_service_client.h
index abc2b57311c..ec021a2bf6c 100644
--- a/chromium/chromecast/browser/metrics/cast_metrics_service_client.h
+++ b/chromium/chromecast/browser/metrics/cast_metrics_service_client.h
@@ -12,10 +12,11 @@
#include "base/memory/scoped_ptr.h"
#include "components/metrics/metrics_service_client.h"
+class PrefRegistrySimple;
class PrefService;
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
class TaskRunner;
}
@@ -45,6 +46,7 @@ class CastMetricsServiceClient : public ::metrics::MetricsServiceClient {
base::TaskRunner* io_task_runner,
PrefService* pref_service,
net::URLRequestContextGetter* request_context);
+ static void RegisterPrefs(PrefRegistrySimple* registry);
void Initialize(CastService* cast_service);
void Finalize();
@@ -92,7 +94,7 @@ class CastMetricsServiceClient : public ::metrics::MetricsServiceClient {
#if defined(OS_LINUX)
ExternalMetrics* external_metrics_;
#endif // defined(OS_LINUX)
- const scoped_refptr<base::MessageLoopProxy> metrics_service_loop_;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
scoped_ptr< ::metrics::MetricsStateManager> metrics_state_manager_;
scoped_ptr< ::metrics::MetricsService> metrics_service_;
net::URLRequestContextGetter* const request_context_;
diff --git a/chromium/chromecast/browser/pref_service_helper.cc b/chromium/chromecast/browser/pref_service_helper.cc
index 3f6f5c607c3..36ab18dcbcf 100644
--- a/chromium/chromecast/browser/pref_service_helper.cc
+++ b/chromium/chromecast/browser/pref_service_helper.cc
@@ -43,8 +43,8 @@ scoped_ptr<PrefService> PrefServiceHelper::CreatePrefService(
const base::FilePath config_path(GetConfigPath());
VLOG(1) << "Loading config from " << config_path.value();
+ registry->RegisterBooleanPref(prefs::kEnableRemoteDebugging, false);
registry->RegisterBooleanPref(prefs::kMetricsIsNewClientID, false);
- registry->RegisterIntegerPref(prefs::kRemoteDebuggingPort, 0);
RegisterPlatformPrefs(registry);
diff --git a/chromium/chromecast/browser/service/cast_service_android.cc b/chromium/chromecast/browser/service/cast_service_android.cc
index 8822c83e7b8..507716c380f 100644
--- a/chromium/chromecast/browser/service/cast_service_android.cc
+++ b/chromium/chromecast/browser/service/cast_service_android.cc
@@ -5,7 +5,7 @@
#include "chromecast/browser/service/cast_service_android.h"
#include "base/bind.h"
-#include "chromecast/android/chromecast_config_android.h"
+#include "chromecast/base/chromecast_config_android.h"
#include "chromecast/browser/metrics/cast_metrics_service_client.h"
namespace chromecast {
diff --git a/chromium/chromecast/browser/url_request_context_factory.cc b/chromium/chromecast/browser/url_request_context_factory.cc
index 9143071fb8e..693a220f3bc 100644
--- a/chromium/chromecast/browser/url_request_context_factory.cc
+++ b/chromium/chromecast/browser/url_request_context_factory.cc
@@ -8,9 +8,9 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/threading/worker_pool.h"
+#include "chromecast/base/chromecast_switches.h"
#include "chromecast/browser/cast_http_user_agent_settings.h"
#include "chromecast/browser/cast_network_delegate.h"
-#include "chromecast/common/chromecast_switches.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
@@ -143,7 +143,7 @@ URLRequestContextFactory::URLRequestContextFactory()
URLRequestContextFactory::~URLRequestContextFactory() {
}
-void URLRequestContextFactory::InitializeOnUIThread() {
+void URLRequestContextFactory::InitializeOnUIThread(net::NetLog* net_log) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Cast http user agent settings must be initialized in UI thread
// because it registers itself to pref notification observer which is not
@@ -157,6 +157,8 @@ void URLRequestContextFactory::InitializeOnUIThread() {
content::BrowserThread::IO),
content::BrowserThread::GetMessageLoopProxyForThread(
content::BrowserThread::FILE)));
+
+ net_log_ = net_log;
}
net::URLRequestContextGetter* URLRequestContextFactory::CreateMainGetter(
@@ -328,6 +330,7 @@ net::URLRequestContext* URLRequestContextFactory::CreateSystemRequestContext() {
system_context->set_cookie_store(
content::CreateCookieStore(content::CookieStoreConfig()));
system_context->set_network_delegate(system_network_delegate_.get());
+ system_context->set_net_log(net_log_);
return system_context;
}
@@ -347,6 +350,7 @@ net::URLRequestContext* URLRequestContextFactory::CreateMediaRequestContext() {
media_context->CopyFrom(main_context);
media_context->set_http_transaction_factory(
media_transaction_factory_.get());
+ media_context->set_net_log(net_log_);
return media_context;
}
@@ -399,6 +403,7 @@ net::URLRequestContext* URLRequestContextFactory::CreateMainRequestContext(
main_transaction_factory_.get());
main_context->set_job_factory(main_job_factory_.get());
main_context->set_network_delegate(app_network_delegate_.get());
+ main_context->set_net_log(net_log_);
return main_context;
}
diff --git a/chromium/chromecast/browser/url_request_context_factory.h b/chromium/chromecast/browser/url_request_context_factory.h
index 5ae43cb7a4a..c0d881d83f9 100644
--- a/chromium/chromecast/browser/url_request_context_factory.h
+++ b/chromium/chromecast/browser/url_request_context_factory.h
@@ -11,6 +11,7 @@
namespace net {
class HttpTransactionFactory;
class HttpUserAgentSettings;
+class NetLog;
class ProxyConfigService;
class URLRequestJobFactory;
} // namespace net
@@ -25,7 +26,7 @@ class URLRequestContextFactory {
~URLRequestContextFactory();
// Some members must be initialized on UI thread.
- void InitializeOnUIThread();
+ void InitializeOnUIThread(net::NetLog* net_log);
// Since main context requires a bunch of input params, if these get called
// multiple times, either multiple main contexts should be supported/managed
@@ -113,6 +114,8 @@ class URLRequestContextFactory {
bool media_dependencies_initialized_;
scoped_ptr<net::HttpTransactionFactory> media_transaction_factory_;
+
+ net::NetLog* net_log_;
};
} // namespace shell
diff --git a/chromium/chromecast/chromecast.gyp b/chromium/chromecast/chromecast.gyp
index ed8261946da..15372f4dbe6 100644
--- a/chromium/chromecast/chromecast.gyp
+++ b/chromium/chromecast/chromecast.gyp
@@ -44,15 +44,13 @@
'public/graphics_properties_shlib.h',
'public/graphics_types.h',
'public/media/decoder_config.h',
+ 'public/media/stream_id.h',
'public/osd_plane.h',
'public/osd_plane_shlib.h',
'public/osd_surface.h',
+ 'public/video_plane.h',
],
},
- # TODO(gunsch): Remove this fake target once it's either added or no
- # longer referenced from internal code.
- {'target_name': 'cast_media_audio', 'type': 'none'},
-
{
'target_name': 'cast_base',
'type': '<(component)',
@@ -62,39 +60,72 @@
'sources': [
'base/cast_paths.cc',
'base/cast_paths.h',
+ 'base/chromecast_switches.cc',
+ 'base/chromecast_switches.h',
+ 'base/error_codes.cc',
+ 'base/error_codes.h',
'base/metrics/cast_histograms.h',
'base/metrics/cast_metrics_helper.cc',
'base/metrics/cast_metrics_helper.h',
'base/metrics/grouped_histogram.cc',
'base/metrics/grouped_histogram.h',
+ 'base/path_utils.cc',
+ 'base/path_utils.h',
+ 'base/process_utils.cc',
+ 'base/process_utils.h',
'base/serializers.cc',
'base/serializers.h'
],
}, # end of target 'cast_base'
{
- 'target_name': 'cast_crash_client',
+ 'target_name': 'cast_crash',
'type': '<(component)',
+ 'include_dirs': [
+ # TODO(gfhuang): we should not need to include this directly, but
+ # somehow depending on component.gyp:breakpad_component is not
+ # working as expected.
+ '../breakpad/src',
+ ],
'dependencies': [
+ 'cast_base',
+ 'cast_version_header',
'../breakpad/breakpad.gyp:breakpad_client',
- '../components/components.gyp:crash_component',
],
'sources': [
+ 'crash/app_state_tracker.cc',
+ 'crash/app_state_tracker.h',
'crash/cast_crash_keys.cc',
'crash/cast_crash_keys.h',
- 'crash/cast_crash_reporter_client.cc',
- 'crash/cast_crash_reporter_client.h',
+ 'crash/cast_crashdump_uploader.cc',
+ 'crash/cast_crashdump_uploader.h',
+ 'crash/linux/crash_util.cc',
+ 'crash/linux/crash_util.h',
+ 'crash/linux/dummy_minidump_generator.cc',
+ 'crash/linux/dummy_minidump_generator.h',
+ 'crash/linux/dump_info.cc',
+ 'crash/linux/dump_info.h',
+ 'crash/linux/minidump_generator.h',
+ 'crash/linux/synchronized_minidump_manager.cc',
+ 'crash/linux/synchronized_minidump_manager.h',
+ 'crash/linux/minidump_params.cc',
+ 'crash/linux/minidump_params.h',
+ 'crash/linux/minidump_writer.cc',
+ 'crash/linux/minidump_writer.h',
+ ],
+ }, # end of target 'cast_crash'
+ {
+ 'target_name': 'cast_crash_client',
+ 'type': '<(component)',
+ 'dependencies': [
+ 'cast_crash',
+ '../components/components.gyp:crash_component',
+ '../content/content.gyp:content_common',
+ ],
+ 'sources' : [
+ # TODO(slan): Move android crash_client here as well.
+ 'app/linux/cast_crash_reporter_client.cc',
+ 'app/linux/cast_crash_reporter_client.h',
],
- 'conditions': [
- ['chromecast_branding=="Chrome"', {
- 'dependencies': [
- 'internal/chromecast_internal.gyp:crash_internal',
- ],
- }, {
- 'sources': [
- 'crash/cast_crash_reporter_client_simple.cc',
- ],
- }],
- ]
}, # end of target 'cast_crash_client'
{
'target_name': 'cast_net',
@@ -102,6 +133,10 @@
'sources': [
'net/connectivity_checker.cc',
'net/connectivity_checker.h',
+ 'net/connectivity_checker_impl.cc',
+ 'net/connectivity_checker_impl.h',
+ 'net/fake_connectivity_checker.cc',
+ 'net/fake_connectivity_checker.h',
'net/net_switches.cc',
'net/net_switches.h',
'net/net_util_cast.cc',
@@ -238,6 +273,8 @@
'browser/cast_download_manager_delegate.h',
'browser/cast_http_user_agent_settings.cc',
'browser/cast_http_user_agent_settings.h',
+ 'browser/cast_net_log.cc',
+ 'browser/cast_net_log.h',
'browser/cast_network_delegate.cc',
'browser/cast_network_delegate.h',
'browser/cast_permission_manager.cc',
@@ -271,8 +308,6 @@
'common/cast_content_client.h',
'common/cast_resource_delegate.cc',
'common/cast_resource_delegate.h',
- 'common/chromecast_switches.cc',
- 'common/chromecast_switches.h',
'common/media/cast_messages.h',
'common/media/cast_message_generator.cc',
'common/media/cast_message_generator.h',
@@ -304,7 +339,6 @@
'browser/pref_service_helper_simple.cc',
'common/platform_client_auth_simple.cc',
'renderer/cast_content_renderer_client_simple.cc',
- 'renderer/key_systems_cast_simple.cc',
],
'conditions': [
['OS=="android"', {
@@ -328,6 +362,8 @@
'sources': [
'browser/metrics/external_metrics.cc',
'browser/metrics/external_metrics.h',
+ 'graphics/cast_screen.cc',
+ 'graphics/cast_screen.h',
],
'dependencies': [
'../components/components.gyp:metrics_serialization',
@@ -354,7 +390,7 @@
'base/cast_sys_info_dummy.h',
],
'conditions': [
- ['chromecast_branding!="Chrome"', {
+ ['chromecast_branding!="Chrome" and OS!="android"', {
'sources': [
'base/cast_sys_info_util_simple.cc',
],
@@ -375,10 +411,10 @@
'message': 'Generating version header file: <@(_outputs)',
'inputs': [
'<(version_path)',
- 'common/version.h.in',
+ 'base/version.h.in',
],
'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/chromecast/common/version.h',
+ '<(SHARED_INTERMEDIATE_DIR)/chromecast/base/version.h',
],
'action': [
'python',
@@ -392,7 +428,7 @@
'-e', 'CAST_BUILD_RELEASE="<!(if test -f <(cast_build_release); then cat <(cast_build_release); else echo eng.${USER}; fi)"',
'-e', 'CAST_IS_DEBUG_BUILD=1 if "<(CONFIGURATION_NAME)" == "Debug" or <(cast_is_debug_build) == 1 else 0',
'-e', 'CAST_PRODUCT_TYPE=<(cast_product_type)',
- 'common/version.h.in',
+ 'base/version.h.in',
'<@(_outputs)',
],
'includes': [
@@ -448,18 +484,22 @@
'sources': [
'android/cast_jni_registrar.cc',
'android/cast_jni_registrar.h',
- 'android/chromecast_config_android.cc',
- 'android/chromecast_config_android.h',
+ 'android/cast_metrics_helper_android.cc',
+ 'android/cast_metrics_helper_android.h',
'android/platform_jni_loader.h',
+ 'app/android/cast_crash_reporter_client_android.cc',
+ 'app/android/cast_crash_reporter_client_android.h',
'app/android/cast_jni_loader.cc',
+ 'app/android/crash_handler.cc',
+ 'app/android/crash_handler.h',
+ 'base/cast_sys_info_android.cc',
+ 'base/cast_sys_info_android.h',
+ 'base/chromecast_config_android.cc',
+ 'base/chromecast_config_android.h',
'browser/android/cast_window_android.cc',
'browser/android/cast_window_android.h',
'browser/android/cast_window_manager.cc',
'browser/android/cast_window_manager.h',
- 'crash/android/cast_crash_reporter_client_android.cc',
- 'crash/android/cast_crash_reporter_client_android.h',
- 'crash/android/crash_handler.cc',
- 'crash/android/crash_handler.h',
],
'conditions': [
['chromecast_branding=="Chrome"', {
@@ -468,24 +508,39 @@
],
}, {
'sources': [
- 'android/chromecast_config_android_stub.cc',
'android/platform_jni_loader_stub.cc',
],
}]
],
}, # end of target 'libcast_shell_android'
{
+ 'target_name': 'cast_base_java',
+ 'type': 'none',
+ 'dependencies': [
+ '../base/base.gyp:base_java',
+ ],
+ 'variables': {
+ 'android_manifest_path': 'android/AndroidManifest.xml',
+ 'java_in_dir': 'base/java',
+ },
+ 'includes': ['../build/java.gypi'],
+ }, # end of target 'cast_base_java'
+ {
'target_name': 'cast_shell_java',
'type': 'none',
'dependencies': [
'<(android_support_v13_target)',
+ 'cast_base_java',
+ 'cast_shell_manifest',
'../base/base.gyp:base_java',
+ '../components/components.gyp:external_video_surface_java',
'../content/content.gyp:content_java',
'../media/media.gyp:media_java',
'../net/net.gyp:net_java',
'../ui/android/ui_android.gyp:ui_java',
],
'variables': {
+ 'android_manifest_path': '<(SHARED_INTERMEDIATE_DIR)/cast_shell_manifest/AndroidManifest.xml',
'has_java_resources': 1,
'java_in_dir': 'browser/android/apk',
'resource_dir': 'browser/android/apk/res',
@@ -531,7 +586,10 @@
'target_name': 'cast_jni_headers',
'type': 'none',
'sources': [
+ 'base/java/src/org/chromium/chromecast/base/ChromecastConfigAndroid.java',
'browser/android/apk/src/org/chromium/chromecast/shell/CastCrashHandler.java',
+ 'browser/android/apk/src/org/chromium/chromecast/shell/CastMetricsHelper.java',
+ 'browser/android/apk/src/org/chromium/chromecast/shell/CastSysInfoAndroid.java',
'browser/android/apk/src/org/chromium/chromecast/shell/CastWindowAndroid.java',
'browser/android/apk/src/org/chromium/chromecast/shell/CastWindowManager.java',
],
@@ -562,8 +620,6 @@
'browser/media/cast_browser_cdm_factory.h',
'browser/media/cma_message_filter_host.cc',
'browser/media/cma_message_filter_host.h',
- 'browser/media/cma_message_loop.cc',
- 'browser/media/cma_message_loop.h',
'browser/media/media_pipeline_host.cc',
'browser/media/media_pipeline_host.h',
'common/media/cma_ipc_common.h',
diff --git a/chromium/chromecast/chromecast_tests.gypi b/chromium/chromecast/chromecast_tests.gypi
index a5a7204fcc4..2c6317ba6ee 100644
--- a/chromium/chromecast/chromecast_tests.gypi
+++ b/chromium/chromecast/chromecast_tests.gypi
@@ -16,9 +16,32 @@
'../testing/gtest.gyp:gtest',
],
'sources': [
+ 'base/error_codes_unittest.cc',
+ 'base/path_utils_unittest.cc',
+ 'base/process_utils_unittest.cc',
'base/serializers_unittest.cc',
],
- },
+ }, # end of cast_base_unittests
+ {
+ 'target_name': 'cast_crash_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ 'chromecast.gyp:cast_crash',
+ '../base/base.gyp:run_all_unittests',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '../breakpad/src',
+ ],
+ 'sources': [
+ 'crash/cast_crashdump_uploader_unittest.cc',
+ 'crash/linux/dummy_minidump_generator_unittest.cc',
+ 'crash/linux/dump_info_unittest.cc',
+ 'crash/linux/synchronized_minidump_manager_unittest.cc',
+ 'crash/linux/minidump_writer_unittest.cc',
+ ],
+ }, # end of cast_crash_unittests
{
'target_name': 'cast_tests',
'type': 'none',
@@ -39,6 +62,7 @@
'type': 'none',
'dependencies': [
'cast_base_unittests',
+ 'cast_crash_unittests',
'../base/base.gyp:base_unittests',
'../content/content_shell_and_tests.gyp:content_unittests',
'../crypto/crypto.gyp:crypto_unittests',
@@ -111,8 +135,8 @@
}],
['OS!="android"', {
'dependencies': [
+ 'cast_shell_unittests',
'cast_shell_browser_test',
- 'cast_shell_media_unittests',
'media/media.gyp:cast_media_unittests',
],
'variables': {
@@ -121,6 +145,19 @@
],
},
}],
+ ['disable_display==1', {
+ 'variables': {
+ 'filters': [
+ # These are not supported by the backend right now. b/21737919
+ 'cast_media_unittests --gtest_filter=-AudioVideoPipelineDeviceTest.VorbisPlayback:AudioVideoPipelineDeviceTest.WebmPlayback',
+ ],
+ }
+ }],
+ ['enable_plugins==1', {
+ 'dependencies': [
+ '../ppapi/ppapi_internal.gyp:ppapi_unittests',
+ ],
+ }],
],
'includes': ['build/tests/test_list.gypi'],
},
@@ -229,26 +266,6 @@
}, { # OS!="android"
'targets': [
{
- 'target_name': 'cast_shell_media_unittests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- 'cast_metrics_test_support',
- 'cast_shell_media',
- 'media/media.gyp:cast_media',
- '../base/base.gyp:base',
- '../base/base.gyp:test_support_base',
- '../ipc/ipc.gyp:test_support_ipc',
- '../media/media.gyp:media_test_support',
- '../testing/gmock.gyp:gmock',
- '../testing/gtest.gyp:gtest',
- '../testing/gtest.gyp:gtest_main',
- ],
- 'sources': [
- 'renderer/media/cma_renderer_unittest.cc',
- 'media/cma/test/run_all_unittests.cc',
- ],
- },
- {
'target_name': 'cast_shell_test_support',
'type': '<(component)',
'defines': [
@@ -280,6 +297,18 @@
'browser/test/chromecast_shell_browser_test.cc',
],
},
+ {
+ 'target_name': 'cast_shell_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ 'chromecast.gyp:cast_crash_client',
+ '../base/base.gyp:run_all_unittests',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'sources': [
+ 'app/linux/cast_crash_reporter_client_unittest.cc',
+ ],
+ }, # end of cast_shell_unittests
], # end of targets
}],
], # end of conditions
diff --git a/chromium/chromecast/common/BUILD.gn b/chromium/chromecast/common/BUILD.gn
new file mode 100644
index 00000000000..127823b3c0b
--- /dev/null
+++ b/chromium/chromecast/common/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2015 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.
+
+source_set("common") {
+ sources = [
+ "cast_content_client.cc",
+ "cast_content_client.h",
+ "cast_resource_delegate.cc",
+ "cast_resource_delegate.h",
+ "global_descriptors.h",
+ "platform_client_auth.h",
+ "pref_names.cc",
+ "pref_names.h",
+ ]
+
+ # TODO(kmackay) Add "platform_client_auth._simple.cc" to sources
+ # if chromecast_branding != "Chrome"
+
+ deps = [
+ "//base",
+ "//chromecast/base:cast_version",
+ "//content/public/common",
+ "//ui/base",
+ "//ui/gfx",
+ ]
+}
diff --git a/chromium/chromecast/common/cast_content_client.cc b/chromium/chromecast/common/cast_content_client.cc
index 4772fdd5c06..ca3a2639a66 100644
--- a/chromium/chromecast/common/cast_content_client.cc
+++ b/chromium/chromecast/common/cast_content_client.cc
@@ -6,7 +6,7 @@
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
-#include "chromecast/common/version.h"
+#include "chromecast/base/version.h"
#include "content/public/common/user_agent.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
diff --git a/chromium/chromecast/common/media/cma_messages.h b/chromium/chromecast/common/media/cma_messages.h
index 3fbed3dbad7..1edb9827794 100644
--- a/chromium/chromecast/common/media/cma_messages.h
+++ b/chromium/chromecast/common/media/cma_messages.h
@@ -50,11 +50,12 @@ IPC_MESSAGE_CONTROL3(CmaHostMsg_CreateAvPipe,
IPC_MESSAGE_CONTROL3(CmaHostMsg_AudioInitialize,
int /* Media pipeline ID */,
chromecast::media::TrackId /* Track ID */,
- media::AudioDecoderConfig /* Audio config */)
+ ::media::AudioDecoderConfig /* Audio config */)
IPC_MESSAGE_CONTROL3(CmaHostMsg_VideoInitialize,
int /* Media pipeline ID */,
chromecast::media::TrackId /* Track ID */,
- media::VideoDecoderConfig /* Video config */)
+ /* Video Config */
+ std::vector<::media::VideoDecoderConfig>)
IPC_MESSAGE_CONTROL3(CmaHostMsg_SetVolume,
int /* Media pipeline ID */,
chromecast::media::TrackId /* Track ID */,
@@ -112,4 +113,4 @@ IPC_MESSAGE_CONTROL3(CmaMsg_PlaybackStatistics,
IPC_MESSAGE_CONTROL3(CmaMsg_NaturalSizeChanged,
int /* Media pipeline ID */,
chromecast::media::TrackId /* Track ID */,
- gfx::Size /* Size */) \ No newline at end of file
+ gfx::Size /* Size */)
diff --git a/chromium/chromecast/common/media/cma_param_traits.cc b/chromium/chromecast/common/media/cma_param_traits.cc
index 33accb04672..8849be19f42 100644
--- a/chromium/chromecast/common/media/cma_param_traits.cc
+++ b/chromium/chromecast/common/media/cma_param_traits.cc
@@ -30,40 +30,37 @@ namespace IPC {
void ParamTraits<media::AudioDecoderConfig>::Write(
Message* m, const media::AudioDecoderConfig& p) {
- ParamTraits<media::AudioCodec>::Write(m, p.codec());
- ParamTraits<media::SampleFormat>::Write(m, p.sample_format());
- ParamTraits<media::ChannelLayout>::Write(m, p.channel_layout());
- ParamTraits<int>::Write(m, p.samples_per_second());
- ParamTraits<bool>::Write(m, p.is_encrypted());
+ WriteParam(m, p.codec());
+ WriteParam(m, p.sample_format());
+ WriteParam(m, p.channel_layout());
+ WriteParam(m, p.samples_per_second());
+ WriteParam(m, p.is_encrypted());
std::vector<uint8> extra_data;
if (p.extra_data_size() > 0) {
extra_data =
std::vector<uint8>(p.extra_data(),
p.extra_data() + p.extra_data_size());
}
- ParamTraits<std::vector<uint8> >::Write(m, extra_data);
+ WriteParam(m, extra_data);
}
bool ParamTraits<media::AudioDecoderConfig>::Read(
- const Message* m, PickleIterator* iter,
+ const Message* m,
+ base::PickleIterator* iter,
media::AudioDecoderConfig* r) {
media::AudioCodec codec;
media::SampleFormat sample_format;
media::ChannelLayout channel_layout;
int samples_per_second;
bool is_encrypted;
- if (!ParamTraits<media::AudioCodec>::Read(m, iter, &codec) ||
- !ParamTraits<media::SampleFormat>::Read(m, iter, &sample_format) ||
- !ParamTraits<media::ChannelLayout>::Read(m, iter, &channel_layout) ||
- !ParamTraits<int>::Read(m, iter, &samples_per_second) ||
- !ParamTraits<bool>::Read(m, iter, &is_encrypted)) {
- return false;
- }
std::vector<uint8> extra_data;
- if (!ParamTraits<std::vector<uint8> >::Read(m, iter, &extra_data))
+ if (!ReadParam(m, iter, &codec) || !ReadParam(m, iter, &sample_format) ||
+ !ReadParam(m, iter, &channel_layout) ||
+ !ReadParam(m, iter, &samples_per_second) ||
+ !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data))
return false;
- const uint8* extra_data_ptr = NULL;
- if (extra_data.size() > 0)
+ const uint8* extra_data_ptr = nullptr;
+ if (!extra_data.empty())
extra_data_ptr = &extra_data[0];
*r = media::AudioDecoderConfig(codec, sample_format, channel_layout,
samples_per_second,
@@ -79,24 +76,25 @@ void ParamTraits<media::AudioDecoderConfig>::Log(
void ParamTraits<media::VideoDecoderConfig>::Write(
Message* m, const media::VideoDecoderConfig& p) {
- ParamTraits<media::VideoCodec>::Write(m, p.codec());
- ParamTraits<media::VideoCodecProfile>::Write(m, p.profile());
- ParamTraits<media::VideoFrame::Format>::Write(m, p.format());
- ParamTraits<gfx::Size>::Write(m, p.coded_size());
- ParamTraits<gfx::Rect>::Write(m, p.visible_rect());
- ParamTraits<gfx::Size>::Write(m, p.natural_size());
- ParamTraits<bool>::Write(m, p.is_encrypted());
+ WriteParam(m, p.codec());
+ WriteParam(m, p.profile());
+ WriteParam(m, p.format());
+ WriteParam(m, p.coded_size());
+ WriteParam(m, p.visible_rect());
+ WriteParam(m, p.natural_size());
+ WriteParam(m, p.is_encrypted());
std::vector<uint8> extra_data;
if (p.extra_data_size() > 0) {
extra_data =
std::vector<uint8>(p.extra_data(),
p.extra_data() + p.extra_data_size());
}
- ParamTraits<std::vector<uint8> >::Write(m, extra_data);
+ WriteParam(m, extra_data);
}
bool ParamTraits<media::VideoDecoderConfig>::Read(
- const Message* m, PickleIterator* iter,
+ const Message* m,
+ base::PickleIterator* iter,
media::VideoDecoderConfig* r) {
media::VideoCodec codec;
media::VideoCodecProfile profile;
@@ -105,20 +103,15 @@ bool ParamTraits<media::VideoDecoderConfig>::Read(
gfx::Rect visible_rect;
gfx::Size natural_size;
bool is_encrypted;
- if (!ParamTraits<media::VideoCodec>::Read(m, iter, &codec) ||
- !ParamTraits<media::VideoCodecProfile>::Read(m, iter, &profile) ||
- !ParamTraits<media::VideoFrame::Format>::Read(m, iter, &format) ||
- !ParamTraits<gfx::Size>::Read(m, iter, &coded_size) ||
- !ParamTraits<gfx::Rect>::Read(m, iter, &visible_rect) ||
- !ParamTraits<gfx::Size>::Read(m, iter, &natural_size) ||
- !ParamTraits<bool>::Read(m, iter, &is_encrypted)) {
- return false;
- }
std::vector<uint8> extra_data;
- if (!ParamTraits<std::vector<uint8> >::Read(m, iter, &extra_data))
+ if (!ReadParam(m, iter, &codec) || !ReadParam(m, iter, &profile) ||
+ !ReadParam(m, iter, &format) || !ReadParam(m, iter, &coded_size) ||
+ !ReadParam(m, iter, &visible_rect) ||
+ !ReadParam(m, iter, &natural_size) ||
+ !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data))
return false;
- const uint8* extra_data_ptr = NULL;
- if (extra_data.size() > 0)
+ const uint8* extra_data_ptr = nullptr;
+ if (!extra_data.empty())
extra_data_ptr = &extra_data[0];
*r = media::VideoDecoderConfig(codec, profile, format,
coded_size, visible_rect, natural_size,
diff --git a/chromium/chromecast/common/media/cma_param_traits.h b/chromium/chromecast/common/media/cma_param_traits.h
index 0bebac35c2a..106012bed8b 100644
--- a/chromium/chromecast/common/media/cma_param_traits.h
+++ b/chromium/chromecast/common/media/cma_param_traits.h
@@ -18,7 +18,7 @@ template <>
struct ParamTraits<media::AudioDecoderConfig> {
typedef media::AudioDecoderConfig param_type;
static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static bool Read(const Message* m, base::PickleIterator* iter, param_type* r);
static void Log(const param_type& p, std::string* l);
};
@@ -26,7 +26,7 @@ template <>
struct ParamTraits<media::VideoDecoderConfig> {
typedef media::VideoDecoderConfig param_type;
static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static bool Read(const Message* m, base::PickleIterator* iter, param_type* r);
static void Log(const param_type& p, std::string* l);
};
diff --git a/chromium/chromecast/common/pref_names.cc b/chromium/chromecast/common/pref_names.cc
index 0b885f50080..7a03c26184d 100644
--- a/chromium/chromecast/common/pref_names.cc
+++ b/chromium/chromecast/common/pref_names.cc
@@ -6,14 +6,13 @@
namespace prefs {
+// Boolean which specifies if remote debugging is enabled
+const char kEnableRemoteDebugging[] = "enable_remote_debugging";
+
// Boolean that specifies whether or not the client_id has been regenerated
// due to bug b/9487011.
const char kMetricsIsNewClientID[] = "user_experience_metrics.is_new_client_id";
-// Port on which to host the remote debugging server. A value of 0 indicates
-// that remote debugging is disabled.
-const char kRemoteDebuggingPort[] = "remote_debugging_port";
-
// Total number of child process crashes (other than renderer / extension
// renderer ones, and plugin children, which are counted separately) since the
// last report.
diff --git a/chromium/chromecast/common/pref_names.h b/chromium/chromecast/common/pref_names.h
index 6caa2cc6eea..26820dc2475 100644
--- a/chromium/chromecast/common/pref_names.h
+++ b/chromium/chromecast/common/pref_names.h
@@ -7,8 +7,8 @@
namespace prefs {
+extern const char kEnableRemoteDebugging[];
extern const char kMetricsIsNewClientID[];
-extern const char kRemoteDebuggingPort[];
extern const char kStabilityChildProcessCrashCount[];
extern const char kStabilityKernelCrashCount[];
extern const char kStabilityOtherUserCrashCount[];
diff --git a/chromium/chromecast/crash/BUILD.gn b/chromium/chromecast/crash/BUILD.gn
new file mode 100644
index 00000000000..d085b353730
--- /dev/null
+++ b/chromium/chromecast/crash/BUILD.gn
@@ -0,0 +1,58 @@
+# Copyright 2015 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.
+
+import("//testing/test.gni")
+
+source_set("crash") {
+ sources = [
+ "app_state_tracker.cc",
+ "app_state_tracker.h",
+ "cast_crash_keys.cc",
+ "cast_crash_keys.h",
+ "cast_crashdump_uploader.cc",
+ "cast_crashdump_uploader.h",
+ "linux/crash_util.cc",
+ "linux/crash_util.h",
+ "linux/dummy_minidump_generator.cc",
+ "linux/dummy_minidump_generator.h",
+ "linux/dump_info.cc",
+ "linux/dump_info.h",
+ "linux/minidump_generator.h",
+ "linux/minidump_params.cc",
+ "linux/minidump_params.h",
+ "linux/minidump_writer.cc",
+ "linux/minidump_writer.h",
+ "linux/synchronized_minidump_manager.cc",
+ "linux/synchronized_minidump_manager.h",
+ ]
+
+ configs += [ "//chromecast:config" ]
+
+ deps = [
+ "//base",
+ "//breakpad:client",
+ "//chromecast/base",
+ "//chromecast/base:cast_version",
+ ]
+}
+
+test("cast_crash_unittests") {
+ sources = [
+ "cast_crashdump_uploader_unittest.cc",
+ "linux/dummy_minidump_generator_unittest.cc",
+ "linux/dump_info_unittest.cc",
+ "linux/minidump_writer_unittest.cc",
+ "linux/synchronized_minidump_manager_unittest.cc",
+ ]
+
+ deps = [
+ ":crash",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//breakpad:client",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/chromecast/crash/DEPS b/chromium/chromecast/crash/DEPS
index 4389c51b6d2..9ebc4972913 100644
--- a/chromium/chromecast/crash/DEPS
+++ b/chromium/chromecast/crash/DEPS
@@ -1,4 +1,3 @@
include_rules = [
"+breakpad",
- "+components/crash",
]
diff --git a/chromium/chromecast/crash/android/DEPS b/chromium/chromecast/crash/android/DEPS
deleted file mode 100644
index 2443d792c84..00000000000
--- a/chromium/chromecast/crash/android/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+chromecast/android",
- "+chromecast/common",
-]
diff --git a/chromium/chromecast/crash/android/crash_handler.cc b/chromium/chromecast/crash/android/crash_handler.cc
deleted file mode 100644
index 1c42dfa931a..00000000000
--- a/chromium/chromecast/crash/android/crash_handler.cc
+++ /dev/null
@@ -1,143 +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/crash/android/crash_handler.h"
-
-#include <jni.h>
-#include <stdlib.h>
-#include <string>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "breakpad/src/client/linux/handler/exception_handler.h"
-#include "breakpad/src/client/linux/handler/minidump_descriptor.h"
-#include "chromecast/common/version.h"
-#include "chromecast/crash/android/cast_crash_reporter_client_android.h"
-#include "components/crash/app/breakpad_linux.h"
-#include "components/crash/app/crash_reporter_client.h"
-#include "content/public/common/content_switches.h"
-#include "jni/CastCrashHandler_jni.h"
-
-namespace {
-
-chromecast::CrashHandler* g_crash_handler = NULL;
-
-bool HandleCrash(void* /* crash_context */) {
- DCHECK(g_crash_handler);
- g_crash_handler->UploadCrashDumps();
-
- // TODO(gunsch): clean up the ATV crash handling code.
- // Don't write another minidump. Chrome's default ExceptionHandler has already
- // written a minidump by this point in the crash handling sequence.
- return false;
-}
-
-// Debug builds: always to crash-staging
-// Release builds: only to crash-staging for local/invalid build numbers
-bool UploadCrashToStaging() {
-#if CAST_IS_DEBUG_BUILD()
- return true;
-#else
- int build_number;
- if (base::StringToInt(CAST_BUILD_INCREMENTAL, &build_number))
- return build_number == 0;
- return true;
-#endif
-}
-
-} // namespace
-
-namespace chromecast {
-
-// static
-void CrashHandler::Initialize(const std::string& process_type,
- const base::FilePath& log_file_path) {
- DCHECK(!g_crash_handler);
- g_crash_handler = new CrashHandler(log_file_path);
- g_crash_handler->Initialize(process_type);
-}
-
-// static
-bool CrashHandler::GetCrashDumpLocation(base::FilePath* crash_dir) {
- DCHECK(g_crash_handler);
- return g_crash_handler->crash_reporter_client_->
- GetCrashDumpLocation(crash_dir);
-}
-
-// static
-bool CrashHandler::RegisterCastCrashJni(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-CrashHandler::CrashHandler(const base::FilePath& log_file_path)
- : log_file_path_(log_file_path),
- crash_reporter_client_(new CastCrashReporterClientAndroid) {
- if (!crash_reporter_client_->GetCrashDumpLocation(&crash_dump_path_)) {
- LOG(ERROR) << "Could not get crash dump location";
- }
- SetCrashReporterClient(crash_reporter_client_.get());
-}
-
-CrashHandler::~CrashHandler() {
- DCHECK(g_crash_handler);
- g_crash_handler = NULL;
-}
-
-void CrashHandler::Initialize(const std::string& process_type) {
- if (process_type.empty()) {
- InitializeUploader();
-
- // ExceptionHandlers are called on crash in reverse order of
- // instantiation. This ExceptionHandler will attempt to upload crashes
- // and the log file written out by the main process.
-
- // Dummy MinidumpDescriptor just to start up another ExceptionHandler.
- google_breakpad::MinidumpDescriptor dummy(crash_dump_path_.value());
- crash_uploader_.reset(new google_breakpad::ExceptionHandler(
- dummy, &HandleCrash, NULL, NULL, true, -1));
-
- breakpad::InitCrashReporter(process_type);
-
- return;
- }
-
- if (process_type != switches::kZygoteProcess) {
- breakpad::InitNonBrowserCrashReporterForAndroid(process_type);
- }
-}
-
-void CrashHandler::InitializeUploader() {
- JNIEnv* env = base::android::AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jstring> crash_dump_path_java =
- base::android::ConvertUTF8ToJavaString(env,
- crash_dump_path_.value());
- Java_CastCrashHandler_initializeUploader(
- env, crash_dump_path_java.obj(), UploadCrashToStaging());
-}
-
-bool CrashHandler::CanUploadCrashDump() {
- DCHECK(crash_reporter_client_);
- return crash_reporter_client_->GetCollectStatsConsent();
-}
-
-void CrashHandler::UploadCrashDumps() {
- VLOG(1) << "Attempting to upload current process crash";
-
- if (CanUploadCrashDump()) {
- JNIEnv* env = base::android::AttachCurrentThread();
- // Current log file location
- base::android::ScopedJavaLocalRef<jstring> log_file_path_java =
- base::android::ConvertUTF8ToJavaString(env, log_file_path_.value());
- Java_CastCrashHandler_uploadCrashDumps(env, log_file_path_java.obj());
- } else {
- VLOG(1) << "Removing crash dumps instead of uploading";
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_CastCrashHandler_removeCrashDumps(env);
- }
-}
-
-} // namespace chromecast
diff --git a/chromium/chromecast/crash/app_state_tracker.cc b/chromium/chromecast/crash/app_state_tracker.cc
new file mode 100644
index 00000000000..b563ece66cd
--- /dev/null
+++ b/chromium/chromecast/crash/app_state_tracker.cc
@@ -0,0 +1,63 @@
+// Copyright 2015 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/crash/app_state_tracker.h"
+
+#include "base/lazy_instance.h"
+#include "chromecast/crash/cast_crash_keys.h"
+
+namespace {
+
+struct CurrentAppState {
+ std::string previous_app;
+ std::string current_app;
+ std::string last_launched_app;
+};
+
+base::LazyInstance<CurrentAppState> g_app_state = LAZY_INSTANCE_INITIALIZER;
+
+CurrentAppState* GetAppState() {
+ return g_app_state.Pointer();
+}
+
+} // namespace
+
+namespace chromecast {
+
+// static
+std::string AppStateTracker::GetLastLaunchedApp() {
+ return GetAppState()->last_launched_app;
+}
+
+// static
+std::string AppStateTracker::GetCurrentApp() {
+ return GetAppState()->current_app;
+}
+
+// static
+std::string AppStateTracker::GetPreviousApp() {
+ return GetAppState()->previous_app;
+}
+
+// static
+void AppStateTracker::SetLastLaunchedApp(const std::string& app_id) {
+ GetAppState()->last_launched_app = app_id;
+
+ // TODO(slan): Currently SetCrashKeyValue is a no-op on chromecast until
+ // we add call to InitCrashKeys
+ base::debug::SetCrashKeyValue(crash_keys::kLastApp, app_id);
+}
+
+// static
+void AppStateTracker::SetCurrentApp(const std::string& app_id) {
+ CurrentAppState* app_state = GetAppState();
+ app_state->previous_app = app_state->current_app;
+ app_state->current_app = app_id;
+
+ base::debug::SetCrashKeyValue(crash_keys::kCurrentApp, app_id);
+ base::debug::SetCrashKeyValue(crash_keys::kPreviousApp,
+ app_state->previous_app);
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/app_state_tracker.h b/chromium/chromecast/crash/app_state_tracker.h
new file mode 100644
index 00000000000..3df8686c951
--- /dev/null
+++ b/chromium/chromecast/crash/app_state_tracker.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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_CRASH_APP_STATE_TRACKER_H_
+#define CHROMECAST_CRASH_APP_STATE_TRACKER_H_
+
+#include <string>
+
+namespace chromecast {
+
+class AppStateTracker {
+ public:
+ // Record |app_id| as the last app that attempted to launch.
+ static void SetLastLaunchedApp(const std::string& app_id);
+
+ // The current app becomes the previous app, |app_id| becomes the current app.
+ static void SetCurrentApp(const std::string& app_id);
+
+ // Returns the id of the app that was last attempted to launch.
+ static std::string GetLastLaunchedApp();
+
+ // Returns the id of the active app.
+ static std::string GetCurrentApp();
+
+ // Returns the id of the app which was previously active.
+ static std::string GetPreviousApp();
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_APP_STATE_TRACKER_H_
diff --git a/chromium/chromecast/crash/cast_crash_reporter_client.cc b/chromium/chromecast/crash/cast_crash_reporter_client.cc
deleted file mode 100644
index 8edbfa6b7b2..00000000000
--- a/chromium/chromecast/crash/cast_crash_reporter_client.cc
+++ /dev/null
@@ -1,58 +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/crash/cast_crash_reporter_client.h"
-
-#include "base/time/time.h"
-#include "components/crash/app/breakpad_linux.h"
-#include "content/public/common/content_switches.h"
-
-namespace chromecast {
-
-namespace {
-
-char* g_process_type = NULL;
-uint64_t g_process_start_time = 0;
-
-} // namespace
-
-// static
-void CastCrashReporterClient::InitCrashReporter(
- const std::string& process_type) {
- g_process_start_time = (base::TimeTicks::Now() -
- base::TimeTicks()).InMilliseconds();
-
- // Save the process type (leaked).
- // Note: "browser" process is identified by empty process type string.
- const std::string& named_process_type(
- process_type.empty() ? "browser" : process_type);
- const size_t process_type_len = named_process_type.size() + 1;
- g_process_type = new char[process_type_len];
- strncpy(g_process_type, named_process_type.c_str(), process_type_len);
-
- // Start up breakpad for this process, if applicable.
- breakpad::InitCrashReporter(process_type);
-}
-
-// static
-char* CastCrashReporterClient::GetProcessType() {
- return g_process_type;
-}
-
-// static
-uint64_t CastCrashReporterClient::GetProcessStartTime() {
- return g_process_start_time;
-}
-
-CastCrashReporterClient::CastCrashReporterClient() {}
-CastCrashReporterClient::~CastCrashReporterClient() {}
-
-bool CastCrashReporterClient::EnableBreakpadForProcess(
- const std::string& process_type) {
- return process_type == switches::kRendererProcess ||
- process_type == switches::kZygoteProcess ||
- process_type == switches::kGpuProcess;
-}
-
-} // namespace chromecast
diff --git a/chromium/chromecast/crash/cast_crash_reporter_client_simple.cc b/chromium/chromecast/crash/cast_crash_reporter_client_simple.cc
deleted file mode 100644
index aef4add13c0..00000000000
--- a/chromium/chromecast/crash/cast_crash_reporter_client_simple.cc
+++ /dev/null
@@ -1,17 +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/crash/cast_crash_reporter_client.h"
-
-#include "base/logging.h"
-
-namespace chromecast {
-
-bool CastCrashReporterClient::HandleCrashDump(const char* crashdump_filename) {
- LOG(INFO) << "Process " << GetProcessType() << " crashed; minidump in "
- << crashdump_filename;
- return true;
-}
-
-} // namespace chromecast
diff --git a/chromium/chromecast/crash/cast_crashdump_uploader.cc b/chromium/chromecast/crash/cast_crashdump_uploader.cc
new file mode 100644
index 00000000000..1c15ac6a864
--- /dev/null
+++ b/chromium/chromecast/crash/cast_crashdump_uploader.cc
@@ -0,0 +1,123 @@
+// Copyright 2015 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/crash/cast_crashdump_uploader.h"
+
+#include <sys/stat.h>
+
+#include "base/logging.h"
+// TODO(slan): Find a replacement for LibcurlWrapper in Chromium to remove the
+// breakpad dependency.
+#include "breakpad/src/common/linux/libcurl_wrapper.h"
+
+namespace chromecast {
+namespace {
+
+// Keep these in sync with "//breakpad/src/client/mac/sender/uploader.mm"
+const char kProdKey[] = "prod";
+const char kVerKey[] = "ver";
+const char kGuidKey[] = "guid";
+const char kPtimeKey[] = "ptime";
+const char kCtimeKey[] = "ctime";
+const char kEmailKey[] = "email";
+const char kCommentsKey[] = "comments";
+
+} // namespace
+
+CastCrashdumpData::CastCrashdumpData() {
+}
+
+CastCrashdumpData::~CastCrashdumpData() {
+}
+
+CastCrashdumpUploader::CastCrashdumpUploader(const CastCrashdumpData& data)
+ : CastCrashdumpUploader(data, new google_breakpad::LibcurlWrapper()) {
+ // This instance of libcurlwrapper will leak.
+}
+
+CastCrashdumpUploader::CastCrashdumpUploader(
+ const CastCrashdumpData& data,
+ google_breakpad::LibcurlWrapper* http_layer)
+ : http_layer_(http_layer), data_(data) {
+ DCHECK(http_layer_);
+}
+
+CastCrashdumpUploader::~CastCrashdumpUploader() {
+}
+
+bool CastCrashdumpUploader::AddAttachment(const std::string& label,
+ const std::string& filename) {
+ attachments_[label] = filename;
+ return true;
+}
+
+bool CastCrashdumpUploader::CheckRequiredParametersArePresent() {
+ return !(data_.product.empty() || data_.version.empty() ||
+ data_.guid.empty() || data_.minidump_pathname.empty());
+}
+
+bool CastCrashdumpUploader::Upload(std::string* response) {
+ if (!http_layer_->Init()) {
+ LOG(ERROR) << "http layer Init failed";
+ return false;
+ }
+
+ if (!CheckRequiredParametersArePresent()) {
+ LOG(ERROR) << "Missing required parameters";
+ return false;
+ }
+
+ struct stat st;
+ if (0 != stat(data_.minidump_pathname.c_str(), &st)) {
+ LOG(ERROR) << data_.minidump_pathname << " does not exist.";
+ return false;
+ }
+
+ if (!http_layer_->AddFile(data_.minidump_pathname, "upload_file_minidump")) {
+ LOG(ERROR) << "Failed to add file: " << data_.minidump_pathname;
+ return false;
+ }
+
+ // Populate |parameters_|.
+ parameters_[kProdKey] = data_.product;
+ parameters_[kVerKey] = data_.version;
+ parameters_[kGuidKey] = data_.guid;
+ parameters_[kPtimeKey] = data_.ptime;
+ parameters_[kCtimeKey] = data_.ctime;
+ parameters_[kEmailKey] = data_.email;
+ parameters_[kCommentsKey] = data_.comments;
+
+ // Add each attachement in |attachments_|.
+ for (auto iter = attachments_.begin(); iter != attachments_.end(); ++iter) {
+ // Search for the attachment.
+ if (0 != stat(iter->second.c_str(), &st)) {
+ LOG(ERROR) << iter->second << " could not be found";
+ return false;
+ }
+
+ // Add the attachment
+ if (!http_layer_->AddFile(iter->second, iter->first)) {
+ LOG(ERROR) << "Failed to add file: " << iter->second
+ << " with label: " << iter->first;
+ return false;
+ }
+ }
+
+ LOG(INFO) << "Sending request to " << data_.crash_server;
+
+ int http_status_code;
+ std::string http_header_data;
+ return http_layer_->SendRequest(data_.crash_server,
+ parameters_,
+ &http_status_code,
+ &http_header_data,
+ response);
+}
+
+void CastCrashdumpUploader::SetParameter(const std::string& key,
+ const std::string& value) {
+ parameters_[key] = value;
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/cast_crashdump_uploader.h b/chromium/chromecast/crash/cast_crashdump_uploader.h
new file mode 100644
index 00000000000..acdfd9ad3b3
--- /dev/null
+++ b/chromium/chromecast/crash/cast_crashdump_uploader.h
@@ -0,0 +1,65 @@
+// Copyright 2015 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_CRASH_CAST_CRASHDUMP_UPLOADER_H_
+#define CHROMECAST_CRASH_CAST_CRASHDUMP_UPLOADER_H_
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+
+namespace google_breakpad {
+class LibcurlWrapper;
+}
+
+namespace chromecast {
+
+struct CastCrashdumpData {
+ CastCrashdumpData();
+ ~CastCrashdumpData();
+
+ std::string product;
+ std::string version;
+ std::string guid;
+ std::string ptime;
+ std::string ctime;
+ std::string email;
+ std::string comments;
+ std::string minidump_pathname;
+ std::string crash_server;
+ std::string proxy_host;
+ std::string proxy_userpassword;
+};
+
+class CastCrashdumpUploader {
+ public:
+ // Does not take ownership of |http_layer|.
+ CastCrashdumpUploader(const CastCrashdumpData& data,
+ google_breakpad::LibcurlWrapper* http_layer);
+ CastCrashdumpUploader(const CastCrashdumpData& data);
+ ~CastCrashdumpUploader();
+
+ bool AddAttachment(const std::string& label, const std::string& filename);
+ void SetParameter(const std::string& key, const std::string& value);
+ bool Upload(std::string* response);
+
+ private:
+ bool CheckRequiredParametersArePresent();
+
+ google_breakpad::LibcurlWrapper* http_layer_;
+ CastCrashdumpData data_;
+
+ // Holds the following mapping for attachments: <label, filepath>
+ std::map<std::string, std::string> attachments_;
+
+ // Holds the following mapping for HTTP request params: <key, value>
+ std::map<std::string, std::string> parameters_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastCrashdumpUploader);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_CAST_CRASHDUMP_UPLOADER_H_
diff --git a/chromium/chromecast/crash/cast_crashdump_uploader_unittest.cc b/chromium/chromecast/crash/cast_crashdump_uploader_unittest.cc
new file mode 100644
index 00000000000..f88cce8488e
--- /dev/null
+++ b/chromium/chromecast/crash/cast_crashdump_uploader_unittest.cc
@@ -0,0 +1,190 @@
+// Copyright 2015 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 <string>
+
+#include "base/files/file_util.h"
+#include "breakpad/src/common/linux/libcurl_wrapper.h"
+#include "chromecast/crash/cast_crashdump_uploader.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+
+class MockLibcurlWrapper : public google_breakpad::LibcurlWrapper {
+ public:
+ MOCK_METHOD0(Init, bool());
+ MOCK_METHOD2(SetProxy,
+ bool(const std::string& proxy_host,
+ const std::string& proxy_userpwd));
+ MOCK_METHOD2(AddFile,
+ bool(const std::string& upload_file_path,
+ const std::string& basename));
+ MOCK_METHOD5(SendRequest,
+ bool(const std::string& url,
+ const std::map<std::string, std::string>& parameters,
+ int* http_status_code,
+ std::string* http_header_data,
+ std::string* http_response_data));
+};
+
+// Declared for the scope of this file to increase readability.
+using testing::_;
+using testing::Return;
+
+TEST(CastCrashdumpUploaderTest, UploadFailsWhenInitFails) {
+ testing::StrictMock<MockLibcurlWrapper> m;
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(false));
+
+ CastCrashdumpData data;
+ data.product = "foobar";
+ data.version = "1.0";
+ data.guid = "AAA-BBB";
+ data.email = "test@test.com";
+ data.comments = "none";
+ data.minidump_pathname = "/tmp/foo.dmp";
+ data.crash_server = "http://foo.com";
+ CastCrashdumpUploader uploader(data, &m);
+
+ ASSERT_FALSE(uploader.Upload(nullptr));
+}
+
+TEST(CastCrashdumpUploaderTest, UploadSucceedsWithValidParameters) {
+ testing::StrictMock<MockLibcurlWrapper> m;
+
+ // Create a temporary file.
+ base::FilePath temp;
+ ASSERT_TRUE(base::CreateTemporaryFile(&temp));
+
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(m, AddFile(temp.value(), _)).WillOnce(Return(true));
+ EXPECT_CALL(m, SendRequest("http://foo.com", _, _, _, _)).Times(1).WillOnce(
+ Return(true));
+
+ CastCrashdumpData data;
+ data.product = "foobar";
+ data.version = "1.0";
+ data.guid = "AAA-BBB";
+ data.email = "test@test.com";
+ data.comments = "none";
+ data.minidump_pathname = temp.value();
+ data.crash_server = "http://foo.com";
+ CastCrashdumpUploader uploader(data, &m);
+
+ ASSERT_TRUE(uploader.Upload(nullptr));
+}
+
+TEST(CastCrashdumpUploaderTest, UploadFailsWithInvalidPathname) {
+ testing::StrictMock<MockLibcurlWrapper> m;
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(m, SendRequest(_, _, _, _, _)).Times(0);
+
+ CastCrashdumpData data;
+ data.product = "foobar";
+ data.version = "1.0";
+ data.guid = "AAA-BBB";
+ data.email = "test@test.com";
+ data.comments = "none";
+ data.minidump_pathname = "/invalid/file/path";
+ data.crash_server = "http://foo.com";
+ CastCrashdumpUploader uploader(data, &m);
+
+ ASSERT_FALSE(uploader.Upload(nullptr));
+}
+
+TEST(CastCrashdumpUploaderTest, UploadFailsWithoutAllRequiredParameters) {
+ testing::StrictMock<MockLibcurlWrapper> m;
+
+ // Create a temporary file.
+ base::FilePath temp;
+ ASSERT_TRUE(base::CreateTemporaryFile(&temp));
+
+ // Has all the require fields for a crashdump.
+ CastCrashdumpData data;
+ data.product = "foobar";
+ data.version = "1.0";
+ data.guid = "AAA-BBB";
+ data.email = "test@test.com";
+ data.comments = "none";
+ data.minidump_pathname = temp.value();
+ data.crash_server = "http://foo.com";
+
+ // Test with empty product name.
+ data.product = "";
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ CastCrashdumpUploader uploader_no_product(data, &m);
+ ASSERT_FALSE(uploader_no_product.Upload(nullptr));
+ data.product = "foobar";
+
+ // Test with empty product version.
+ data.version = "";
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ CastCrashdumpUploader uploader_no_version(data, &m);
+ ASSERT_FALSE(uploader_no_version.Upload(nullptr));
+ data.version = "1.0";
+
+ // Test with empty client GUID.
+ data.guid = "";
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ CastCrashdumpUploader uploader_no_guid(data, &m);
+ ASSERT_FALSE(uploader_no_guid.Upload(nullptr));
+}
+
+TEST(CastCrashdumpUploaderTest, UploadFailsWithInvalidAttachment) {
+ testing::StrictMock<MockLibcurlWrapper> m;
+
+ // Create a temporary file.
+ base::FilePath minidump;
+ ASSERT_TRUE(base::CreateTemporaryFile(&minidump));
+
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(m, AddFile(minidump.value(), _)).WillOnce(Return(true));
+
+ CastCrashdumpData data;
+ data.product = "foobar";
+ data.version = "1.0";
+ data.guid = "AAA-BBB";
+ data.email = "test@test.com";
+ data.comments = "none";
+ data.minidump_pathname = minidump.value();
+ data.crash_server = "http://foo.com";
+ CastCrashdumpUploader uploader(data, &m);
+
+ // Add a file that does not exist as an attachment.
+ uploader.AddAttachment("label", "/path/does/not/exist");
+ ASSERT_FALSE(uploader.Upload(nullptr));
+}
+
+TEST(CastCrashdumpUploaderTest, UploadSucceedsWithValidAttachment) {
+ testing::StrictMock<MockLibcurlWrapper> m;
+
+ // Create a temporary file.
+ base::FilePath minidump;
+ ASSERT_TRUE(base::CreateTemporaryFile(&minidump));
+
+ // Create a valid attachment.
+ base::FilePath attachment;
+ ASSERT_TRUE(base::CreateTemporaryFile(&attachment));
+
+ EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(m, AddFile(minidump.value(), _)).WillOnce(Return(true));
+ EXPECT_CALL(m, AddFile(attachment.value(), _)).WillOnce(Return(true));
+ EXPECT_CALL(m, SendRequest(_, _, _, _, _)).Times(1).WillOnce(Return(true));
+
+ CastCrashdumpData data;
+ data.product = "foobar";
+ data.version = "1.0";
+ data.guid = "AAA-BBB";
+ data.email = "test@test.com";
+ data.comments = "none";
+ data.minidump_pathname = minidump.value();
+ data.crash_server = "http://foo.com";
+ CastCrashdumpUploader uploader(data, &m);
+
+ // Add a file that does not exist as an attachment.
+ uploader.AddAttachment("label", attachment.value());
+ ASSERT_TRUE(uploader.Upload(nullptr));
+}
+
+} // namespace chromeceast
diff --git a/chromium/chromecast/crash/linux/crash_util.cc b/chromium/chromecast/crash/linux/crash_util.cc
new file mode 100644
index 00000000000..e80b179c16e
--- /dev/null
+++ b/chromium/chromecast/crash/linux/crash_util.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 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/crash/linux/crash_util.h"
+
+#include <stdlib.h>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/time/time.h"
+#include "chromecast/base/path_utils.h"
+#include "chromecast/base/version.h"
+#include "chromecast/crash/app_state_tracker.h"
+#include "chromecast/crash/linux/dummy_minidump_generator.h"
+#include "chromecast/crash/linux/minidump_writer.h"
+
+namespace chromecast {
+
+namespace {
+
+// This can be set to a callback for testing. This allows us to inject a fake
+// dumpstate routine to avoid calling an executable during an automated test.
+// This value should not be mutated through any other function except
+// CrashUtil::SetDumpStateCbForTest().
+static base::Callback<int(const std::string&)>* g_dumpstate_cb = nullptr;
+
+} // namespace
+
+// static
+uint64_t CrashUtil::GetCurrentTimeMs() {
+ return (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
+}
+
+// static
+bool CrashUtil::RequestUploadCrashDump(
+ const std::string& existing_minidump_path,
+ const std::string& crashed_process_name,
+ uint64_t crashed_process_start_time_ms) {
+ LOG(INFO) << "Request to upload crash dump " << existing_minidump_path
+ << " for process " << crashed_process_name;
+
+ // Note: Do not use Chromium IO methods in this function. When cast_shell
+ // crashes, this function can be called by any thread, which may not allow IO.
+ // Use stdlib system calls for IO instead.
+ uint64_t uptime_ms = GetCurrentTimeMs() - crashed_process_start_time_ms;
+ MinidumpParams params(crashed_process_name,
+ uptime_ms,
+ "", // suffix
+ AppStateTracker::GetPreviousApp(),
+ AppStateTracker::GetCurrentApp(),
+ AppStateTracker::GetLastLaunchedApp(),
+ CAST_BUILD_RELEASE,
+ CAST_BUILD_INCREMENTAL);
+ DummyMinidumpGenerator minidump_generator(existing_minidump_path);
+
+ base::FilePath filename = base::FilePath(existing_minidump_path).BaseName();
+
+ scoped_ptr<MinidumpWriter> writer;
+ if (g_dumpstate_cb) {
+ writer.reset(new MinidumpWriter(
+ &minidump_generator, filename.value(), params, *g_dumpstate_cb));
+ } else {
+ writer.reset(
+ new MinidumpWriter(&minidump_generator, filename.value(), params));
+ }
+ bool success = false;
+ writer->set_non_blocking(false);
+ success = (0 == writer->Write()); // error already logged.
+
+ // In case the file is still in $TEMP, remove it.
+ if (remove(existing_minidump_path.c_str()) < 0 && errno != ENOENT) {
+ LOG(ERROR) << "Unable to delete temp minidump file "
+ << existing_minidump_path << ": " << strerror(errno);
+ success = false;
+ }
+
+ // Use std::endl to flush the log stream in case this process exits.
+ LOG(INFO) << "Request to upload crash dump finished. "
+ << "Exit now if it is main process that crashed." << std::endl;
+
+ return success;
+}
+
+void CrashUtil::SetDumpStateCbForTest(
+ const base::Callback<int(const std::string&)>& cb) {
+ DCHECK(!g_dumpstate_cb);
+ g_dumpstate_cb = new base::Callback<int(const std::string&)>(cb);
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/crash_util.h b/chromium/chromecast/crash/linux/crash_util.h
new file mode 100644
index 00000000000..04de5651676
--- /dev/null
+++ b/chromium/chromecast/crash/linux/crash_util.h
@@ -0,0 +1,37 @@
+// Copyright 2015 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_CRASH_LINUX_CRASH_UTIL_H_
+#define CHROMECAST_CRASH_LINUX_CRASH_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/callback.h"
+
+namespace chromecast {
+
+class CrashUtil {
+ public:
+ // Helper function to request upload an existing minidump file. Returns true
+ // on success, false otherwise.
+ static bool RequestUploadCrashDump(const std::string& existing_minidump_path,
+ const std::string& crashed_process_name,
+ uint64_t crashed_process_start_time_ms);
+
+ // Util function to get current time in ms. This is used to record
+ // crashed_process_start_time_ms in client side.
+ static uint64_t GetCurrentTimeMs();
+
+ // Call this to set a callback to be used instead of invoking an executable
+ // in a seperate process. See MinidumpWriter::SetDumpStateCbForTest() for more
+ // details on this callback's signature.
+ static void SetDumpStateCbForTest(
+ const base::Callback<int(const std::string&)>& cb);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_CRASH_UTIL_H_
diff --git a/chromium/chromecast/crash/linux/dummy_minidump_generator.cc b/chromium/chromecast/crash/linux/dummy_minidump_generator.cc
new file mode 100644
index 00000000000..019febfc497
--- /dev/null
+++ b/chromium/chromecast/crash/linux/dummy_minidump_generator.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 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/crash/linux/dummy_minidump_generator.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <vector>
+
+#include "base/logging.h"
+
+namespace chromecast {
+
+namespace {
+
+const int kBufferSize = 32768;
+
+} // namespace
+
+DummyMinidumpGenerator::DummyMinidumpGenerator(
+ const std::string& existing_minidump_path)
+ : existing_minidump_path_(existing_minidump_path) {
+}
+
+bool DummyMinidumpGenerator::Generate(const std::string& minidump_path) {
+ // Use stdlib calls here to avoid potential IO restrictions on this thread.
+
+ // Return false if the file does not exist.
+ struct stat st;
+ if (stat(existing_minidump_path_.c_str(), &st) != 0) {
+ PLOG(ERROR) << existing_minidump_path_.c_str() << " does not exist: ";
+ return false;
+ }
+
+ LOG(INFO) << "Moving minidump from " << existing_minidump_path_ << " to "
+ << minidump_path << " for further uploading.";
+
+ // Attempt to rename(). If this operation fails, the files are on different
+ // volumes. Fall back to a copy and delete.
+ if (rename(existing_minidump_path_.c_str(), minidump_path.c_str()) < 0) {
+ // Any errors will be logged within CopyAndDelete().
+ return CopyAndDelete(minidump_path);
+ }
+
+ return true;
+}
+
+bool DummyMinidumpGenerator::CopyAndDelete(const std::string& dest_path) {
+ FILE* src = fopen(existing_minidump_path_.c_str(), "r");
+ if (!src) {
+ PLOG(ERROR) << existing_minidump_path_ << " failed to open: ";
+ return false;
+ }
+
+ FILE* dest = fopen(dest_path.c_str(), "w");
+ if (!dest) {
+ PLOG(ERROR) << dest_path << " failed to open: ";
+ return false;
+ }
+
+ // Copy all bytes from |src| into |dest|.
+ std::vector<char> buffer(kBufferSize);
+ bool success = false;
+ while (!success) {
+ size_t bytes_read = fread(&buffer[0], 1, buffer.size(), src);
+ if (bytes_read < buffer.size()) {
+ if (feof(src)) {
+ success = true;
+ } else {
+ // An error occurred.
+ PLOG(ERROR) << "Error reading " << existing_minidump_path_ << ": ";
+ break;
+ }
+ }
+
+ size_t bytes_written = fwrite(&buffer[0], 1, bytes_read, dest);
+ if (bytes_written < bytes_read) {
+ // An error occurred.
+ PLOG(ERROR) << "Error writing to " << dest_path << ": ";
+ success = false;
+ break;
+ }
+ }
+
+ // Close both files.
+ fclose(src);
+ fclose(dest);
+
+ // Attempt to delete file at |existing_minidump_path_|. We should log this
+ // error, but the function should not fail if the file is not removed.
+ if (remove(existing_minidump_path_.c_str()) < 0)
+ PLOG(ERROR) << "Could not remove " << existing_minidump_path_ << ": ";
+
+ return success;
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/dummy_minidump_generator.h b/chromium/chromecast/crash/linux/dummy_minidump_generator.h
new file mode 100644
index 00000000000..eb031250035
--- /dev/null
+++ b/chromium/chromecast/crash/linux/dummy_minidump_generator.h
@@ -0,0 +1,47 @@
+// Copyright 2015 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_CRASH_LINUX_DUMMY_MINIDUMP_GENERATOR_H_
+#define CHROMECAST_CRASH_LINUX_DUMMY_MINIDUMP_GENERATOR_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "chromecast/crash/linux/minidump_generator.h"
+
+namespace chromecast {
+
+class DummyMinidumpGenerator : public MinidumpGenerator {
+ public:
+ // A dummy minidump generator to move an existing minidump into
+ // crash_uploader's monitoring path ($HOME/minidumps). The path is monitored
+ // with file lock-control, so that third process should not write to it
+ // directly.
+ explicit DummyMinidumpGenerator(const std::string& existing_minidump_path);
+
+ // MinidumpGenerator implementation:
+ bool Generate(const std::string& minidump_path) override;
+
+ // Provide access to internal utility for testing.
+ bool CopyAndDeleteForTest(const std::string& dest_path) {
+ return CopyAndDelete(dest_path);
+ }
+
+ private:
+ // Copies the contents of the file at |existing_minidump_path_| to the file at
+ // |dest_path|. If the copy operation succeeds, delete the file at
+ // |existing_minidump_path_|. Returns false if |existing_minidump_path_| can't
+ // be opened, or if the copy operation fails. Ideally, we would use Chrome
+ // utilities for a task like this, but we must ensure that this operation can
+ // occur on any thread (regardless of IO restrictions).
+ bool CopyAndDelete(const std::string& dest_path);
+
+ const std::string existing_minidump_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(DummyMinidumpGenerator);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_DUMMY_MINIDUMP_GENERATOR_H_
diff --git a/chromium/chromecast/crash/linux/dummy_minidump_generator_unittest.cc b/chromium/chromecast/crash/linux/dummy_minidump_generator_unittest.cc
new file mode 100644
index 00000000000..c38304f270b
--- /dev/null
+++ b/chromium/chromecast/crash/linux/dummy_minidump_generator_unittest.cc
@@ -0,0 +1,157 @@
+// Copyright 2015 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 <string>
+
+#include "base/files/file_util.h"
+#include "base/rand_util.h"
+#include "chromecast/crash/linux/dummy_minidump_generator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+
+namespace {
+// This value should stay in sync with the internal buffer size used in
+// CopyAndDelete().
+const int kInternalBufferSize = 32768;
+} // namespace
+
+TEST(DummyMinidumpGeneratorTest, GenerateFailsWithInvalidPath) {
+ // Create directory in which to put minidump.
+ base::FilePath minidump_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+
+ // Attempt to generate a minidump from an invalid path.
+ DummyMinidumpGenerator generator("/path/does/not/exist/minidump.dmp");
+ ASSERT_FALSE(generator.Generate(minidump_dir.Append("minidump.dmp").value()));
+}
+
+TEST(DummyMinidumpGeneratorTest, GenerateSucceedsWithValidPath) {
+ // Create directory in which to put minidump.
+ base::FilePath minidump_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+
+ // Create a fake minidump file.
+ base::FilePath fake_minidump;
+ ASSERT_TRUE(base::CreateTemporaryFile(&fake_minidump));
+ const std::string data("Test contents of the minidump file.\n");
+ ASSERT_EQ(static_cast<int>(data.size()),
+ base::WriteFile(fake_minidump, data.c_str(), data.size()));
+
+ DummyMinidumpGenerator generator(fake_minidump.value());
+ base::FilePath new_minidump = minidump_dir.Append("minidump.dmp");
+ EXPECT_TRUE(generator.Generate(new_minidump.value()));
+
+ // Original file should not exist, and new file should contain original
+ // contents.
+ std::string copied_data;
+ EXPECT_FALSE(base::PathExists(fake_minidump));
+ ASSERT_TRUE(base::PathExists(new_minidump));
+ EXPECT_TRUE(base::ReadFileToString(new_minidump, &copied_data));
+ EXPECT_EQ(data, copied_data);
+}
+
+TEST(DummyMinidumpGeneratorTest, CopyAndDeleteFailsWithInvalidSource) {
+ // Create directory in which to put minidump.
+ base::FilePath minidump_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+
+ // Attempt to copy from an invalid path.
+ DummyMinidumpGenerator generator("/path/does/not/exist/minidump.dmp");
+ ASSERT_FALSE(generator.CopyAndDeleteForTest(
+ minidump_dir.Append("minidump.dmp").value()));
+}
+
+TEST(DummyMinidumpGeneratorTest, CopyAndDeleteSucceedsWithSmallSource) {
+ // Create directory in which to put minidump.
+ base::FilePath minidump_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+
+ // Create a fake minidump file.
+ base::FilePath fake_minidump;
+ ASSERT_TRUE(base::CreateTemporaryFile(&fake_minidump));
+ const std::string data("Test contents of the minidump file.\n");
+ ASSERT_EQ(static_cast<int>(data.size()),
+ base::WriteFile(fake_minidump, data.c_str(), data.size()));
+
+ base::FilePath new_minidump = minidump_dir.Append("minidump.dmp");
+ DummyMinidumpGenerator generator(fake_minidump.value());
+ ASSERT_TRUE(generator.CopyAndDeleteForTest(new_minidump.value()));
+
+ // Original file should not exist, and new file should contain original
+ // contents.
+ std::string copied_data;
+ EXPECT_FALSE(base::PathExists(fake_minidump));
+ ASSERT_TRUE(base::PathExists(new_minidump));
+ EXPECT_TRUE(base::ReadFileToString(new_minidump, &copied_data));
+ EXPECT_EQ(data, copied_data);
+}
+
+TEST(DummyMinidumpGeneratorTest, CopyAndDeleteSucceedsWithLargeSource) {
+ // Create directory in which to put minidump.
+ base::FilePath minidump_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+
+ // Create a large fake minidump file.
+ // Note: The file must be greater than the size of the buffer used to copy the
+ // file in CopyAndDelete(). Create a big string in memory.
+ base::FilePath fake_minidump;
+ ASSERT_TRUE(base::CreateTemporaryFile(&fake_minidump));
+ size_t str_len = kInternalBufferSize * 10 + 1;
+ const std::string data = base::RandBytesAsString(str_len);
+
+ // Write the string to the file and verify that the file is big enough.
+ ASSERT_EQ(static_cast<int>(data.size()),
+ base::WriteFile(fake_minidump, data.c_str(), data.size()));
+ int64_t filesize = 0;
+ ASSERT_TRUE(base::GetFileSize(fake_minidump, &filesize));
+ ASSERT_GT(filesize, kInternalBufferSize);
+
+ base::FilePath new_minidump = minidump_dir.Append("minidump.dmp");
+ DummyMinidumpGenerator generator(fake_minidump.value());
+ ASSERT_TRUE(generator.CopyAndDeleteForTest(new_minidump.value()));
+
+ // Original file should not exist, and new file should contain original
+ // contents.
+ std::string copied_data;
+ EXPECT_FALSE(base::PathExists(fake_minidump));
+ ASSERT_TRUE(base::PathExists(new_minidump));
+ EXPECT_TRUE(base::ReadFileToString(new_minidump, &copied_data));
+ EXPECT_EQ(data, copied_data);
+}
+
+TEST(DummyMinidumpGeneratorTest, CopyAndDeleteSucceedsWhenEOFAlignsWithBuffer) {
+ // Create directory in which to put minidump.
+ base::FilePath minidump_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &minidump_dir));
+
+ // Create a large fake minidump file.
+ // Note: The file must be greater than the size of the buffer used to copy the
+ // file in CopyAndDelete(). Create a big string in memory.
+ base::FilePath fake_minidump;
+ ASSERT_TRUE(base::CreateTemporaryFile(&fake_minidump));
+ size_t str_len = kInternalBufferSize;
+ const std::string data = base::RandBytesAsString(str_len);
+
+ // Write the string to the file and verify that the file is big enough.
+ ASSERT_EQ(static_cast<int>(data.size()),
+ base::WriteFile(fake_minidump, data.c_str(), data.size()));
+ int64_t filesize = 0;
+ ASSERT_TRUE(base::GetFileSize(fake_minidump, &filesize));
+ ASSERT_EQ(kInternalBufferSize, filesize);
+
+ base::FilePath new_minidump = minidump_dir.Append("minidump.dmp");
+ DummyMinidumpGenerator generator(fake_minidump.value());
+ ASSERT_TRUE(generator.CopyAndDeleteForTest(new_minidump.value()));
+
+ // Original file should not exist, and new file should contain original
+ // contents.
+ std::string copied_data;
+ EXPECT_FALSE(base::PathExists(fake_minidump));
+ ASSERT_TRUE(base::PathExists(new_minidump));
+ EXPECT_TRUE(base::ReadFileToString(new_minidump, &copied_data));
+ EXPECT_EQ(data, copied_data);
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/dump_info.cc b/chromium/chromecast/crash/linux/dump_info.cc
new file mode 100644
index 00000000000..c98ddf948dd
--- /dev/null
+++ b/chromium/chromecast/crash/linux/dump_info.cc
@@ -0,0 +1,138 @@
+// Copyright 2015 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/crash/linux/dump_info.h"
+
+#include <stdlib.h>
+
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+
+namespace chromecast {
+
+namespace {
+
+const char kDumpTimeFormat[] = "%Y-%m-%d %H:%M:%S";
+const unsigned kDumpTimeMaxLen = 255;
+
+const int kNumRequiredParams = 5;
+} // namespace
+
+DumpInfo::DumpInfo(const std::string& entry) : valid_(false) {
+ // TODO(slan): This ctor is doing non-trivial work. Change this.
+ if ((valid_ = ParseEntry(entry)) == true) {
+ entry_ = GetEntryAsString();
+ }
+}
+
+DumpInfo::DumpInfo(const std::string& crashed_process_dump,
+ const std::string& logfile,
+ const time_t& dump_time,
+ const MinidumpParams& params)
+ : crashed_process_dump_(crashed_process_dump),
+ logfile_(logfile),
+ dump_time_(dump_time),
+ params_(params),
+ valid_(false) {
+ // The format is
+ // <name>|<dump time>|<dump>|<uptime>|<logfile>|<suffix>|<prev_app_name>|
+ // <curent_app name>|<last_app_name>
+ // <dump time> is in the format of kDumpTimeFormat
+
+ // Validate the time passed in.
+ struct tm* tm = gmtime(&dump_time);
+ char buf[kDumpTimeMaxLen];
+ int n = strftime(buf, kDumpTimeMaxLen, kDumpTimeFormat, tm);
+ if (n <= 0) {
+ LOG(INFO) << "strftime failed";
+ return;
+ }
+ entry_ = GetEntryAsString();
+ valid_ = true;
+}
+
+DumpInfo::~DumpInfo() {
+}
+
+std::string DumpInfo::GetEntryAsString() {
+ struct tm* tm = gmtime(&dump_time_);
+ char buf[kDumpTimeMaxLen];
+ int n = strftime(buf, kDumpTimeMaxLen, kDumpTimeFormat, tm);
+ DCHECK_GT(n, 0);
+
+ std::stringstream entrystream;
+ entrystream << params_.process_name << "|" << buf << "|"
+ << crashed_process_dump_ << "|" << params_.process_uptime << "|"
+ << logfile_ << "|" << params_.suffix << "|"
+ << params_.previous_app_name << "|" << params_.current_app_name
+ << "|" << params_.last_app_name << "|"
+ << params_.cast_release_version << "|"
+ << params_.cast_build_number << std::endl;
+ return entrystream.str();
+}
+
+bool DumpInfo::ParseEntry(const std::string& entry) {
+ // The format is
+ // <name>|<dump time>|<dump>|<uptime>|<logfile>{|<suffix>{|<prev_app_name>{
+ // |<current_app name>{|last_launched_app_name}}}}
+ // <dump time> is in the format |kDumpTimeFormat|
+ std::vector<std::string> fields;
+ base::SplitString(entry, '|', &fields);
+ if (fields.size() < kNumRequiredParams) {
+ LOG(INFO) << "Invalid entry: Too few fields.";
+ return false;
+ }
+
+ // Extract required fields.
+ params_.process_name = fields[0];
+ if (!SetDumpTimeFromString(fields[1]))
+ return false;
+ crashed_process_dump_ = fields[2];
+ params_.process_uptime = atoll(fields[3].c_str());
+ logfile_ = fields[4];
+
+ // Extract all other optional fields.
+ for (size_t i = 5; i < fields.size(); ++i) {
+ const std::string& temp = fields[i];
+ switch (i) {
+ case 5: // Optional field: suffix
+ params_.suffix = temp;
+ break;
+ case 6: // Optional field: prev_app_name
+ params_.previous_app_name = temp;
+ break;
+ case 7: // Optional field: current_app_name
+ params_.current_app_name = temp;
+ break;
+ case 8: // Optional field: last_launched_app_name
+ params_.last_app_name = temp;
+ break;
+ case 9: // extract an optional cast release version
+ params_.cast_release_version = temp;
+ break;
+ case 10: // extract an optional cast build number
+ params_.cast_build_number = temp;
+ break;
+ default:
+ LOG(INFO) << "Entry has too many fields invalid";
+ return false;
+ }
+ }
+ valid_ = true;
+ return true;
+}
+
+bool DumpInfo::SetDumpTimeFromString(const std::string& timestr) {
+ struct tm tm = {0};
+ char* text = strptime(timestr.c_str(), kDumpTimeFormat, &tm);
+ dump_time_ = mktime(&tm);
+ if (!text || dump_time_ < 0) {
+ LOG(INFO) << "Failed to convert dump time invalid";
+ return false;
+ }
+ return true;
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/dump_info.h b/chromium/chromecast/crash/linux/dump_info.h
new file mode 100644
index 00000000000..7425f5d982d
--- /dev/null
+++ b/chromium/chromecast/crash/linux/dump_info.h
@@ -0,0 +1,66 @@
+// Copyright 2015 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_CRASH_LINUX_DUMP_INFO_H_
+#define CHROMECAST_CRASH_LINUX_DUMP_INFO_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "chromecast/crash/linux/minidump_params.h"
+
+namespace chromecast {
+
+// Class that encapsulates the construction and parsing of dump entries
+// in the log file.
+class DumpInfo {
+ public:
+ // Attempt to construct a DumpInfo object by parsing the given entry string
+ // and extracting the contained information and populate the relevant
+ // fields.
+ explicit DumpInfo(const std::string& entry);
+
+ // Attempt to construct a DumpInfo object that has the following info:
+ //
+ // -crashed_process_dump: the full path of the dump written
+ // -crashed_process_logfile: the full path of the logfile written
+ // -dump_time: the time of the dump written
+ // -params: a structure containing other useful crash information
+ //
+ // As a result of construction, the |entry_| will be filled with the
+ // appropriate string to add to the log file.
+ DumpInfo(const std::string& crashed_process_dump,
+ const std::string& crashed_process_logfile,
+ const time_t& dump_time,
+ const MinidumpParams& params);
+
+ ~DumpInfo();
+
+ const std::string& crashed_process_dump() const {
+ return crashed_process_dump_;
+ }
+ const std::string& logfile() const { return logfile_; }
+ const time_t& dump_time() const { return dump_time_; }
+ const std::string& entry() const { return entry_; }
+ const MinidumpParams& params() const { return params_; }
+ const bool valid() const { return valid_; }
+
+ private:
+ bool ParseEntry(const std::string& entry);
+ bool SetDumpTimeFromString(const std::string& timestr);
+ std::string GetEntryAsString();
+
+ std::string crashed_process_dump_;
+ std::string logfile_;
+ time_t dump_time_;
+ std::string entry_;
+ MinidumpParams params_;
+ bool valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(DumpInfo);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_DUMP_INFO_H_
diff --git a/chromium/chromecast/crash/linux/dump_info_unittest.cc b/chromium/chromecast/crash/linux/dump_info_unittest.cc
new file mode 100644
index 00000000000..e99daa47831
--- /dev/null
+++ b/chromium/chromecast/crash/linux/dump_info_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2015 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 <time.h>
+
+#include "chromecast/crash/linux/dump_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+
+TEST(DumpInfoTest, EmptyStringIsNotValid) {
+ DumpInfo dump_info("");
+ ASSERT_FALSE(dump_info.valid());
+}
+
+TEST(DumpInfoTest, TooFewFieldsIsNotValid) {
+ DumpInfo dump_info("name|2001-11-12 18:31:01|dump_string");
+ ASSERT_FALSE(dump_info.valid());
+}
+
+TEST(DumpInfoTest, BadTimeStringIsNotValid) {
+ DumpInfo info("name|Mar 23 2014 01:23:45|dump_string|123456789|logfile.log");
+ ASSERT_FALSE(info.valid());
+}
+
+TEST(DumpInfoTest, AllRequiredFieldsIsValid) {
+ DumpInfo info("name|2001-11-12 18:31:01|dump_string|123456789|logfile.log");
+ struct tm tm = {0};
+ tm.tm_isdst = 0;
+ tm.tm_sec = 1;
+ tm.tm_min = 31;
+ tm.tm_hour = 18;
+ tm.tm_mday = 12;
+ tm.tm_mon = 10;
+ tm.tm_year = 101;
+ time_t dump_time = mktime(&tm);
+
+ ASSERT_TRUE(info.valid());
+ ASSERT_EQ("name", info.params().process_name);
+ ASSERT_EQ(dump_time, info.dump_time());
+ ASSERT_EQ("dump_string", info.crashed_process_dump());
+ ASSERT_EQ(123456789u, info.params().process_uptime);
+ ASSERT_EQ("logfile.log", info.logfile());
+}
+
+TEST(DumpInfoTest, EmptyProcessNameIsValid) {
+ DumpInfo dump_info("|2001-11-12 18:31:01|dump_string|123456789|logfile.log");
+ ASSERT_TRUE(dump_info.valid());
+}
+
+TEST(DumpInfoTest, SomeRequiredFieldsEmptyIsValid) {
+ DumpInfo info("name|2001-11-12 18:31:01|||");
+ struct tm tm = {0};
+ tm.tm_isdst = 0;
+ tm.tm_sec = 1;
+ tm.tm_min = 31;
+ tm.tm_hour = 18;
+ tm.tm_mday = 12;
+ tm.tm_mon = 10;
+ tm.tm_year = 101;
+ time_t dump_time = mktime(&tm);
+
+ ASSERT_TRUE(info.valid());
+ ASSERT_EQ("name", info.params().process_name);
+ ASSERT_EQ(dump_time, info.dump_time());
+ ASSERT_EQ("", info.crashed_process_dump());
+ ASSERT_EQ(0u, info.params().process_uptime);
+ ASSERT_EQ("", info.logfile());
+}
+
+TEST(DumpInfoTest, AllOptionalFieldsIsValid) {
+ DumpInfo info(
+ "name|2001-11-12 18:31:01|dump_string|123456789|logfile.log|"
+ "suffix|previous_app|current_app|last_app|RELEASE|BUILD_NUMBER");
+ struct tm tm = {0};
+ tm.tm_isdst = 0;
+ tm.tm_sec = 1;
+ tm.tm_min = 31;
+ tm.tm_hour = 18;
+ tm.tm_mday = 12;
+ tm.tm_mon = 10;
+ tm.tm_year = 101;
+ time_t dump_time = mktime(&tm);
+
+ ASSERT_TRUE(info.valid());
+ ASSERT_EQ("name", info.params().process_name);
+ ASSERT_EQ(dump_time, info.dump_time());
+ ASSERT_EQ("dump_string", info.crashed_process_dump());
+ ASSERT_EQ(123456789u, info.params().process_uptime);
+ ASSERT_EQ("logfile.log", info.logfile());
+
+ ASSERT_EQ("suffix", info.params().suffix);
+ ASSERT_EQ("previous_app", info.params().previous_app_name);
+ ASSERT_EQ("current_app", info.params().current_app_name);
+ ASSERT_EQ("last_app", info.params().last_app_name);
+}
+
+TEST(DumpInfoTest, SomeOptionalFieldsIsValid) {
+ DumpInfo info(
+ "name|2001-11-12 18:31:01|dump_string|123456789|logfile.log|"
+ "suffix|previous_app");
+ struct tm tm = {0};
+ tm.tm_isdst = 0;
+ tm.tm_sec = 1;
+ tm.tm_min = 31;
+ tm.tm_hour = 18;
+ tm.tm_mday = 12;
+ tm.tm_mon = 10;
+ tm.tm_year = 101;
+ time_t dump_time = mktime(&tm);
+
+ ASSERT_TRUE(info.valid());
+ ASSERT_EQ("name", info.params().process_name);
+ ASSERT_EQ(dump_time, info.dump_time());
+ ASSERT_EQ("dump_string", info.crashed_process_dump());
+ ASSERT_EQ(123456789u, info.params().process_uptime);
+ ASSERT_EQ("logfile.log", info.logfile());
+
+ ASSERT_EQ("suffix", info.params().suffix);
+ ASSERT_EQ("previous_app", info.params().previous_app_name);
+}
+
+TEST(DumpInfoTest, TooManyFieldsIsNotValid) {
+ DumpInfo info(
+ "name|2001-11-12 18:31:01|dump_string|123456789|logfile.log|"
+ "suffix|previous_app|current_app|last_app|VERSION|BUILD_NUM|extra_field");
+ ASSERT_FALSE(info.valid());
+}
+
+} // chromecast \ No newline at end of file
diff --git a/chromium/chromecast/crash/linux/minidump_generator.h b/chromium/chromecast/crash/linux/minidump_generator.h
new file mode 100644
index 00000000000..9780e430ec7
--- /dev/null
+++ b/chromium/chromecast/crash/linux/minidump_generator.h
@@ -0,0 +1,23 @@
+// Copyright 2015 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_CRASH_LINUX_MINIDUMP_GENERATOR_H_
+#define CHROMECAST_CRASH_LINUX_MINIDUMP_GENERATOR_H_
+
+#include <string>
+
+namespace chromecast {
+
+class MinidumpGenerator {
+ public:
+ virtual ~MinidumpGenerator() {}
+
+ // Interface to generate a minidump file in given path.
+ // This is called inside MinidumpWriter::DoWorkLocked().
+ virtual bool Generate(const std::string& minidump_path) = 0;
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_MINIDUMP_GENERATOR_H_
diff --git a/chromium/chromecast/crash/linux/minidump_params.cc b/chromium/chromecast/crash/linux/minidump_params.cc
new file mode 100644
index 00000000000..3d532830c48
--- /dev/null
+++ b/chromium/chromecast/crash/linux/minidump_params.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 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/crash/linux/minidump_params.h"
+
+namespace chromecast {
+
+MinidumpParams::MinidumpParams(const std::string& p_process_name,
+ const uint64_t p_process_uptime,
+ const std::string& p_suffix,
+ const std::string& p_previous_app_name,
+ const std::string& p_current_app_name,
+ const std::string& p_last_app_name,
+ const std::string& p_cast_release_version,
+ const std::string& p_cast_build_number)
+ : process_name(p_process_name),
+ process_uptime(p_process_uptime),
+ suffix(p_suffix),
+ previous_app_name(p_previous_app_name),
+ current_app_name(p_current_app_name),
+ last_app_name(p_last_app_name),
+ cast_release_version(p_cast_release_version),
+ cast_build_number(p_cast_build_number) {
+}
+
+MinidumpParams::MinidumpParams() : process_uptime(0) {
+}
+
+MinidumpParams::MinidumpParams(const MinidumpParams& params) = default;
+
+MinidumpParams::~MinidumpParams() {
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/minidump_params.h b/chromium/chromecast/crash/linux/minidump_params.h
new file mode 100644
index 00000000000..1a1c15518ad
--- /dev/null
+++ b/chromium/chromecast/crash/linux/minidump_params.h
@@ -0,0 +1,39 @@
+// Copyright 2015 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_CRASH_LINUX_MINIDUMP_PARAMS_H_
+#define CHROMECAST_CRASH_LINUX_MINIDUMP_PARAMS_H_
+
+#include <string>
+
+namespace chromecast {
+
+struct MinidumpParams {
+ MinidumpParams();
+ MinidumpParams(const std::string& p_process_name,
+ const uint64_t p_process_uptime,
+ const std::string& p_suffix,
+ const std::string& p_previous_app_name,
+ const std::string& p_current_app_name,
+ const std::string& p_last_app_name,
+ const std::string& p_cast_release_version,
+ const std::string& p_cast_build_number);
+ MinidumpParams(const MinidumpParams& params);
+ ~MinidumpParams();
+
+ std::string process_name;
+ uint64_t process_uptime;
+ std::string suffix;
+ std::string previous_app_name;
+ std::string current_app_name;
+ std::string last_app_name;
+ // Release version is in the format of "major.minor", such as "1.15".
+ std::string cast_release_version;
+ // Build number is numerical string such as "20000".
+ std::string cast_build_number;
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_MINIDUMP_PARAMS_H_
diff --git a/chromium/chromecast/crash/linux/minidump_writer.cc b/chromium/chromecast/crash/linux/minidump_writer.cc
new file mode 100644
index 00000000000..5f4016e1c4e
--- /dev/null
+++ b/chromium/chromecast/crash/linux/minidump_writer.cc
@@ -0,0 +1,135 @@
+// Copyright 2015 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/crash/linux/minidump_writer.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "chromecast/base/path_utils.h"
+#include "chromecast/base/process_utils.h"
+#include "chromecast/crash/linux/dump_info.h"
+#include "chromecast/crash/linux/minidump_generator.h"
+
+namespace chromecast {
+
+namespace {
+
+const char kDumpStateSuffix[] = ".txt.gz";
+
+const int kDefaultDumpIntervalHours = 24;
+const int kDefaultMaxDumps = 5;
+const int kDefaultMaxRecentDumps = 5;
+
+// Fork and run dumpstate, saving results to minidump_name + ".txt.gz".
+int DumpState(const std::string& minidump_name) {
+ std::vector<std::string> argv;
+ argv.push_back(GetBinPathASCII("dumpstate").value());
+ argv.push_back("-w");
+ argv.push_back("crash-request");
+ argv.push_back("-z");
+ argv.push_back("-o");
+ argv.push_back(
+ minidump_name); // dumpstate appends ".txt.gz" to the filename.
+
+ std::string log;
+ if (!chromecast::GetAppOutput(argv, &log)) {
+ LOG(ERROR) << "failed to execute dumpstate";
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace
+
+MinidumpWriter::MinidumpWriter(MinidumpGenerator* minidump_generator,
+ const std::string& minidump_filename,
+ const MinidumpParams& params,
+ const DumpStateCallback& dump_state_cb)
+ : minidump_generator_(minidump_generator),
+ minidump_path_(minidump_filename),
+ params_(params),
+ max_dumps_(kDefaultMaxDumps),
+ dump_interval_(base::TimeDelta::FromHours(kDefaultDumpIntervalHours)),
+ max_recent_dumps_(kDefaultMaxRecentDumps),
+ dump_state_cb_(dump_state_cb) {
+}
+
+MinidumpWriter::MinidumpWriter(MinidumpGenerator* minidump_generator,
+ const std::string& minidump_filename,
+ const MinidumpParams& params)
+ : MinidumpWriter(minidump_generator,
+ minidump_filename,
+ params,
+ base::Bind(&DumpState)) {
+}
+
+MinidumpWriter::~MinidumpWriter() {
+}
+
+int MinidumpWriter::DoWork() {
+ // If path is not absolute, append it to |dump_path_|.
+ if (!minidump_path_.value().empty() && minidump_path_.value()[0] != '/')
+ minidump_path_ = dump_path_.Append(minidump_path_);
+
+ // The path should be a file in the |dump_path_| directory.
+ if (dump_path_ != minidump_path_.DirName()) {
+ LOG(INFO) << "The absolute path: " << minidump_path_.value() << " is not"
+ << "in the correct directory: " << dump_path_.value();
+ return -1;
+ }
+
+ // Query if we are able to write another minidump.
+ if (!CanWriteDump()) {
+ LOG(INFO) << "Skipping writing of dump due to limits";
+ return -1;
+ }
+
+ // Generate a minidump at the specified |minidump_path_|.
+ if (!minidump_generator_->Generate(minidump_path_.value())) {
+ LOG(ERROR) << "Generate minidump failed " << minidump_path_.value();
+ return -1;
+ }
+
+ // Run the dumpstate callback.
+ DCHECK(!dump_state_cb_.is_null());
+ if (dump_state_cb_.Run(minidump_path_.value()) < 0) {
+ LOG(ERROR) << "DumpState callback failed.";
+ return -1;
+ }
+
+ // Add this entry to the lockfile.
+ const DumpInfo info(minidump_path_.value(),
+ minidump_path_.value() + kDumpStateSuffix,
+ time(NULL),
+ params_);
+ if (AddEntryToLockFile(info) < 0) {
+ LOG(ERROR) << "lockfile logging failed";
+ return -1;
+ }
+
+ return 0;
+}
+
+bool MinidumpWriter::CanWriteDump() {
+ const auto& dumps = GetDumpMetadata();
+
+ // If no more dumps can be written, return false.
+ if (static_cast<int>(dumps.size()) >= max_dumps_)
+ return false;
+
+ // If too many dumps have been written recently, return false.
+ time_t cur_time = time(0);
+ int recent_dumps = 0;
+ for (auto dump : dumps) {
+ if (difftime(cur_time, dump->dump_time()) <= dump_interval_.InSecondsF()) {
+ if (++recent_dumps >= max_recent_dumps_)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace crash_manager
diff --git a/chromium/chromecast/crash/linux/minidump_writer.h b/chromium/chromecast/crash/linux/minidump_writer.h
new file mode 100644
index 00000000000..69e6233133c
--- /dev/null
+++ b/chromium/chromecast/crash/linux/minidump_writer.h
@@ -0,0 +1,85 @@
+// Copyright 2015 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_CRASH_LINUX_MINIDUMP_WRITER_H_
+#define CHROMECAST_CRASH_LINUX_MINIDUMP_WRITER_H_
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "chromecast/crash/linux/minidump_params.h"
+#include "chromecast/crash/linux/synchronized_minidump_manager.h"
+
+namespace chromecast {
+
+class MinidumpGenerator;
+
+// Class for writing a minidump with synchronized access to the minidumps
+// directory.
+class MinidumpWriter : public SynchronizedMinidumpManager {
+ public:
+ typedef base::Callback<int(const std::string&)> DumpStateCallback;
+
+ // Constructs a writer for a minidump. If |minidump_filename| is absolute, it
+ // must be a path to a file in the |dump_path_| directory. Otherwise, it
+ // should be a filename only, in which case, |minidump_generator| creates
+ // a minidump at $HOME/minidumps/|minidump_filename|. |params| describes the
+ // minidump metadata. |dump_state_cb| is Run() to generate a log dump. Please
+ // see the comments on |dump_state_cb_| below for details about this
+ // parameter.
+ // This does not take ownership of |minidump_generator|.
+ MinidumpWriter(MinidumpGenerator* minidump_generator,
+ const std::string& minidump_filename,
+ const MinidumpParams& params,
+ const base::Callback<int(const std::string&)>& dump_state_cb);
+
+ // Like the constructor above, but the default implementation of
+ // |dump_state_cb_| is used inside DoWork().
+ MinidumpWriter(MinidumpGenerator* minidump_generator,
+ const std::string& minidump_filename,
+ const MinidumpParams& params);
+
+ ~MinidumpWriter() override;
+
+ // Acquires exclusive access to the minidumps directory and generates a
+ // minidump and a log to be uploaded later. Returns 0 if successful, -1
+ // otherwise.
+ int Write() { return AcquireLockAndDoWork(); }
+
+ int max_dumps() const { return max_dumps_; }
+ int max_recent_dumps() const { return max_recent_dumps_; }
+ const base::TimeDelta& dump_interval() const { return dump_interval_; };
+
+ protected:
+ // MinidumpManager implementation:
+ int DoWork() override;
+
+ private:
+ // Returns true if we can write another dump, false otherwise. We can write
+ // another dump if the number of minidumps is strictly less than |max_dumps_|
+ // and the number of minidumps which occurred within the last |dump_interval_|
+ // is strictly less than |max_recent_dumps_|.
+ bool CanWriteDump();
+
+ MinidumpGenerator* const minidump_generator_;
+ base::FilePath minidump_path_;
+ const MinidumpParams params_;
+
+ const int max_dumps_;
+ const base::TimeDelta dump_interval_;
+ const int max_recent_dumps_;
+
+ // This callback is Run() to dump a log to |minidump_path_|.txt.gz, taking
+ // |minidump_path_| as a parameter. It returns 0 on success, and a negative
+ // integer otherwise. If a callback is not passed in the constructor, the
+ // default implemementaion is used.
+ DumpStateCallback dump_state_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(MinidumpWriter);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_MINIDUMP_WRITER_H_
diff --git a/chromium/chromecast/crash/linux/minidump_writer_unittest.cc b/chromium/chromecast/crash/linux/minidump_writer_unittest.cc
new file mode 100644
index 00000000000..c096f7ae60e
--- /dev/null
+++ b/chromium/chromecast/crash/linux/minidump_writer_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright 2015 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 <fstream>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/scoped_path_override.h"
+#include "chromecast/crash/linux/minidump_generator.h"
+#include "chromecast/crash/linux/minidump_writer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace {
+
+const char kDumplogFile[] = "dumplog";
+const char kLockfileName[] = "lockfile";
+const char kMinidumpSubdir[] = "minidumps";
+
+std::string GetCurrentTimeASCII() {
+ char cur_time[20];
+ time_t now = time(NULL);
+ struct tm* tm = gmtime(&now);
+ strftime(cur_time, 20, "%Y-%m-%d %H:%M:%S", tm);
+ return std::string(cur_time);
+}
+
+class FakeMinidumpGenerator : public MinidumpGenerator {
+ public:
+ FakeMinidumpGenerator() {}
+ ~FakeMinidumpGenerator() override {}
+
+ // MinidumpGenerator implementation:
+ bool Generate(const std::string& minidump_path) override { return true; }
+};
+
+int FakeDumpState(const std::string& minidump_path) {
+ return 0;
+}
+
+} // namespace
+
+class MinidumpWriterTest : public testing::Test {
+ protected:
+ MinidumpWriterTest() {}
+ ~MinidumpWriterTest() override {}
+
+ void SetUp() override {
+ // Set up a temporary directory which will be used as our fake home dir.
+ base::FilePath fake_home_dir;
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir));
+ home_.reset(new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir));
+ minidump_dir_ = fake_home_dir.Append(kMinidumpSubdir);
+ dumplog_file_ = minidump_dir_.Append(kDumplogFile);
+
+ // Create the minidump directory and lockfile.
+ ASSERT_TRUE(base::CreateDirectory(minidump_dir_));
+ base::File lockfile(
+ minidump_dir_.Append(kLockfileName),
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ ASSERT_TRUE(lockfile.IsValid());
+ }
+
+ FakeMinidumpGenerator fake_generator_;
+ base::FilePath minidump_dir_;
+ base::FilePath dumplog_file_;
+
+ private:
+ scoped_ptr<base::ScopedPathOverride> home_;
+
+ DISALLOW_COPY_AND_ASSIGN(MinidumpWriterTest);
+};
+
+TEST_F(MinidumpWriterTest, Write_FailsWithIncorrectMinidumpPath) {
+ MinidumpWriter writer(&fake_generator_,
+ "/path/to/wrong/dir",
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ ASSERT_EQ(-1, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_FailsWithMultiLevelRelativeMinidumpPath) {
+ MinidumpWriter writer(&fake_generator_,
+ "subdir/dumplog",
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ ASSERT_EQ(-1, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_SucceedsWithSimpleFilename) {
+ MinidumpWriter writer(&fake_generator_,
+ "dumplog",
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ ASSERT_EQ(0, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_SucceedsWithCorrectMinidumpPath) {
+ MinidumpWriter writer(&fake_generator_,
+ dumplog_file_.value(),
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ ASSERT_EQ(0, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_FailsWithSubdirInCorrectPath) {
+ MinidumpWriter writer(&fake_generator_,
+ dumplog_file_.Append("subdir/logfile").value(),
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+ ASSERT_EQ(-1, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_FailsWhenTooManyDumpsPresent) {
+ MinidumpWriter writer(&fake_generator_,
+ dumplog_file_.value(),
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ // Write dump logs to the lockfile.
+ std::ofstream lockfile(minidump_dir_.Append(kLockfileName).value());
+ ASSERT_TRUE(lockfile.is_open());
+ size_t too_many_dumps = writer.max_dumps() + 1;
+ for (size_t i = 0; i < too_many_dumps; ++i) {
+ lockfile << "p|2012-01-01 01:02:03|/dump/path||" << std::endl;
+ }
+ lockfile.close();
+
+ ASSERT_EQ(-1, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_FailsWhenTooManyRecentDumpsPresent) {
+ MinidumpWriter writer(&fake_generator_,
+ dumplog_file_.value(),
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ // Write dump logs to the lockfile.
+ std::ofstream lockfile(minidump_dir_.Append(kLockfileName).value());
+ ASSERT_TRUE(lockfile.is_open());
+ size_t too_many_recent_dumps = writer.max_recent_dumps() + 1;
+ for (size_t i = 0; i < too_many_recent_dumps; ++i) {
+ lockfile << "|" << GetCurrentTimeASCII() << "|/dump/path||" << std::endl;
+ }
+
+ ASSERT_EQ(-1, writer.Write());
+}
+
+TEST_F(MinidumpWriterTest, Write_SucceedsWhenDumpLimitsNotExceeded) {
+ MinidumpWriter writer(&fake_generator_,
+ dumplog_file_.value(),
+ MinidumpParams(),
+ base::Bind(&FakeDumpState));
+
+ ASSERT_GT(writer.max_dumps(), 1);
+ ASSERT_GT(writer.max_recent_dumps(), 0);
+
+ // Write an old dump logs to the lockfile.
+ std::ofstream lockfile(minidump_dir_.Append(kLockfileName).value());
+ ASSERT_TRUE(lockfile.is_open());
+ lockfile << "p|2012-01-01 01:02:03|/dump/path||" << std::endl;
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/synchronized_minidump_manager.cc b/chromium/chromecast/crash/linux/synchronized_minidump_manager.cc
new file mode 100644
index 00000000000..358427a2dd3
--- /dev/null
+++ b/chromium/chromecast/crash/linux/synchronized_minidump_manager.cc
@@ -0,0 +1,219 @@
+// Copyright 2015 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/crash/linux/synchronized_minidump_manager.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+
+#include "base/logging.h"
+#include "chromecast/base/path_utils.h"
+#include "chromecast/crash/linux/dump_info.h"
+
+namespace chromecast {
+
+namespace {
+
+const mode_t kDirMode = 0770;
+const mode_t kFileMode = 0660;
+const char kLockfileName[] = "lockfile";
+const char kMinidumpsDir[] = "minidumps";
+
+} // namespace
+
+SynchronizedMinidumpManager::SynchronizedMinidumpManager()
+ : non_blocking_(false), lockfile_fd_(-1) {
+ dump_path_ = GetHomePathASCII(kMinidumpsDir);
+ lockfile_path_ = dump_path_.Append(kLockfileName).value();
+}
+
+SynchronizedMinidumpManager::~SynchronizedMinidumpManager() {
+ // Release the lock if held.
+ ReleaseLockFile();
+}
+
+// TODO(slan): Move some of this pruning logic to ReleaseLockFile?
+int SynchronizedMinidumpManager::GetNumDumps(bool delete_all_dumps) {
+ DIR* dirp;
+ struct dirent* dptr;
+ int num_dumps = 0;
+
+ // folder does not exist
+ dirp = opendir(dump_path_.value().c_str());
+ if (dirp == NULL) {
+ LOG(ERROR) << "Unable to open directory " << dump_path_.value();
+ return 0;
+ }
+
+ while ((dptr = readdir(dirp)) != NULL) {
+ struct stat buf;
+ const std::string file_fullname = dump_path_.value() + "/" + dptr->d_name;
+ if (lstat(file_fullname.c_str(), &buf) == -1 || !S_ISREG(buf.st_mode)) {
+ // if we cannot lstat this file, it is probably bad, so skip
+ // if the file is not regular, skip
+ continue;
+ }
+ // 'lockfile' is not counted
+ if (lockfile_path_ != file_fullname) {
+ ++num_dumps;
+ if (delete_all_dumps) {
+ LOG(INFO) << "Removing " << dptr->d_name
+ << "which was not in the lockfile";
+ if (remove(file_fullname.c_str()) < 0) {
+ LOG(INFO) << "remove failed. error " << strerror(errno);
+ }
+ }
+ }
+ }
+
+ closedir(dirp);
+ return num_dumps;
+}
+
+int SynchronizedMinidumpManager::AcquireLockAndDoWork() {
+ int success = -1;
+ if (AcquireLockFile() >= 0) {
+ success = DoWork();
+ ReleaseLockFile();
+ }
+ return success;
+}
+
+const ScopedVector<DumpInfo>& SynchronizedMinidumpManager::GetDumpMetadata() {
+ DCHECK_GE(lockfile_fd_, 0);
+ if (!dump_metadata_)
+ ParseLockFile();
+ return *dump_metadata_;
+}
+
+int SynchronizedMinidumpManager::AcquireLockFile() {
+ DCHECK_LT(lockfile_fd_, 0);
+ // Make the directory for the minidumps if it does not exist.
+ if (mkdir(dump_path_.value().c_str(), kDirMode) < 0 && errno != EEXIST) {
+ LOG(ERROR) << "mkdir for " << dump_path_.value().c_str()
+ << " failed. error = " << strerror(errno);
+ return -1;
+ }
+
+ // Open the lockfile. Create it if it does not exist.
+ lockfile_fd_ = open(lockfile_path_.c_str(), O_RDWR | O_CREAT, kFileMode);
+
+ // If opening or creating the lockfile failed, we don't want to proceed
+ // with dump writing for fear of exhausting up system resources.
+ if (lockfile_fd_ < 0) {
+ LOG(ERROR) << "open lockfile failed " << lockfile_path_;
+ return -1;
+ }
+
+ // Acquire the lock on the file. Whether or not we are in non-blocking mode,
+ // flock failure means that we did not acquire it and this method should fail.
+ int operation_mode = non_blocking_ ? (LOCK_EX | LOCK_NB) : LOCK_EX;
+ if (flock(lockfile_fd_, operation_mode) < 0) {
+ ReleaseLockFile();
+ LOG(INFO) << "flock lockfile failed, error = " << strerror(errno);
+ return -1;
+ }
+
+ // The lockfile is open and locked. Parse it to provide subclasses with a
+ // record of all the current dumps.
+ if (ParseLockFile() < 0) {
+ LOG(ERROR) << "Lockfile did not parse correctly. ";
+ return -1;
+ }
+
+ // We successfully have acquired the lock.
+ return 0;
+}
+
+int SynchronizedMinidumpManager::ParseLockFile() {
+ DCHECK_GE(lockfile_fd_, 0);
+ DCHECK(!dump_metadata_);
+
+ scoped_ptr<ScopedVector<DumpInfo> > dumps(new ScopedVector<DumpInfo>());
+ std::string entry;
+
+ // Instead of using |lockfile_fd_|, use <fstream> for readability.
+ std::ifstream in(lockfile_path_);
+ if (!in.is_open()) {
+ NOTREACHED();
+ LOG(ERROR) << lockfile_path_ << " could not be opened.";
+ return -1;
+ }
+
+ // Grab each entry.
+ while (std::getline(in, entry)) {
+ scoped_ptr<DumpInfo> info(new DumpInfo(entry));
+ if (info->valid() && info->crashed_process_dump().size() > 0) {
+ dumps->push_back(info.Pass());
+ } else {
+ LOG(WARNING) << "Entry is not valid: " << entry;
+ return -1;
+ }
+ }
+
+ dump_metadata_ = dumps.Pass();
+ return 0;
+}
+
+int SynchronizedMinidumpManager::AddEntryToLockFile(const DumpInfo& dump_info) {
+ DCHECK_LE(0, lockfile_fd_);
+
+ // Make sure dump_info is valid.
+ if (!dump_info.valid()) {
+ LOG(ERROR) << "Entry to be added is invalid";
+ return -1;
+ }
+
+ // Open the file.
+ std::ofstream out(lockfile_path_, std::ios::app);
+ if (!out.is_open()) {
+ NOTREACHED() << "Lockfile would not open.";
+ return -1;
+ }
+
+ // Write the string and close the file.
+ out << dump_info.entry();
+ out.close();
+ return 0;
+}
+
+int SynchronizedMinidumpManager::RemoveEntryFromLockFile(int index) {
+ const auto& entries = GetDumpMetadata();
+ if (index < 0 || static_cast<size_t>(index) >= entries.size())
+ return -1;
+
+ // Remove the entry and write all remaining entries to file.
+ dump_metadata_->erase(dump_metadata_->begin() + index);
+ std::ofstream out(lockfile_path_);
+ for (auto info : *dump_metadata_) {
+ out << info->entry();
+ }
+ out.close();
+ return 0;
+}
+
+void SynchronizedMinidumpManager::ReleaseLockFile() {
+ // flock is associated with the fd entry in the open fd table, so closing
+ // all fd's will release the lock. To be safe, we explicitly unlock.
+ if (lockfile_fd_ >= 0) {
+ flock(lockfile_fd_, LOCK_UN);
+ close(lockfile_fd_);
+
+ // We may use this object again, so we should reset this.
+ lockfile_fd_ = -1;
+ }
+
+ dump_metadata_.reset();
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/crash/linux/synchronized_minidump_manager.h b/chromium/chromecast/crash/linux/synchronized_minidump_manager.h
new file mode 100644
index 00000000000..4adaa30cfc1
--- /dev/null
+++ b/chromium/chromecast/crash/linux/synchronized_minidump_manager.h
@@ -0,0 +1,106 @@
+// Copyright 2015 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_CRASH_LINUX_SYNCHRONIZED_MINIDUMP_MANAGER_H_
+#define CHROMECAST_CRASH_LINUX_SYNCHRONIZED_MINIDUMP_MANAGER_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+
+namespace chromecast {
+
+class DumpInfo;
+
+// Abstract base class for mutually-exclusive minidump handling. Ensures
+// synchronized access among instances of this class to the minidumps directory
+// using a file lock. The "lockfile" also holds serialized metadata about each
+// of the minidumps in the directory. Derived classes should not access the
+// lockfile directly. Instead, use protected methods to query and modify the
+// metadata, but only within the implementation of DoWork().
+class SynchronizedMinidumpManager {
+ public:
+ virtual ~SynchronizedMinidumpManager();
+
+ // Returns whether this object's file locking method is nonblocking or not.
+ bool non_blocking() { return non_blocking_; }
+
+ // Sets the file locking mechansim to be nonblocking or not.
+ void set_non_blocking(bool non_blocking) { non_blocking_ = non_blocking; }
+
+ protected:
+ SynchronizedMinidumpManager();
+
+ // Acquires the lock, calls DoWork(), then releases the lock when DoWork()
+ // returns. Derived classes should expose a method which calls this. Returns
+ // the status of DoWork(), or -1 if the lock was not successfully acquired.
+ int AcquireLockAndDoWork();
+
+ // Derived classes must implement this method. It will be called from
+ // DoWorkLocked after the lock has been successfully acquired. The lockfile
+ // shall be accessed and mutated only through the methods below. All other
+ // files shall be managed as needed by the derived class.
+ virtual int DoWork() = 0;
+
+ // Access the container holding all the metadata for the dumps. Note that
+ // the child class must only call this inside DoWork(). This is lazy. If the
+ // lockfile has not been parsed yet, it will be parsed when this is called.
+ const ScopedVector<DumpInfo>& GetDumpMetadata();
+
+ // Serialize |dump_info| and append it to the lockfile. Note that the child
+ // class must only call this inside DoWork(). This should be the only method
+ // used to write to the lockfile. Only call this if the minidump has been
+ // generated in the minidumps directory successfully. Returns 0 on success,
+ // -1 otherwise.
+ int AddEntryToLockFile(const DumpInfo& dump_info);
+
+ // Remove the lockfile entry at |index| in the container returned by
+ // GetDumpMetadata(). If the index is invalid or an IO error occurred, returns
+ // -1. Otherwise returns 0. When this function returns, both the in-memory
+ // containter returned by GetDumpMetadata and the persistent lockfile will be
+ // current.
+ int RemoveEntryFromLockFile(int index);
+
+ // Get the number of un-uploaded dumps in the dump_path directory.
+ // If delete_all_dumps is true, also delete all these files, this is used to
+ // clean lingering dump files.
+ int GetNumDumps(bool delete_all_dumps);
+
+ // TODO(slan): Remove this accessor. All I/O on the lockfile in inherited
+ // classes should be done via GetDumpMetadata(), AddEntryToLockFile(), and
+ // RemoveEntryFromLockFile().
+ const std::string& lockfile_path() { return lockfile_path_; }
+
+ // If true, the flock on the lockfile will be nonblocking
+ bool non_blocking_;
+
+ // Cached path for the minidumps directory.
+ base::FilePath dump_path_;
+
+ private:
+ // Acquire the lock file. Blocks if another process holds it, or if called
+ // a second time by the same process. Returns the fd of the lockfile if
+ // successful, or -1 if failed.
+ int AcquireLockFile();
+
+ // Parse the lockfile, populating |dumps_| for descendants to use. Return -1
+ // if an error occurred. Otherwise, return 0. This must not be called unless
+ // |this| has acquired the lock.
+ int ParseLockFile();
+
+ // Release the lock file with the associated *fd*.
+ void ReleaseLockFile();
+
+ std::string lockfile_path_;
+ int lockfile_fd_;
+ scoped_ptr<ScopedVector<DumpInfo> > dump_metadata_;
+
+ DISALLOW_COPY_AND_ASSIGN(SynchronizedMinidumpManager);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_CRASH_LINUX_SYNCHRONIZED_MINIDUMP_MANAGER_H_
diff --git a/chromium/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc b/chromium/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
new file mode 100644
index 00000000000..ea3e908b3e9
--- /dev/null
+++ b/chromium/chromecast/crash/linux/synchronized_minidump_manager_unittest.cc
@@ -0,0 +1,388 @@
+// Copyright 2015 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 <fcntl.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <sys/stat.h> // mkdir
+#include <sys/types.h> //
+#include <stdio.h> // perror
+#include <time.h>
+
+#include <fstream>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/process/launch.h"
+#include "base/test/scoped_path_override.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "chromecast/crash/linux/dump_info.h"
+#include "chromecast/crash/linux/synchronized_minidump_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace {
+
+const char kLockfileName[] = "lockfile";
+const char kMinidumpSubdir[] = "minidumps";
+
+ScopedVector<DumpInfo> GetCurrentDumps(const std::string& logfile_path) {
+ ScopedVector<DumpInfo> dumps;
+ std::string entry;
+
+ std::ifstream in(logfile_path);
+ DCHECK(in.is_open());
+ while (std::getline(in, entry)) {
+ scoped_ptr<DumpInfo> info(new DumpInfo(entry));
+ dumps.push_back(info.Pass());
+ }
+ return dumps.Pass();
+}
+
+// A trivial implementation of SynchronizedMinidumpManager, which does no work
+// to the
+// minidump and exposes its protected members for testing.
+class SynchronizedMinidumpManagerSimple : public SynchronizedMinidumpManager {
+ public:
+ SynchronizedMinidumpManagerSimple()
+ : SynchronizedMinidumpManager(),
+ work_done_(false),
+ add_entry_return_code_(-1),
+ lockfile_path_(dump_path_.Append(kLockfileName).value()) {}
+ ~SynchronizedMinidumpManagerSimple() override {}
+
+ void SetDumpInfoToWrite(scoped_ptr<DumpInfo> dump_info) {
+ dump_info_ = dump_info.Pass();
+ }
+
+ int DoWorkLocked() { return AcquireLockAndDoWork(); }
+
+ // SynchronizedMinidumpManager implementation:
+ int DoWork() override {
+ if (dump_info_)
+ add_entry_return_code_ = AddEntryToLockFile(*dump_info_);
+ work_done_ = true;
+ return 0;
+ }
+
+ // Accessors for testing.
+ const std::string& dump_path() { return dump_path_.value(); }
+ const std::string& lockfile_path() { return lockfile_path_; }
+ bool work_done() { return work_done_; }
+ int add_entry_return_code() { return add_entry_return_code_; }
+
+ private:
+ bool work_done_;
+ int add_entry_return_code_;
+ std::string lockfile_path_;
+ scoped_ptr<DumpInfo> dump_info_;
+};
+
+void DoWorkLockedTask(SynchronizedMinidumpManagerSimple* manager) {
+ manager->DoWorkLocked();
+}
+
+class SleepySynchronizedMinidumpManagerSimple
+ : public SynchronizedMinidumpManagerSimple {
+ public:
+ SleepySynchronizedMinidumpManagerSimple(int sleep_duration_ms)
+ : SynchronizedMinidumpManagerSimple(),
+ sleep_duration_ms_(sleep_duration_ms) {}
+ ~SleepySynchronizedMinidumpManagerSimple() override {}
+
+ // SynchronizedMinidumpManager implementation:
+ int DoWork() override {
+ // The lock has been acquired. Fall asleep for |kSleepDurationMs|, then
+ // write the file.
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMilliseconds(sleep_duration_ms_));
+ return SynchronizedMinidumpManagerSimple::DoWork();
+ }
+
+ private:
+ const int sleep_duration_ms_;
+};
+
+class SynchronizedMinidumpManagerTest : public testing::Test {
+ public:
+ SynchronizedMinidumpManagerTest() {}
+ ~SynchronizedMinidumpManagerTest() override {}
+
+ void SetUp() override {
+ // Set up a temporary directory which will be used as our fake home dir.
+ ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_));
+ path_override_.reset(
+ new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_));
+ minidump_dir_ = fake_home_dir_.Append(kMinidumpSubdir);
+ lockfile_ = minidump_dir_.Append(kLockfileName);
+
+ // Create a minidump directory.
+ ASSERT_TRUE(base::CreateDirectory(minidump_dir_));
+ ASSERT_TRUE(base::IsDirectoryEmpty(minidump_dir_));
+
+ // Create a lockfile in that directory.
+ base::File lockfile(
+ lockfile_, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ ASSERT_TRUE(lockfile.IsValid());
+ }
+
+ void TearDown() override {
+ // Remove the temp directory.
+ path_override_.reset();
+ ASSERT_TRUE(base::DeleteFile(fake_home_dir_, true));
+ }
+
+ protected:
+ base::FilePath fake_home_dir_; // Path to the test home directory.
+ base::FilePath minidump_dir_; // Path the the minidump directory.
+ base::FilePath lockfile_; // Path to the lockfile in |minidump_dir_|.
+
+ private:
+ scoped_ptr<base::ScopedPathOverride> path_override_;
+};
+
+} // namespace
+
+TEST_F(SynchronizedMinidumpManagerTest, FilePathsAreCorrect) {
+ SynchronizedMinidumpManagerSimple manager;
+
+ // Verify file paths for directory and lock file.
+ ASSERT_EQ(minidump_dir_.value(), manager.dump_path());
+ ASSERT_EQ(lockfile_.value(), manager.lockfile_path());
+}
+
+TEST_F(SynchronizedMinidumpManagerTest, AcquireLockOnNonExistentDirectory) {
+ // The directory was created in SetUp(). Delete it and its contents.
+ ASSERT_TRUE(base::DeleteFile(minidump_dir_, true));
+ ASSERT_FALSE(base::PathExists(minidump_dir_));
+
+ SynchronizedMinidumpManagerSimple manager;
+ ASSERT_EQ(0, manager.DoWorkLocked());
+ ASSERT_TRUE(manager.work_done());
+
+ // Verify the directory and the lockfile both exist.
+ ASSERT_TRUE(base::DirectoryExists(minidump_dir_));
+ ASSERT_TRUE(base::PathExists(lockfile_));
+}
+
+TEST_F(SynchronizedMinidumpManagerTest, AcquireLockOnExistingEmptyDirectory) {
+ // The lockfile was created in SetUp(). Delete it.
+ ASSERT_TRUE(base::DeleteFile(lockfile_, false));
+ ASSERT_FALSE(base::PathExists(lockfile_));
+
+ SynchronizedMinidumpManagerSimple manager;
+ ASSERT_EQ(0, manager.DoWorkLocked());
+ ASSERT_TRUE(manager.work_done());
+
+ // Verify the directory and the lockfile both exist.
+ ASSERT_TRUE(base::DirectoryExists(minidump_dir_));
+ ASSERT_TRUE(base::PathExists(lockfile_));
+}
+
+TEST_F(SynchronizedMinidumpManagerTest,
+ AcquireLockOnExistingDirectoryWithLockfile) {
+ SynchronizedMinidumpManagerSimple manager;
+ ASSERT_EQ(0, manager.DoWorkLocked());
+ ASSERT_TRUE(manager.work_done());
+
+ // Verify the directory and the lockfile both exist.
+ ASSERT_TRUE(base::DirectoryExists(minidump_dir_));
+ ASSERT_TRUE(base::PathExists(lockfile_));
+}
+
+TEST_F(SynchronizedMinidumpManagerTest,
+ AddEntryToLockFile_FailsWithInvalidEntry) {
+ // Test that the manager tried to log the entry and failed.
+ SynchronizedMinidumpManagerSimple manager;
+ manager.SetDumpInfoToWrite(make_scoped_ptr(new DumpInfo("")));
+ ASSERT_EQ(0, manager.DoWorkLocked());
+ ASSERT_EQ(-1, manager.add_entry_return_code());
+
+ // Verify the lockfile is untouched.
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile_.value());
+ ASSERT_EQ(0u, dumps.size());
+}
+
+TEST_F(SynchronizedMinidumpManagerTest,
+ AddEntryToLockFile_SucceedsWithValidEntries) {
+ // Sample parameters.
+ time_t now = time(0);
+ MinidumpParams params;
+ params.process_name = "process";
+
+ // Write the first entry.
+ SynchronizedMinidumpManagerSimple manager;
+ manager.SetDumpInfoToWrite(
+ make_scoped_ptr(new DumpInfo("dump1", "log1", now, params)));
+ ASSERT_EQ(0, manager.DoWorkLocked());
+ ASSERT_EQ(0, manager.add_entry_return_code());
+
+ // Test that the manager was successful in logging the entry.
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile_.value());
+ ASSERT_EQ(1u, dumps.size());
+
+ // Write the second entry.
+ manager.SetDumpInfoToWrite(
+ make_scoped_ptr(new DumpInfo("dump2", "log2", now, params)));
+ ASSERT_EQ(0, manager.DoWorkLocked());
+ ASSERT_EQ(0, manager.add_entry_return_code());
+
+ // Test that the second entry is also valid.
+ dumps = GetCurrentDumps(lockfile_.value());
+ ASSERT_EQ(2u, dumps.size());
+
+ // TODO(slan): Weird time incosistencies making this fail.
+ // ASSERT_EQ(dumps[0]->entry(), DumpInfo("dump", "log", now, params).entry());
+}
+
+TEST_F(SynchronizedMinidumpManagerTest,
+ AcquireLockFile_FailsWhenNonBlockingAndFileLocked) {
+ // Lock the lockfile here. Note that the Chromium base::File tools permit
+ // multiple locks on the same process to succeed, so we must use POSIX system
+ // calls to accomplish this.
+ int fd = open(lockfile_.value().c_str(), O_RDWR | O_CREAT, 0660);
+ ASSERT_GE(fd, 0);
+ ASSERT_EQ(0, flock(fd, LOCK_EX));
+
+ SynchronizedMinidumpManagerSimple manager;
+ manager.set_non_blocking(true);
+ ASSERT_EQ(-1, manager.DoWorkLocked());
+ ASSERT_FALSE(manager.work_done());
+
+ // Test that the manager was not able to log the crash dump.
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile_.value());
+ ASSERT_EQ(0u, dumps.size());
+}
+
+TEST_F(SynchronizedMinidumpManagerTest,
+ AcquireLockFile_WaitsForOtherThreadWhenBlocking) {
+ // Create some parameters for a minidump.
+ time_t now = time(0);
+ MinidumpParams params;
+ params.process_name = "process";
+
+ // Create a manager that grabs the lock then sleeps. Post a DoWork task to
+ // another thread. |sleepy_manager| will grab the lock and hold it for
+ // |sleep_time_ms|. It will then write a dump and release the lock.
+ const int sleep_time_ms = 100;
+ SleepySynchronizedMinidumpManagerSimple sleepy_manager(sleep_time_ms);
+ sleepy_manager.SetDumpInfoToWrite(
+ make_scoped_ptr(new DumpInfo("dump", "log", now, params)));
+ base::Thread sleepy_thread("sleepy");
+ sleepy_thread.Start();
+ sleepy_thread.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&DoWorkLockedTask, base::Unretained(&sleepy_manager)));
+
+ // Meanwhile, this thread should wait brielfy to allow the other thread to
+ // grab the lock.
+ const int concurrency_delay = 50;
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMilliseconds(concurrency_delay));
+
+ // |sleepy_manager| has the lock by now, but has not released it. Attempt to
+ // grab it. DoWorkLocked() should block until |manager| has a chance to write
+ // the dump.
+ SynchronizedMinidumpManagerSimple manager;
+ manager.SetDumpInfoToWrite(
+ make_scoped_ptr(new DumpInfo("dump", "log", now, params)));
+ manager.set_non_blocking(false);
+
+ EXPECT_EQ(0, manager.DoWorkLocked());
+ EXPECT_EQ(0, manager.add_entry_return_code());
+ EXPECT_TRUE(manager.work_done());
+
+ // Check that the other manager was also successful.
+ EXPECT_EQ(0, sleepy_manager.add_entry_return_code());
+ EXPECT_TRUE(sleepy_manager.work_done());
+
+ // Test that both entries were logged.
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile_.value());
+ EXPECT_EQ(2u, dumps.size());
+}
+
+// TODO(slan): These tests are passing but forking them is creating duplicates
+// of all tests in this thread. Figure out how to lock the file more cleanly
+// from another process.
+TEST_F(SynchronizedMinidumpManagerTest,
+ DISABLED_AcquireLockFile_FailsWhenNonBlockingAndLockedFromOtherProcess) {
+ // Fork the process.
+ pid_t pid = base::ForkWithFlags(0u, nullptr, nullptr);
+ if (pid != 0) {
+ // The child process should instantiate a manager which immediately grabs
+ // the lock, and falls aleep for some period of time, then writes a dump,
+ // and finally releases the lock.
+ SleepySynchronizedMinidumpManagerSimple sleepy_manager(100);
+ ASSERT_EQ(0, sleepy_manager.DoWorkLocked());
+ ASSERT_TRUE(sleepy_manager.work_done());
+ return;
+ }
+
+ // Meanwhile, this process should wait brielfy to allow the other thread to
+ // grab the lock.
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
+
+ SynchronizedMinidumpManagerSimple manager;
+ manager.set_non_blocking(true);
+ ASSERT_EQ(-1, manager.DoWorkLocked());
+ ASSERT_FALSE(manager.work_done());
+
+ // Test that the manager was not able to log the crash dump.
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile_.value());
+ ASSERT_EQ(0u, dumps.size());
+}
+
+// TODO(slan): These tests are passing but forking them is creating duplicates
+// of all tests in this thread. Figure out how to lock the file more cleanly
+// from another process.
+TEST_F(SynchronizedMinidumpManagerTest,
+ DISABLED_AcquireLockFile_WaitsForOtherProcessWhenBlocking) {
+ // Create some parameters for a minidump.
+ time_t now = time(0);
+ MinidumpParams params;
+ params.process_name = "process";
+
+ // Fork the process.
+ pid_t pid = base::ForkWithFlags(0u, nullptr, nullptr);
+ if (pid != 0) {
+ // The child process should instantiate a manager which immediately grabs
+ // the lock, and falls aleep for some period of time, then writes a dump,
+ // and finally releases the lock.
+ SleepySynchronizedMinidumpManagerSimple sleepy_manager(100);
+ sleepy_manager.SetDumpInfoToWrite(
+ make_scoped_ptr(new DumpInfo("dump", "log", now, params)));
+ ASSERT_EQ(0, sleepy_manager.DoWorkLocked());
+ ASSERT_TRUE(sleepy_manager.work_done());
+ return;
+ }
+
+ // Meanwhile, this process should wait brielfy to allow the other thread to
+ // grab the lock.
+ const int concurrency_delay = 50;
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMilliseconds(concurrency_delay));
+
+ // |sleepy_manager| has the lock by now, but has not released it. Attempt to
+ // grab it. DoWorkLocked() should block until |manager| has a chance to write
+ // the dump.
+ SynchronizedMinidumpManagerSimple manager;
+ manager.SetDumpInfoToWrite(
+ make_scoped_ptr(new DumpInfo("dump", "log", now, params)));
+ manager.set_non_blocking(false);
+
+ EXPECT_EQ(0, manager.DoWorkLocked());
+ EXPECT_EQ(0, manager.add_entry_return_code());
+ EXPECT_TRUE(manager.work_done());
+
+ // Test that both entries were logged.
+ ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile_.value());
+ EXPECT_EQ(2u, dumps.size());
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/graphics/cast_egl_platform_default.cc b/chromium/chromecast/graphics/cast_egl_platform_default.cc
index 3cb9a1b8c32..9a59408c681 100644
--- a/chromium/chromecast/graphics/cast_egl_platform_default.cc
+++ b/chromium/chromecast/graphics/cast_egl_platform_default.cc
@@ -29,6 +29,7 @@ class EglPlatformDefault : public CastEglPlatform {
return nullptr;
}
void DestroyWindow(NativeWindowType window) override {}
+ bool MultipleSurfaceUnsupported() override { return false; }
};
} // namespace
diff --git a/chromium/chromecast/graphics/cast_screen.cc b/chromium/chromecast/graphics/cast_screen.cc
new file mode 100644
index 00000000000..2cf113f8ff6
--- /dev/null
+++ b/chromium/chromecast/graphics/cast_screen.cc
@@ -0,0 +1,88 @@
+// Copyright 2015 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/graphics/cast_screen.h"
+
+#include "ui/aura/env.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/screen.h"
+
+namespace chromecast {
+
+namespace {
+
+const int64 kDisplayId = 1;
+
+const int k720pWidth = 1280;
+const int k720pHeight = 720;
+
+// When CastScreen is first initialized, we may not have any display info
+// available. These constants hold the initial size that we default to, and
+// the size can be updated when we have actual display info at hand with
+// UpdateDisplaySize().
+const int kInitDisplayWidth = k720pWidth;
+const int kInitDisplayHeight = k720pHeight;
+
+} // namespace
+
+CastScreen::~CastScreen() {
+}
+
+void CastScreen::UpdateDisplaySize(const gfx::Size& size) {
+ display_.SetScaleAndBounds(1.0f, gfx::Rect(size));
+}
+
+gfx::Point CastScreen::GetCursorScreenPoint() {
+ return aura::Env::GetInstance()->last_mouse_location();
+}
+
+gfx::NativeWindow CastScreen::GetWindowUnderCursor() {
+ NOTIMPLEMENTED();
+ return gfx::NativeWindow(nullptr);
+}
+
+gfx::NativeWindow CastScreen::GetWindowAtScreenPoint(const gfx::Point& point) {
+ NOTIMPLEMENTED();
+ return gfx::NativeWindow(nullptr);
+}
+
+int CastScreen::GetNumDisplays() const {
+ return 1;
+}
+
+std::vector<gfx::Display> CastScreen::GetAllDisplays() const {
+ return std::vector<gfx::Display>(1, display_);
+}
+
+gfx::Display CastScreen::GetDisplayNearestWindow(
+ gfx::NativeWindow window) const {
+ return display_;
+}
+
+gfx::Display CastScreen::GetDisplayNearestPoint(const gfx::Point& point) const {
+ return display_;
+}
+
+gfx::Display CastScreen::GetDisplayMatching(const gfx::Rect& match_rect) const {
+ return display_;
+}
+
+gfx::Display CastScreen::GetPrimaryDisplay() const {
+ return display_;
+}
+
+void CastScreen::AddObserver(gfx::DisplayObserver* observer) {
+}
+
+void CastScreen::RemoveObserver(gfx::DisplayObserver* observer) {
+}
+
+CastScreen::CastScreen() : display_(kDisplayId) {
+ display_.SetScaleAndBounds(1.0f,
+ gfx::Rect(kInitDisplayWidth, kInitDisplayHeight));
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/graphics/cast_screen.h b/chromium/chromecast/graphics/cast_screen.h
new file mode 100644
index 00000000000..50fbf70931d
--- /dev/null
+++ b/chromium/chromecast/graphics/cast_screen.h
@@ -0,0 +1,54 @@
+// Copyright 2015 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_GRAPHICS_CAST_SCREEN_H_
+#define CHROMECAST_GRAPHICS_CAST_SCREEN_H_
+
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
+
+namespace chromecast {
+
+namespace shell {
+class CastBrowserMainParts;
+} // namespace shell
+
+// CastScreen is Chromecast's own minimal implementation of gfx::Screen.
+// Right now, it almost exactly duplicates the behavior of aura's TestScreen
+// class for necessary methods. The instantiation of CastScreen occurs in
+// CastBrowserMainParts, where its ownership is assigned to CastBrowserProcess.
+// To then subsequently access CastScreen, see CastBrowerProcess.
+class CastScreen : public gfx::Screen {
+ public:
+ ~CastScreen() override;
+
+ // Updates the primary display size.
+ void UpdateDisplaySize(const gfx::Size& size);
+
+ // gfx::Screen overrides:
+ gfx::Point GetCursorScreenPoint() override;
+ gfx::NativeWindow GetWindowUnderCursor() override;
+ gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override;
+ int GetNumDisplays() const override;
+ std::vector<gfx::Display> GetAllDisplays() const override;
+ gfx::Display GetDisplayNearestWindow(gfx::NativeView view) const override;
+ gfx::Display GetDisplayNearestPoint(const gfx::Point& point) const override;
+ gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) const override;
+ gfx::Display GetPrimaryDisplay() const override;
+ void AddObserver(gfx::DisplayObserver* observer) override;
+ void RemoveObserver(gfx::DisplayObserver* observer) override;
+
+ private:
+ CastScreen();
+
+ gfx::Display display_;
+
+ friend class shell::CastBrowserMainParts;
+
+ DISALLOW_COPY_AND_ASSIGN(CastScreen);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_GRAPHICS_CAST_SCREEN_H_
diff --git a/chromium/chromecast/media/BUILD.gn b/chromium/chromecast/media/BUILD.gn
index 6a8c6a6a3df..eb95dcd3903 100644
--- a/chromium/chromecast/media/BUILD.gn
+++ b/chromium/chromecast/media/BUILD.gn
@@ -12,18 +12,20 @@ group("media") {
]
}
-test("unittests") {
+test("cast_media_unittests") {
sources = [
- "//media/base",
"cma/backend/audio_video_pipeline_device_unittest.cc",
"cma/base/balanced_media_task_runner_unittest.cc",
"cma/base/buffering_controller_unittest.cc",
"cma/base/buffering_frame_provider_unittest.cc",
"cma/filters/demuxer_stream_adapter_unittest.cc",
+ "cma/filters/multi_demuxer_stream_adapter_unittest.cc",
"cma/ipc/media_message_fifo_unittest.cc",
"cma/ipc/media_message_unittest.cc",
"cma/ipc_streamer/av_streamer_unittest.cc",
"cma/pipeline/audio_video_pipeline_impl_unittest.cc",
+ "cma/test/demuxer_stream_for_test.cc",
+ "cma/test/demuxer_stream_for_test.h",
"cma/test/frame_generator_for_test.cc",
"cma/test/frame_generator_for_test.h",
"cma/test/frame_segmenter_for_test.cc",
@@ -37,17 +39,19 @@ test("unittests") {
"cma/test/run_all_unittests.cc",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
":media",
"//base",
"//base:i18n",
"//base/test:test_support",
"//chromecast/base/metrics:test_support",
+ "//chromecast/public",
"//media",
"//media/base:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//ui/gfx/geometry",
]
-
- configs += [ "//chromecast:config" ]
}
diff --git a/chromium/chromecast/media/DEPS b/chromium/chromecast/media/DEPS
index f2506bb5ad6..f980e38b56d 100644
--- a/chromium/chromecast/media/DEPS
+++ b/chromium/chromecast/media/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+gpu",
"+media/base",
"+media/cdm",
"+media/renderers",
diff --git a/chromium/chromecast/media/base/BUILD.gn b/chromium/chromecast/media/base/BUILD.gn
index 64992f331f2..e47f8500b04 100644
--- a/chromium/chromecast/media/base/BUILD.gn
+++ b/chromium/chromecast/media/base/BUILD.gn
@@ -5,6 +5,10 @@
import("//build/config/crypto.gni")
import("//chromecast/chromecast.gni")
+declare_args() {
+ libcast_media_target = ""
+}
+
source_set("base") {
sources = [
"decrypt_context.cc",
@@ -15,24 +19,44 @@ source_set("base") {
"key_systems_common.h",
"media_caps.cc",
"media_caps.h",
+ "media_message_loop.cc",
+ "media_message_loop.h",
"switching_media_renderer.cc",
"switching_media_renderer.h",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
"//base",
"//crypto",
"//crypto:platform",
+ "//media",
"//third_party/widevine/cdm:version_h",
]
- configs += [ "//chromecast:config" ]
-
if (is_chromecast_chrome_branded) {
deps += [
+ "${libcast_media_target}",
# TODO(gyp): add dependency on internal/chromecast_internal:media_base_internal
]
} else {
sources += [ "key_systems_common_simple.cc" ]
+
+ deps += [ ":libcast_media_default" ]
}
}
+
+shared_library("libcast_media_default") {
+ output_name = "libcast_media_1.0"
+
+ sources = [
+ "cast_media_default.cc",
+ ]
+
+ configs += [ "//chromecast:config" ]
+
+ deps = [
+ "//chromecast/public",
+ ]
+}
diff --git a/chromium/chromecast/media/base/cast_media_default.cc b/chromium/chromecast/media/base/cast_media_default.cc
index 0cc03d38705..0c177126ad6 100644
--- a/chromium/chromecast/media/base/cast_media_default.cc
+++ b/chromium/chromecast/media/base/cast_media_default.cc
@@ -3,14 +3,43 @@
// found in the LICENSE file.
#include "chromecast/public/cast_media_shlib.h"
+#include "chromecast/public/graphics_types.h"
+#include "chromecast/public/video_plane.h"
namespace chromecast {
namespace media {
+namespace {
+
+class DefaultVideoPlane : public VideoPlane {
+ public:
+ ~DefaultVideoPlane() override {}
+
+ Size GetScreenResolution() override {
+ return Size(1920, 1080);
+ }
+
+ void SetGeometry(const RectF& display_rect,
+ CoordinateType coordinate_type,
+ Transform transform) override {}
+
+ void OnScreenResolutionChanged(const Size& screen_res) override {}
+};
+
+DefaultVideoPlane* g_video_plane = nullptr;
+
+} // namespace
void CastMediaShlib::Initialize(const std::vector<std::string>& argv) {
+ g_video_plane = new DefaultVideoPlane();
}
void CastMediaShlib::Finalize() {
+ delete g_video_plane;
+ g_video_plane = nullptr;
+}
+
+VideoPlane* CastMediaShlib::GetVideoPlane() {
+ return g_video_plane;
}
} // namespace media
diff --git a/chromium/chromecast/browser/media/cma_message_loop.cc b/chromium/chromecast/media/base/media_message_loop.cc
index 8ba93e01c99..17e22132d73 100644
--- a/chromium/chromecast/browser/media/cma_message_loop.cc
+++ b/chromium/chromecast/media/base/media_message_loop.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chromecast/browser/media/cma_message_loop.h"
+#include "chromecast/media/base/media_message_loop.h"
#include "base/threading/thread.h"
@@ -10,26 +10,21 @@ namespace chromecast {
namespace media {
// static
-scoped_refptr<base::MessageLoopProxy> CmaMessageLoop::GetMessageLoopProxy() {
- return GetInstance()->thread_->message_loop_proxy();
-}
-
-// static
-scoped_refptr<base::SingleThreadTaskRunner> CmaMessageLoop::GetTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner> MediaMessageLoop::GetTaskRunner() {
return GetInstance()->thread_->task_runner();
}
// static
-CmaMessageLoop* CmaMessageLoop::GetInstance() {
- return Singleton<CmaMessageLoop>::get();
+MediaMessageLoop* MediaMessageLoop::GetInstance() {
+ return Singleton<MediaMessageLoop>::get();
}
-CmaMessageLoop::CmaMessageLoop()
+MediaMessageLoop::MediaMessageLoop()
: thread_(new base::Thread("CmaThread")) {
thread_->Start();
}
-CmaMessageLoop::~CmaMessageLoop() {
+MediaMessageLoop::~MediaMessageLoop() {
// This will automatically shutdown the thread.
}
diff --git a/chromium/chromecast/media/base/media_message_loop.h b/chromium/chromecast/media/base/media_message_loop.h
new file mode 100644
index 00000000000..e9f1e09abc2
--- /dev/null
+++ b/chromium/chromecast/media/base/media_message_loop.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef CHROMECAST_MEDIA_BASE_MEDIA_MESSAGE_LOOP_H_
+#define CHROMECAST_MEDIA_BASE_MEDIA_MESSAGE_LOOP_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+class Thread;
+}
+
+namespace chromecast {
+namespace media {
+
+class MediaMessageLoop {
+ public:
+ static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner();
+
+ private:
+ friend struct DefaultSingletonTraits<MediaMessageLoop>;
+ friend class Singleton<MediaMessageLoop>;
+
+ static MediaMessageLoop* GetInstance();
+
+ MediaMessageLoop();
+ ~MediaMessageLoop();
+
+ scoped_ptr<base::Thread> thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaMessageLoop);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_BASE_MEDIA_MESSAGE_LOOP_H_
diff --git a/chromium/chromecast/media/cdm/browser_cdm_cast.cc b/chromium/chromecast/media/cdm/browser_cdm_cast.cc
index b62df02cb8b..607c03d9ee7 100644
--- a/chromium/chromecast/media/cdm/browser_cdm_cast.cc
+++ b/chromium/chromecast/media/cdm/browser_cdm_cast.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "media/base/cdm_key_information.h"
#include "media/base/cdm_promise.h"
#include "media/cdm/player_tracker_impl.h"
@@ -54,28 +54,16 @@ void BrowserCdmCast::UnregisterPlayer(int registration_id) {
player_tracker_impl_->UnregisterPlayer(registration_id);
}
-void BrowserCdmCast::LoadSession(
- ::media::MediaKeys::SessionType session_type,
- const std::string& session_id,
- scoped_ptr<::media::NewSessionCdmPromise> promise) {
- NOTREACHED() << "LoadSession not supported";
- legacy_session_error_cb_.Run(
- session_id, ::media::MediaKeys::Exception::NOT_SUPPORTED_ERROR, 0,
- std::string());
-}
-
::media::CdmContext* BrowserCdmCast::GetCdmContext() {
NOTREACHED();
return nullptr;
}
-void BrowserCdmCast::OnSessionMessage(const std::string& session_id,
- const std::vector<uint8_t>& message,
- const GURL& destination_url) {
- // Note: Message type is not supported in Chromecast. Do our best guess here.
- ::media::MediaKeys::MessageType message_type =
- destination_url.is_empty() ? ::media::MediaKeys::LICENSE_REQUEST
- : ::media::MediaKeys::LICENSE_RENEWAL;
+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,
@@ -101,24 +89,22 @@ void BrowserCdmCast::OnSessionKeysChange(
player_tracker_impl_->NotifyNewKey();
}
-// A macro runs current member function on |cdm_loop_| thread.
+// A macro runs current member function on |task_runner_| thread.
#define FORWARD_ON_CDM_THREAD(param_fn, ...) \
- cdm_loop_->PostTask( \
- FROM_HERE, \
- base::Bind(&BrowserCdmCast::param_fn, \
+ task_runner_->PostTask( \
+ FROM_HERE, \
+ base::Bind(&BrowserCdmCast::param_fn, \
base::Unretained(browser_cdm_cast_.get()), ##__VA_ARGS__))
-
BrowserCdmCastUi::BrowserCdmCastUi(
scoped_ptr<BrowserCdmCast> browser_cdm_cast,
- const scoped_refptr<base::MessageLoopProxy>& cdm_loop)
- : browser_cdm_cast_(browser_cdm_cast.Pass()),
- cdm_loop_(cdm_loop) {
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : browser_cdm_cast_(browser_cdm_cast.Pass()), task_runner_(task_runner) {
}
BrowserCdmCastUi::~BrowserCdmCastUi() {
DCHECK(thread_checker_.CalledOnValidThread());
- cdm_loop_->DeleteSoon(FROM_HERE, browser_cdm_cast_.release());
+ task_runner_->DeleteSoon(FROM_HERE, browser_cdm_cast_.release());
}
int BrowserCdmCastUi::RegisterPlayer(const base::Closure& new_key_cb,
diff --git a/chromium/chromecast/media/cdm/browser_cdm_cast.h b/chromium/chromecast/media/cdm/browser_cdm_cast.h
index 7a83a08dcc8..0e24a518975 100644
--- a/chromium/chromecast/media/cdm/browser_cdm_cast.h
+++ b/chromium/chromecast/media/cdm/browser_cdm_cast.h
@@ -19,7 +19,7 @@
#include "media/cdm/json_web_key.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace media {
@@ -55,9 +55,6 @@ class BrowserCdmCast : public ::media::BrowserCdm {
void UnregisterPlayer(int registration_id) override;
// ::media::BrowserCdm implementation:
- void LoadSession(::media::MediaKeys::SessionType session_type,
- const std::string& session_id,
- scoped_ptr<::media::NewSessionCdmPromise> promise) override;
::media::CdmContext* GetCdmContext() override;
// Returns the decryption context needed to decrypt frames encrypted with
@@ -69,7 +66,8 @@ class BrowserCdmCast : public ::media::BrowserCdm {
protected:
void OnSessionMessage(const std::string& session_id,
const std::vector<uint8_t>& message,
- const GURL& destination_url);
+ const GURL& destination_url,
+ ::media::MediaKeys::MessageType message_type);
void OnSessionClosed(const std::string& session_id);
void OnSessionKeysChange(const std::string& session_id,
const ::media::KeyIdAndKeyPairs& keys);
@@ -101,7 +99,7 @@ class BrowserCdmCastUi : public ::media::BrowserCdm {
public:
BrowserCdmCastUi(
scoped_ptr<BrowserCdmCast> browser_cdm_cast,
- const scoped_refptr<base::MessageLoopProxy>& cdm_loop);
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
~BrowserCdmCastUi() override;
// PlayerTracker implementation:
@@ -134,7 +132,7 @@ class BrowserCdmCastUi : public ::media::BrowserCdm {
::media::CdmContext* GetCdmContext() override;
scoped_ptr<BrowserCdmCast> browser_cdm_cast_;
- scoped_refptr<base::MessageLoopProxy> cdm_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/chromecast/media/cdm/chromecast_init_data.cc b/chromium/chromecast/media/cdm/chromecast_init_data.cc
new file mode 100644
index 00000000000..7f4d03fed00
--- /dev/null
+++ b/chromium/chromecast/media/cdm/chromecast_init_data.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 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/chromecast_init_data.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "media/base/bit_reader.h"
+#include "media/cdm/cenc_utils.h"
+
+namespace chromecast {
+namespace media {
+
+#define RCHECK(x) \
+ do { \
+ if (!(x)) \
+ return false; \
+ } while (0)
+
+namespace {
+
+const uint8_t kChromecastPlayreadyUuid[] = {
+ 0x2b, 0xf8, 0x66, 0x80, 0xc6, 0xe5, 0x4e, 0x24,
+ 0xbe, 0x23, 0x0f, 0x81, 0x5a, 0x60, 0x6e, 0xb2};
+
+} // namespace
+
+ChromecastInitData::ChromecastInitData() {
+}
+
+ChromecastInitData::~ChromecastInitData() {
+}
+
+bool FindChromecastInitData(const std::vector<uint8_t>& init_data,
+ InitDataMessageType type,
+ ChromecastInitData* chromecast_init_data_out) {
+ // Chromecast initData assumes a CENC data format and searches for PSSH boxes
+ // with SystemID |kChromecastPlayreadyUuid|. The PSSH box content is as
+ // follows:
+ // * |type| (2 bytes, InitDataMessageType)
+ // * |data| (all remaining bytes)
+ // Data may or may not be present and is specific to the given |type|.
+
+ std::vector<uint8_t> pssh_data;
+ if (!::media::GetPsshData(
+ init_data, std::vector<uint8_t>(kChromecastPlayreadyUuid,
+ kChromecastPlayreadyUuid +
+ sizeof(kChromecastPlayreadyUuid)),
+ &pssh_data)) {
+ return false;
+ }
+
+ ::media::BitReader reader(vector_as_array(&pssh_data), pssh_data.size());
+
+ uint16_t msg_type;
+ RCHECK(reader.ReadBits(2 * 8, &msg_type));
+ RCHECK(msg_type < static_cast<uint16_t>(InitDataMessageType::END));
+ RCHECK(msg_type == static_cast<uint16_t>(type));
+
+ chromecast_init_data_out->type = static_cast<InitDataMessageType>(msg_type);
+ chromecast_init_data_out->data.assign(
+ pssh_data.begin() + reader.bits_read() / 8, pssh_data.end());
+ return true;
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cdm/chromecast_init_data.h b/chromium/chromecast/media/cdm/chromecast_init_data.h
new file mode 100644
index 00000000000..d7de627e64f
--- /dev/null
+++ b/chromium/chromecast/media/cdm/chromecast_init_data.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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_INIT_DATA_H_
+#define CHROMECAST_MEDIA_CDM_INIT_DATA_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace chromecast {
+namespace media {
+
+enum class InitDataMessageType {
+ UNKNOWN = 0x0,
+ CUSTOM_DATA = 0x1,
+ ENABLE_SECURE_STOP = 0x2,
+ END
+};
+
+// Structured data for EME initialization as parsed from an initData blob.
+struct ChromecastInitData {
+ ChromecastInitData();
+ ~ChromecastInitData();
+
+ InitDataMessageType type;
+ std::vector<uint8_t> data;
+};
+
+// Searches for a ChromecastInitData blob inside a CENC |init_data| message of
+// type |type|. If such a blob is found, returns true and fills
+// |chromecast_init_data_out|. If not found, returns false.
+bool FindChromecastInitData(const std::vector<uint8_t>& init_data,
+ InitDataMessageType type,
+ ChromecastInitData* chromecast_init_data_out);
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CDM_INIT_DATA_H_
diff --git a/chromium/chromecast/media/cdm/chromecast_init_data_unittest.cc b/chromium/chromecast/media/cdm/chromecast_init_data_unittest.cc
new file mode 100644
index 00000000000..640b95c8376
--- /dev/null
+++ b/chromium/chromecast/media/cdm/chromecast_init_data_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 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/chromecast_init_data.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace media {
+
+TEST(ChromecastInitDataTest, TestPsshCustomData) {
+ const uint8_t kInitDataBlob[] = {
+ 0x00, 0x00, 0x00, 0x32, // length
+ 0x70, 0x73, 0x73, 0x68, // 'pssh'
+ 0x00, 0x00, 0x00, 0x00, // version / flags
+ 0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24, 0xBE,
+ 0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2, // UUID
+ 0x00, 0x00, 0x00, 0x12, // data size
+ 0x00, 0x01, // message type (CUSTOM_DATA)
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x63, 0x75, 0x73, 0x74,
+ 0x6F, 0x6D, 0x20, 0x64, 0x61, 0x74, 0x61 // 'Test custom data'
+ };
+
+ ChromecastInitData init_data;
+ EXPECT_TRUE(FindChromecastInitData(
+ std::vector<uint8_t>(kInitDataBlob,
+ kInitDataBlob + sizeof(kInitDataBlob)),
+ InitDataMessageType::CUSTOM_DATA, &init_data));
+
+ EXPECT_EQ(InitDataMessageType::CUSTOM_DATA, init_data.type);
+ EXPECT_EQ(16u, init_data.data.size());
+ EXPECT_EQ("Test custom data",
+ std::string(init_data.data.begin(), init_data.data.end()));
+}
+
+TEST(ChromecastInitDataTest, TestPsshCustomData_NoSize) {
+ const uint8_t kInitDataBlob[] = {
+ 0x00, 0x00, 0x00, 0x2E, // length
+ 0x70, 0x73, 0x73, 0x68, // 'pssh'
+ 0x00, 0x00, 0x00, 0x00, // version / flags
+ 0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24, 0xBE,
+ 0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2, // UUID
+ // [missing size should be present here].
+ 0x00, 0x01, // message type (CUSTOM_DATA)
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x63, 0x75, 0x73, 0x74,
+ 0x6F, 0x6D, 0x20, 0x64, 0x61, 0x74, 0x61 // 'Test custom data'
+ };
+
+ ChromecastInitData init_data;
+ EXPECT_FALSE(FindChromecastInitData(
+ std::vector<uint8_t>(kInitDataBlob,
+ kInitDataBlob + sizeof(kInitDataBlob)),
+ InitDataMessageType::CUSTOM_DATA, &init_data));
+}
+
+TEST(ChromecastInitDataTest, TestPsshSecureStop) {
+ const uint8_t kInitDataBlob[] = {
+ 0x00, 0x00, 0x00, 0x22, // length
+ 0x70, 0x73, 0x73, 0x68, // 'pssh'
+ 0x00, 0x00, 0x00, 0x00, // version / flags
+ 0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24,
+ 0xBE, 0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2, // UUID
+ 0x00, 0x00, 0x00, 0x02, // data size
+ 0x00, 0x02, // message type (ENABLE_SECURE_STOP)
+ };
+
+ ChromecastInitData init_data;
+ EXPECT_TRUE(FindChromecastInitData(
+ std::vector<uint8_t>(kInitDataBlob,
+ kInitDataBlob + sizeof(kInitDataBlob)),
+ InitDataMessageType::ENABLE_SECURE_STOP, &init_data));
+
+ EXPECT_EQ(InitDataMessageType::ENABLE_SECURE_STOP, init_data.type);
+ EXPECT_EQ(0u, init_data.data.size());
+}
+
+TEST(ChromecastInitDataTest, TestPsshSecureStop_NoSize) {
+ const uint8_t kInitDataBlob[] = {
+ 0x00, 0x00, 0x00, 0x1E, // length
+ 0x70, 0x73, 0x73, 0x68, // 'pssh'
+ 0x00, 0x00, 0x00, 0x00, // version / flags
+ 0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24,
+ 0xBE, 0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2, // UUID
+ // [missing size should be present here].
+ 0x00, 0x02, // message type (ENABLE_SECURE_STOP)
+ };
+
+ ChromecastInitData init_data;
+ EXPECT_FALSE(FindChromecastInitData(
+ std::vector<uint8_t>(kInitDataBlob,
+ kInitDataBlob + sizeof(kInitDataBlob)),
+ InitDataMessageType::ENABLE_SECURE_STOP, &init_data));
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cdm/playready_drm_delegate_android.cc b/chromium/chromecast/media/cdm/playready_drm_delegate_android.cc
index 135fc44bd52..2cb856bdefc 100644
--- a/chromium/chromecast/media/cdm/playready_drm_delegate_android.cc
+++ b/chromium/chromecast/media/cdm/playready_drm_delegate_android.cc
@@ -5,7 +5,7 @@
#include "chromecast/media/cdm/playready_drm_delegate_android.h"
#include "base/logging.h"
-#include "media/base/bit_reader.h"
+#include "chromecast/media/cdm/chromecast_init_data.h"
namespace chromecast {
namespace media {
@@ -14,13 +14,6 @@ const uint8_t kPlayreadyUuid[16] = {
0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86,
0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95};
-const uint8_t kPlayreadyCustomDataUuid[] = {
- 0x2b, 0xf8, 0x66, 0x80, 0xc6, 0xe5, 0x4e, 0x24,
- 0xbe, 0x23, 0x0f, 0x81, 0x5a, 0x60, 0x6e, 0xb2};
-
-// ASCII "uuid" as an 4-byte integer
-const uint32_t kBoxTypeUuid = 1970628964;
-
PlayreadyDrmDelegateAndroid::PlayreadyDrmDelegateAndroid() {
}
@@ -34,47 +27,18 @@ const ::media::UUID PlayreadyDrmDelegateAndroid::GetUUID() const {
bool PlayreadyDrmDelegateAndroid::OnCreateSession(
const ::media::EmeInitDataType init_data_type,
- const std::vector<uint8_t>& init_data,
- std::vector<uint8_t>* /* init_data_out */,
- std::vector<std::string>* optional_parameters_out) {
+ const std::vector<uint8_t>& init_data,
+ std::vector<uint8_t>* /* init_data_out */,
+ std::vector<std::string>* optional_parameters_out) {
if (init_data_type == ::media::EmeInitDataType::CENC) {
- ::media::BitReader reader(&init_data[0], init_data.size());
- while (reader.bits_available() > 64) {
- uint32_t box_size;
- uint32_t box_type;
- reader.ReadBits(32, &box_size);
- reader.ReadBits(32, &box_type);
- int bytes_read = 8;
-
- if (box_type != kBoxTypeUuid) {
- if (box_size < 8 + sizeof(kPlayreadyCustomDataUuid)) {
- break;
- }
- // Box size includes the bytes already consumed
- reader.SkipBits((box_size - bytes_read) * 8);
- continue;
- }
-
- // "uuid" was found, look for custom data format as per b/10246367
- reader.SkipBits(128);
- bytes_read += 16;
- if (!memcmp(&init_data[0] + reader.bits_read() / 8,
- kPlayreadyCustomDataUuid, 16)) {
- reader.SkipBits((box_size - bytes_read) * 8);
- continue;
- }
-
- int custom_data_size = box_size - bytes_read;
- DCHECK(reader.bits_read() % 8 == 0);
- int total_bytes_read = reader.bits_read() / 8;
-
+ ChromecastInitData custom_data;
+ if (FindChromecastInitData(init_data, InitDataMessageType::CUSTOM_DATA,
+ &custom_data)) {
optional_parameters_out->clear();
optional_parameters_out->push_back("PRCustomData");
optional_parameters_out->push_back(
- std::string(&init_data[0] + total_bytes_read,
- &init_data[0] + total_bytes_read + custom_data_size));
- reader.SkipBits(custom_data_size * 8);
- LOG(INFO) << "Including " << custom_data_size
+ std::string(custom_data.data.begin(), custom_data.data.end()));
+ LOG(INFO) << "Including " << custom_data.data.size()
<< " bytes of custom PlayReady data";
}
}
diff --git a/chromium/chromecast/media/cma/backend/BUILD.gn b/chromium/chromecast/media/cma/backend/BUILD.gn
index 6526a1f746b..51e62441010 100644
--- a/chromium/chromecast/media/cma/backend/BUILD.gn
+++ b/chromium/chromecast/media/cma/backend/BUILD.gn
@@ -6,24 +6,28 @@ source_set("backend") {
sources = [
"audio_pipeline_device.cc",
"audio_pipeline_device.h",
+ "audio_pipeline_device_default.cc",
+ "audio_pipeline_device_default.h",
"media_clock_device.cc",
"media_clock_device.h",
+ "media_clock_device_default.cc",
+ "media_clock_device_default.h",
"media_component_device.cc",
"media_component_device.h",
+ "media_component_device_default.cc",
+ "media_component_device_default.h",
"media_pipeline_device.cc",
"media_pipeline_device.h",
- "media_pipeline_device_fake.cc",
- "media_pipeline_device_fake.h",
- "media_pipeline_device_fake_factory.cc",
+ "media_pipeline_device_factory.h",
+ "media_pipeline_device_factory_default.cc",
+ "media_pipeline_device_factory_default.h",
+ "media_pipeline_device_factory_simple.cc",
"media_pipeline_device_params.cc",
"media_pipeline_device_params.h",
"video_pipeline_device.cc",
"video_pipeline_device.h",
- "video_plane.cc",
- "video_plane.h",
- "video_plane_fake.cc",
- "video_plane_fake.h",
- "video_plane_fake_factory.cc",
+ "video_pipeline_device_default.cc",
+ "video_pipeline_device_default.h",
]
deps = [
diff --git a/chromium/chromecast/media/cma/backend/audio_pipeline_device_default.cc b/chromium/chromecast/media/cma/backend/audio_pipeline_device_default.cc
new file mode 100644
index 00000000000..6d1bb8d500b
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/audio_pipeline_device_default.cc
@@ -0,0 +1,84 @@
+// Copyright 2015 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/audio_pipeline_device_default.h"
+
+#include "chromecast/media/cma/backend/media_component_device_default.h"
+
+namespace chromecast {
+namespace media {
+
+AudioPipelineDeviceDefault::AudioPipelineDeviceDefault(
+ MediaClockDevice* media_clock_device)
+ : pipeline_(new MediaComponentDeviceDefault(media_clock_device)) {
+ DetachFromThread();
+}
+
+AudioPipelineDeviceDefault::~AudioPipelineDeviceDefault() {
+}
+
+void AudioPipelineDeviceDefault::SetClient(const Client& client) {
+ pipeline_->SetClient(client);
+}
+
+MediaComponentDevice::State AudioPipelineDeviceDefault::GetState() const {
+ return pipeline_->GetState();
+}
+
+bool AudioPipelineDeviceDefault::SetState(State new_state) {
+ bool success = pipeline_->SetState(new_state);
+ if (!success)
+ return false;
+
+ if (new_state == kStateIdle) {
+ DCHECK(IsValidConfig(config_));
+ }
+ if (new_state == kStateUninitialized) {
+ config_ = AudioConfig();
+ }
+ return true;
+}
+
+bool AudioPipelineDeviceDefault::SetStartPts(base::TimeDelta time) {
+ return pipeline_->SetStartPts(time);
+}
+
+MediaComponentDevice::FrameStatus AudioPipelineDeviceDefault::PushFrame(
+ const scoped_refptr<DecryptContext>& decrypt_context,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const FrameStatusCB& completion_cb) {
+ return pipeline_->PushFrame(decrypt_context, buffer, completion_cb);
+}
+
+base::TimeDelta AudioPipelineDeviceDefault::GetRenderingTime() const {
+ return pipeline_->GetRenderingTime();
+}
+
+base::TimeDelta AudioPipelineDeviceDefault::GetRenderingDelay() const {
+ return pipeline_->GetRenderingDelay();
+}
+
+bool AudioPipelineDeviceDefault::SetConfig(const AudioConfig& config) {
+ DCHECK(CalledOnValidThread());
+ if (!IsValidConfig(config))
+ return false;
+ config_ = config;
+ if (config.extra_data_size > 0)
+ config_extra_data_.assign(config.extra_data,
+ config.extra_data + config.extra_data_size);
+ else
+ config_extra_data_.clear();
+ return true;
+}
+
+void AudioPipelineDeviceDefault::SetStreamVolumeMultiplier(float multiplier) {
+ DCHECK(CalledOnValidThread());
+}
+
+bool AudioPipelineDeviceDefault::GetStatistics(Statistics* stats) const {
+ return pipeline_->GetStatistics(stats);
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/audio_pipeline_device_default.h b/chromium/chromecast/media/cma/backend/audio_pipeline_device_default.h
new file mode 100644
index 00000000000..f8a1a84c1d5
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/audio_pipeline_device_default.h
@@ -0,0 +1,52 @@
+// Copyright 2015 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_AUDIO_PIPELINE_DEVICE_DEFAULT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_PIPELINE_DEVICE_DEFAULT_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "chromecast/media/cma/backend/audio_pipeline_device.h"
+#include "chromecast/public/media/decoder_config.h"
+
+namespace chromecast {
+namespace media {
+
+class MediaClockDevice;
+class MediaComponentDeviceDefault;
+
+class AudioPipelineDeviceDefault : public AudioPipelineDevice {
+ public:
+ explicit AudioPipelineDeviceDefault(MediaClockDevice* media_clock_device);
+ ~AudioPipelineDeviceDefault() override;
+
+ // AudioPipelineDevice implementation.
+ void SetClient(const Client& client) override;
+ State GetState() const override;
+ bool SetState(State new_state) override;
+ bool SetStartPts(base::TimeDelta time) override;
+ FrameStatus PushFrame(
+ const scoped_refptr<DecryptContext>& decrypt_context,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const FrameStatusCB& completion_cb) override;
+ base::TimeDelta GetRenderingTime() const override;
+ base::TimeDelta GetRenderingDelay() const override;
+ bool SetConfig(const AudioConfig& config) override;
+ void SetStreamVolumeMultiplier(float multiplier) override;
+ bool GetStatistics(Statistics* stats) const override;
+
+ private:
+ scoped_ptr<MediaComponentDeviceDefault> pipeline_;
+
+ AudioConfig config_;
+ std::vector<uint8_t> config_extra_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioPipelineDeviceDefault);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_PIPELINE_DEVICE_DEFAULT_H_
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 972d20af679..9c84b2f4ee4 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
@@ -14,14 +14,16 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chromecast/media/base/decrypt_context.h"
#include "chromecast/media/cma/backend/audio_pipeline_device.h"
#include "chromecast/media/cma/backend/media_clock_device.h"
#include "chromecast/media/cma/backend/media_pipeline_device.h"
+#include "chromecast/media/cma/backend/media_pipeline_device_factory.h"
#include "chromecast/media/cma/backend/media_pipeline_device_params.h"
#include "chromecast/media/cma/backend/video_pipeline_device.h"
#include "chromecast/media/cma/base/decoder_buffer_adapter.h"
@@ -168,7 +170,8 @@ void AudioVideoPipelineDeviceTest::LoadAudioStream(std::string filename) {
media_pipeline_device_->GetAudioPipelineDevice();
bool success = audio_pipeline_device->SetConfig(
- DecoderConfigAdapter::ToCastAudioConfig(demux_result.audio_config));
+ DecoderConfigAdapter::ToCastAudioConfig(kPrimary,
+ demux_result.audio_config));
ASSERT_TRUE(success);
VLOG(2) << "Got " << frames.size() << " audio input frames";
@@ -207,8 +210,8 @@ void AudioVideoPipelineDeviceTest::LoadVideoStream(std::string filename,
DemuxResult demux_result = FFmpegDemuxForTest(file_path,
/*audio*/ false);
frames = demux_result.frames;
- video_config =
- DecoderConfigAdapter::ToCastVideoConfig(demux_result.video_config);
+ video_config = DecoderConfigAdapter::ToCastVideoConfig(
+ kPrimary, demux_result.video_config);
}
VideoPipelineDevice* video_pipeline_device =
@@ -237,18 +240,16 @@ void AudioVideoPipelineDeviceTest::Start() {
pause_pattern_idx_ = 0;
for (size_t i = 0; i < component_device_feeders_.size(); i++) {
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&MediaComponentDeviceFeederForTest::Feed,
- base::Unretained(component_device_feeders_[i])));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&MediaComponentDeviceFeederForTest::Feed,
+ base::Unretained(component_device_feeders_[i])));
}
media_clock_device_->SetState(MediaClockDevice::kStateRunning);
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
- base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
+ base::Unretained(this)));
}
void AudioVideoPipelineDeviceTest::MonitorLoop() {
@@ -265,19 +266,17 @@ void AudioVideoPipelineDeviceTest::MonitorLoop() {
pause_pattern_[pause_pattern_idx_].length.InMilliseconds() << "ms";
// Wait for pause finish
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AudioVideoPipelineDeviceTest::OnPauseCompleted,
- base::Unretained(this)),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&AudioVideoPipelineDeviceTest::OnPauseCompleted,
+ base::Unretained(this)),
pause_pattern_[pause_pattern_idx_].length);
return;
}
// Check state again in a little while
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
- base::Unretained(this)),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&AudioVideoPipelineDeviceTest::MonitorLoop,
+ base::Unretained(this)),
kMonitorLoopDelay);
}
@@ -324,7 +323,9 @@ void AudioVideoPipelineDeviceTest::OnEos(
void AudioVideoPipelineDeviceTest::Initialize() {
// Create the media device.
MediaPipelineDeviceParams params;
- media_pipeline_device_.reset(CreateMediaPipelineDevice(params).release());
+ scoped_ptr<MediaPipelineDeviceFactory> device_factory =
+ GetMediaPipelineDeviceFactory(params);
+ media_pipeline_device_.reset(new MediaPipelineDevice(device_factory.Pass()));
media_clock_device_ = media_pipeline_device_->GetMediaClockDevice();
// Clock initialization and configuration.
diff --git a/chromium/chromecast/media/cma/backend/media_clock_device_default.cc b/chromium/chromecast/media/cma/backend/media_clock_device_default.cc
new file mode 100644
index 00000000000..086083dda3f
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_clock_device_default.cc
@@ -0,0 +1,84 @@
+// Copyright 2015 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/media_clock_device_default.h"
+
+#include "media/base/buffers.h"
+
+namespace chromecast {
+namespace media {
+
+MediaClockDeviceDefault::MediaClockDeviceDefault()
+ : state_(kStateUninitialized),
+ media_time_(::media::kNoTimestamp()) {
+ DetachFromThread();
+}
+
+MediaClockDeviceDefault::~MediaClockDeviceDefault() {
+}
+
+MediaClockDevice::State MediaClockDeviceDefault::GetState() const {
+ DCHECK(CalledOnValidThread());
+ return state_;
+}
+
+bool MediaClockDeviceDefault::SetState(State new_state) {
+ DCHECK(CalledOnValidThread());
+ if (!MediaClockDevice::IsValidStateTransition(state_, new_state))
+ return false;
+
+ if (new_state == state_)
+ return true;
+
+ state_ = new_state;
+
+ if (state_ == kStateRunning) {
+ stc_ = base::TimeTicks::Now();
+ DCHECK(media_time_ != ::media::kNoTimestamp());
+ return true;
+ }
+
+ if (state_ == kStateIdle) {
+ media_time_ = ::media::kNoTimestamp();
+ return true;
+ }
+
+ return true;
+}
+
+bool MediaClockDeviceDefault::ResetTimeline(base::TimeDelta time) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(state_, kStateIdle);
+ media_time_ = time;
+ return true;
+}
+
+bool MediaClockDeviceDefault::SetRate(float rate) {
+ DCHECK(CalledOnValidThread());
+ if (state_ == kStateRunning) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ media_time_ = media_time_ + (now - stc_) * rate_;
+ stc_ = now;
+ }
+
+ rate_ = rate;
+ return true;
+}
+
+base::TimeDelta MediaClockDeviceDefault::GetTime() {
+ DCHECK(CalledOnValidThread());
+ if (state_ != kStateRunning)
+ return media_time_;
+
+ if (media_time_ == ::media::kNoTimestamp())
+ return ::media::kNoTimestamp();
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta interpolated_media_time =
+ media_time_ + (now - stc_) * rate_;
+ return interpolated_media_time;
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/media_clock_device_default.h b/chromium/chromecast/media/cma/backend/media_clock_device_default.h
new file mode 100644
index 00000000000..1ac43875210
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_clock_device_default.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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_MEDIA_CLOCK_DEVICE_DEFAULT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_CLOCK_DEVICE_DEFAULT_H_
+
+#include "base/macros.h"
+#include "chromecast/media/cma/backend/media_clock_device.h"
+
+namespace chromecast {
+namespace media {
+
+class MediaClockDeviceDefault : public MediaClockDevice {
+ public:
+ MediaClockDeviceDefault();
+ ~MediaClockDeviceDefault() override;
+
+ // MediaClockDevice implementation.
+ State GetState() const override;
+ bool SetState(State new_state) override;
+ bool ResetTimeline(base::TimeDelta time) override;
+ bool SetRate(float rate) override;
+ base::TimeDelta GetTime() override;
+
+ private:
+ State state_;
+
+ // Media time sampled at STC time |stc_|.
+ base::TimeDelta media_time_;
+ base::TimeTicks stc_;
+
+ float rate_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaClockDeviceDefault);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_CLOCK_DEVICE_DEFAULT_H_
diff --git a/chromium/chromecast/media/cma/backend/media_component_device_default.cc b/chromium/chromecast/media/cma/backend/media_component_device_default.cc
new file mode 100644
index 00000000000..3ed5f01f395
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_component_device_default.cc
@@ -0,0 +1,189 @@
+// Copyright 2015 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/media_component_device_default.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
+#include "chromecast/media/cma/base/decoder_buffer_base.h"
+#include "media/base/buffers.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+// Maximum number of frames that can be buffered.
+const size_t kMaxFrameCount = 20;
+
+} // namespace
+
+MediaComponentDeviceDefault::DefaultDecoderBuffer::DefaultDecoderBuffer()
+ : size(0) {
+}
+
+MediaComponentDeviceDefault::DefaultDecoderBuffer::~DefaultDecoderBuffer() {
+}
+
+MediaComponentDeviceDefault::MediaComponentDeviceDefault(
+ MediaClockDevice* media_clock_device)
+ : media_clock_device_(media_clock_device),
+ state_(kStateUninitialized),
+ rendering_time_(::media::kNoTimestamp()),
+ decoded_frame_count_(0),
+ decoded_byte_count_(0),
+ scheduled_rendering_task_(false),
+ weak_factory_(this) {
+ weak_this_ = weak_factory_.GetWeakPtr();
+ DetachFromThread();
+}
+
+MediaComponentDeviceDefault::~MediaComponentDeviceDefault() {
+}
+
+void MediaComponentDeviceDefault::SetClient(const Client& client) {
+ DCHECK(CalledOnValidThread());
+ client_ = client;
+}
+
+MediaComponentDevice::State MediaComponentDeviceDefault::GetState() const {
+ DCHECK(CalledOnValidThread());
+ return state_;
+}
+
+bool MediaComponentDeviceDefault::SetState(State new_state) {
+ DCHECK(CalledOnValidThread());
+ if (!MediaComponentDevice::IsValidStateTransition(state_, new_state))
+ return false;
+ state_ = new_state;
+
+ if (state_ == kStateIdle) {
+ // Back to the idle state: reset a bunch of parameters.
+ is_eos_ = false;
+ rendering_time_ = ::media::kNoTimestamp();
+ decoded_frame_count_ = 0;
+ decoded_byte_count_ = 0;
+ frames_.clear();
+ pending_buffer_ = scoped_refptr<DecoderBufferBase>();
+ frame_pushed_cb_.Reset();
+ return true;
+ }
+
+ if (state_ == kStateRunning) {
+ if (!scheduled_rendering_task_) {
+ scheduled_rendering_task_ = true;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaComponentDeviceDefault::RenderTask, weak_this_));
+ }
+ return true;
+ }
+
+ return true;
+}
+
+bool MediaComponentDeviceDefault::SetStartPts(base::TimeDelta time) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(state_, kStateIdle);
+ rendering_time_ = time;
+ return true;
+}
+
+MediaComponentDevice::FrameStatus MediaComponentDeviceDefault::PushFrame(
+ const scoped_refptr<DecryptContext>& decrypt_context,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const FrameStatusCB& completion_cb) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(state_ == kStatePaused || state_ == kStateRunning);
+ DCHECK(!is_eos_);
+ DCHECK(!pending_buffer_.get());
+ DCHECK(buffer.get());
+
+ if (buffer->end_of_stream()) {
+ is_eos_ = true;
+ return kFrameSuccess;
+ }
+
+ if (frames_.size() > kMaxFrameCount) {
+ pending_buffer_ = buffer;
+ frame_pushed_cb_ = completion_cb;
+ return kFramePending;
+ }
+
+ DefaultDecoderBuffer fake_buffer;
+ fake_buffer.size = buffer->data_size();
+ fake_buffer.pts = buffer->timestamp();
+ frames_.push_back(fake_buffer);
+ return kFrameSuccess;
+}
+
+base::TimeDelta MediaComponentDeviceDefault::GetRenderingTime() const {
+ return rendering_time_;
+}
+
+base::TimeDelta MediaComponentDeviceDefault::GetRenderingDelay() const {
+ NOTIMPLEMENTED();
+ return ::media::kNoTimestamp();
+}
+
+void MediaComponentDeviceDefault::RenderTask() {
+ scheduled_rendering_task_ = false;
+
+ if (state_ != kStateRunning)
+ return;
+
+ base::TimeDelta media_time = media_clock_device_->GetTime();
+ if (media_time == ::media::kNoTimestamp()) {
+ scheduled_rendering_task_ = true;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&MediaComponentDeviceDefault::RenderTask, weak_this_),
+ base::TimeDelta::FromMilliseconds(50));
+ return;
+ }
+
+ while (!frames_.empty() && frames_.front().pts <= media_time) {
+ rendering_time_ = frames_.front().pts;
+ decoded_frame_count_++;
+ decoded_byte_count_ += frames_.front().size;
+ frames_.pop_front();
+ if (pending_buffer_.get()) {
+ DefaultDecoderBuffer fake_buffer;
+ fake_buffer.size = pending_buffer_->data_size();
+ fake_buffer.pts = pending_buffer_->timestamp();
+ frames_.push_back(fake_buffer);
+ pending_buffer_ = scoped_refptr<DecoderBufferBase>();
+ base::ResetAndReturn(&frame_pushed_cb_).Run(kFrameSuccess);
+ }
+ }
+
+ if (frames_.empty() && is_eos_) {
+ if (!client_.eos_cb.is_null())
+ client_.eos_cb.Run();
+ return;
+ }
+
+ scheduled_rendering_task_ = true;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&MediaComponentDeviceDefault::RenderTask, weak_this_),
+ base::TimeDelta::FromMilliseconds(50));
+}
+
+bool MediaComponentDeviceDefault::GetStatistics(Statistics* stats) const {
+ if (state_ != kStateRunning)
+ return false;
+
+ // Note: what is returned here is not the number of samples but the number of
+ // frames. The value is different for audio.
+ stats->decoded_bytes = decoded_byte_count_;
+ stats->decoded_samples = decoded_frame_count_;
+ stats->dropped_samples = 0;
+ return true;
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/media_component_device_default.h b/chromium/chromecast/media/cma/backend/media_component_device_default.h
new file mode 100644
index 00000000000..5aea387ac13
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_component_device_default.h
@@ -0,0 +1,84 @@
+// Copyright 2015 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_MEDIA_COMPONENT_DEVICE_DEFAULT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_COMPONENT_DEVICE_DEFAULT_H_
+
+#include <list>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chromecast/media/cma/backend/media_clock_device.h"
+#include "chromecast/media/cma/backend/media_component_device.h"
+
+namespace chromecast {
+namespace media {
+
+class MediaComponentDeviceDefault : public MediaComponentDevice {
+ public:
+ explicit MediaComponentDeviceDefault(MediaClockDevice* media_clock_device);
+ ~MediaComponentDeviceDefault() override;
+
+ // MediaComponentDevice implementation.
+ void SetClient(const Client& client) override;
+ State GetState() const override;
+ bool SetState(State new_state) override;
+ bool SetStartPts(base::TimeDelta time) override;
+ FrameStatus PushFrame(
+ const scoped_refptr<DecryptContext>& decrypt_context,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const FrameStatusCB& completion_cb) override;
+ base::TimeDelta GetRenderingTime() const override;
+ base::TimeDelta GetRenderingDelay() const override;
+ bool GetStatistics(Statistics* stats) const override;
+
+ private:
+ struct DefaultDecoderBuffer {
+ DefaultDecoderBuffer();
+ ~DefaultDecoderBuffer();
+
+ // Buffer size.
+ size_t size;
+
+ // Presentation timestamp.
+ base::TimeDelta pts;
+ };
+
+ void RenderTask();
+
+ MediaClockDevice* const media_clock_device_;
+ Client client_;
+
+ State state_;
+
+ // Indicate whether the end of stream has been received.
+ bool is_eos_;
+
+ // Media time of the last rendered audio sample.
+ base::TimeDelta rendering_time_;
+
+ // Frame decoded/rendered since the pipeline left the idle state.
+ uint64 decoded_frame_count_;
+ uint64 decoded_byte_count_;
+
+ // List of frames not rendered yet.
+ std::list<DefaultDecoderBuffer> frames_;
+
+ // Indicate whether there is a scheduled rendering task.
+ bool scheduled_rendering_task_;
+
+ // Pending frame.
+ scoped_refptr<DecoderBufferBase> pending_buffer_;
+ FrameStatusCB frame_pushed_cb_;
+
+ base::WeakPtr<MediaComponentDeviceDefault> weak_this_;
+ base::WeakPtrFactory<MediaComponentDeviceDefault> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaComponentDeviceDefault);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_COMPONENT_DEVICE_DEFAULT_H_
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device.cc b/chromium/chromecast/media/cma/backend/media_pipeline_device.cc
index ea120c47829..ec2370b553d 100644
--- a/chromium/chromecast/media/cma/backend/media_pipeline_device.cc
+++ b/chromium/chromecast/media/cma/backend/media_pipeline_device.cc
@@ -4,10 +4,28 @@
#include "chromecast/media/cma/backend/media_pipeline_device.h"
+#include "chromecast/media/cma/backend/audio_pipeline_device_default.h"
+#include "chromecast/media/cma/backend/media_clock_device_default.h"
+#include "chromecast/media/cma/backend/media_pipeline_device_factory.h"
+#include "chromecast/media/cma/backend/video_pipeline_device_default.h"
+
namespace chromecast {
namespace media {
-MediaPipelineDevice::MediaPipelineDevice() {
+MediaPipelineDevice::MediaPipelineDevice(
+ scoped_ptr<MediaPipelineDeviceFactory> factory)
+ : media_clock_device_(factory->CreateMediaClockDevice()),
+ audio_pipeline_device_(factory->CreateAudioPipelineDevice()),
+ video_pipeline_device_(factory->CreateVideoPipelineDevice()) {
+}
+
+MediaPipelineDevice::MediaPipelineDevice(
+ scoped_ptr<MediaClockDevice> media_clock_device,
+ scoped_ptr<AudioPipelineDevice> audio_pipeline_device,
+ scoped_ptr<VideoPipelineDevice> video_pipeline_device)
+ : media_clock_device_(media_clock_device.Pass()),
+ audio_pipeline_device_(audio_pipeline_device.Pass()),
+ video_pipeline_device_(video_pipeline_device.Pass()) {
}
MediaPipelineDevice::~MediaPipelineDevice() {
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device.h b/chromium/chromecast/media/cma/backend/media_pipeline_device.h
index 8a961dc7fda..e010176965c 100644
--- a/chromium/chromecast/media/cma/backend/media_pipeline_device.h
+++ b/chromium/chromecast/media/cma/backend/media_pipeline_device.h
@@ -5,6 +5,7 @@
#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_H_
+#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
@@ -12,29 +13,45 @@ namespace chromecast {
namespace media {
class AudioPipelineDevice;
class MediaClockDevice;
+class MediaPipelineDeviceFactory;
class MediaPipelineDeviceParams;
class VideoPipelineDevice;
// MediaPipelineDevice is the owner of the underlying audio/video/clock
-// devices.
+// devices. It ensures that the clock outlives the audio and video devices, so
+// it is safe for them to reference the clock with a raw pointer.
class MediaPipelineDevice {
public:
- MediaPipelineDevice();
- virtual ~MediaPipelineDevice();
-
- virtual AudioPipelineDevice* GetAudioPipelineDevice() const = 0;
-
- virtual VideoPipelineDevice* GetVideoPipelineDevice() const = 0;
-
- virtual MediaClockDevice* GetMediaClockDevice() const = 0;
+ // Constructs object using clock, audio, video created by given factory.
+ explicit MediaPipelineDevice(scoped_ptr<MediaPipelineDeviceFactory> factory);
+
+ // Constructs explicitly from separate clock, audio, video elements
+ MediaPipelineDevice(scoped_ptr<MediaClockDevice> media_clock_device,
+ scoped_ptr<AudioPipelineDevice> audio_pipeline_device,
+ scoped_ptr<VideoPipelineDevice> video_pipeline_device);
+ ~MediaPipelineDevice();
+
+ AudioPipelineDevice* GetAudioPipelineDevice() const {
+ return audio_pipeline_device_.get();
+ }
+ VideoPipelineDevice* GetVideoPipelineDevice() const {
+ return video_pipeline_device_.get();
+ }
+ MediaClockDevice* GetMediaClockDevice() const {
+ return media_clock_device_.get();
+ }
private:
+ scoped_ptr<MediaClockDevice> media_clock_device_;
+ scoped_ptr<AudioPipelineDevice> audio_pipeline_device_;
+ scoped_ptr<VideoPipelineDevice> video_pipeline_device_;
+
DISALLOW_COPY_AND_ASSIGN(MediaPipelineDevice);
};
-// Factory to create a MediaPipelineDevice.
-scoped_ptr<MediaPipelineDevice> CreateMediaPipelineDevice(
- const MediaPipelineDeviceParams& params);
+// Factory method to create a MediaPipelineDevice.
+typedef base::Callback<scoped_ptr<MediaPipelineDevice>(
+ const MediaPipelineDeviceParams&)> CreatePipelineDeviceCB;
} // namespace media
} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_factory.h b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory.h
new file mode 100644
index 00000000000..28da11994d9
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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_MEDIA_PIPELINE_DEVICE_FACTORY_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace chromecast {
+namespace media {
+
+class AudioPipelineDevice;
+class MediaClockDevice;
+class MediaPipelineDeviceParams;
+class VideoPipelineDevice;
+
+// Factory for creating platform-specific clock, audio and video devices.
+// A new factory will be instantiated for each media player instance.
+class MediaPipelineDeviceFactory {
+ public:
+ MediaPipelineDeviceFactory() {}
+ virtual ~MediaPipelineDeviceFactory() {}
+
+ virtual scoped_ptr<MediaClockDevice> CreateMediaClockDevice() = 0;
+ virtual scoped_ptr<AudioPipelineDevice> CreateAudioPipelineDevice() = 0;
+ virtual scoped_ptr<VideoPipelineDevice> CreateVideoPipelineDevice() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaPipelineDeviceFactory);
+};
+
+// Creates the platform-specific pipeline device factory.
+// TODO(halliwell): move into libcast_media
+scoped_ptr<MediaPipelineDeviceFactory> GetMediaPipelineDeviceFactory(
+ const MediaPipelineDeviceParams& params);
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_H_
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.cc b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.cc
new file mode 100644
index 00000000000..78663fe4962
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 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/media_pipeline_device_factory_default.h"
+
+#include "chromecast/media/cma/backend/audio_pipeline_device_default.h"
+#include "chromecast/media/cma/backend/media_clock_device_default.h"
+#include "chromecast/media/cma/backend/video_pipeline_device_default.h"
+
+namespace chromecast {
+namespace media {
+
+MediaPipelineDeviceFactoryDefault::MediaPipelineDeviceFactoryDefault()
+ : clock_(nullptr) {
+}
+
+scoped_ptr<MediaClockDevice>
+MediaPipelineDeviceFactoryDefault::CreateMediaClockDevice() {
+ DCHECK(!clock_);
+ clock_ = new MediaClockDeviceDefault();
+ return make_scoped_ptr(clock_);
+}
+
+scoped_ptr<AudioPipelineDevice>
+MediaPipelineDeviceFactoryDefault::CreateAudioPipelineDevice() {
+ DCHECK(clock_);
+ return make_scoped_ptr(new AudioPipelineDeviceDefault(clock_));
+}
+
+scoped_ptr<VideoPipelineDevice>
+MediaPipelineDeviceFactoryDefault::CreateVideoPipelineDevice() {
+ DCHECK(clock_);
+ return make_scoped_ptr(new VideoPipelineDeviceDefault(clock_));
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.h b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.h
new file mode 100644
index 00000000000..1927847a99a
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_default.h
@@ -0,0 +1,36 @@
+// Copyright 2015 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_MEDIA_PIPELINE_DEVICE_FACTORY_DEFAULT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_DEFAULT_H_
+
+#include "chromecast/media/cma/backend/media_pipeline_device_factory.h"
+
+namespace chromecast {
+namespace media {
+
+// Factory that instantiates default (stub) media pipeline device elements.
+class MediaPipelineDeviceFactoryDefault : public MediaPipelineDeviceFactory {
+ public:
+ MediaPipelineDeviceFactoryDefault();
+ ~MediaPipelineDeviceFactoryDefault() override {}
+
+ // MediaPipelineDeviceFactory implementation
+ scoped_ptr<MediaClockDevice> CreateMediaClockDevice() override;
+ scoped_ptr<AudioPipelineDevice> CreateAudioPipelineDevice() override;
+ scoped_ptr<VideoPipelineDevice> CreateVideoPipelineDevice() override;
+
+ private:
+ // Owned by MediaPipelineDevice, but we hold raw pointer in order to wire up
+ // to audio and video devices. MediaPipelineDevice guarantees the clock will
+ // outlive the audio and video devices.
+ MediaClockDevice* clock_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaPipelineDeviceFactoryDefault);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FACTORY_DEFAULT_H_
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_simple.cc b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_simple.cc
new file mode 100644
index 00000000000..92efca15342
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/media_pipeline_device_factory_simple.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 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/media_pipeline_device_factory_default.h"
+
+namespace chromecast {
+namespace media {
+
+// Creates default (no-op) media pipeline device elements.
+scoped_ptr<MediaPipelineDeviceFactory> GetMediaPipelineDeviceFactory(
+ const MediaPipelineDeviceParams& params) {
+ return make_scoped_ptr(new MediaPipelineDeviceFactoryDefault());
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_fake.cc b/chromium/chromecast/media/cma/backend/media_pipeline_device_fake.cc
deleted file mode 100644
index 60d9576764a..00000000000
--- a/chromium/chromecast/media/cma/backend/media_pipeline_device_fake.cc
+++ /dev/null
@@ -1,583 +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/cma/backend/media_pipeline_device_fake.h"
-
-#include <list>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "chromecast/media/cma/backend/audio_pipeline_device.h"
-#include "chromecast/media/cma/backend/media_clock_device.h"
-#include "chromecast/media/cma/backend/media_component_device.h"
-#include "chromecast/media/cma/backend/video_pipeline_device.h"
-#include "chromecast/media/cma/base/decoder_buffer_base.h"
-#include "chromecast/public/media/decoder_config.h"
-#include "media/base/buffers.h"
-
-namespace chromecast {
-namespace media {
-
-class MediaClockDeviceFake : public MediaClockDevice {
- public:
- MediaClockDeviceFake();
- ~MediaClockDeviceFake() override;
-
- // MediaClockDevice implementation.
- State GetState() const override;
- bool SetState(State new_state) override;
- bool ResetTimeline(base::TimeDelta time) override;
- bool SetRate(float rate) override;
- base::TimeDelta GetTime() override;
-
- private:
- State state_;
-
- // Media time sampled at STC time |stc_|.
- base::TimeDelta media_time_;
- base::TimeTicks stc_;
-
- float rate_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaClockDeviceFake);
-};
-
-MediaClockDeviceFake::MediaClockDeviceFake()
- : state_(kStateUninitialized),
- media_time_(::media::kNoTimestamp()) {
- DetachFromThread();
-}
-
-MediaClockDeviceFake::~MediaClockDeviceFake() {
-}
-
-MediaClockDevice::State MediaClockDeviceFake::GetState() const {
- DCHECK(CalledOnValidThread());
- return state_;
-}
-
-bool MediaClockDeviceFake::SetState(State new_state) {
- DCHECK(CalledOnValidThread());
- if (!MediaClockDevice::IsValidStateTransition(state_, new_state))
- return false;
-
- if (new_state == state_)
- return true;
-
- state_ = new_state;
-
- if (state_ == kStateRunning) {
- stc_ = base::TimeTicks::Now();
- DCHECK(media_time_ != ::media::kNoTimestamp());
- return true;
- }
-
- if (state_ == kStateIdle) {
- media_time_ = ::media::kNoTimestamp();
- return true;
- }
-
- return true;
-}
-
-bool MediaClockDeviceFake::ResetTimeline(base::TimeDelta time) {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(state_, kStateIdle);
- media_time_ = time;
- return true;
-}
-
-bool MediaClockDeviceFake::SetRate(float rate) {
- DCHECK(CalledOnValidThread());
- if (state_ == kStateRunning) {
- base::TimeTicks now = base::TimeTicks::Now();
- media_time_ = media_time_ + (now - stc_) * rate_;
- stc_ = now;
- }
-
- rate_ = rate;
- return true;
-}
-
-base::TimeDelta MediaClockDeviceFake::GetTime() {
- DCHECK(CalledOnValidThread());
- if (state_ != kStateRunning)
- return media_time_;
-
- if (media_time_ == ::media::kNoTimestamp())
- return ::media::kNoTimestamp();
-
- base::TimeTicks now = base::TimeTicks::Now();
- base::TimeDelta interpolated_media_time =
- media_time_ + (now - stc_) * rate_;
- return interpolated_media_time;
-}
-
-
-namespace {
-
-// Maximum number of frames that can be buffered.
-const size_t kMaxFrameCount = 20;
-
-} // namespace
-
-class MediaComponentDeviceFake : public MediaComponentDevice {
- public:
- explicit MediaComponentDeviceFake(MediaClockDeviceFake* media_clock_device);
- ~MediaComponentDeviceFake() override;
-
- // MediaComponentDevice implementation.
- void SetClient(const Client& client) override;
- State GetState() const override;
- bool SetState(State new_state) override;
- bool SetStartPts(base::TimeDelta time) override;
- FrameStatus PushFrame(
- const scoped_refptr<DecryptContext>& decrypt_context,
- const scoped_refptr<DecoderBufferBase>& buffer,
- const FrameStatusCB& completion_cb) override;
- base::TimeDelta GetRenderingTime() const override;
- base::TimeDelta GetRenderingDelay() const override;
- bool GetStatistics(Statistics* stats) const override;
-
- private:
- struct FakeDecoderBuffer {
- FakeDecoderBuffer();
- ~FakeDecoderBuffer();
-
- // Buffer size.
- size_t size;
-
- // Presentation timestamp.
- base::TimeDelta pts;
- };
-
- void RenderTask();
-
- MediaClockDeviceFake* const media_clock_device_;
- Client client_;
-
- State state_;
-
- // Indicate whether the end of stream has been received.
- bool is_eos_;
-
- // Media time of the last rendered audio sample.
- base::TimeDelta rendering_time_;
-
- // Frame decoded/rendered since the pipeline left the idle state.
- uint64 decoded_frame_count_;
- uint64 decoded_byte_count_;
-
- // List of frames not rendered yet.
- std::list<FakeDecoderBuffer> frames_;
-
- // Indicate whether there is a scheduled rendering task.
- bool scheduled_rendering_task_;
-
- // Pending frame.
- scoped_refptr<DecoderBufferBase> pending_buffer_;
- FrameStatusCB frame_pushed_cb_;
-
- base::WeakPtr<MediaComponentDeviceFake> weak_this_;
- base::WeakPtrFactory<MediaComponentDeviceFake> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaComponentDeviceFake);
-};
-
-MediaComponentDeviceFake::FakeDecoderBuffer::FakeDecoderBuffer()
- : size(0) {
-}
-
-MediaComponentDeviceFake::FakeDecoderBuffer::~FakeDecoderBuffer() {
-}
-
-MediaComponentDeviceFake::MediaComponentDeviceFake(
- MediaClockDeviceFake* media_clock_device)
- : media_clock_device_(media_clock_device),
- state_(kStateUninitialized),
- rendering_time_(::media::kNoTimestamp()),
- decoded_frame_count_(0),
- decoded_byte_count_(0),
- scheduled_rendering_task_(false),
- weak_factory_(this) {
- weak_this_ = weak_factory_.GetWeakPtr();
- DetachFromThread();
-}
-
-MediaComponentDeviceFake::~MediaComponentDeviceFake() {
-}
-
-void MediaComponentDeviceFake::SetClient(const Client& client) {
- DCHECK(CalledOnValidThread());
- client_ = client;
-}
-
-MediaComponentDevice::State MediaComponentDeviceFake::GetState() const {
- DCHECK(CalledOnValidThread());
- return state_;
-}
-
-bool MediaComponentDeviceFake::SetState(State new_state) {
- DCHECK(CalledOnValidThread());
- if (!MediaComponentDevice::IsValidStateTransition(state_, new_state))
- return false;
- state_ = new_state;
-
- if (state_ == kStateIdle) {
- // Back to the idle state: reset a bunch of parameters.
- is_eos_ = false;
- rendering_time_ = ::media::kNoTimestamp();
- decoded_frame_count_ = 0;
- decoded_byte_count_ = 0;
- frames_.clear();
- pending_buffer_ = scoped_refptr<DecoderBufferBase>();
- frame_pushed_cb_.Reset();
- return true;
- }
-
- if (state_ == kStateRunning) {
- if (!scheduled_rendering_task_) {
- scheduled_rendering_task_ = true;
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&MediaComponentDeviceFake::RenderTask, weak_this_));
- }
- return true;
- }
-
- return true;
-}
-
-bool MediaComponentDeviceFake::SetStartPts(base::TimeDelta time) {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(state_, kStateIdle);
- rendering_time_ = time;
- return true;
-}
-
-MediaComponentDevice::FrameStatus MediaComponentDeviceFake::PushFrame(
- const scoped_refptr<DecryptContext>& decrypt_context,
- const scoped_refptr<DecoderBufferBase>& buffer,
- const FrameStatusCB& completion_cb) {
- DCHECK(CalledOnValidThread());
- DCHECK(state_ == kStatePaused || state_ == kStateRunning);
- DCHECK(!is_eos_);
- DCHECK(!pending_buffer_.get());
- DCHECK(buffer.get());
-
- if (buffer->end_of_stream()) {
- is_eos_ = true;
- return kFrameSuccess;
- }
-
- if (frames_.size() > kMaxFrameCount) {
- pending_buffer_ = buffer;
- frame_pushed_cb_ = completion_cb;
- return kFramePending;
- }
-
- FakeDecoderBuffer fake_buffer;
- fake_buffer.size = buffer->data_size();
- fake_buffer.pts = buffer->timestamp();
- frames_.push_back(fake_buffer);
- return kFrameSuccess;
-}
-
-base::TimeDelta MediaComponentDeviceFake::GetRenderingTime() const {
- return rendering_time_;
-}
-
-base::TimeDelta MediaComponentDeviceFake::GetRenderingDelay() const {
- NOTIMPLEMENTED();
- return ::media::kNoTimestamp();
-}
-
-void MediaComponentDeviceFake::RenderTask() {
- scheduled_rendering_task_ = false;
-
- if (state_ != kStateRunning)
- return;
-
- base::TimeDelta media_time = media_clock_device_->GetTime();
- if (media_time == ::media::kNoTimestamp()) {
- scheduled_rendering_task_ = true;
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&MediaComponentDeviceFake::RenderTask, weak_this_),
- base::TimeDelta::FromMilliseconds(50));
- return;
- }
-
- while (!frames_.empty() && frames_.front().pts <= media_time) {
- rendering_time_ = frames_.front().pts;
- decoded_frame_count_++;
- decoded_byte_count_ += frames_.front().size;
- frames_.pop_front();
- if (pending_buffer_.get()) {
- FakeDecoderBuffer fake_buffer;
- fake_buffer.size = pending_buffer_->data_size();
- fake_buffer.pts = pending_buffer_->timestamp();
- frames_.push_back(fake_buffer);
- pending_buffer_ = scoped_refptr<DecoderBufferBase>();
- base::ResetAndReturn(&frame_pushed_cb_).Run(kFrameSuccess);
- }
- }
-
- if (frames_.empty() && is_eos_) {
- if (!client_.eos_cb.is_null())
- client_.eos_cb.Run();
- return;
- }
-
- scheduled_rendering_task_ = true;
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&MediaComponentDeviceFake::RenderTask, weak_this_),
- base::TimeDelta::FromMilliseconds(50));
-}
-
-bool MediaComponentDeviceFake::GetStatistics(Statistics* stats) const {
- if (state_ != kStateRunning)
- return false;
-
- // Note: what is returned here is not the number of samples but the number of
- // frames. The value is different for audio.
- stats->decoded_bytes = decoded_byte_count_;
- stats->decoded_samples = decoded_frame_count_;
- stats->dropped_samples = 0;
- return true;
-}
-
-
-class AudioPipelineDeviceFake : public AudioPipelineDevice {
- public:
- explicit AudioPipelineDeviceFake(MediaClockDeviceFake* media_clock_device);
- ~AudioPipelineDeviceFake() override;
-
- // AudioPipelineDevice implementation.
- void SetClient(const Client& client) override;
- State GetState() const override;
- bool SetState(State new_state) override;
- bool SetStartPts(base::TimeDelta time) override;
- FrameStatus PushFrame(
- const scoped_refptr<DecryptContext>& decrypt_context,
- const scoped_refptr<DecoderBufferBase>& buffer,
- const FrameStatusCB& completion_cb) override;
- base::TimeDelta GetRenderingTime() const override;
- base::TimeDelta GetRenderingDelay() const override;
- bool SetConfig(const AudioConfig& config) override;
- void SetStreamVolumeMultiplier(float multiplier) override;
- bool GetStatistics(Statistics* stats) const override;
-
- private:
- scoped_ptr<MediaComponentDeviceFake> fake_pipeline_;
-
- AudioConfig config_;
- std::vector<uint8_t> config_extra_data_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioPipelineDeviceFake);
-};
-
-AudioPipelineDeviceFake::AudioPipelineDeviceFake(
- MediaClockDeviceFake* media_clock_device)
- : fake_pipeline_(new MediaComponentDeviceFake(media_clock_device)) {
- DetachFromThread();
-}
-
-AudioPipelineDeviceFake::~AudioPipelineDeviceFake() {
-}
-
-void AudioPipelineDeviceFake::SetClient(const Client& client) {
- fake_pipeline_->SetClient(client);
-}
-
-MediaComponentDevice::State AudioPipelineDeviceFake::GetState() const {
- return fake_pipeline_->GetState();
-}
-
-bool AudioPipelineDeviceFake::SetState(State new_state) {
- bool success = fake_pipeline_->SetState(new_state);
- if (!success)
- return false;
-
- if (new_state == kStateIdle) {
- DCHECK(IsValidConfig(config_));
- }
- if (new_state == kStateUninitialized) {
- config_ = AudioConfig();
- }
- return true;
-}
-
-bool AudioPipelineDeviceFake::SetStartPts(base::TimeDelta time) {
- return fake_pipeline_->SetStartPts(time);
-}
-
-MediaComponentDevice::FrameStatus AudioPipelineDeviceFake::PushFrame(
- const scoped_refptr<DecryptContext>& decrypt_context,
- const scoped_refptr<DecoderBufferBase>& buffer,
- const FrameStatusCB& completion_cb) {
- return fake_pipeline_->PushFrame(decrypt_context, buffer, completion_cb);
-}
-
-base::TimeDelta AudioPipelineDeviceFake::GetRenderingTime() const {
- return fake_pipeline_->GetRenderingTime();
-}
-
-base::TimeDelta AudioPipelineDeviceFake::GetRenderingDelay() const {
- return fake_pipeline_->GetRenderingDelay();
-}
-
-bool AudioPipelineDeviceFake::SetConfig(const AudioConfig& config) {
- DCHECK(CalledOnValidThread());
- if (!IsValidConfig(config))
- return false;
- config_ = config;
- if (config.extra_data_size > 0)
- config_extra_data_.assign(config.extra_data,
- config.extra_data + config.extra_data_size);
- else
- config_extra_data_.clear();
- return true;
-}
-
-void AudioPipelineDeviceFake::SetStreamVolumeMultiplier(float multiplier) {
- DCHECK(CalledOnValidThread());
-}
-
-bool AudioPipelineDeviceFake::GetStatistics(Statistics* stats) const {
- return fake_pipeline_->GetStatistics(stats);
-}
-
-
-class VideoPipelineDeviceFake : public VideoPipelineDevice {
- public:
- explicit VideoPipelineDeviceFake(MediaClockDeviceFake* media_clock_device);
- ~VideoPipelineDeviceFake() override;
-
- // VideoPipelineDevice implementation.
- void SetClient(const Client& client) override;
- State GetState() const override;
- bool SetState(State new_state) override;
- bool SetStartPts(base::TimeDelta time) override;
- FrameStatus PushFrame(
- const scoped_refptr<DecryptContext>& decrypt_context,
- const scoped_refptr<DecoderBufferBase>& buffer,
- const FrameStatusCB& completion_cb) override;
- base::TimeDelta GetRenderingTime() const override;
- base::TimeDelta GetRenderingDelay() const override;
- void SetVideoClient(const VideoClient& client) override;
- bool SetConfig(const VideoConfig& config) override;
- bool GetStatistics(Statistics* stats) const override;
-
- private:
- scoped_ptr<MediaComponentDeviceFake> fake_pipeline_;
-
- VideoConfig config_;
- std::vector<uint8_t> config_extra_data_;
-
- DISALLOW_COPY_AND_ASSIGN(VideoPipelineDeviceFake);
-};
-
-VideoPipelineDeviceFake::VideoPipelineDeviceFake(
- MediaClockDeviceFake* media_clock_device)
- : fake_pipeline_(new MediaComponentDeviceFake(media_clock_device)) {
- DetachFromThread();
-}
-
-VideoPipelineDeviceFake::~VideoPipelineDeviceFake() {
-}
-
-void VideoPipelineDeviceFake::SetClient(const Client& client) {
- fake_pipeline_->SetClient(client);
-}
-
-MediaComponentDevice::State VideoPipelineDeviceFake::GetState() const {
- return fake_pipeline_->GetState();
-}
-
-bool VideoPipelineDeviceFake::SetState(State new_state) {
- bool success = fake_pipeline_->SetState(new_state);
- if (!success)
- return false;
-
- if (new_state == kStateIdle) {
- DCHECK(IsValidConfig(config_));
- }
- if (new_state == kStateUninitialized) {
- config_ = VideoConfig();
- }
- return true;
-}
-
-bool VideoPipelineDeviceFake::SetStartPts(base::TimeDelta time) {
- return fake_pipeline_->SetStartPts(time);
-}
-
-MediaComponentDevice::FrameStatus VideoPipelineDeviceFake::PushFrame(
- const scoped_refptr<DecryptContext>& decrypt_context,
- const scoped_refptr<DecoderBufferBase>& buffer,
- const FrameStatusCB& completion_cb) {
- return fake_pipeline_->PushFrame(decrypt_context, buffer, completion_cb);
-}
-
-base::TimeDelta VideoPipelineDeviceFake::GetRenderingTime() const {
- return fake_pipeline_->GetRenderingTime();
-}
-
-base::TimeDelta VideoPipelineDeviceFake::GetRenderingDelay() const {
- return fake_pipeline_->GetRenderingDelay();
-}
-
-void VideoPipelineDeviceFake::SetVideoClient(const VideoClient& client) {
-}
-
-bool VideoPipelineDeviceFake::SetConfig(const VideoConfig& config) {
- DCHECK(CalledOnValidThread());
- if (!IsValidConfig(config))
- return false;
- config_ = config;
- if (config.extra_data_size > 0)
- config_extra_data_.assign(config.extra_data,
- config.extra_data + config.extra_data_size);
- else
- config_extra_data_.clear();
- return true;
-}
-
-bool VideoPipelineDeviceFake::GetStatistics(Statistics* stats) const {
- return fake_pipeline_->GetStatistics(stats);
-}
-
-
-MediaPipelineDeviceFake::MediaPipelineDeviceFake()
- : media_clock_device_(new MediaClockDeviceFake()),
- audio_pipeline_device_(
- new AudioPipelineDeviceFake(media_clock_device_.get())),
- video_pipeline_device_(
- new VideoPipelineDeviceFake(media_clock_device_.get())) {
-}
-
-MediaPipelineDeviceFake::~MediaPipelineDeviceFake() {
-}
-
-AudioPipelineDevice* MediaPipelineDeviceFake::GetAudioPipelineDevice() const {
- return audio_pipeline_device_.get();
-}
-
-VideoPipelineDevice* MediaPipelineDeviceFake::GetVideoPipelineDevice() const {
- return video_pipeline_device_.get();
-}
-
-MediaClockDevice* MediaPipelineDeviceFake::GetMediaClockDevice() const {
- return media_clock_device_.get();
-}
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_fake.h b/chromium/chromecast/media/cma/backend/media_pipeline_device_fake.h
deleted file mode 100644
index 248c9a4322e..00000000000
--- a/chromium/chromecast/media/cma/backend/media_pipeline_device_fake.h
+++ /dev/null
@@ -1,40 +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.
-
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FAKE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_FAKE_H_
-
-#include "chromecast/media/cma/backend/media_pipeline_device.h"
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace chromecast {
-namespace media {
-class AudioPipelineDeviceFake;
-class MediaClockDeviceFake;
-class VideoPipelineDeviceFake;
-
-class MediaPipelineDeviceFake : public MediaPipelineDevice {
- public:
- MediaPipelineDeviceFake();
- ~MediaPipelineDeviceFake() override;
-
- // MediaPipelineDevice implementation.
- AudioPipelineDevice* GetAudioPipelineDevice() const override;
- VideoPipelineDevice* GetVideoPipelineDevice() const override;
- MediaClockDevice* GetMediaClockDevice() const override;
-
- private:
- scoped_ptr<MediaClockDeviceFake> media_clock_device_;
- scoped_ptr<AudioPipelineDeviceFake> audio_pipeline_device_;
- scoped_ptr<VideoPipelineDeviceFake> video_pipeline_device_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaPipelineDeviceFake);
-};
-
-} // namespace media
-} // namespace chromecast
-
-#endif // CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_H_
diff --git a/chromium/chromecast/media/cma/backend/media_pipeline_device_fake_factory.cc b/chromium/chromecast/media/cma/backend/media_pipeline_device_fake_factory.cc
deleted file mode 100644
index 646a4637158..00000000000
--- a/chromium/chromecast/media/cma/backend/media_pipeline_device_fake_factory.cc
+++ /dev/null
@@ -1,18 +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/cma/backend/media_pipeline_device_fake.h"
-
-#include "base/memory/scoped_ptr.h"
-
-namespace chromecast {
-namespace media {
-
-scoped_ptr<MediaPipelineDevice> CreateMediaPipelineDevice(
- const MediaPipelineDeviceParams& params) {
- return scoped_ptr<MediaPipelineDevice>(new MediaPipelineDeviceFake());
-}
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/video_pipeline_device_default.cc b/chromium/chromecast/media/cma/backend/video_pipeline_device_default.cc
new file mode 100644
index 00000000000..90970cbdbd1
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/video_pipeline_device_default.cc
@@ -0,0 +1,83 @@
+// Copyright 2015 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/video_pipeline_device_default.h"
+
+#include "chromecast/media/cma/backend/media_component_device_default.h"
+
+namespace chromecast {
+namespace media {
+
+VideoPipelineDeviceDefault::VideoPipelineDeviceDefault(
+ MediaClockDevice* media_clock_device)
+ : pipeline_(new MediaComponentDeviceDefault(media_clock_device)) {
+ DetachFromThread();
+}
+
+VideoPipelineDeviceDefault::~VideoPipelineDeviceDefault() {
+}
+
+void VideoPipelineDeviceDefault::SetClient(const Client& client) {
+ pipeline_->SetClient(client);
+}
+
+MediaComponentDevice::State VideoPipelineDeviceDefault::GetState() const {
+ return pipeline_->GetState();
+}
+
+bool VideoPipelineDeviceDefault::SetState(State new_state) {
+ bool success = pipeline_->SetState(new_state);
+ if (!success)
+ return false;
+
+ if (new_state == kStateIdle) {
+ DCHECK(IsValidConfig(config_));
+ }
+ if (new_state == kStateUninitialized) {
+ config_ = VideoConfig();
+ }
+ return true;
+}
+
+bool VideoPipelineDeviceDefault::SetStartPts(base::TimeDelta time) {
+ return pipeline_->SetStartPts(time);
+}
+
+MediaComponentDevice::FrameStatus VideoPipelineDeviceDefault::PushFrame(
+ const scoped_refptr<DecryptContext>& decrypt_context,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const FrameStatusCB& completion_cb) {
+ return pipeline_->PushFrame(decrypt_context, buffer, completion_cb);
+}
+
+base::TimeDelta VideoPipelineDeviceDefault::GetRenderingTime() const {
+ return pipeline_->GetRenderingTime();
+}
+
+base::TimeDelta VideoPipelineDeviceDefault::GetRenderingDelay() const {
+ return pipeline_->GetRenderingDelay();
+}
+
+void VideoPipelineDeviceDefault::SetVideoClient(const VideoClient& client) {
+}
+
+bool VideoPipelineDeviceDefault::SetConfig(const VideoConfig& config) {
+ DCHECK(CalledOnValidThread());
+ if (!IsValidConfig(config))
+ return false;
+ config_ = config;
+ if (config.extra_data_size > 0)
+ config_extra_data_.assign(config.extra_data,
+ config.extra_data + config.extra_data_size);
+ else
+ config_extra_data_.clear();
+ return true;
+}
+
+bool VideoPipelineDeviceDefault::GetStatistics(Statistics* stats) const {
+ return pipeline_->GetStatistics(stats);
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/video_pipeline_device_default.h b/chromium/chromecast/media/cma/backend/video_pipeline_device_default.h
new file mode 100644
index 00000000000..49a4a0316ee
--- /dev/null
+++ b/chromium/chromecast/media/cma/backend/video_pipeline_device_default.h
@@ -0,0 +1,53 @@
+// Copyright 2015 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_VIDEO_PIPELINE_DEVICE_DEFAULT_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PIPELINE_DEVICE_DEFAULT_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "chromecast/media/cma/backend/video_pipeline_device.h"
+#include "chromecast/public/media/decoder_config.h"
+
+namespace chromecast {
+namespace media {
+
+class MediaClockDevice;
+class MediaComponentDeviceDefault;
+
+class VideoPipelineDeviceDefault : public VideoPipelineDevice {
+ public:
+ explicit VideoPipelineDeviceDefault(MediaClockDevice* media_clock_device);
+ ~VideoPipelineDeviceDefault() override;
+
+ // VideoPipelineDevice implementation.
+ void SetClient(const Client& client) override;
+ State GetState() const override;
+ bool SetState(State new_state) override;
+ bool SetStartPts(base::TimeDelta time) override;
+ FrameStatus PushFrame(
+ const scoped_refptr<DecryptContext>& decrypt_context,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const FrameStatusCB& completion_cb) override;
+ base::TimeDelta GetRenderingTime() const override;
+ base::TimeDelta GetRenderingDelay() const override;
+ void SetVideoClient(const VideoClient& client) override;
+ bool SetConfig(const VideoConfig& config) override;
+ bool GetStatistics(Statistics* stats) const override;
+
+ private:
+ scoped_ptr<MediaComponentDeviceDefault> pipeline_;
+
+ VideoConfig config_;
+ std::vector<uint8_t> config_extra_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(VideoPipelineDeviceDefault);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PIPELINE_DEVICE_DEFAULT_H_
+
diff --git a/chromium/chromecast/media/cma/backend/video_plane.cc b/chromium/chromecast/media/cma/backend/video_plane.cc
deleted file mode 100644
index 5d8097f2a62..00000000000
--- a/chromium/chromecast/media/cma/backend/video_plane.cc
+++ /dev/null
@@ -1,54 +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/cma/backend/video_plane.h"
-
-#include "base/memory/singleton.h"
-
-namespace chromecast {
-namespace media {
-
-VideoPlane::VideoPlane() {
-}
-
-VideoPlane::~VideoPlane() {
-}
-
-class VideoPlaneRegistry {
- public:
- static VideoPlaneRegistry* GetInstance() {
- return Singleton<VideoPlaneRegistry>::get();
- }
-
- VideoPlane* GetVideoPlane();
-
- private:
- friend struct DefaultSingletonTraits<VideoPlaneRegistry>;
- friend class Singleton<VideoPlaneRegistry>;
-
- VideoPlaneRegistry();
- virtual ~VideoPlaneRegistry();
-
- scoped_ptr<VideoPlane> video_plane_;
-
- DISALLOW_COPY_AND_ASSIGN(VideoPlaneRegistry);
-};
-
-VideoPlaneRegistry::VideoPlaneRegistry() :
- video_plane_(CreateVideoPlane()) {
-}
-
-VideoPlaneRegistry::~VideoPlaneRegistry() {
-}
-
-VideoPlane* VideoPlaneRegistry::GetVideoPlane() {
- return video_plane_.get();
-}
-
-VideoPlane* GetVideoPlane() {
- return VideoPlaneRegistry::GetInstance()->GetVideoPlane();
-}
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/video_plane.h b/chromium/chromecast/media/cma/backend/video_plane.h
deleted file mode 100644
index a5f864c6d50..00000000000
--- a/chromium/chromecast/media/cma/backend/video_plane.h
+++ /dev/null
@@ -1,62 +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.
-
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PLANE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PLANE_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace gfx {
-class QuadF;
-class Size;
-}
-
-namespace chromecast {
-namespace media {
-
-class VideoPlane {
- public:
- enum CoordinateType {
- // Graphics plane as coordinate type.
- COORDINATE_TYPE_GRAPHICS_PLANE = 0,
- // Output display screen as coordinate type.
- COORDINATE_TYPE_SCREEN_RESOLUTION = 1,
- };
-
- VideoPlane();
- virtual ~VideoPlane();
-
- // Gets output screen resolution.
- virtual gfx::Size GetScreenResolution() = 0;
-
- // Updates the video plane geometry.
- // |quad.p1()| corresponds to the top left of the original video,
- // |quad.p2()| to the top right of the original video,
- // and so on.
- // Depending on the underlying hardware, the exact geometry
- // might not be honored.
- // |coordinate_type| indicates what coordinate type |quad| refers to.
- virtual void SetGeometry(const gfx::QuadF& quad,
- CoordinateType coordinate_type) = 0;
-
- // Should be invoked whenever screen resolution changes (e.g. when a device is
- // plugged into a new HDMI port and a new HDMI EDID is received).
- // VideoPlane should reposition itself according to the new screen resolution.
- virtual void OnScreenResolutionChanged(const gfx::Size& screen_res) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(VideoPlane);
-};
-
-// Factory to create a VideoPlane.
-scoped_ptr<VideoPlane> CreateVideoPlane();
-
-// Global accessor to the video plane.
-VideoPlane* GetVideoPlane();
-
-} // namespace media
-} // namespace chromecast
-
-#endif // CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PLANE_H_
diff --git a/chromium/chromecast/media/cma/backend/video_plane_fake.cc b/chromium/chromecast/media/cma/backend/video_plane_fake.cc
deleted file mode 100644
index 73fa39ef5b6..00000000000
--- a/chromium/chromecast/media/cma/backend/video_plane_fake.cc
+++ /dev/null
@@ -1,33 +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/cma/backend/video_plane_fake.h"
-
-#include "base/logging.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace chromecast {
-namespace media {
-
-VideoPlaneFake::VideoPlaneFake() {
-}
-
-VideoPlaneFake::~VideoPlaneFake() {
-}
-
-gfx::Size VideoPlaneFake::GetScreenResolution() {
- return gfx::Size(1920, 1080);
-}
-
-void VideoPlaneFake::SetGeometry(const gfx::QuadF& quad,
- CoordinateType coordinate_type) {
- // Nothing to be done.
-}
-
-void VideoPlaneFake::OnScreenResolutionChanged(const gfx::Size& screen_res) {
-}
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/backend/video_plane_fake.h b/chromium/chromecast/media/cma/backend/video_plane_fake.h
deleted file mode 100644
index 5fe04e6accb..00000000000
--- a/chromium/chromecast/media/cma/backend/video_plane_fake.h
+++ /dev/null
@@ -1,31 +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.
-
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PLANE_FAKE_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PLANE_FAKE_H_
-
-#include "base/macros.h"
-#include "chromecast/media/cma/backend/video_plane.h"
-
-namespace chromecast {
-namespace media {
-
-class VideoPlaneFake : public VideoPlane {
- public:
- VideoPlaneFake();
- ~VideoPlaneFake() override;
-
- // VideoPlane implementation.
- gfx::Size GetScreenResolution() override;
- void SetGeometry(const gfx::QuadF& quad,
- CoordinateType coordinate_type) override;
- void OnScreenResolutionChanged(const gfx::Size& screen_res) override;
-
- DISALLOW_COPY_AND_ASSIGN(VideoPlaneFake);
-};
-
-} // namespace media
-} // namespace chromecast
-
-#endif // CHROMECAST_MEDIA_CMA_BACKEND_VIDEO_PLANE_FAKE_H_
diff --git a/chromium/chromecast/media/cma/backend/video_plane_fake_factory.cc b/chromium/chromecast/media/cma/backend/video_plane_fake_factory.cc
deleted file mode 100644
index 310c8bc878a..00000000000
--- a/chromium/chromecast/media/cma/backend/video_plane_fake_factory.cc
+++ /dev/null
@@ -1,15 +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/cma/backend/video_plane_fake.h"
-
-namespace chromecast {
-namespace media {
-
-scoped_ptr<VideoPlane> CreateVideoPlane() {
- return make_scoped_ptr(new VideoPlaneFake());
-}
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/base/BUILD.gn b/chromium/chromecast/media/cma/base/BUILD.gn
index b919439cde6..49dbbdedfe4 100644
--- a/chromium/chromecast/media/cma/base/BUILD.gn
+++ b/chromium/chromecast/media/cma/base/BUILD.gn
@@ -21,15 +21,21 @@ source_set("base") {
"decoder_buffer_adapter.h",
"decoder_buffer_base.cc",
"decoder_buffer_base.h",
+ "decoder_config_adapter.cc",
+ "decoder_config_adapter.h",
"media_task_runner.cc",
"media_task_runner.h",
+ "simple_media_task_runner.cc",
+ "simple_media_task_runner.h",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
"//base",
"//chromecast/base",
+ "//chromecast/base/metrics",
"//media",
+ "//media:shared_memory_support",
]
-
- configs += [ "//chromecast:config" ]
}
diff --git a/chromium/chromecast/media/cma/base/balanced_media_task_runner_factory.cc b/chromium/chromecast/media/cma/base/balanced_media_task_runner_factory.cc
index f365534e457..3aba0730afe 100644
--- a/chromium/chromecast/media/cma/base/balanced_media_task_runner_factory.cc
+++ b/chromium/chromecast/media/cma/base/balanced_media_task_runner_factory.cc
@@ -244,8 +244,14 @@ void BalancedMediaTaskRunnerFactory::OnNewTask() {
void BalancedMediaTaskRunnerFactory::UnregisterMediaTaskRunner(
const scoped_refptr<BalancedMediaTaskRunner>& media_task_runner) {
- base::AutoLock auto_lock(lock_);
- task_runners_.erase(media_task_runner);
+ {
+ base::AutoLock auto_lock(lock_);
+ task_runners_.erase(media_task_runner);
+ }
+ // After removing one of the task runners some of the other task runners might
+ // need to be waken up, if they are no longer blocked by the balancing
+ // restrictions with the old stream.
+ OnNewTask();
}
} // namespace media
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 b572e500247..02e29d4334f 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,6 +9,7 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
@@ -100,7 +101,7 @@ void BalancedMediaTaskRunnerTest::SetupTest(
for (size_t k = 0; k < n; k++) {
contexts_[k].media_task_runner =
media_task_runner_factory_->CreateMediaTaskRunner(
- base::MessageLoopProxy::current());
+ base::ThreadTaskRunnerHandle::Get());
contexts_[k].is_pending_task = false;
contexts_[k].task_index = 0;
contexts_[k].task_timestamp_list.resize(
@@ -149,10 +150,9 @@ void BalancedMediaTaskRunnerTest::ScheduleTask() {
if (context.task_index >= context.task_timestamp_list.size() ||
context.is_pending_task) {
pattern_index_ = next_pattern_index;
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask,
- base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask,
+ base::Unretained(this)));
return;
}
@@ -177,10 +177,9 @@ void BalancedMediaTaskRunnerTest::ScheduleTask() {
context.task_index++;
pattern_index_ = next_pattern_index;
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask,
- base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask,
+ base::Unretained(this)));
}
void BalancedMediaTaskRunnerTest::Task(
@@ -190,6 +189,13 @@ void BalancedMediaTaskRunnerTest::Task(
expected_task_timestamps_.pop_front();
contexts_[task_runner_id].is_pending_task = false;
+
+ // Release task runner if the task has ended
+ // otherwise, the task runner may may block other streams
+ auto& context = contexts_[task_runner_id];
+ if (context.task_index >= context.task_timestamp_list.size()) {
+ context.media_task_runner = nullptr;
+ }
}
void BalancedMediaTaskRunnerTest::OnTestTimeout() {
@@ -259,5 +265,29 @@ TEST_F(BalancedMediaTaskRunnerTest, TwoTaskRunnerUnbalanced) {
EXPECT_TRUE(expected_task_timestamps_.empty());
}
+TEST_F(BalancedMediaTaskRunnerTest, TwoStreamsOfDifferentLength) {
+ scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
+
+ std::vector<std::vector<int>> timestamps = {
+ // One longer stream and one shorter stream.
+ // The longer stream runs first, then the shorter stream begins.
+ // After shorter stream ends, it shouldn't block the longer one.
+ {0, 20, 40, 60, 80, 100, 120, 140, 160},
+ {51, 61, 71, 81},
+ };
+
+ std::vector<int> expected_timestamps = {
+ 0, 20, 40, 60, 51, 80, 61, 71, 81, 100, 120, 140, 160};
+
+ std::vector<size_t> scheduling_pattern = {
+ 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0};
+
+ SetupTest(base::TimeDelta::FromMilliseconds(30), timestamps,
+ scheduling_pattern, expected_timestamps);
+ ProcessAllTasks();
+ message_loop->Run();
+ EXPECT_TRUE(expected_task_timestamps_.empty());
+}
+
} // namespace media
} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/base/buffering_controller.cc b/chromium/chromecast/media/cma/base/buffering_controller.cc
index 9e7cb6c9c01..3cd47bc9593 100644
--- a/chromium/chromecast/media/cma/base/buffering_controller.cc
+++ b/chromium/chromecast/media/cma/base/buffering_controller.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "chromecast/base/metrics/cast_metrics_helper.h"
#include "chromecast/media/cma/base/buffering_state.h"
#include "chromecast/media/cma/base/cma_logging.h"
diff --git a/chromium/chromecast/media/cma/base/buffering_frame_provider.cc b/chromium/chromecast/media/cma/base/buffering_frame_provider.cc
index b8d56985da4..7371426fc5f 100644
--- a/chromium/chromecast/media/cma/base/buffering_frame_provider.cc
+++ b/chromium/chromecast/media/cma/base/buffering_frame_provider.cc
@@ -114,7 +114,7 @@ void BufferingFrameProvider::RequestBufferIfNeeded() {
return;
is_pending_request_ = true;
- coded_frame_provider_->Read(BindToCurrentLoop(
+ coded_frame_provider_->Read(::media::BindToCurrentLoop(
base::Bind(&BufferingFrameProvider::OnNewBuffer, weak_this_)));
}
diff --git a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc
index 45095da169b..ed8a779b5c0 100644
--- a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc
+++ b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.cc
@@ -10,17 +10,31 @@ namespace chromecast {
namespace media {
DecoderBufferAdapter::DecoderBufferAdapter(
- const scoped_refptr< ::media::DecoderBuffer>& buffer)
- : buffer_(buffer) {
+ const scoped_refptr<::media::DecoderBuffer>& buffer)
+ : DecoderBufferAdapter(kPrimary, buffer) {
+}
+
+DecoderBufferAdapter::DecoderBufferAdapter(
+ StreamId stream_id, const scoped_refptr<::media::DecoderBuffer>& buffer)
+ : stream_id_(stream_id),
+ buffer_(buffer) {
}
DecoderBufferAdapter::~DecoderBufferAdapter() {
}
+StreamId DecoderBufferAdapter::stream_id() const {
+ return stream_id_;
+}
+
base::TimeDelta DecoderBufferAdapter::timestamp() const {
return buffer_->timestamp();
}
+void DecoderBufferAdapter::set_timestamp(const base::TimeDelta& timestamp) {
+ buffer_->set_timestamp(timestamp);
+}
+
const uint8* DecoderBufferAdapter::data() const {
return buffer_->data();
}
diff --git a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h
index 054e60ee59e..7c48ec8a40b 100644
--- a/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h
+++ b/chromium/chromecast/media/cma/base/decoder_buffer_adapter.h
@@ -20,11 +20,17 @@ namespace media {
// into a DecoderBufferBase.
class DecoderBufferAdapter : public DecoderBufferBase {
public:
+ // Using explicit constructor without providing stream Id will set it to
+ // kPrimary by default.
explicit DecoderBufferAdapter(
- const scoped_refptr< ::media::DecoderBuffer>& buffer);
+ const scoped_refptr<::media::DecoderBuffer>& buffer);
+ DecoderBufferAdapter(
+ StreamId stream_id, const scoped_refptr<::media::DecoderBuffer>& buffer);
// DecoderBufferBase implementation.
+ StreamId stream_id() const override;
base::TimeDelta timestamp() const override;
+ void set_timestamp(const base::TimeDelta& timestamp) override;
const uint8* data() const override;
uint8* writable_data() const override;
size_t data_size() const override;
@@ -34,7 +40,8 @@ class DecoderBufferAdapter : public DecoderBufferBase {
private:
~DecoderBufferAdapter() override;
- scoped_refptr< ::media::DecoderBuffer> const buffer_;
+ StreamId stream_id_;
+ scoped_refptr<::media::DecoderBuffer> const buffer_;
DISALLOW_COPY_AND_ASSIGN(DecoderBufferAdapter);
};
diff --git a/chromium/chromecast/media/cma/base/decoder_buffer_base.h b/chromium/chromecast/media/cma/base/decoder_buffer_base.h
index 099b44d7a9e..1fca1b27e91 100644
--- a/chromium/chromecast/media/cma/base/decoder_buffer_base.h
+++ b/chromium/chromecast/media/cma/base/decoder_buffer_base.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
+#include "chromecast/public/media/stream_id.h"
namespace media {
class DecryptConfig;
@@ -25,9 +26,16 @@ class DecoderBufferBase
public:
DecoderBufferBase();
+ // Returns the stream id of this decoder buffer belonging to. it's optional
+ // and default value is kPrimary.
+ virtual StreamId stream_id() const = 0;
+
// Returns the PTS of the frame.
virtual base::TimeDelta timestamp() const = 0;
+ // Sets the PTS of the frame.
+ virtual void set_timestamp(const base::TimeDelta& timestamp) = 0;
+
// Gets the frame data.
virtual const uint8* data() const = 0;
virtual uint8* writable_data() const = 0;
diff --git a/chromium/chromecast/media/cma/base/decoder_config_adapter.cc b/chromium/chromecast/media/cma/base/decoder_config_adapter.cc
index 793395c9c14..b75d5f2be86 100644
--- a/chromium/chromecast/media/cma/base/decoder_config_adapter.cc
+++ b/chromium/chromecast/media/cma/base/decoder_config_adapter.cc
@@ -32,6 +32,29 @@ AudioCodec ToAudioCodec(const ::media::AudioCodec audio_codec) {
return kAudioCodecUnknown;
}
+SampleFormat ToSampleFormat(const ::media::SampleFormat sample_format) {
+ switch (sample_format) {
+ case ::media::kUnknownSampleFormat:
+ return kUnknownSampleFormat;
+ case ::media::kSampleFormatU8:
+ return kSampleFormatU8;
+ case ::media::kSampleFormatS16:
+ return kSampleFormatS16;
+ case ::media::kSampleFormatS32:
+ return kSampleFormatS32;
+ case ::media::kSampleFormatF32:
+ return kSampleFormatF32;
+ case ::media::kSampleFormatPlanarS16:
+ return kSampleFormatPlanarS16;
+ case ::media::kSampleFormatPlanarF32:
+ return kSampleFormatPlanarF32;
+ case ::media::kSampleFormatPlanarS32:
+ return kSampleFormatPlanarS32;
+ }
+ NOTREACHED();
+ return kUnknownSampleFormat;
+}
+
// Converts ::media::VideoCodec to chromecast::media::VideoCodec. Any unknown or
// unsupported codec will be converted to chromecast::media::kCodecUnknown.
VideoCodec ToVideoCodec(const ::media::VideoCodec video_codec) {
@@ -83,36 +106,108 @@ VideoProfile ToVideoProfile(const ::media::VideoCodecProfile codec_profile) {
return kVideoProfileUnknown;
}
+::media::ChannelLayout ToMediaChannelLayout(int channel_number) {
+ switch (channel_number) {
+ case 1:
+ return ::media::ChannelLayout::CHANNEL_LAYOUT_MONO;
+ case 2:
+ return ::media::ChannelLayout::CHANNEL_LAYOUT_STEREO;
+ default:
+ return ::media::ChannelLayout::CHANNEL_LAYOUT_UNSUPPORTED;
+ }
+}
+
+::media::SampleFormat ToMediaSampleFormat(const SampleFormat sample_format) {
+ switch (sample_format) {
+ case kUnknownSampleFormat:
+ return ::media::kUnknownSampleFormat;
+ case kSampleFormatU8:
+ return ::media::kSampleFormatU8;
+ case kSampleFormatS16:
+ return ::media::kSampleFormatS16;
+ case kSampleFormatS32:
+ return ::media::kSampleFormatS32;
+ case kSampleFormatF32:
+ return ::media::kSampleFormatF32;
+ case kSampleFormatPlanarS16:
+ return ::media::kSampleFormatPlanarS16;
+ case kSampleFormatPlanarF32:
+ return ::media::kSampleFormatPlanarF32;
+ case kSampleFormatPlanarS32:
+ return ::media::kSampleFormatPlanarS32;
+ default:
+ NOTREACHED();
+ return ::media::kUnknownSampleFormat;
+ }
+}
+
+::media::AudioCodec ToMediaAudioCodec(
+ const chromecast::media::AudioCodec codec) {
+ switch (codec) {
+ case kAudioCodecUnknown:
+ return ::media::kUnknownAudioCodec;
+ case kCodecAAC:
+ return ::media::kCodecAAC;
+ case kCodecMP3:
+ return ::media::kCodecMP3;
+ case kCodecPCM:
+ return ::media::kCodecPCM;
+ case kCodecPCM_S16BE:
+ return ::media::kCodecPCM_S16BE;
+ case kCodecVorbis:
+ return ::media::kCodecVorbis;
+ case kCodecOpus:
+ return ::media::kCodecOpus;
+ default:
+ return ::media::kUnknownAudioCodec;
+ }
+}
+
} // namespace
// static
AudioConfig DecoderConfigAdapter::ToCastAudioConfig(
+ StreamId id,
const ::media::AudioDecoderConfig& config) {
AudioConfig audio_config;
if (!config.IsValidConfig()) {
return audio_config;
}
+ audio_config.id = id;
audio_config.codec = ToAudioCodec(config.codec());
+ audio_config.sample_format = ToSampleFormat(config.sample_format());
audio_config.bytes_per_channel = config.bytes_per_channel();
audio_config.channel_number =
::media::ChannelLayoutToChannelCount(config.channel_layout()),
- audio_config.samples_per_second = config.samples_per_second();
- audio_config.extra_data = (config.extra_data_size() > 0) ?
- config.extra_data() : nullptr;
+ audio_config.samples_per_second = config.samples_per_second();
+ audio_config.extra_data =
+ (config.extra_data_size() > 0) ? config.extra_data() : nullptr;
audio_config.extra_data_size = config.extra_data_size();
audio_config.is_encrypted = config.is_encrypted();
return audio_config;
}
// static
+::media::AudioDecoderConfig DecoderConfigAdapter::ToMediaAudioDecoderConfig(
+ const AudioConfig& config) {
+ return ::media::AudioDecoderConfig(
+ ToMediaAudioCodec(config.codec),
+ ToMediaSampleFormat(config.sample_format),
+ ToMediaChannelLayout(config.channel_number), config.samples_per_second,
+ config.extra_data, config.extra_data_size, config.is_encrypted);
+}
+
+// static
VideoConfig DecoderConfigAdapter::ToCastVideoConfig(
+ StreamId id,
const ::media::VideoDecoderConfig& config) {
VideoConfig video_config;
if (!config.IsValidConfig()) {
return video_config;
}
+ video_config.id = id;
video_config.codec = ToVideoCodec(config.codec());
video_config.profile = ToVideoProfile(config.profile());
video_config.extra_data = (config.extra_data_size() > 0) ?
diff --git a/chromium/chromecast/media/cma/base/decoder_config_adapter.h b/chromium/chromecast/media/cma/base/decoder_config_adapter.h
index f04c1c2f1d3..07a54a6dd6c 100644
--- a/chromium/chromecast/media/cma/base/decoder_config_adapter.h
+++ b/chromium/chromecast/media/cma/base/decoder_config_adapter.h
@@ -16,10 +16,16 @@ class DecoderConfigAdapter {
public:
// Converts ::media::AudioDecoderConfig to chromecast::media::AudioConfig.
static AudioConfig ToCastAudioConfig(
+ StreamId id,
const ::media::AudioDecoderConfig& config);
+ // Converts chromecast::media::AudioConfig to ::media::AudioDecoderConfig.
+ static ::media::AudioDecoderConfig ToMediaAudioDecoderConfig(
+ const AudioConfig& config);
+
// Converts ::media::VideoDecoderConfig to chromecast::media::VideoConfig.
static VideoConfig ToCastVideoConfig(
+ StreamId id,
const ::media::VideoDecoderConfig& config);
};
diff --git a/chromium/chromecast/media/cma/base/simple_media_task_runner.cc b/chromium/chromecast/media/cma/base/simple_media_task_runner.cc
new file mode 100644
index 00000000000..c4a54395f66
--- /dev/null
+++ b/chromium/chromecast/media/cma/base/simple_media_task_runner.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 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/simple_media_task_runner.h"
+
+#include "base/single_thread_task_runner.h"
+
+namespace chromecast {
+namespace media {
+
+SimpleMediaTaskRunner::SimpleMediaTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : task_runner_(task_runner) {
+}
+
+SimpleMediaTaskRunner::~SimpleMediaTaskRunner() {
+}
+
+bool SimpleMediaTaskRunner::PostMediaTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta timestamp) {
+ return task_runner_->PostTask(from_here, task);
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/base/simple_media_task_runner.h b/chromium/chromecast/media/cma/base/simple_media_task_runner.h
new file mode 100644
index 00000000000..67979f70f1d
--- /dev/null
+++ b/chromium/chromecast/media/cma/base/simple_media_task_runner.h
@@ -0,0 +1,42 @@
+// Copyright 2015 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_BASE_SIMPLE_MEDIA_TASK_RUNNER_H_
+#define CHROMECAST_MEDIA_CMA_BASE_SIMPLE_MEDIA_TASK_RUNNER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "chromecast/media/cma/base/media_task_runner.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace chromecast {
+namespace media {
+
+// This is a light version of task runner which post tasks immediately
+// by ignoring the timestamps once receiving the request.
+class SimpleMediaTaskRunner : public MediaTaskRunner {
+ public:
+ SimpleMediaTaskRunner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ // MediaTaskRunner implementation.
+ bool PostMediaTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta timestamp) override;
+
+ private:
+ ~SimpleMediaTaskRunner() override;
+
+ scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleMediaTaskRunner);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_BASE_SIMPLE_MEDIA_TASK_RUNNER_H_
diff --git a/chromium/chromecast/media/cma/filters/BUILD.gn b/chromium/chromecast/media/cma/filters/BUILD.gn
index 605075533f9..7126bbb2941 100644
--- a/chromium/chromecast/media/cma/filters/BUILD.gn
+++ b/chromium/chromecast/media/cma/filters/BUILD.gn
@@ -8,13 +8,20 @@ source_set("filters") {
"cma_renderer.h",
"demuxer_stream_adapter.cc",
"demuxer_stream_adapter.h",
+ "hole_frame_factory.cc",
+ "hole_frame_factory.h",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
"//base",
+ "//chromecast/base",
"//chromecast/media/cma/base",
+ "//chromecast/media/cma/pipeline",
+ "//gpu/command_buffer/client:gles2_interface",
+ "//gpu/command_buffer/common",
"//media",
+ "//ui/gfx/geometry",
]
-
- configs += [ "//chromecast:config" ]
}
diff --git a/chromium/chromecast/media/cma/filters/cma_renderer.cc b/chromium/chromecast/media/cma/filters/cma_renderer.cc
index b8e7b42ba9a..d2ec2bd82e3 100644
--- a/chromium/chromecast/media/cma/filters/cma_renderer.cc
+++ b/chromium/chromecast/media/cma/filters/cma_renderer.cc
@@ -7,10 +7,12 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
#include "chromecast/media/cma/base/cma_logging.h"
#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/media/cma/filters/hole_frame_factory.h"
#include "chromecast/media/cma/pipeline/audio_pipeline.h"
#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
#include "chromecast/media/cma/pipeline/media_pipeline.h"
@@ -21,8 +23,8 @@
#include "media/base/demuxer_stream_provider.h"
#include "media/base/pipeline_status.h"
#include "media/base/time_delta_interpolator.h"
-#include "media/base/video_frame.h"
#include "media/base/video_renderer_sink.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
#include "ui/gfx/geometry/size.h"
namespace chromecast {
@@ -37,8 +39,10 @@ const base::TimeDelta kMaxDeltaFetcher(
} // namespace
-CmaRenderer::CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline,
- ::media::VideoRendererSink* video_renderer_sink)
+CmaRenderer::CmaRenderer(
+ scoped_ptr<MediaPipeline> media_pipeline,
+ ::media::VideoRendererSink* video_renderer_sink,
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories)
: media_task_runner_factory_(
new BalancedMediaTaskRunnerFactory(kMaxDeltaFetcher)),
media_pipeline_(media_pipeline.Pass()),
@@ -53,6 +57,7 @@ CmaRenderer::CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline,
received_video_eos_(false),
initial_natural_size_(gfx::Size()),
initial_video_hole_created_(false),
+ gpu_factories_(gpu_factories),
time_interpolator_(
new ::media::TimeDeltaInterpolator(&default_tick_clock_)),
playback_rate_(1.0),
@@ -94,6 +99,9 @@ void CmaRenderer::Initialize(
DCHECK(demuxer_stream_provider->GetStream(::media::DemuxerStream::AUDIO) ||
demuxer_stream_provider->GetStream(::media::DemuxerStream::VIDEO));
+ // Deferred from ctor so as to initialise on correct thread.
+ hole_frame_factory_.reset(new HoleFrameFactory(gpu_factories_));
+
BeginStateTransition();
demuxer_stream_provider_ = demuxer_stream_provider;
@@ -151,7 +159,6 @@ void CmaRenderer::StartPlayingFrom(base::TimeDelta time) {
return;
}
-#if defined(VIDEO_HOLE)
// Create a video hole frame just before starting playback.
// Note that instead of creating the video hole frame in Initialize(), we do
// it here because paint_cb_ (which eventually calls OnOpacityChanged)
@@ -162,9 +169,8 @@ void CmaRenderer::StartPlayingFrom(base::TimeDelta time) {
if (!initial_video_hole_created_) {
initial_video_hole_created_ = true;
video_renderer_sink_->PaintFrameUsingOldRenderingPath(
- ::media::VideoFrame::CreateHoleFrame(initial_natural_size_));
+ hole_frame_factory_->CreateHoleFrame(initial_natural_size_));
}
-#endif
{
base::AutoLock auto_lock(time_interpolator_lock_);
@@ -232,13 +238,14 @@ void CmaRenderer::InitializeAudioPipeline() {
DCHECK_EQ(state_, kUninitialized) << state_;
DCHECK(!init_cb_.is_null());
- ::media::PipelineStatusCB audio_initialization_done_cb =
- ::media::BindToCurrentLoop(
- base::Bind(&CmaRenderer::OnAudioPipelineInitializeDone, weak_this_));
-
::media::DemuxerStream* stream =
demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO);
+ ::media::PipelineStatusCB audio_initialization_done_cb =
+ ::media::BindToCurrentLoop(
+ base::Bind(&CmaRenderer::OnAudioPipelineInitializeDone, weak_this_,
+ stream != nullptr));
if (!stream) {
+ CMALOG(kLogControl) << __FUNCTION__ << ": no audio stream, skipping init.";
audio_initialization_done_cb.Run(::media::PIPELINE_OK);
return;
}
@@ -253,11 +260,8 @@ void CmaRenderer::InitializeAudioPipeline() {
base::Bind(&CmaRenderer::OnStatisticsUpdated, weak_this_));
audio_pipeline_->SetClient(av_pipeline_client);
- scoped_ptr<CodedFrameProvider> frame_provider(
- new DemuxerStreamAdapter(
- base::MessageLoopProxy::current(),
- media_task_runner_factory_,
- stream));
+ scoped_ptr<CodedFrameProvider> frame_provider(new DemuxerStreamAdapter(
+ base::ThreadTaskRunnerHandle::Get(), media_task_runner_factory_, stream));
const ::media::AudioDecoderConfig& config = stream->audio_decoder_config();
if (config.codec() == ::media::kCodecAAC)
@@ -268,7 +272,9 @@ void CmaRenderer::InitializeAudioPipeline() {
}
void CmaRenderer::OnAudioPipelineInitializeDone(
+ bool audio_stream_present,
::media::PipelineStatus status) {
+ CMALOG(kLogControl) << __FUNCTION__ << ": state=" << state_;
DCHECK(thread_checker_.CalledOnValidThread());
// OnError() may be fired at any time, even before initialization is complete.
@@ -281,8 +287,8 @@ void CmaRenderer::OnAudioPipelineInitializeDone(
base::ResetAndReturn(&init_cb_).Run(status);
return;
}
- has_audio_ = true;
+ has_audio_ = audio_stream_present;
InitializeVideoPipeline();
}
@@ -291,13 +297,14 @@ void CmaRenderer::InitializeVideoPipeline() {
DCHECK_EQ(state_, kUninitialized) << state_;
DCHECK(!init_cb_.is_null());
- ::media::PipelineStatusCB video_initialization_done_cb =
- ::media::BindToCurrentLoop(
- base::Bind(&CmaRenderer::OnVideoPipelineInitializeDone, weak_this_));
-
::media::DemuxerStream* stream =
demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO);
+ ::media::PipelineStatusCB video_initialization_done_cb =
+ ::media::BindToCurrentLoop(
+ base::Bind(&CmaRenderer::OnVideoPipelineInitializeDone, weak_this_,
+ stream != nullptr));
if (!stream) {
+ CMALOG(kLogControl) << __FUNCTION__ << ": no video stream, skipping init.";
video_initialization_done_cb.Run(::media::PIPELINE_OK);
return;
}
@@ -314,11 +321,8 @@ void CmaRenderer::InitializeVideoPipeline() {
base::Bind(&CmaRenderer::OnNaturalSizeChanged, weak_this_));
video_pipeline_->SetClient(client);
- scoped_ptr<CodedFrameProvider> frame_provider(
- new DemuxerStreamAdapter(
- base::MessageLoopProxy::current(),
- media_task_runner_factory_,
- stream));
+ scoped_ptr<CodedFrameProvider> frame_provider(new DemuxerStreamAdapter(
+ base::ThreadTaskRunnerHandle::Get(), media_task_runner_factory_, stream));
const ::media::VideoDecoderConfig& config = stream->video_decoder_config();
if (config.codec() == ::media::kCodecH264)
@@ -326,14 +330,18 @@ void CmaRenderer::InitializeVideoPipeline() {
initial_natural_size_ = config.natural_size();
+ std::vector<::media::VideoDecoderConfig> configs;
+ configs.push_back(config);
media_pipeline_->InitializeVideo(
- config,
+ configs,
frame_provider.Pass(),
video_initialization_done_cb);
}
void CmaRenderer::OnVideoPipelineInitializeDone(
+ bool video_stream_present,
::media::PipelineStatus status) {
+ CMALOG(kLogControl) << __FUNCTION__ << ": state=" << state_;
DCHECK(thread_checker_.CalledOnValidThread());
// OnError() may be fired at any time, even before initialization is complete.
@@ -346,17 +354,16 @@ void CmaRenderer::OnVideoPipelineInitializeDone(
base::ResetAndReturn(&init_cb_).Run(status);
return;
}
- has_video_ = true;
+ has_video_ = video_stream_present;
CompleteStateTransition(kFlushed);
base::ResetAndReturn(&init_cb_).Run(::media::PIPELINE_OK);
}
void CmaRenderer::OnEosReached(bool is_audio) {
DCHECK(thread_checker_.CalledOnValidThread());
- CMALOG(kLogControl) << __FUNCTION__;
if (state_ != kPlaying) {
- LOG(WARNING) << "Ignoring a late EOS event";
+ LOG(WARNING) << __FUNCTION__ << " Ignoring a late EOS event";
return;
}
@@ -370,6 +377,9 @@ void CmaRenderer::OnEosReached(bool is_audio) {
bool audio_finished = !has_audio_ || received_audio_eos_;
bool video_finished = !has_video_ || received_video_eos_;
+ CMALOG(kLogControl) << __FUNCTION__
+ << " audio_finished=" << audio_finished
+ << " video_finished=" << video_finished;
if (audio_finished && video_finished)
ended_cb_.Run();
}
@@ -382,10 +392,8 @@ void CmaRenderer::OnStatisticsUpdated(
void CmaRenderer::OnNaturalSizeChanged(const gfx::Size& size) {
DCHECK(thread_checker_.CalledOnValidThread());
-#if defined(VIDEO_HOLE)
video_renderer_sink_->PaintFrameUsingOldRenderingPath(
- ::media::VideoFrame::CreateHoleFrame(size));
-#endif
+ hole_frame_factory_->CreateHoleFrame(size));
}
void CmaRenderer::OnPlaybackTimeUpdated(
diff --git a/chromium/chromecast/media/cma/filters/cma_renderer.h b/chromium/chromecast/media/cma/filters/cma_renderer.h
index d33699ea586..f76226bd215 100644
--- a/chromium/chromecast/media/cma/filters/cma_renderer.h
+++ b/chromium/chromecast/media/cma/filters/cma_renderer.h
@@ -16,11 +16,12 @@
#include "ui/gfx/geometry/size.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace media {
class DemuxerStreamProvider;
+class GpuVideoAcceleratorFactories;
class TimeDeltaInterpolator;
class VideoFrame;
class VideoRendererSink;
@@ -30,13 +31,16 @@ namespace chromecast {
namespace media {
class AudioPipeline;
class BalancedMediaTaskRunnerFactory;
+class HoleFrameFactory;
class MediaPipeline;
class VideoPipeline;
class CmaRenderer : public ::media::Renderer {
public:
CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline,
- ::media::VideoRendererSink* video_renderer_sink);
+ ::media::VideoRendererSink* video_renderer_sink,
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>&
+ gpu_factories);
~CmaRenderer() override;
// ::media::Renderer implementation:
@@ -70,9 +74,11 @@ class CmaRenderer : public ::media::Renderer {
// the order below, with a successful initialization making it to
// OnVideoPipelineInitializeDone, regardless of which streams are present.
void InitializeAudioPipeline();
- void OnAudioPipelineInitializeDone(::media::PipelineStatus status);
+ void OnAudioPipelineInitializeDone(bool audio_stream_present,
+ ::media::PipelineStatus status);
void InitializeVideoPipeline();
- void OnVideoPipelineInitializeDone(::media::PipelineStatus status);
+ void OnVideoPipelineInitializeDone(bool video_stream_present,
+ ::media::PipelineStatus status);
// Callbacks for AvPipelineClient.
void OnEosReached(bool is_audio);
@@ -123,9 +129,11 @@ class CmaRenderer : public ::media::Renderer {
bool received_audio_eos_;
bool received_video_eos_;
- // Data members for helping the creation of the initial video hole frame.
+ // Data members for helping the creation of the video hole frame.
gfx::Size initial_natural_size_;
bool initial_video_hole_created_;
+ scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_;
+ scoped_ptr<HoleFrameFactory> hole_frame_factory_;
// Lock protecting access to |time_interpolator_|.
base::Lock time_interpolator_lock_;
diff --git a/chromium/chromecast/media/cma/filters/demuxer_stream_adapter.cc b/chromium/chromecast/media/cma/filters/demuxer_stream_adapter.cc
index c2fd5a47861..40725237bb7 100644
--- a/chromium/chromecast/media/cma/filters/demuxer_stream_adapter.cc
+++ b/chromium/chromecast/media/cma/filters/demuxer_stream_adapter.cc
@@ -10,7 +10,7 @@
#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
#include "chromecast/media/cma/base/cma_logging.h"
#include "chromecast/media/cma/base/decoder_buffer_adapter.h"
-#include "chromecast/media/cma/base/media_task_runner.h"
+#include "chromecast/media/cma/base/simple_media_task_runner.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/buffers.h"
#include "media/base/decoder_buffer.h"
@@ -19,52 +19,14 @@
namespace chromecast {
namespace media {
-namespace {
-
-class DummyMediaTaskRunner : public MediaTaskRunner {
- public:
- DummyMediaTaskRunner(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
-
- // MediaTaskRunner implementation.
- bool PostMediaTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta timestamp) override;
-
- private:
- ~DummyMediaTaskRunner() override;
-
- scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(DummyMediaTaskRunner);
-};
-
-DummyMediaTaskRunner::DummyMediaTaskRunner(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
- : task_runner_(task_runner) {
-}
-
-DummyMediaTaskRunner::~DummyMediaTaskRunner() {
-}
-
-bool DummyMediaTaskRunner::PostMediaTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta timestamp) {
- return task_runner_->PostTask(from_here, task);
-}
-
-} // namespace
-
DemuxerStreamAdapter::DemuxerStreamAdapter(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const scoped_refptr<BalancedMediaTaskRunnerFactory>&
- media_task_runner_factory,
+ media_task_runner_factory,
::media::DemuxerStream* demuxer_stream)
: task_runner_(task_runner),
media_task_runner_factory_(media_task_runner_factory),
- media_task_runner_(new DummyMediaTaskRunner(task_runner)),
+ media_task_runner_(new SimpleMediaTaskRunner(task_runner)),
demuxer_stream_(demuxer_stream),
is_pending_read_(false),
is_pending_demuxer_read_(false),
@@ -152,7 +114,7 @@ void DemuxerStreamAdapter::RequestBuffer(const ReadCB& read_cb) {
void DemuxerStreamAdapter::OnNewBuffer(
const ReadCB& read_cb,
::media::DemuxerStream::Status status,
- const scoped_refptr< ::media::DecoderBuffer>& input) {
+ const scoped_refptr<::media::DecoderBuffer>& input) {
DCHECK(thread_checker_.CalledOnValidThread());
is_pending_demuxer_read_ = false;
diff --git a/chromium/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc b/chromium/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
index 084acd7e3a4..f7d668a1973 100644
--- a/chromium/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
+++ b/chromium/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
@@ -8,11 +8,14 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
#include "chromecast/media/cma/base/decoder_buffer_base.h"
#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer_stream.h"
@@ -22,134 +25,6 @@
namespace chromecast {
namespace media {
-namespace {
-
-class DummyDemuxerStream : public ::media::DemuxerStream {
- public:
- // Creates a demuxer stream which provides frames either with a delay
- // or instantly. The scheduling pattern is the following:
- // - provides |delayed_frame_count| frames with a delay,
- // - then provides the following |cycle_count| - |delayed_frame_count|
- // instantly,
- // - then provides |delayed_frame_count| frames with a delay,
- // - ... and so on.
- // Special cases:
- // - all frames are delayed: |delayed_frame_count| = |cycle_count|
- // - all frames are provided instantly: |delayed_frame_count| = 0
- // |config_idx| is a list of frame index before which there is
- // a change of decoder configuration.
- DummyDemuxerStream(int cycle_count,
- int delayed_frame_count,
- const std::list<int>& config_idx);
- ~DummyDemuxerStream() override;
-
- // ::media::DemuxerStream implementation.
- void Read(const ReadCB& read_cb) override;
- ::media::AudioDecoderConfig audio_decoder_config() override;
- ::media::VideoDecoderConfig video_decoder_config() override;
- Type type() const override;
- bool SupportsConfigChanges() override;
- ::media::VideoRotation video_rotation() override;
-
- bool has_pending_read() const {
- return has_pending_read_;
- }
-
- private:
- void DoRead(const ReadCB& read_cb);
-
- // Demuxer configuration.
- const int cycle_count_;
- const int delayed_frame_count_;
- std::list<int> config_idx_;
-
- // Number of frames sent so far.
- int frame_count_;
-
- bool has_pending_read_;
-
- DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream);
-};
-
-DummyDemuxerStream::DummyDemuxerStream(
- int cycle_count,
- int delayed_frame_count,
- const std::list<int>& config_idx)
- : cycle_count_(cycle_count),
- delayed_frame_count_(delayed_frame_count),
- config_idx_(config_idx),
- frame_count_(0),
- has_pending_read_(false) {
- DCHECK_LE(delayed_frame_count, cycle_count);
-}
-
-DummyDemuxerStream::~DummyDemuxerStream() {
-}
-
-void DummyDemuxerStream::Read(const ReadCB& read_cb) {
- has_pending_read_ = true;
- if (!config_idx_.empty() && config_idx_.front() == frame_count_) {
- config_idx_.pop_front();
- has_pending_read_ = false;
- read_cb.Run(kConfigChanged,
- scoped_refptr< ::media::DecoderBuffer>());
- return;
- }
-
- if ((frame_count_ % cycle_count_) < delayed_frame_count_) {
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&DummyDemuxerStream::DoRead, base::Unretained(this),
- read_cb),
- base::TimeDelta::FromMilliseconds(20));
- return;
- }
- DoRead(read_cb);
-}
-
-::media::AudioDecoderConfig DummyDemuxerStream::audio_decoder_config() {
- LOG(FATAL) << "DummyDemuxerStream is a video DemuxerStream";
- return ::media::AudioDecoderConfig();
-}
-
-::media::VideoDecoderConfig DummyDemuxerStream::video_decoder_config() {
- gfx::Size coded_size(640, 480);
- gfx::Rect visible_rect(640, 480);
- gfx::Size natural_size(640, 480);
- return ::media::VideoDecoderConfig(
- ::media::kCodecH264,
- ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
- ::media::VideoFrame::YV12,
- coded_size,
- visible_rect,
- natural_size,
- NULL, 0,
- false);
-}
-
-::media::DemuxerStream::Type DummyDemuxerStream::type() const {
- return VIDEO;
-}
-
-bool DummyDemuxerStream::SupportsConfigChanges() {
- return true;
-}
-
-::media::VideoRotation DummyDemuxerStream::video_rotation() {
- return ::media::VIDEO_ROTATION_0;
-}
-
-void DummyDemuxerStream::DoRead(const ReadCB& read_cb) {
- has_pending_read_ = false;
- scoped_refptr< ::media::DecoderBuffer> buffer(
- new ::media::DecoderBuffer(16));
- buffer->set_timestamp(frame_count_ * base::TimeDelta::FromMilliseconds(40));
- frame_count_++;
- read_cb.Run(kOk, buffer);
-}
-
-} // namespace
-
class DemuxerStreamAdapterTest : public testing::Test {
public:
DemuxerStreamAdapterTest();
@@ -181,7 +56,7 @@ class DemuxerStreamAdapterTest : public testing::Test {
// List of expected frame indices with decoder config changes.
std::list<int> config_idx_;
- scoped_ptr<DummyDemuxerStream> demuxer_stream_;
+ scoped_ptr<DemuxerStreamForTest> demuxer_stream_;
scoped_ptr<CodedFrameProvider> coded_frame_provider_;
@@ -197,11 +72,9 @@ DemuxerStreamAdapterTest::~DemuxerStreamAdapterTest() {
void DemuxerStreamAdapterTest::Initialize(
::media::DemuxerStream* demuxer_stream) {
- coded_frame_provider_.reset(
- new DemuxerStreamAdapter(
- base::MessageLoopProxy::current(),
- scoped_refptr<BalancedMediaTaskRunnerFactory>(),
- demuxer_stream));
+ coded_frame_provider_.reset(new DemuxerStreamAdapter(
+ base::ThreadTaskRunnerHandle::Get(),
+ scoped_refptr<BalancedMediaTaskRunnerFactory>(), demuxer_stream));
}
void DemuxerStreamAdapterTest::Start() {
@@ -286,9 +159,8 @@ TEST_F(DemuxerStreamAdapterTest, NoDelay) {
int cycle_count = 1;
int delayed_frame_count = 0;
- demuxer_stream_.reset(
- new DummyDemuxerStream(
- cycle_count, delayed_frame_count, config_idx_));
+ demuxer_stream_.reset(new DemuxerStreamForTest(
+ -1, cycle_count, delayed_frame_count, config_idx_));
scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
Initialize(demuxer_stream_.get());
@@ -307,9 +179,8 @@ TEST_F(DemuxerStreamAdapterTest, AllDelayed) {
int cycle_count = 1;
int delayed_frame_count = 1;
- demuxer_stream_.reset(
- new DummyDemuxerStream(
- cycle_count, delayed_frame_count, config_idx_));
+ demuxer_stream_.reset(new DemuxerStreamForTest(
+ -1, cycle_count, delayed_frame_count, config_idx_));
scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
Initialize(demuxer_stream_.get());
@@ -329,9 +200,8 @@ TEST_F(DemuxerStreamAdapterTest, AllDelayedEarlyFlush) {
int cycle_count = 1;
int delayed_frame_count = 1;
- demuxer_stream_.reset(
- new DummyDemuxerStream(
- cycle_count, delayed_frame_count, config_idx_));
+ demuxer_stream_.reset(new DemuxerStreamForTest(
+ -1, cycle_count, delayed_frame_count, config_idx_));
scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
Initialize(demuxer_stream_.get());
diff --git a/chromium/chromecast/media/cma/filters/hole_frame_factory.cc b/chromium/chromecast/media/cma/filters/hole_frame_factory.cc
new file mode 100644
index 00000000000..caad1886dec
--- /dev/null
+++ b/chromium/chromecast/media/cma/filters/hole_frame_factory.cc
@@ -0,0 +1,79 @@
+// Copyright 2015 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/filters/hole_frame_factory.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "chromecast/base/chromecast_switches.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "media/base/video_frame.h"
+#include "media/renderers/gpu_video_accelerator_factories.h"
+
+namespace chromecast {
+namespace media {
+
+HoleFrameFactory::HoleFrameFactory(
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories)
+ : gpu_factories_(gpu_factories),
+ texture_(0),
+ image_id_(0),
+ sync_point_(0),
+ use_legacy_hole_punching_(
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableLegacyHolePunching)) {
+ if (!use_legacy_hole_punching_) {
+ gpu::gles2::GLES2Interface* gl = gpu_factories_->GetGLES2Interface();
+ CHECK(gl);
+
+ gl->GenTextures(1, &texture_);
+ gl->BindTexture(GL_TEXTURE_2D, texture_);
+ image_id_ = gl->CreateGpuMemoryBufferImageCHROMIUM(1, 1, GL_RGBA,
+ GL_SCANOUT_CHROMIUM);
+ gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_);
+
+ gl->GenMailboxCHROMIUM(mailbox_.name);
+ gl->ProduceTextureDirectCHROMIUM(texture_, GL_TEXTURE_2D, mailbox_.name);
+
+ sync_point_ = gl->InsertSyncPointCHROMIUM();
+ }
+}
+
+HoleFrameFactory::~HoleFrameFactory() {
+ if (texture_ != 0) {
+ gpu::gles2::GLES2Interface* gl = gpu_factories_->GetGLES2Interface();
+ gl->BindTexture(GL_TEXTURE_2D, texture_);
+ gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_);
+ gl->DeleteTextures(1, &texture_);
+ gl->DestroyImageCHROMIUM(image_id_);
+ }
+}
+
+scoped_refptr<::media::VideoFrame> HoleFrameFactory::CreateHoleFrame(
+ const gfx::Size& size) {
+ if (use_legacy_hole_punching_) {
+#if defined(VIDEO_HOLE)
+ return ::media::VideoFrame::CreateHoleFrame(size);
+#endif
+ NOTREACHED();
+ }
+
+ scoped_refptr<::media::VideoFrame> frame =
+ ::media::VideoFrame::WrapNativeTexture(
+ ::media::VideoFrame::XRGB,
+ gpu::MailboxHolder(mailbox_, GL_TEXTURE_2D, sync_point_),
+ ::media::VideoFrame::ReleaseMailboxCB(),
+ size, // coded_size
+ gfx::Rect(size), // visible rect
+ size, // natural size
+ base::TimeDelta()); // timestamp
+ frame->metadata()->SetBoolean(::media::VideoFrameMetadata::ALLOW_OVERLAY,
+ true);
+ return frame;
+}
+
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/filters/hole_frame_factory.h b/chromium/chromecast/media/cma/filters/hole_frame_factory.h
new file mode 100644
index 00000000000..e817a3e93f3
--- /dev/null
+++ b/chromium/chromecast/media/cma/filters/hole_frame_factory.h
@@ -0,0 +1,51 @@
+// Copyright 2015 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_FILTERS_HOLE_FRAME_FACTORY_H_
+#define CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_
+
+#include <GLES2/gl2.h>
+
+#include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/common/mailbox.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace media {
+class GpuVideoAcceleratorFactories;
+class VideoFrame;
+}
+
+namespace chromecast {
+namespace media {
+
+// Creates VideoFrames for CMA - currently supports both overlay frames
+// (native textures that get turned into transparent holes in the browser
+// compositor), and legacy VIDEO_HOLE codepath.
+// All calls (including ctor/dtor) must be on media thread.
+class HoleFrameFactory {
+ public:
+ explicit HoleFrameFactory(const scoped_refptr<
+ ::media::GpuVideoAcceleratorFactories>& gpu_factories);
+ ~HoleFrameFactory();
+
+ scoped_refptr<::media::VideoFrame> CreateHoleFrame(const gfx::Size& size);
+
+ private:
+ scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_;
+ gpu::Mailbox mailbox_;
+ GLuint texture_;
+ GLuint image_id_;
+ GLuint sync_point_;
+ bool use_legacy_hole_punching_;
+
+ DISALLOW_COPY_AND_ASSIGN(HoleFrameFactory);
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_
diff --git a/chromium/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc b/chromium/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc
new file mode 100644
index 00000000000..6aaf213228a
--- /dev/null
+++ b/chromium/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright 2015 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 "base/basictypes.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
+#include "chromecast/media/cma/base/decoder_buffer_base.h"
+#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/video_decoder_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+// Maximum pts diff between frames
+const int kMaxPtsDiffMs = 2000;
+} // namespace
+
+// Test for multiple streams
+class MultiDemuxerStreamAdaptersTest : public testing::Test {
+ public:
+ MultiDemuxerStreamAdaptersTest();
+ ~MultiDemuxerStreamAdaptersTest() override;
+
+ void Start();
+
+ protected:
+ void OnTestTimeout();
+ void OnNewFrame(CodedFrameProvider* frame_provider,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const ::media::AudioDecoderConfig& audio_config,
+ const ::media::VideoDecoderConfig& video_config);
+
+ // Number of expected read frames.
+ int total_expected_frames_;
+
+ // Number of frames actually read so far.
+ int frame_received_count_;
+
+ // List of expected frame indices with decoder config changes.
+ std::list<int> config_idx_;
+
+ ScopedVector<DemuxerStreamForTest> demuxer_streams_;
+
+ ScopedVector<CodedFrameProvider> coded_frame_providers_;
+
+ private:
+ // exit if all of the streams end
+ void OnEos();
+
+ // Number of reading-streams
+ int running_stream_count_;
+
+ scoped_refptr<BalancedMediaTaskRunnerFactory> media_task_runner_factory_;
+ DISALLOW_COPY_AND_ASSIGN(MultiDemuxerStreamAdaptersTest);
+};
+
+MultiDemuxerStreamAdaptersTest::MultiDemuxerStreamAdaptersTest() {
+}
+
+MultiDemuxerStreamAdaptersTest::~MultiDemuxerStreamAdaptersTest() {
+}
+
+void MultiDemuxerStreamAdaptersTest::Start() {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&MultiDemuxerStreamAdaptersTest::OnTestTimeout,
+ base::Unretained(this)),
+ base::TimeDelta::FromSeconds(5));
+
+ media_task_runner_factory_ = new BalancedMediaTaskRunnerFactory(
+ base::TimeDelta::FromMilliseconds(kMaxPtsDiffMs));
+
+ coded_frame_providers_.clear();
+ frame_received_count_ = 0;
+
+ for (auto& stream : demuxer_streams_) {
+ coded_frame_providers_.push_back(make_scoped_ptr(
+ new DemuxerStreamAdapter(base::ThreadTaskRunnerHandle::Get(),
+ media_task_runner_factory_, stream)));
+ }
+ running_stream_count_ = coded_frame_providers_.size();
+
+ // read each stream
+ for (auto& code_frame_provider : coded_frame_providers_) {
+ auto read_cb = base::Bind(&MultiDemuxerStreamAdaptersTest::OnNewFrame,
+ base::Unretained(this), code_frame_provider);
+
+ base::Closure task =
+ base::Bind(&CodedFrameProvider::Read,
+ base::Unretained(code_frame_provider), read_cb);
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
+ }
+}
+
+void MultiDemuxerStreamAdaptersTest::OnTestTimeout() {
+ if (running_stream_count_ != 0) {
+ ADD_FAILURE() << "Test timed out";
+ }
+}
+
+void MultiDemuxerStreamAdaptersTest::OnNewFrame(
+ CodedFrameProvider* frame_provider,
+ const scoped_refptr<DecoderBufferBase>& buffer,
+ const ::media::AudioDecoderConfig& audio_config,
+ const ::media::VideoDecoderConfig& video_config) {
+ if (buffer->end_of_stream()) {
+ OnEos();
+ return;
+ }
+
+ frame_received_count_++;
+ auto read_cb = base::Bind(&MultiDemuxerStreamAdaptersTest::OnNewFrame,
+ base::Unretained(this), frame_provider);
+ frame_provider->Read(read_cb);
+}
+
+void MultiDemuxerStreamAdaptersTest::OnEos() {
+ running_stream_count_--;
+ ASSERT_GE(running_stream_count_, 0);
+ if (running_stream_count_ == 0) {
+ ASSERT_EQ(frame_received_count_, total_expected_frames_);
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+}
+
+TEST_F(MultiDemuxerStreamAdaptersTest, EarlyEos) {
+ // We have more than one streams here. One of them is much shorter than the
+ // others. When the shortest stream reaches EOS, other streams should still
+ // run as usually. BalancedTaskRunner should not be blocked.
+ int frame_count_short = 2;
+ int frame_count_long =
+ frame_count_short +
+ kMaxPtsDiffMs / DemuxerStreamForTest::kDemuxerStreamForTestFrameDuration +
+ 100;
+ demuxer_streams_.push_back(scoped_ptr<DemuxerStreamForTest>(
+ new DemuxerStreamForTest(frame_count_short, 2, 0, config_idx_)));
+ demuxer_streams_.push_back(scoped_ptr<DemuxerStreamForTest>(
+ new DemuxerStreamForTest(frame_count_long, 10, 0, config_idx_)));
+
+ total_expected_frames_ = frame_count_short + frame_count_long;
+
+ scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
+ message_loop->PostTask(FROM_HERE,
+ base::Bind(&MultiDemuxerStreamAdaptersTest::Start,
+ base::Unretained(this)));
+ message_loop->Run();
+}
+} // namespace media
+} // namespace chromecast
diff --git a/chromium/chromecast/media/cma/ipc/BUILD.gn b/chromium/chromecast/media/cma/ipc/BUILD.gn
index 037b3bdd6a7..85ed2ac0376 100644
--- a/chromium/chromecast/media/cma/ipc/BUILD.gn
+++ b/chromium/chromecast/media/cma/ipc/BUILD.gn
@@ -13,9 +13,10 @@ source_set("ipc") {
"media_message_type.h",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
"//base",
+ "//chromecast/media/cma/base",
]
-
- configs += [ "//chromecast:config" ]
}
diff --git a/chromium/chromecast/media/cma/ipc/media_message_fifo.cc b/chromium/chromecast/media/cma/ipc/media_message_fifo.cc
index 5e4b239bc5d..bd68f3f8673 100644
--- a/chromium/chromecast/media/cma/ipc/media_message_fifo.cc
+++ b/chromium/chromecast/media/cma/ipc/media_message_fifo.cc
@@ -8,7 +8,8 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "chromecast/media/cma/base/cma_logging.h"
#include "chromecast/media/cma/ipc/media_memory_chunk.h"
#include "chromecast/media/cma/ipc/media_message.h"
@@ -78,15 +79,15 @@ class FifoOwnedMemory : public MediaMemoryChunk {
DISALLOW_COPY_AND_ASSIGN(FifoOwnedMemory);
};
-FifoOwnedMemory::FifoOwnedMemory(
- void* data, size_t size,
- const scoped_refptr<MediaMessageFlag>& flag,
- const base::Closure& release_msg_cb)
- : task_runner_(base::MessageLoopProxy::current()),
- release_msg_cb_(release_msg_cb),
- data_(data),
- size_(size),
- flag_(flag) {
+FifoOwnedMemory::FifoOwnedMemory(void* data,
+ size_t size,
+ const scoped_refptr<MediaMessageFlag>& flag,
+ const base::Closure& release_msg_cb)
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ release_msg_cb_(release_msg_cb),
+ data_(data),
+ size_(size),
+ flag_(flag) {
}
FifoOwnedMemory::~FifoOwnedMemory() {
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 ed758182ce4..6680451374b 100644
--- a/chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc
+++ b/chromium/chromecast/media/cma/ipc/media_message_fifo_unittest.cc
@@ -135,12 +135,9 @@ TEST(MediaMessageFifoTest, AlternateWriteRead) {
false));
base::WaitableEvent event(false, false);
- thread->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&MsgProducerConsumer,
- base::Passed(&producer_fifo),
- base::Passed(&consumer_fifo),
- &event));
+ thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MsgProducerConsumer, base::Passed(&producer_fifo),
+ base::Passed(&consumer_fifo), &event));
event.Wait();
thread.reset();
@@ -170,18 +167,12 @@ TEST(MediaMessageFifoTest, MultiThreaded) {
base::WaitableEvent consumer_event_done(false, false);
const int msg_count = 2048;
- producer_thread->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&MsgProducer,
- base::Passed(&producer_fifo),
- msg_count,
- &producer_event_done));
- consumer_thread->message_loop_proxy()->PostTask(
- FROM_HERE,
- base::Bind(&MsgConsumer,
- base::Passed(&consumer_fifo),
- msg_count,
- &consumer_event_done));
+ producer_thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MsgProducer, base::Passed(&producer_fifo),
+ msg_count, &producer_event_done));
+ consumer_thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MsgConsumer, base::Passed(&consumer_fifo),
+ msg_count, &consumer_event_done));
producer_event_done.Wait();
consumer_event_done.Wait();
diff --git a/chromium/chromecast/media/cma/ipc_streamer/BUILD.gn b/chromium/chromecast/media/cma/ipc_streamer/BUILD.gn
index aa87709333e..4601f073399 100644
--- a/chromium/chromecast/media/cma/ipc_streamer/BUILD.gn
+++ b/chromium/chromecast/media/cma/ipc_streamer/BUILD.gn
@@ -18,11 +18,13 @@ source_set("ipc_streamer") {
"video_decoder_config_marshaller.h",
]
+ configs += [ "//chromecast:config" ]
+
deps = [
"//base",
"//chromecast/media/cma/base",
+ "//chromecast/media/cma/ipc",
"//media",
+ "//ui/gfx/geometry",
]
-
- configs += [ "//chromecast:config" ]
}
diff --git a/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc b/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
index 6bc25edc386..09fc5b5e99c 100644
--- a/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
+++ b/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
@@ -6,7 +6,8 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "chromecast/media/cma/base/coded_frame_provider.h"
#include "chromecast/media/cma/base/decoder_buffer_base.h"
#include "chromecast/media/cma/ipc/media_memory_chunk.h"
@@ -55,7 +56,8 @@ void AvStreamerProxy::Start() {
}
void AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) {
- is_running_ = false;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!done_cb.is_null());
pending_av_data_ = false;
pending_audio_config_ = ::media::AudioDecoderConfig();
@@ -63,7 +65,27 @@ void AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) {
pending_buffer_ = scoped_refptr<DecoderBufferBase>();
pending_read_ = false;
- frame_provider_->Flush(done_cb);
+ is_running_ = false;
+
+ // If there's another pending Flush, for example, the pipeline is stopped
+ // while another seek is pending, then we don't need to call Flush again. Save
+ // the callback and fire it later when Flush is done.
+ pending_stop_flush_cb_list_.push_back(done_cb);
+ if (pending_stop_flush_cb_list_.size() == 1) {
+ frame_provider_->Flush(
+ base::Bind(&AvStreamerProxy::OnStopAndFlushDone, weak_this_));
+ }
+}
+
+void AvStreamerProxy::OnStopAndFlushDone() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Flush is done. Fire all the "flush done" callbacks in order. This is
+ // necessary to guarantee proper state transition in pipeline.
+ for (const auto& cb : pending_stop_flush_cb_list_) {
+ cb.Run();
+ }
+ pending_stop_flush_cb_list_.clear();
}
void AvStreamerProxy::OnFifoReadEvent() {
@@ -128,7 +150,7 @@ void AvStreamerProxy::ProcessPendingData() {
}
pending_av_data_ = false;
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&AvStreamerProxy::RequestBufferIfNeeded, weak_this_));
}
diff --git a/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.h b/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.h
index e750c85ae8c..9d24abc7e0e 100644
--- a/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.h
+++ b/chromium/chromecast/media/cma/ipc_streamer/av_streamer_proxy.h
@@ -5,6 +5,8 @@
#ifndef CHROMECAST_MEDIA_CMA_IPC_STREAMER_AV_STREAMER_PROXY_H_
#define CHROMECAST_MEDIA_CMA_IPC_STREAMER_AV_STREAMER_PROXY_H_
+#include <list>
+
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
@@ -55,6 +57,8 @@ class AvStreamerProxy {
bool SendVideoDecoderConfig(const ::media::VideoDecoderConfig& config);
bool SendBuffer(const scoped_refptr<DecoderBufferBase>& buffer);
+ void OnStopAndFlushDone();
+
base::ThreadChecker thread_checker_;
scoped_ptr<CodedFrameProvider> frame_provider_;
@@ -76,6 +80,9 @@ class AvStreamerProxy {
::media::VideoDecoderConfig pending_video_config_;
scoped_refptr<DecoderBufferBase> pending_buffer_;
+ // List of pending callbacks in StopAndFlush
+ std::list<base::Closure> pending_stop_flush_cb_list_;
+
base::WeakPtr<AvStreamerProxy> weak_this_;
base::WeakPtrFactory<AvStreamerProxy> weak_factory_;
diff --git a/chromium/chromecast/media/cma/ipc_streamer/av_streamer_unittest.cc b/chromium/chromecast/media/cma/ipc_streamer/av_streamer_unittest.cc
index c8720561c1a..9aff31d3be9 100644
--- a/chromium/chromecast/media/cma/ipc_streamer/av_streamer_unittest.cc
+++ b/chromium/chromecast/media/cma/ipc_streamer/av_streamer_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chromecast/media/cma/base/decoder_buffer_base.h"
@@ -54,14 +55,20 @@ class AvStreamerTest : public testing::Test {
~AvStreamerTest() override;
// Setups the test.
- void Configure(
- size_t frame_count,
- const std::vector<bool>& provider_delayed_pattern,
- const std::vector<bool>& consumer_delayed_pattern);
+ void Configure(size_t frame_count,
+ const std::vector<bool>& provider_delayed_pattern,
+ const std::vector<bool>& consumer_delayed_pattern,
+ bool delay_flush);
// Starts the test.
void Start();
+ // Back to back flush
+ void FlushThenStop();
+
+ // Timeout indicates test failure
+ void OnTestTimeout();
+
protected:
scoped_ptr<uint64[]> fifo_mem_;
@@ -69,13 +76,17 @@ class AvStreamerTest : public testing::Test {
scoped_ptr<CodedFrameProviderHost> coded_frame_provider_host_;
scoped_ptr<MockFrameConsumer> frame_consumer_;
+ // number of pending cb in StopAndFlush
+ int stop_and_flush_cb_count_;
+
private:
- void OnTestTimeout();
void OnTestCompleted();
void OnFifoRead();
void OnFifoWrite();
+ void OnStopAndFlush();
+
DISALLOW_COPY_AND_ASSIGN(AvStreamerTest);
};
@@ -88,7 +99,8 @@ AvStreamerTest::~AvStreamerTest() {
void AvStreamerTest::Configure(
size_t frame_count,
const std::vector<bool>& provider_delayed_pattern,
- const std::vector<bool>& consumer_delayed_pattern) {
+ const std::vector<bool>& consumer_delayed_pattern,
+ bool delay_flush) {
// Frame generation on the producer and consumer side.
std::vector<FrameGeneratorForTest::FrameSpec> frame_specs;
frame_specs.resize(frame_count);
@@ -108,6 +120,7 @@ void AvStreamerTest::Configure(
scoped_ptr<MockFrameProvider> frame_provider(new MockFrameProvider());
frame_provider->Configure(provider_delayed_pattern,
frame_generator_provider.Pass());
+ frame_provider->SetDelayFlush(delay_flush);
size_t fifo_size_div_8 = 512;
fifo_mem_.reset(new uint64[fifo_size_div_8]);
@@ -141,19 +154,33 @@ void AvStreamerTest::Configure(
consumer_delayed_pattern,
false,
frame_generator_consumer.Pass());
+
+ stop_and_flush_cb_count_ = 0;
}
void AvStreamerTest::Start() {
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&AvStreamerProxy::Start,
- base::Unretained(av_buffer_proxy_.get())));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&AvStreamerProxy::Start,
+ base::Unretained(av_buffer_proxy_.get())));
frame_consumer_->Start(
base::Bind(&AvStreamerTest::OnTestCompleted,
base::Unretained(this)));
}
+void AvStreamerTest::FlushThenStop() {
+ base::Closure cb =
+ base::Bind(&AvStreamerTest::OnStopAndFlush, base::Unretained(this));
+
+ stop_and_flush_cb_count_++;
+ av_buffer_proxy_->StopAndFlush(cb);
+
+ ASSERT_EQ(stop_and_flush_cb_count_, 1);
+
+ stop_and_flush_cb_count_++;
+ av_buffer_proxy_->StopAndFlush(cb);
+}
+
void AvStreamerTest::OnTestTimeout() {
ADD_FAILURE() << "Test timed out";
if (base::MessageLoop::current())
@@ -165,17 +192,23 @@ void AvStreamerTest::OnTestCompleted() {
}
void AvStreamerTest::OnFifoWrite() {
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&CodedFrameProviderHost::OnFifoWriteEvent,
base::Unretained(coded_frame_provider_host_.get())));
}
void AvStreamerTest::OnFifoRead() {
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&AvStreamerProxy::OnFifoReadEvent,
- base::Unretained(av_buffer_proxy_.get())));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&AvStreamerProxy::OnFifoReadEvent,
+ base::Unretained(av_buffer_proxy_.get())));
+}
+
+void AvStreamerTest::OnStopAndFlush() {
+ stop_and_flush_cb_count_--;
+ if (stop_and_flush_cb_count_ == 0) {
+ OnTestCompleted();
+ }
}
TEST_F(AvStreamerTest, FastProviderSlowConsumer) {
@@ -183,14 +216,14 @@ TEST_F(AvStreamerTest, FastProviderSlowConsumer) {
bool consumer_delayed_pattern[] = { true };
const size_t frame_count = 100u;
- Configure(
- frame_count,
- std::vector<bool>(
- provider_delayed_pattern,
- provider_delayed_pattern + arraysize(provider_delayed_pattern)),
- std::vector<bool>(
- consumer_delayed_pattern,
- consumer_delayed_pattern + arraysize(consumer_delayed_pattern)));
+ Configure(frame_count,
+ std::vector<bool>(
+ provider_delayed_pattern,
+ provider_delayed_pattern + arraysize(provider_delayed_pattern)),
+ std::vector<bool>(
+ consumer_delayed_pattern,
+ consumer_delayed_pattern + arraysize(consumer_delayed_pattern)),
+ false);
scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
message_loop->PostTask(
@@ -204,14 +237,14 @@ TEST_F(AvStreamerTest, SlowProviderFastConsumer) {
bool consumer_delayed_pattern[] = { false };
const size_t frame_count = 100u;
- Configure(
- frame_count,
- std::vector<bool>(
- provider_delayed_pattern,
- provider_delayed_pattern + arraysize(provider_delayed_pattern)),
- std::vector<bool>(
- consumer_delayed_pattern,
- consumer_delayed_pattern + arraysize(consumer_delayed_pattern)));
+ Configure(frame_count,
+ std::vector<bool>(
+ provider_delayed_pattern,
+ provider_delayed_pattern + arraysize(provider_delayed_pattern)),
+ std::vector<bool>(
+ consumer_delayed_pattern,
+ consumer_delayed_pattern + arraysize(consumer_delayed_pattern)),
+ false);
scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
message_loop->PostTask(
@@ -233,14 +266,14 @@ TEST_F(AvStreamerTest, SlowFastProducerConsumer) {
};
const size_t frame_count = 100u;
- Configure(
- frame_count,
- std::vector<bool>(
- provider_delayed_pattern,
- provider_delayed_pattern + arraysize(provider_delayed_pattern)),
- std::vector<bool>(
- consumer_delayed_pattern,
- consumer_delayed_pattern + arraysize(consumer_delayed_pattern)));
+ Configure(frame_count,
+ std::vector<bool>(
+ provider_delayed_pattern,
+ provider_delayed_pattern + arraysize(provider_delayed_pattern)),
+ std::vector<bool>(
+ consumer_delayed_pattern,
+ consumer_delayed_pattern + arraysize(consumer_delayed_pattern)),
+ false);
scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
message_loop->PostTask(
@@ -249,5 +282,41 @@ TEST_F(AvStreamerTest, SlowFastProducerConsumer) {
message_loop->Run();
};
+// Test case for when AvStreamerProxy::StopAndFlush is invoked while a previous
+// flush is pending. This can happen when pipeline is stopped while a seek/flush
+// is pending.
+TEST_F(AvStreamerTest, StopInFlush) {
+ // We don't care about the delayed pattern. Setting to true to make sure the
+ // test won't exit before flush is called.
+ bool dummy_delayed_pattern[] = {true};
+ std::vector<bool> dummy_delayed_pattern_vector(
+ dummy_delayed_pattern,
+ dummy_delayed_pattern + arraysize(dummy_delayed_pattern));
+ const size_t frame_count = 100u;
+
+ // Delay flush callback in frame provider
+ Configure(frame_count, dummy_delayed_pattern_vector,
+ dummy_delayed_pattern_vector, true);
+
+ scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
+
+ // Flush takes 10ms to finish. 1s timeout is enough for this test.
+ message_loop->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&AvStreamerTest::OnTestTimeout, base::Unretained(this)),
+ base::TimeDelta::FromSeconds(1));
+
+ message_loop->PostTask(
+ FROM_HERE, base::Bind(&AvStreamerTest::Start, base::Unretained(this)));
+
+ // Let AvStreamerProxy run for a while. Fire flush and stop later
+ message_loop->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&AvStreamerTest::FlushThenStop, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(10));
+
+ message_loop->Run();
+}
+
} // namespace media
} // namespace chromecast
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 a377ae66337..ab3a2587851 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
@@ -24,7 +24,9 @@ class DecoderBufferFromMsg : public DecoderBufferBase {
void Initialize();
// DecoderBufferBase implementation.
+ StreamId stream_id() const override;
base::TimeDelta timestamp() const override;
+ void set_timestamp(const base::TimeDelta& timestamp) override;
const uint8* data() const override;
uint8* writable_data() const override;
size_t data_size() const override;
@@ -37,6 +39,9 @@ class DecoderBufferFromMsg : public DecoderBufferBase {
// Indicates whether this is an end of stream frame.
bool is_eos_;
+ // Stream Id this decoder buffer belongs to.
+ StreamId stream_id_;
+
// Frame timestamp.
base::TimeDelta pts_;
@@ -56,6 +61,7 @@ class DecoderBufferFromMsg : public DecoderBufferBase {
DecoderBufferFromMsg::DecoderBufferFromMsg(
scoped_ptr<MediaMessage> msg)
: is_eos_(true),
+ stream_id_(kPrimary),
msg_(msg.Pass()),
data_(NULL) {
CHECK(msg_);
@@ -71,6 +77,8 @@ void DecoderBufferFromMsg::Initialize() {
if (is_eos_)
return;
+ CHECK(msg_->ReadPod(&stream_id_));
+
int64 pts_internal = 0;
CHECK(msg_->ReadPod(&pts_internal));
pts_ = base::TimeDelta::FromInternalValue(pts_internal);
@@ -99,10 +107,18 @@ void DecoderBufferFromMsg::Initialize() {
}
}
+StreamId DecoderBufferFromMsg::stream_id() const {
+ return stream_id_;
+}
+
base::TimeDelta DecoderBufferFromMsg::timestamp() const {
return pts_;
}
+void DecoderBufferFromMsg::set_timestamp(const base::TimeDelta& timestamp) {
+ pts_ = timestamp;
+}
+
const uint8* DecoderBufferFromMsg::data() const {
CHECK(msg_->IsSerializedMsgAvailable());
return data_;
@@ -135,6 +151,7 @@ void DecoderBufferBaseMarshaller::Write(
if (buffer->end_of_stream())
return;
+ CHECK(msg->WritePod(buffer->stream_id()));
CHECK(msg->WritePod(buffer->timestamp().ToInternalValue()));
bool has_decrypt_config =
diff --git a/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
index 3dbc028fc6c..006ea820437 100644
--- a/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
@@ -109,8 +109,9 @@ void AudioPipelineImpl::Initialize(
if (frame_provider)
SetCodedFrameProvider(frame_provider.Pass());
+ DCHECK(audio_config.IsValidConfig());
if (!audio_device_->SetConfig(
- DecoderConfigAdapter::ToCastAudioConfig(audio_config)) ||
+ DecoderConfigAdapter::ToCastAudioConfig(kPrimary, audio_config)) ||
!av_pipeline_impl_->Initialize()) {
status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
return;
@@ -124,14 +125,15 @@ void AudioPipelineImpl::SetVolume(float volume) {
}
void AudioPipelineImpl::OnUpdateConfig(
+ StreamId id,
const ::media::AudioDecoderConfig& audio_config,
const ::media::VideoDecoderConfig& video_config) {
if (audio_config.IsValidConfig()) {
- CMALOG(kLogControl) << "AudioPipelineImpl::OnUpdateConfig "
+ CMALOG(kLogControl) << "AudioPipelineImpl::OnUpdateConfig id:" << id << " "
<< audio_config.AsHumanReadableString();
bool success = audio_device_->SetConfig(
- DecoderConfigAdapter::ToCastAudioConfig(audio_config));
+ DecoderConfigAdapter::ToCastAudioConfig(id, audio_config));
if (!success && !audio_client_.playback_error_cb.is_null())
audio_client_.playback_error_cb.Run(::media::PIPELINE_ERROR_DECODE);
}
diff --git a/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.h b/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.h
index 7d2e63a1314..31cadf91680 100644
--- a/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.h
+++ b/chromium/chromecast/media/cma/pipeline/audio_pipeline_impl.h
@@ -12,6 +12,7 @@
#include "base/threading/thread_checker.h"
#include "chromecast/media/cma/pipeline/audio_pipeline.h"
#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
+#include "chromecast/public/media/stream_id.h"
namespace media {
class AudioDecoderConfig;
@@ -57,7 +58,8 @@ class AudioPipelineImpl : public AudioPipeline {
private:
void OnFlushDone(const ::media::PipelineStatusCB& status_cb);
- void OnUpdateConfig(const ::media::AudioDecoderConfig& audio_config,
+ void OnUpdateConfig(StreamId id,
+ const ::media::AudioDecoderConfig& audio_config,
const ::media::VideoDecoderConfig& video_config);
AudioPipelineDevice* audio_device_;
diff --git a/chromium/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromium/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index 9c17c7b2330..9b9dc120e71 100644
--- a/chromium/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromium/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -9,12 +9,13 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chromecast/media/cma/backend/audio_pipeline_device.h"
#include "chromecast/media/cma/backend/media_clock_device.h"
#include "chromecast/media/cma/backend/media_pipeline_device.h"
-#include "chromecast/media/cma/backend/media_pipeline_device_fake.h"
+#include "chromecast/media/cma/backend/media_pipeline_device_factory_default.h"
#include "chromecast/media/cma/base/buffering_controller.h"
#include "chromecast/media/cma/base/decoder_buffer_base.h"
#include "chromecast/media/cma/pipeline/audio_pipeline_impl.h"
@@ -59,8 +60,10 @@ class AudioVideoPipelineImplTest : public testing::Test {
AudioVideoPipelineImplTest::AudioVideoPipelineImplTest()
: media_pipeline_(new MediaPipelineImpl()) {
- scoped_ptr<MediaPipelineDevice> media_pipeline_device(
- new MediaPipelineDeviceFake());
+ scoped_ptr<MediaPipelineDeviceFactory> factory =
+ make_scoped_ptr(new MediaPipelineDeviceFactoryDefault());
+ scoped_ptr<MediaPipelineDevice> media_pipeline_device =
+ make_scoped_ptr(new MediaPipelineDevice(factory.Pass()));
media_pipeline_->Initialize(kLoadTypeURL, media_pipeline_device.Pass());
media_pipeline_->SetPlaybackRate(1.0);
}
@@ -90,14 +93,15 @@ void AudioVideoPipelineImplTest::Initialize(
::media::CHANNEL_LAYOUT_STEREO,
44100,
NULL, 0, false);
- ::media::VideoDecoderConfig video_config(
+ std::vector<::media::VideoDecoderConfig> video_configs;
+ video_configs.push_back(::media::VideoDecoderConfig(
::media::kCodecH264,
::media::H264PROFILE_MAIN,
::media::VideoFrame::I420,
gfx::Size(640, 480),
gfx::Rect(0, 0, 640, 480),
gfx::Size(640, 480),
- NULL, 0, false);
+ NULL, 0, false));
// Frame generation on the producer side.
std::vector<FrameGeneratorForTest::FrameSpec> frame_specs;
@@ -134,11 +138,11 @@ void AudioVideoPipelineImplTest::Initialize(
next_task) :
base::Bind(&MediaPipeline::InitializeVideo,
base::Unretained(media_pipeline_.get()),
- video_config,
+ video_configs,
base::Passed(&frame_provider_base),
next_task);
- base::MessageLoopProxy::current()->PostTask(FROM_HERE, task);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
}
void AudioVideoPipelineImplTest::StartPlaying(
@@ -159,10 +163,9 @@ void AudioVideoPipelineImplTest::Flush(
::media::PipelineStatusCB next_task =
base::Bind(&AudioVideoPipelineImplTest::Stop, base::Unretained(this),
done_cb);
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&MediaPipeline::Flush,
- base::Unretained(media_pipeline_.get()),
+ base::Bind(&MediaPipeline::Flush, base::Unretained(media_pipeline_.get()),
next_task));
}
diff --git a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc
index 9ff88e99225..5c6c69538a2 100644
--- a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -6,8 +6,9 @@
#include "base/bind.h"
#include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
#include "chromecast/media/base/decrypt_context.h"
#include "chromecast/media/cdm/browser_cdm_cast.h"
#include "chromecast/media/cma/backend/media_clock_device.h"
@@ -124,9 +125,8 @@ bool AvPipelineImpl::StartPlayingFrom(
// Start feeding the pipeline.
enable_feeding_ = true;
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
return true;
}
@@ -221,14 +221,13 @@ void AvPipelineImpl::OnNewFrame(
pending_read_ = false;
if (audio_config.IsValidConfig() || video_config.IsValidConfig())
- update_config_cb_.Run(audio_config, video_config);
+ update_config_cb_.Run(buffer->stream_id(), audio_config, video_config);
pending_buffer_ = buffer;
ProcessPendingBuffer();
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
}
void AvPipelineImpl::ProcessPendingBuffer() {
@@ -237,7 +236,7 @@ void AvPipelineImpl::ProcessPendingBuffer() {
// Initiate a read if there isn't already one.
if (!pending_buffer_.get() && !pending_read_) {
- base::MessageLoopProxy::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&AvPipelineImpl::FetchBufferIfNeeded, weak_this_));
return;
@@ -307,9 +306,8 @@ void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status) {
state_ = kError;
return;
}
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&AvPipelineImpl::ProcessPendingBuffer, weak_this_));
}
void AvPipelineImpl::OnCdmStateChanged() {
diff --git a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h
index 20b3fc4feda..70395fc95d6 100644
--- a/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h
+++ b/chromium/chromecast/media/cma/pipeline/av_pipeline_impl.h
@@ -14,6 +14,7 @@
#include "base/threading/thread_checker.h"
#include "chromecast/media/cma/backend/media_component_device.h"
#include "chromecast/media/cma/pipeline/av_pipeline_client.h"
+#include "chromecast/public/media/stream_id.h"
namespace media {
class AudioDecoderConfig;
@@ -42,7 +43,8 @@ class AvPipelineImpl {
};
typedef base::Callback<
- void(const ::media::AudioDecoderConfig&,
+ void(StreamId id,
+ const ::media::AudioDecoderConfig&,
const ::media::VideoDecoderConfig&)> UpdateConfigCB;
AvPipelineImpl(
diff --git a/chromium/chromecast/media/cma/pipeline/decrypt_util.cc b/chromium/chromecast/media/cma/pipeline/decrypt_util.cc
index 1f1fbe85c62..abd466148a4 100644
--- a/chromium/chromecast/media/cma/pipeline/decrypt_util.cc
+++ b/chromium/chromecast/media/cma/pipeline/decrypt_util.cc
@@ -22,7 +22,9 @@ class DecoderBufferClear : public DecoderBufferBase {
explicit DecoderBufferClear(const scoped_refptr<DecoderBufferBase>& buffer);
// DecoderBufferBase implementation.
+ StreamId stream_id() const override;
base::TimeDelta timestamp() const override;
+ void set_timestamp(const base::TimeDelta& timestamp) override;
const uint8* data() const override;
uint8* writable_data() const override;
size_t data_size() const override;
@@ -45,10 +47,18 @@ DecoderBufferClear::DecoderBufferClear(
DecoderBufferClear::~DecoderBufferClear() {
}
+StreamId DecoderBufferClear::stream_id() const {
+ return buffer_->stream_id();
+}
+
base::TimeDelta DecoderBufferClear::timestamp() const {
return buffer_->timestamp();
}
+void DecoderBufferClear::set_timestamp(const base::TimeDelta& timestamp) {
+ buffer_->set_timestamp(timestamp);
+}
+
const uint8* DecoderBufferClear::data() const {
return buffer_->data();
}
diff --git a/chromium/chromecast/media/cma/pipeline/media_pipeline.h b/chromium/chromecast/media/cma/pipeline/media_pipeline.h
index 6b127cb276b..6026cdcc874 100644
--- a/chromium/chromecast/media/cma/pipeline/media_pipeline.h
+++ b/chromium/chromecast/media/cma/pipeline/media_pipeline.h
@@ -47,7 +47,7 @@ class MediaPipeline {
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) = 0;
virtual void InitializeVideo(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) = 0;
diff --git a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index ced7df14cc0..fe5a2ebd10d 100644
--- a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -9,7 +9,8 @@
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "chromecast/media/cdm/browser_cdm_cast.h"
#include "chromecast/media/cma/backend/media_clock_device.h"
@@ -143,7 +144,7 @@ void MediaPipelineImpl::InitializeAudio(
}
void MediaPipelineImpl::InitializeVideo(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -154,14 +155,14 @@ void MediaPipelineImpl::InitializeVideo(
return;
}
has_video_ = true;
- video_pipeline_->Initialize(config, frame_provider.Pass(), status_cb);
+ video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb);
}
void MediaPipelineImpl::StartPlayingFrom(base::TimeDelta time) {
CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_audio_ || has_video_);
- DCHECK(!pending_callbacks_);
+ DCHECK(!pending_flush_callbacks_);
// Reset the start of the timeline.
DCHECK_EQ(clock_device_->GetState(), MediaClockDevice::kStateIdle);
@@ -179,9 +180,8 @@ void MediaPipelineImpl::StartPlayingFrom(base::TimeDelta time) {
statistics_rolling_counter_ = 0;
if (!pending_time_update_task_) {
pending_time_update_task_ = true;
- base::MessageLoopProxy::current()->PostTask(
- FROM_HERE,
- base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_));
}
// Setup the audio and video pipeline for the new timeline.
@@ -209,7 +209,7 @@ void MediaPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
CMALOG(kLogControl) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_audio_ || has_video_);
- DCHECK(!pending_callbacks_);
+ DCHECK(!pending_flush_callbacks_);
// No need to update media time anymore.
enable_time_update_ = false;
@@ -236,7 +236,7 @@ void MediaPipelineImpl::Flush(const ::media::PipelineStatusCB& status_cb) {
}
::media::PipelineStatusCB transition_cb =
base::Bind(&MediaPipelineImpl::StateTransition, weak_this_, status_cb);
- pending_callbacks_ =
+ pending_flush_callbacks_ =
::media::SerialRunner::Run(bound_fns, transition_cb);
}
@@ -244,7 +244,11 @@ void MediaPipelineImpl::Stop() {
CMALOG(kLogControl) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_audio_ || has_video_);
- DCHECK(!pending_callbacks_);
+
+ // Cancel pending flush callbacks since we are about to stop/shutdown
+ // audio/video pipelines. This will ensure A/V Flush won't happen in
+ // stopped state.
+ pending_flush_callbacks_.reset();
// No need to update media time anymore.
enable_time_update_ = false;
@@ -282,7 +286,7 @@ VideoPipelineImpl* MediaPipelineImpl::GetVideoPipelineImpl() const {
void MediaPipelineImpl::StateTransition(
const ::media::PipelineStatusCB& status_cb,
::media::PipelineStatus status) {
- pending_callbacks_.reset();
+ pending_flush_callbacks_.reset();
status_cb.Run(status);
}
@@ -326,9 +330,8 @@ void MediaPipelineImpl::UpdateMediaTime() {
base::TimeDelta media_time(clock_device_->GetTime());
if (media_time == ::media::kNoTimestamp()) {
pending_time_update_task_ = true;
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
kTimeUpdateInterval);
return;
}
@@ -356,9 +359,8 @@ void MediaPipelineImpl::UpdateMediaTime() {
client_.time_update_cb.Run(media_time, max_rendering_time, stc);
pending_time_update_task_ = true;
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&MediaPipelineImpl::UpdateMediaTime, weak_this_),
kTimeUpdateInterval);
}
diff --git a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h
index eb14a555b98..71a5384ee66 100644
--- a/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromium/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -45,7 +45,7 @@ class MediaPipelineImpl : public MediaPipeline {
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) override;
void InitializeVideo(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) override;
void StartPlayingFrom(base::TimeDelta time) override;
@@ -83,7 +83,7 @@ class MediaPipelineImpl : public MediaPipeline {
bool has_video_;
scoped_ptr<AudioPipelineImpl> audio_pipeline_;
scoped_ptr<VideoPipelineImpl> video_pipeline_;
- scoped_ptr< ::media::SerialRunner> pending_callbacks_;
+ scoped_ptr< ::media::SerialRunner> pending_flush_callbacks_;
// Playback rate set by the upper layer.
float target_playback_rate_;
diff --git a/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc
index fda8b445ba4..38335318bd3 100644
--- a/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc
+++ b/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -101,11 +101,10 @@ void VideoPipelineImpl::SetClient(const VideoPipelineClient& client) {
}
void VideoPipelineImpl::Initialize(
- const ::media::VideoDecoderConfig& video_config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) {
- CMALOG(kLogControl) << "VideoPipelineImpl::Initialize "
- << video_config.AsHumanReadableString();
+ CMALOG(kLogControl) << __FUNCTION__ << " config (" << configs.size() << ")";
VideoPipelineDevice::VideoClient client;
client.natural_size_changed_cb =
base::Bind(&VideoPipelineImpl::OnNaturalSizeChanged, weak_this_);
@@ -113,8 +112,23 @@ void VideoPipelineImpl::Initialize(
if (frame_provider)
SetCodedFrameProvider(frame_provider.Pass());
- if (!video_device_->SetConfig(
- DecoderConfigAdapter::ToCastVideoConfig(video_config)) ||
+ if (configs.empty()) {
+ status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
+ return;
+ }
+ DCHECK(configs.size() <= 2);
+ DCHECK(configs[0].IsValidConfig());
+ VideoConfig video_config =
+ DecoderConfigAdapter::ToCastVideoConfig(kPrimary, configs[0]);
+ VideoConfig secondary_config;
+ if (configs.size() == 2) {
+ DCHECK(configs[1].IsValidConfig());
+ secondary_config = DecoderConfigAdapter::ToCastVideoConfig(kSecondary,
+ configs[1]);
+ video_config.additional_config = &secondary_config;
+ }
+
+ if (!video_device_->SetConfig(video_config) ||
!av_pipeline_impl_->Initialize()) {
status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
return;
@@ -124,14 +138,15 @@ void VideoPipelineImpl::Initialize(
}
void VideoPipelineImpl::OnUpdateConfig(
+ StreamId id,
const ::media::AudioDecoderConfig& audio_config,
const ::media::VideoDecoderConfig& video_config) {
if (video_config.IsValidConfig()) {
- CMALOG(kLogControl) << "VideoPipelineImpl::OnUpdateConfig "
+ CMALOG(kLogControl) << "VideoPipelineImpl::OnUpdateConfig id:" << id << " "
<< video_config.AsHumanReadableString();
bool success = video_device_->SetConfig(
- DecoderConfigAdapter::ToCastVideoConfig(video_config));
+ DecoderConfigAdapter::ToCastVideoConfig(id, video_config));
if (!success &&
!video_client_.av_pipeline_client.playback_error_cb.is_null()) {
video_client_.av_pipeline_client.playback_error_cb.Run(
diff --git a/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.h b/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.h
index e065ac1df20..25f875fcf63 100644
--- a/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.h
+++ b/chromium/chromecast/media/cma/pipeline/video_pipeline_impl.h
@@ -11,6 +11,7 @@
#include "base/threading/thread_checker.h"
#include "chromecast/media/cma/pipeline/video_pipeline.h"
#include "chromecast/media/cma/pipeline/video_pipeline_client.h"
+#include "chromecast/public/media/stream_id.h"
namespace gfx {
class Size;
@@ -43,7 +44,7 @@ class VideoPipelineImpl : public VideoPipeline {
// Functions to control the state of the audio pipeline.
void Initialize(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb);
bool StartPlayingFrom(base::TimeDelta time,
@@ -59,7 +60,8 @@ class VideoPipelineImpl : public VideoPipeline {
private:
void OnFlushDone(const ::media::PipelineStatusCB& status_cb);
- void OnUpdateConfig(const ::media::AudioDecoderConfig& audio_config,
+ void OnUpdateConfig(StreamId id,
+ const ::media::AudioDecoderConfig& audio_config,
const ::media::VideoDecoderConfig& video_config);
void OnNaturalSizeChanged(const gfx::Size& size);
diff --git a/chromium/chromecast/media/empty.cc b/chromium/chromecast/media/empty.cc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/chromium/chromecast/media/empty.cc
diff --git a/chromium/chromecast/media/media.gyp b/chromium/chromecast/media/media.gyp
index 20b1dc0c134..86879e5b24a 100644
--- a/chromium/chromecast/media/media.gyp
+++ b/chromium/chromecast/media/media.gyp
@@ -10,6 +10,13 @@
'use_default_libcast_media%': 1,
},
'targets': [
+ # TODO(gunsch): delete this target once Chromecast M44/earlier is obsolete.
+ # See: b/21639416
+ {
+ 'target_name': 'libffmpegsumo',
+ 'type': 'loadable_module',
+ 'sources': ['empty.cc'],
+ },
{
'target_name': 'media_base',
'type': '<(component)',
@@ -30,6 +37,8 @@
'base/media_caps.h',
'base/media_codec_support.cc',
'base/media_codec_support.h',
+ 'base/media_message_loop.cc',
+ 'base/media_message_loop.h',
'base/switching_media_renderer.cc',
'base/switching_media_renderer.h',
],
@@ -56,6 +65,8 @@
'sources': [
'cdm/browser_cdm_cast.cc',
'cdm/browser_cdm_cast.h',
+ 'cdm/chromecast_init_data.cc',
+ 'cdm/chromecast_init_data.h',
],
'conditions': [
['use_playready==1', {
@@ -99,6 +110,8 @@
'cma/base/decoder_config_adapter.h',
'cma/base/media_task_runner.cc',
'cma/base/media_task_runner.h',
+ 'cma/base/simple_media_task_runner.cc',
+ 'cma/base/simple_media_task_runner.h',
],
},
{
@@ -116,22 +129,27 @@
'sources': [
'cma/backend/audio_pipeline_device.cc',
'cma/backend/audio_pipeline_device.h',
+ 'cma/backend/audio_pipeline_device_default.cc',
+ 'cma/backend/audio_pipeline_device_default.h',
'cma/backend/media_clock_device.cc',
'cma/backend/media_clock_device.h',
+ 'cma/backend/media_clock_device_default.cc',
+ 'cma/backend/media_clock_device_default.h',
'cma/backend/media_component_device.cc',
'cma/backend/media_component_device.h',
+ 'cma/backend/media_component_device_default.cc',
+ 'cma/backend/media_component_device_default.h',
'cma/backend/media_pipeline_device.cc',
'cma/backend/media_pipeline_device.h',
- 'cma/backend/media_pipeline_device_fake.cc',
- 'cma/backend/media_pipeline_device_fake.h',
+ 'cma/backend/media_pipeline_device_factory.h',
+ 'cma/backend/media_pipeline_device_factory_default.cc',
+ 'cma/backend/media_pipeline_device_factory_default.h',
'cma/backend/media_pipeline_device_params.cc',
'cma/backend/media_pipeline_device_params.h',
'cma/backend/video_pipeline_device.cc',
+ 'cma/backend/video_pipeline_device_default.cc',
+ 'cma/backend/video_pipeline_device_default.h',
'cma/backend/video_pipeline_device.h',
- 'cma/backend/video_plane.cc',
- 'cma/backend/video_plane.h',
- 'cma/backend/video_plane_fake.cc',
- 'cma/backend/video_plane_fake.h',
],
'conditions': [
['chromecast_branding=="Chrome"', {
@@ -140,8 +158,7 @@
],
}, {
'sources': [
- 'cma/backend/media_pipeline_device_fake_factory.cc',
- 'cma/backend/video_plane_fake_factory.cc',
+ 'cma/backend/media_pipeline_device_factory_simple.cc'
],
}],
],
@@ -195,17 +212,7 @@
'../../base/base.gyp:base',
'../../crypto/crypto.gyp:crypto',
'../../media/media.gyp:media',
- ],
- 'conditions': [
- ['chromecast_branding=="Chrome"', {
- 'dependencies': [
- '../internal/cast_system.gyp:openssl',
- ],
- }, {
- 'dependencies': [
- '../../third_party/boringssl/boringssl.gyp:boringssl',
- ],
- }],
+ '../../third_party/boringssl/boringssl.gyp:boringssl',
],
'sources': [
'cma/pipeline/audio_pipeline.cc',
@@ -245,6 +252,8 @@
'cma/filters/cma_renderer.h',
'cma/filters/demuxer_stream_adapter.cc',
'cma/filters/demuxer_stream_adapter.h',
+ 'cma/filters/hole_frame_factory.cc',
+ 'cma/filters/hole_frame_factory.h',
],
},
{
@@ -269,21 +278,28 @@
'../../base/base.gyp:base_i18n',
'../../base/base.gyp:test_support_base',
'../../chromecast/chromecast.gyp:cast_metrics_test_support',
+ '../../gpu/gpu.gyp:gpu_unittest_utils',
'../../media/media.gyp:media_test_support',
'../../testing/gmock.gyp:gmock',
'../../testing/gtest.gyp:gtest',
'../../testing/gtest.gyp:gtest_main',
+ '../../ui/gfx/gfx.gyp:gfx_test_support',
],
'sources': [
+ 'cdm/chromecast_init_data_unittest.cc',
'cma/backend/audio_video_pipeline_device_unittest.cc',
'cma/base/balanced_media_task_runner_unittest.cc',
'cma/base/buffering_controller_unittest.cc',
'cma/base/buffering_frame_provider_unittest.cc',
'cma/filters/demuxer_stream_adapter_unittest.cc',
+ 'cma/filters/multi_demuxer_stream_adapter_unittest.cc',
'cma/ipc/media_message_fifo_unittest.cc',
'cma/ipc/media_message_unittest.cc',
'cma/ipc_streamer/av_streamer_unittest.cc',
'cma/pipeline/audio_video_pipeline_impl_unittest.cc',
+ 'cma/test/cma_end_to_end_test.cc',
+ 'cma/test/demuxer_stream_for_test.cc',
+ 'cma/test/demuxer_stream_for_test.h',
'cma/test/frame_generator_for_test.cc',
'cma/test/frame_generator_for_test.h',
'cma/test/frame_segmenter_for_test.cc',
diff --git a/chromium/chromecast/net/BUILD.gn b/chromium/chromecast/net/BUILD.gn
new file mode 100644
index 00000000000..a4818650823
--- /dev/null
+++ b/chromium/chromecast/net/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2015 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.
+
+source_set("net") {
+ sources = [
+ "connectivity_checker.cc",
+ "connectivity_checker.h",
+ "connectivity_checker_impl.cc",
+ "connectivity_checker_impl.h",
+ "fake_connectivity_checker.cc",
+ "fake_connectivity_checker.h",
+ "net_switches.cc",
+ "net_switches.h",
+ "net_util_cast.cc",
+ "net_util_cast.h",
+ ]
+
+ if (!is_android) {
+ sources += [
+ "network_change_notifier_factory_cast.cc",
+ "network_change_notifier_factory_cast.h",
+ ]
+ }
+
+ deps = [
+ "//base",
+ "//chromecast/base:cast_sys_info",
+ "//chromecast/public",
+ "//net",
+ ]
+}
diff --git a/chromium/chromecast/net/connectivity_checker.cc b/chromium/chromecast/net/connectivity_checker.cc
index de3081291f3..873ab1e1a57 100644
--- a/chromium/chromecast/net/connectivity_checker.cc
+++ b/chromium/chromecast/net/connectivity_checker.cc
@@ -4,73 +4,16 @@
#include "chromecast/net/connectivity_checker.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "chromecast/net/net_switches.h"
-#include "net/base/request_priority.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_response_info.h"
-#include "net/http/http_status_code.h"
-#include "net/proxy/proxy_config.h"
-#include "net/proxy/proxy_config_service_fixed.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_builder.h"
+#include "chromecast/net/connectivity_checker_impl.h"
namespace chromecast {
-namespace {
-
-// How often connectivity checks are performed in seconds
-const unsigned int kConnectivityPeriodSeconds = 1;
-
-// Number of consecutive bad responses received before connectivity status is
-// changed to offline
-const unsigned int kNumBadResponses = 3;
-
-// Default url for connectivity checking.
-const char kDefaultConnectivityCheckUrl[] =
- "https://clients3.google.com/generate_204";
-
-} // namespace
-
-ConnectivityChecker::ConnectivityChecker(
- const scoped_refptr<base::MessageLoopProxy>& loop_proxy)
+ConnectivityChecker::ConnectivityChecker()
: connectivity_observer_list_(
- new ObserverListThreadSafe<ConnectivityObserver>()),
- loop_proxy_(loop_proxy),
- connected_(false),
- bad_responses_(0) {
- DCHECK(loop_proxy_.get());
- loop_proxy->PostTask(FROM_HERE,
- base::Bind(&ConnectivityChecker::Initialize, this));
-}
-
-void ConnectivityChecker::Initialize() {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- base::CommandLine::StringType check_url_str =
- command_line->GetSwitchValueNative(switches::kConnectivityCheckUrl);
- connectivity_check_url_.reset(new GURL(
- check_url_str.empty() ? kDefaultConnectivityCheckUrl : check_url_str));
-
- net::URLRequestContextBuilder builder;
- builder.set_proxy_config_service(
- new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect()));
- builder.DisableHttpCache();
- url_request_context_.reset(builder.Build());
-
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
- net::NetworkChangeNotifier::AddIPAddressObserver(this);
- loop_proxy_->PostTask(FROM_HERE,
- base::Bind(&ConnectivityChecker::Check, this));
+ new base::ObserverListThreadSafe<ConnectivityObserver>()) {
}
ConnectivityChecker::~ConnectivityChecker() {
- DCHECK(loop_proxy_.get());
- net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
- loop_proxy_->DeleteSoon(FROM_HERE, url_request_context_.release());
- loop_proxy_->DeleteSoon(FROM_HERE, url_request_.release());
}
void ConnectivityChecker::AddConnectivityObserver(
@@ -83,102 +26,16 @@ void ConnectivityChecker::RemoveConnectivityObserver(
connectivity_observer_list_->RemoveObserver(observer);
}
-bool ConnectivityChecker::Connected() const {
- return connected_;
-}
-
-void ConnectivityChecker::SetConnectivity(bool connected) {
- if (connected_ == connected)
- return;
-
- connected_ = connected;
+void ConnectivityChecker::Notify(bool connected) {
+ DCHECK(connectivity_observer_list_.get());
connectivity_observer_list_->Notify(
FROM_HERE, &ConnectivityObserver::OnConnectivityChanged, connected);
- LOG(INFO) << "Global connection is: " << (connected ? "Up" : "Down");
-}
-
-void ConnectivityChecker::Check() {
- if (!loop_proxy_->BelongsToCurrentThread()) {
- loop_proxy_->PostTask(FROM_HERE,
- base::Bind(&ConnectivityChecker::Check, this));
- return;
- }
- DCHECK(url_request_context_.get());
-
- // Don't check connectivity if network is offline, because internet could be
- // accessible via netifs ignored.
- if (net::NetworkChangeNotifier::IsOffline())
- return;
-
- // If url_request_ is non-null, there is already a check going on. Don't
- // start another.
- if (url_request_.get())
- return;
-
- VLOG(1) << "Connectivity check: url=" << *connectivity_check_url_;
- url_request_ = url_request_context_->CreateRequest(
- *connectivity_check_url_, net::MAXIMUM_PRIORITY, this);
- url_request_->set_method("HEAD");
- url_request_->Start();
-}
-
-void ConnectivityChecker::OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) {
- VLOG(2) << "OnConnectionTypeChanged " << type;
- if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
- SetConnectivity(false);
-
- Cancel();
- Check();
-}
-
-void ConnectivityChecker::OnIPAddressChanged() {
- VLOG(2) << "OnIPAddressChanged";
-
- Cancel();
- Check();
-}
-
-void ConnectivityChecker::OnResponseStarted(net::URLRequest* request) {
- int http_response_code =
- (request->status().is_success() &&
- request->response_info().headers.get() != NULL)
- ? request->response_info().headers->response_code()
- : net::HTTP_BAD_REQUEST;
-
- // Clears resources.
- url_request_.reset(NULL); // URLRequest::Cancel() is called in destructor.
-
- if (http_response_code < 400) {
- VLOG(1) << "Connectivity check succeeded";
- bad_responses_ = 0;
- SetConnectivity(true);
- return;
- }
-
- VLOG(1) << "Connectivity check failed: " << http_response_code;
- ++bad_responses_;
- if (bad_responses_ > kNumBadResponses) {
- bad_responses_ = kNumBadResponses;
- SetConnectivity(false);
- }
-
- // Check again
- loop_proxy_->PostDelayedTask(
- FROM_HERE, base::Bind(&ConnectivityChecker::Check, this),
- base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds));
-}
-
-void ConnectivityChecker::OnReadCompleted(net::URLRequest* request,
- int bytes_read) {
- NOTREACHED();
}
-void ConnectivityChecker::Cancel() {
- if (url_request_.get()) {
- VLOG(2) << "Cancel connectivity check in progress";
- url_request_.reset(NULL); // URLRequest::Cancel() is called in destructor.
- }
+// static
+scoped_refptr<ConnectivityChecker> ConnectivityChecker::Create(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+ return make_scoped_refptr(new ConnectivityCheckerImpl(task_runner));
}
} // namespace chromecast
diff --git a/chromium/chromecast/net/connectivity_checker.h b/chromium/chromecast/net/connectivity_checker.h
index c52b8a624da..fcfb878bde3 100644
--- a/chromium/chromecast/net/connectivity_checker.h
+++ b/chromium/chromecast/net/connectivity_checker.h
@@ -7,33 +7,23 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "net/base/network_change_notifier.h"
-#include "net/url_request/url_request.h"
+#include "base/observer_list_threadsafe.h"
class GURL;
namespace base {
-class MessageLoopProxy;
-}
-
-namespace net {
-class URLRequestContext;
+class SingleThreadTaskRunner;
}
namespace chromecast {
-// Simple class to check network connectivity by sending a HEAD http request
-// to given url.
+// Checks if internet connectivity is available.
class ConnectivityChecker
- : public base::RefCountedThreadSafe<ConnectivityChecker>,
- public net::URLRequest::Delegate,
- public net::NetworkChangeNotifier::ConnectionTypeObserver,
- public net::NetworkChangeNotifier::IPAddressObserver {
+ : public base::RefCountedThreadSafe<ConnectivityChecker> {
public:
class ConnectivityObserver {
public:
- // Will be called when internet connectivity changes
+ // Will be called when internet connectivity changes.
virtual void OnConnectivityChanged(bool connected) = 0;
protected:
@@ -44,52 +34,31 @@ class ConnectivityChecker
DISALLOW_COPY_AND_ASSIGN(ConnectivityObserver);
};
- explicit ConnectivityChecker(
- const scoped_refptr<base::MessageLoopProxy>& loop_proxy);
+ static scoped_refptr<ConnectivityChecker> Create(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ ConnectivityChecker();
void AddConnectivityObserver(ConnectivityObserver* observer);
void RemoveConnectivityObserver(ConnectivityObserver* observer);
- // Returns if there is internet connectivity
- bool Connected() const;
+ // Returns if there is internet connectivity.
+ virtual bool Connected() const = 0;
- // Checks for connectivity
- void Check();
+ // Checks for connectivity.
+ virtual void Check() = 0;
protected:
- ~ConnectivityChecker() override;
+ virtual ~ConnectivityChecker();
+
+ // Notifies observes that connectivity has changed.
+ void Notify(bool connected);
private:
friend class base::RefCountedThreadSafe<ConnectivityChecker>;
- // UrlRequest::Delegate implementation:
- void OnResponseStarted(net::URLRequest* request) override;
- void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
-
- // Initializes ConnectivityChecker
- void Initialize();
-
- // NetworkChangeNotifier::ConnectionTypeObserver implementation:
- void OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) override;
-
- // net::NetworkChangeNotifier::IPAddressObserver implementation:
- void OnIPAddressChanged() override;
-
- // Cancels current connectivity checking in progress.
- void Cancel();
-
- // Sets connectivity and alerts observers if it has changed
- void SetConnectivity(bool connected);
-
- scoped_ptr<GURL> connectivity_check_url_;
- scoped_ptr<net::URLRequestContext> url_request_context_;
- scoped_ptr<net::URLRequest> url_request_;
- const scoped_refptr<ObserverListThreadSafe<ConnectivityObserver> >
+ const scoped_refptr<base::ObserverListThreadSafe<ConnectivityObserver>>
connectivity_observer_list_;
- const scoped_refptr<base::MessageLoopProxy> loop_proxy_;
- bool connected_;
- unsigned int bad_responses_;
DISALLOW_COPY_AND_ASSIGN(ConnectivityChecker);
};
diff --git a/chromium/chromecast/net/connectivity_checker_impl.cc b/chromium/chromecast/net/connectivity_checker_impl.cc
new file mode 100644
index 00000000000..d298d1bbfde
--- /dev/null
+++ b/chromium/chromecast/net/connectivity_checker_impl.cc
@@ -0,0 +1,195 @@
+// Copyright 2015 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/net/connectivity_checker_impl.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "chromecast/net/net_switches.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_response_info.h"
+#include "net/http/http_status_code.h"
+#include "net/proxy/proxy_config.h"
+#include "net/proxy/proxy_config_service_fixed.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+
+namespace chromecast {
+
+namespace {
+
+// How often connectivity checks are performed in seconds.
+const unsigned int kConnectivityPeriodSeconds = 1;
+
+// Number of consecutive connectivity check errors before status is changed
+// to offline.
+const unsigned int kNumErrorsToNotifyOffline = 3;
+
+// Request timeout value in seconds.
+const unsigned int kRequestTimeoutInSeconds = 3;
+
+// Default url for connectivity checking.
+const char kDefaultConnectivityCheckUrl[] =
+ "https://clients3.google.com/generate_204";
+
+} // namespace
+
+ConnectivityCheckerImpl::ConnectivityCheckerImpl(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : ConnectivityChecker(),
+ task_runner_(task_runner),
+ connected_(false),
+ check_errors_(0) {
+ DCHECK(task_runner_.get());
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&ConnectivityCheckerImpl::Initialize, this));
+}
+
+void ConnectivityCheckerImpl::Initialize() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ base::CommandLine::StringType check_url_str =
+ command_line->GetSwitchValueNative(switches::kConnectivityCheckUrl);
+ connectivity_check_url_.reset(new GURL(
+ check_url_str.empty() ? kDefaultConnectivityCheckUrl : check_url_str));
+
+ net::URLRequestContextBuilder builder;
+ builder.set_proxy_config_service(
+ new net::ProxyConfigServiceFixed(net::ProxyConfig::CreateDirect()));
+ builder.DisableHttpCache();
+ url_request_context_.reset(builder.Build());
+
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&ConnectivityCheckerImpl::Check, this));
+}
+
+ConnectivityCheckerImpl::~ConnectivityCheckerImpl() {
+ DCHECK(task_runner_.get());
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+ task_runner_->DeleteSoon(FROM_HERE, url_request_.release());
+ task_runner_->DeleteSoon(FROM_HERE, url_request_context_.release());
+}
+
+bool ConnectivityCheckerImpl::Connected() const {
+ return connected_;
+}
+
+void ConnectivityCheckerImpl::SetConnected(bool connected) {
+ if (connected_ == connected)
+ return;
+
+ connected_ = connected;
+ Notify(connected);
+ LOG(INFO) << "Global connection is: " << (connected ? "Up" : "Down");
+}
+
+void ConnectivityCheckerImpl::Check() {
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&ConnectivityCheckerImpl::Check, this));
+ return;
+ }
+ DCHECK(url_request_context_.get());
+
+ // Don't check connectivity if network is offline, because Internet could be
+ // accessible via netifs ignored.
+ if (net::NetworkChangeNotifier::IsOffline())
+ return;
+
+ // If url_request_ is non-null, there is already a check going on. Don't
+ // start another.
+ if (url_request_.get())
+ return;
+
+ VLOG(1) << "Connectivity check: url=" << *connectivity_check_url_;
+ url_request_ = url_request_context_->CreateRequest(
+ *connectivity_check_url_, net::MAXIMUM_PRIORITY, this);
+ url_request_->set_method("HEAD");
+ url_request_->Start();
+
+ timeout_.Reset(base::Bind(&ConnectivityCheckerImpl::OnUrlRequestTimeout,
+ this));
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ timeout_.callback(),
+ base::TimeDelta::FromSeconds(kRequestTimeoutInSeconds));
+}
+
+void ConnectivityCheckerImpl::OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) {
+ VLOG(2) << "OnNetworkChanged " << type;
+ Cancel();
+
+ if (type == net::NetworkChangeNotifier::CONNECTION_NONE) {
+ SetConnected(false);
+ return;
+ }
+
+ Check();
+}
+
+void ConnectivityCheckerImpl::OnResponseStarted(net::URLRequest* request) {
+ timeout_.Cancel();
+ int http_response_code =
+ (request->status().is_success() &&
+ request->response_info().headers.get() != NULL)
+ ? request->response_info().headers->response_code()
+ : net::HTTP_BAD_REQUEST;
+
+ // Clears resources.
+ url_request_.reset(NULL); // URLRequest::Cancel() is called in destructor.
+
+ if (http_response_code < 400) {
+ VLOG(1) << "Connectivity check succeeded";
+ check_errors_ = 0;
+ SetConnected(true);
+ return;
+ }
+ VLOG(1) << "Connectivity check failed: " << http_response_code;
+ OnUrlRequestError();
+}
+
+void ConnectivityCheckerImpl::OnReadCompleted(net::URLRequest* request,
+ int bytes_read) {
+ NOTREACHED();
+}
+
+void ConnectivityCheckerImpl::OnSSLCertificateError(
+ net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) {
+ LOG(ERROR) << "OnSSLCertificateError: cert_status=" << ssl_info.cert_status;
+ timeout_.Cancel();
+ OnUrlRequestError();
+}
+
+void ConnectivityCheckerImpl::OnUrlRequestError() {
+ ++check_errors_;
+ if (check_errors_ > kNumErrorsToNotifyOffline) {
+ check_errors_ = kNumErrorsToNotifyOffline;
+ SetConnected(false);
+ }
+ url_request_.reset(NULL);
+ // Check again.
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&ConnectivityCheckerImpl::Check, this),
+ base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds));
+}
+
+void ConnectivityCheckerImpl::OnUrlRequestTimeout() {
+ LOG(ERROR) << "time out";
+ OnUrlRequestError();
+}
+
+void ConnectivityCheckerImpl::Cancel() {
+ if (!url_request_.get())
+ return;
+ VLOG(2) << "Cancel connectivity check in progress";
+ timeout_.Cancel();
+ url_request_.reset(NULL); // URLRequest::Cancel() is called in destructor.
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/net/connectivity_checker_impl.h b/chromium/chromecast/net/connectivity_checker_impl.h
new file mode 100644
index 00000000000..da15039de75
--- /dev/null
+++ b/chromium/chromecast/net/connectivity_checker_impl.h
@@ -0,0 +1,85 @@
+// Copyright 2015 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_NET_CONNECTIVITY_CHECKER_IMPL_H_
+#define CHROMECAST_NET_CONNECTIVITY_CHECKER_IMPL_H_
+
+#include "base/cancelable_callback.h"
+#include "chromecast/net/connectivity_checker.h"
+#include "net/base/network_change_notifier.h"
+#include "net/url_request/url_request.h"
+
+class GURL;
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace net {
+class SSLInfo;
+class URLRequest;
+class URLRequestContext;
+}
+
+namespace chromecast {
+
+// Simple class to check network connectivity by sending a HEAD http request
+// to given url.
+class ConnectivityCheckerImpl
+ : public ConnectivityChecker,
+ public net::URLRequest::Delegate,
+ public net::NetworkChangeNotifier::NetworkChangeObserver {
+ public:
+ explicit ConnectivityCheckerImpl(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ // ConnectivityChecker implementation:
+ bool Connected() const override;
+ void Check() override;
+
+ protected:
+ ~ConnectivityCheckerImpl() override;
+
+ private:
+ // UrlRequest::Delegate implementation:
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
+ void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) override;
+
+ // Initializes ConnectivityChecker
+ void Initialize();
+
+ // net::NetworkChangeNotifier::NetworkChangeObserver implementation:
+ void OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) override;
+
+ // Cancels current connectivity checking in progress.
+ void Cancel();
+
+ // Sets connectivity and alerts observers if it has changed
+ void SetConnected(bool connected);
+
+ // Called when URL request failed.
+ void OnUrlRequestError();
+
+ // Called when URL request timed out.
+ void OnUrlRequestTimeout();
+
+ scoped_ptr<GURL> connectivity_check_url_;
+ scoped_ptr<net::URLRequestContext> url_request_context_;
+ scoped_ptr<net::URLRequest> url_request_;
+ const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ bool connected_;
+ // Number of connectivity check errors.
+ unsigned int check_errors_;
+ base::CancelableCallback<void()> timeout_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectivityCheckerImpl);
+};
+
+} // namespace chromecast
+
+#endif // CHROMECAST_NET_CONNECTIVITY_CHECKER_IMPL_H_
diff --git a/chromium/chromecast/net/fake_connectivity_checker.cc b/chromium/chromecast/net/fake_connectivity_checker.cc
new file mode 100644
index 00000000000..fc3caed6ae3
--- /dev/null
+++ b/chromium/chromecast/net/fake_connectivity_checker.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 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/net/fake_connectivity_checker.h"
+
+namespace chromecast {
+
+FakeConnectivityChecker::FakeConnectivityChecker()
+ : ConnectivityChecker(),
+ connected_(true) {
+}
+
+FakeConnectivityChecker::~FakeConnectivityChecker() {}
+
+bool FakeConnectivityChecker::Connected() const {
+ return connected_;
+}
+
+void FakeConnectivityChecker::Check() {
+}
+
+void FakeConnectivityChecker::SetConnectedForTest(bool connected) {
+ if (connected_ == connected)
+ return;
+
+ connected_ = connected;
+ Notify(connected);
+}
+
+} // namespace chromecast
diff --git a/chromium/chromecast/net/fake_connectivity_checker.h b/chromium/chromecast/net/fake_connectivity_checker.h
new file mode 100644
index 00000000000..7381b8f0ddc
--- /dev/null
+++ b/chromium/chromecast/net/fake_connectivity_checker.h
@@ -0,0 +1,32 @@
+// Copyright 2015 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/net/connectivity_checker.h"
+
+namespace chromecast {
+
+// A simple fake connectivity checker for testing. Will appeared to be
+// connected by default.
+class FakeConnectivityChecker : public ConnectivityChecker {
+ public:
+ FakeConnectivityChecker();
+
+ // ConnectivityChecker implementation:
+ bool Connected() const override;
+ void Check() override;
+
+ // Sets connectivity and notifies observers if it has changed.
+ void SetConnectedForTest(bool connected);
+
+ protected:
+ ~FakeConnectivityChecker() override;
+
+ private:
+ friend class base::RefCountedThreadSafe<FakeConnectivityChecker>;
+ bool connected_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeConnectivityChecker);
+};
+
+} // namespace chromecast
diff --git a/chromium/chromecast/public/BUILD.gn b/chromium/chromecast/public/BUILD.gn
new file mode 100644
index 00000000000..5ad19d36e33
--- /dev/null
+++ b/chromium/chromecast/public/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2015 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.
+
+source_set("public") {
+ sources = [
+ "cast_egl_platform.h",
+ "cast_egl_platform_shlib.h",
+ "cast_media_shlib.h",
+ "cast_sys_info.h",
+ "chromecast_export.h",
+ "graphics_properties_shlib.h",
+ "graphics_types.h",
+ "osd_plane.h",
+ "osd_plane_shlib.h",
+ "osd_surface.h",
+ "video_plane.h",
+ ]
+}
diff --git a/chromium/chromecast/public/cast_egl_platform.h b/chromium/chromecast/public/cast_egl_platform.h
index c1350f6964f..a597f9f8ed2 100644
--- a/chromium/chromecast/public/cast_egl_platform.h
+++ b/chromium/chromecast/public/cast_egl_platform.h
@@ -53,6 +53,11 @@ class CastEglPlatform {
virtual NativeWindowType CreateWindow(NativeDisplayType display_type,
const Size& size) = 0;
virtual void DestroyWindow(NativeWindowType window) = 0;
+
+ // Specifies if creating multiple surfaces on a window is broken on this
+ // platform and a new window is required. This should return false on most
+ // implementations.
+ virtual bool MultipleSurfaceUnsupported() = 0;
};
} // namespace chromecast
diff --git a/chromium/chromecast/public/cast_media_shlib.h b/chromium/chromecast/public/cast_media_shlib.h
index 6f2d60d6cd1..8b776da8a43 100644
--- a/chromium/chromecast/public/cast_media_shlib.h
+++ b/chromium/chromecast/public/cast_media_shlib.h
@@ -13,6 +13,8 @@
namespace chromecast {
namespace media {
+class VideoPlane;
+
// Provides access to platform-specific media systems and hardware resources.
// In cast_shell, all usage is from the browser process. An implementation is
// assumed to be in an uninitialized state initially. When uninitialized, no
@@ -32,6 +34,11 @@ class CHROMECAST_EXPORT CastMediaShlib {
// state. The implementation must release all media-related hardware
// resources.
static void Finalize();
+
+ // Gets the VideoPlane instance for managing the hardware video plane.
+ // While an implementation is in an initialized state, this function may be
+ // called at any time. The VideoPlane object must be destroyed in Finalize.
+ static VideoPlane* GetVideoPlane();
};
} // namespace media
diff --git a/chromium/chromecast/public/graphics_types.h b/chromium/chromecast/public/graphics_types.h
index 09ac12ba29b..841dc00ac81 100644
--- a/chromium/chromecast/public/graphics_types.h
+++ b/chromium/chromecast/public/graphics_types.h
@@ -18,6 +18,17 @@ struct Rect {
int height;
};
+struct RectF {
+ RectF(float w, float h) : x(0), y(0), width(w), height(h) {}
+ RectF(float arg_x, float arg_y, float w, float h)
+ : x(arg_x), y(arg_y), width(w), height(h) {}
+
+ float x;
+ float y;
+ float width;
+ float height;
+};
+
struct Size {
Size(int w, int h) : width(w), height(h) {}
diff --git a/chromium/chromecast/public/media/decoder_config.h b/chromium/chromecast/public/media/decoder_config.h
index b1077af5763..45fd1d4cab4 100644
--- a/chromium/chromecast/public/media/decoder_config.h
+++ b/chromium/chromecast/public/media/decoder_config.h
@@ -8,24 +8,20 @@
#include <stdint.h>
#include <vector>
+#include "chromecast/public/media/stream_id.h"
+
namespace chromecast {
namespace media {
-namespace {
-
// Maximum audio bytes per sample.
static const int kMaxBytesPerSample = 4;
// Maximum audio sampling rate.
static const int kMaxSampleRate = 192000;
-} // namespace
-
enum AudioCodec {
- kAudioCodecUnknown = -1,
-
- kAudioCodecMin = 0,
- kCodecAAC = kAudioCodecMin,
+ kAudioCodecUnknown = 0,
+ kCodecAAC,
kCodecMP3,
kCodecPCM,
kCodecPCM_S16BE,
@@ -34,14 +30,28 @@ enum AudioCodec {
kCodecEAC3,
kCodecAC3,
kCodecDTS,
+
+ kAudioCodecMin = kAudioCodecUnknown,
kAudioCodecMax = kCodecDTS,
};
-enum VideoCodec {
- kVideoCodecUnknown = -1,
+enum SampleFormat {
+ kUnknownSampleFormat = 0,
+ kSampleFormatU8, // Unsigned 8-bit w/ bias of 128.
+ kSampleFormatS16, // Signed 16-bit.
+ kSampleFormatS32, // Signed 32-bit.
+ kSampleFormatF32, // Float 32-bit.
+ kSampleFormatPlanarS16, // Signed 16-bit planar.
+ kSampleFormatPlanarF32, // Float 32-bit planar.
+ kSampleFormatPlanarS32, // Signed 32-bit planar.
+
+ kSampleFormatMin = kUnknownSampleFormat,
+ kSampleFormatMax = kSampleFormatPlanarS32,
+};
- kVideoCodecMin = 0,
- kCodecH264 = kVideoCodecMin,
+enum VideoCodec {
+ kVideoCodecUnknown = 0,
+ kCodecH264,
kCodecVC1,
kCodecMPEG2,
kCodecMPEG4,
@@ -49,15 +59,15 @@ enum VideoCodec {
kCodecVP8,
kCodecVP9,
kCodecHEVC,
+
+ kVideoCodecMin = kVideoCodecUnknown,
kVideoCodecMax = kCodecHEVC,
};
// Profile for Video codec.
enum VideoProfile {
- kVideoProfileUnknown = -1,
-
- kVideoProfileMin = 0,
- kH264Baseline = kVideoProfileMin,
+ kVideoProfileUnknown = 0,
+ kH264Baseline,
kH264Main,
kH264Extended,
kH264High,
@@ -70,6 +80,8 @@ enum VideoProfile {
kH264MultiviewHigh,
kVP8ProfileAny,
kVP9ProfileAny,
+
+ kVideoProfileMin = kVideoProfileUnknown,
kVideoProfileMax = kVP9ProfileAny,
};
@@ -78,16 +90,22 @@ enum VideoProfile {
// determine if the configuration is still valid or not.
struct AudioConfig {
AudioConfig()
- : codec(kAudioCodecUnknown),
- bytes_per_channel(0),
- channel_number(0),
- samples_per_second(0),
- extra_data(nullptr),
- extra_data_size(0),
- is_encrypted(false) {}
-
+ : id(kPrimary),
+ codec(kAudioCodecUnknown),
+ sample_format(kUnknownSampleFormat),
+ bytes_per_channel(0),
+ channel_number(0),
+ samples_per_second(0),
+ extra_data(nullptr),
+ extra_data_size(0),
+ is_encrypted(false) {}
+
+ // Stream id.
+ StreamId id;
// Audio codec.
AudioCodec codec;
+ // The format of each audio sample.
+ SampleFormat sample_format;
// Number of bytes in each channel.
int bytes_per_channel;
// Number of channels in this audio stream.
@@ -109,13 +127,16 @@ struct AudioConfig {
// determine if the configuration is still valid or not.
struct VideoConfig {
VideoConfig()
- : codec(kVideoCodecUnknown),
+ : id(kPrimary),
+ codec(kVideoCodecUnknown),
profile(kVideoProfileUnknown),
additional_config(nullptr),
extra_data(nullptr),
extra_data_size(0),
is_encrypted(false) {}
+ // Stream Id.
+ StreamId id;
// Video codec.
VideoCodec codec;
// Video codec profile.
@@ -140,6 +161,10 @@ struct VideoConfig {
inline bool IsValidConfig(const AudioConfig& config) {
return config.codec >= kAudioCodecMin &&
config.codec <= kAudioCodecMax &&
+ config.codec != kAudioCodecUnknown &&
+ config.sample_format >= kSampleFormatMin &&
+ config.sample_format <= kSampleFormatMax &&
+ config.sample_format != kUnknownSampleFormat &&
config.channel_number > 0 &&
config.bytes_per_channel > 0 &&
config.bytes_per_channel <= kMaxBytesPerSample &&
@@ -148,7 +173,9 @@ inline bool IsValidConfig(const AudioConfig& config) {
}
inline bool IsValidConfig(const VideoConfig& config) {
- return config.codec >= kVideoCodecMin && config.codec <= kVideoCodecMax;
+ return config.codec >= kVideoCodecMin &&
+ config.codec <= kVideoCodecMax &&
+ config.codec != kVideoCodecUnknown;
}
} // namespace media
diff --git a/chromium/chromecast/public/media/stream_id.h b/chromium/chromecast/public/media/stream_id.h
new file mode 100644
index 00000000000..6641fd54ca9
--- /dev/null
+++ b/chromium/chromecast/public/media/stream_id.h
@@ -0,0 +1,19 @@
+// Copyright 2015 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_PUBLIC_MEDIA_STREAM_ID_H_
+#define CHROMECAST_PUBLIC_MEDIA_STREAM_ID_H_
+
+namespace chromecast {
+namespace media {
+
+enum StreamId {
+ kPrimary = 0,
+ kSecondary
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_PUBLIC_MEDIA_STREAM_ID_H_
diff --git a/chromium/chromecast/public/video_plane.h b/chromium/chromecast/public/video_plane.h
new file mode 100644
index 00000000000..890e7a051b8
--- /dev/null
+++ b/chromium/chromecast/public/video_plane.h
@@ -0,0 +1,55 @@
+// Copyright 2015 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_PUBLIC_VIDEO_PLANE_H_
+#define CHROMECAST_PUBLIC_VIDEO_PLANE_H_
+
+namespace chromecast {
+struct RectF;
+struct Size;
+
+namespace media {
+
+class VideoPlane {
+ public:
+ // List of possible hardware transforms that can be applied to video.
+ // Rotations are anticlockwise.
+ enum Transform {
+ TRANSFORM_NONE,
+ ROTATE_90,
+ ROTATE_180,
+ ROTATE_270,
+ FLIP_HORIZONTAL,
+ FLIP_VERTICAL,
+ };
+
+ enum CoordinateType {
+ // Graphics plane as coordinate type.
+ COORDINATE_TYPE_GRAPHICS_PLANE = 0,
+ // Output display screen as coordinate type.
+ COORDINATE_TYPE_SCREEN_RESOLUTION = 1,
+ };
+
+ virtual ~VideoPlane() {}
+
+ // Gets output screen resolution.
+ virtual Size GetScreenResolution() = 0;
+
+ // Updates the video plane geometry.
+ // |display_rect| specifies the rectangle that the video should occupy.
+ // |coordinate_type| gives the coordinate space of |display_rect|.
+ // |transform| specifies how the video should be transformed within that
+ // rectangle.
+ virtual void SetGeometry(const RectF& display_rect,
+ CoordinateType coordinate_type,
+ Transform transform) = 0;
+
+ // Notifies VideoPlane that screen resolution has changed.
+ virtual void OnScreenResolutionChanged(const Size& screen_res) = 0;
+};
+
+} // namespace media
+} // namespace chromecast
+
+#endif // CHROMECAST_PUBLIC_VIDEO_PLANE_H_
diff --git a/chromium/chromecast/renderer/cast_content_renderer_client.cc b/chromium/chromecast/renderer/cast_content_renderer_client.cc
index cfce89371aa..1f7c4a68d19 100644
--- a/chromium/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromium/chromecast/renderer/cast_content_renderer_client.cc
@@ -7,9 +7,11 @@
#include <sys/sysinfo.h>
#include "base/command_line.h"
+#include "base/location.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/strings/string_number_conversions.h"
-#include "chromecast/common/chromecast_switches.h"
+#include "base/thread_task_runner_handle.h"
+#include "chromecast/base/chromecast_switches.h"
#include "chromecast/crash/cast_crash_keys.h"
#include "chromecast/media/base/media_caps.h"
#include "chromecast/renderer/cast_media_load_deferrer.h"
@@ -58,9 +60,8 @@ void PlatformPollFreemem(void) {
}
// Setup next poll.
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&PlatformPollFreemem),
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&PlatformPollFreemem),
base::TimeDelta::FromMilliseconds(kPollingIntervalMS));
}
#endif
@@ -71,18 +72,27 @@ const blink::WebColor kColorBlack = 0xFF000000;
class CastRenderViewObserver : content::RenderViewObserver {
public:
- explicit CastRenderViewObserver(content::RenderView* render_view);
+ CastRenderViewObserver(CastContentRendererClient* client,
+ content::RenderView* render_view);
~CastRenderViewObserver() override {}
void DidClearWindowObject(blink::WebLocalFrame* frame) override;
+
+ private:
+ CastContentRendererClient* const client_;
+
+ DISALLOW_COPY_AND_ASSIGN(CastRenderViewObserver);
};
-CastRenderViewObserver::CastRenderViewObserver(content::RenderView* render_view)
- : content::RenderViewObserver(render_view) {
+CastRenderViewObserver::CastRenderViewObserver(
+ CastContentRendererClient* client,
+ content::RenderView* render_view)
+ : content::RenderViewObserver(render_view),
+ client_(client) {
}
void CastRenderViewObserver::DidClearWindowObject(blink::WebLocalFrame* frame) {
- PlatformAddRendererNativeBindings(frame);
+ client_->AddRendererNativeBindings(frame);
}
} // namespace
@@ -93,9 +103,18 @@ CastContentRendererClient::CastContentRendererClient() {
CastContentRendererClient::~CastContentRendererClient() {
}
+void CastContentRendererClient::AddRendererNativeBindings(
+ blink::WebLocalFrame* frame) {
+}
+
+std::vector<scoped_refptr<IPC::MessageFilter>>
+CastContentRendererClient::GetRendererMessageFilters() {
+ return std::vector<scoped_refptr<IPC::MessageFilter>>();
+}
+
void CastContentRendererClient::RenderThreadStarted() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-#if defined(USE_NSS_CERTS)
+#if !defined(USE_OPENSSL)
// Note: Copied from chrome_render_process_observer.cc to fix b/8676652.
//
// On platforms where the system NSS shared libraries are used,
@@ -120,7 +139,7 @@ void CastContentRendererClient::RenderThreadStarted() {
}
cast_observer_.reset(
- new CastRenderProcessObserver(PlatformGetRendererMessageFilters()));
+ new CastRenderProcessObserver(GetRendererMessageFilters()));
prescient_networking_dispatcher_.reset(
new network_hints::PrescientNetworkingDispatcher());
@@ -160,19 +179,19 @@ void CastContentRendererClient::RenderViewCreated(
}
// Note: RenderView will own the lifetime of its observer.
- new CastRenderViewObserver(render_view);
+ new CastRenderViewObserver(this, render_view);
}
void CastContentRendererClient::AddKeySystems(
std::vector< ::media::KeySystemInfo>* key_systems) {
AddChromecastKeySystems(key_systems);
- AddChromecastPlatformKeySystems(key_systems);
}
#if !defined(OS_ANDROID)
scoped_ptr<::media::RendererFactory>
CastContentRendererClient::CreateMediaRendererFactory(
::content::RenderFrame* render_frame,
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories,
const scoped_refptr<::media::MediaLog>& media_log) {
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!cmd_line->HasSwitch(switches::kEnableCmaMediaPipeline))
@@ -180,7 +199,7 @@ CastContentRendererClient::CreateMediaRendererFactory(
return scoped_ptr<::media::RendererFactory>(
new chromecast::media::ChromecastMediaRendererFactory(
- media_log, render_frame->GetRoutingID()));
+ gpu_factories, media_log, render_frame->GetRoutingID()));
}
#endif
diff --git a/chromium/chromecast/renderer/cast_content_renderer_client.h b/chromium/chromecast/renderer/cast_content_renderer_client.h
index efdc3a5a9f6..0ee87ed6bd5 100644
--- a/chromium/chromecast/renderer/cast_content_renderer_client.h
+++ b/chromium/chromecast/renderer/cast_content_renderer_client.h
@@ -22,18 +22,21 @@ namespace chromecast {
namespace shell {
class CastRenderProcessObserver;
-// Adds any platform-specific bindings to the current frame.
-void PlatformAddRendererNativeBindings(blink::WebLocalFrame* frame);
-
class CastContentRendererClient : public content::ContentRendererClient {
public:
- CastContentRendererClient();
+ // Creates an implementation of CastContentRendererClient. Platform should
+ // link in an implementation as needed.
+ static scoped_ptr<CastContentRendererClient> Create();
+
~CastContentRendererClient() override;
+ // Adds any platform-specific bindings to the current frame.
+ virtual void AddRendererNativeBindings(blink::WebLocalFrame* frame);
+
// Returns any MessageFilters from the platform implementation that should
// be added to the render process.
- std::vector<scoped_refptr<IPC::MessageFilter>>
- PlatformGetRendererMessageFilters();
+ virtual std::vector<scoped_refptr<IPC::MessageFilter>>
+ GetRendererMessageFilters();
// ContentRendererClient implementation:
void RenderThreadStarted() override;
@@ -41,14 +44,18 @@ class CastContentRendererClient : public content::ContentRendererClient {
void AddKeySystems(
std::vector< ::media::KeySystemInfo>* key_systems) override;
#if !defined(OS_ANDROID)
- scoped_ptr<media::RendererFactory> CreateMediaRendererFactory(
+ scoped_ptr<::media::RendererFactory> CreateMediaRendererFactory(
content::RenderFrame* render_frame,
- const scoped_refptr<media::MediaLog>& media_log) override;
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories,
+ const scoped_refptr<::media::MediaLog>& media_log) override;
#endif
blink::WebPrescientNetworking* GetPrescientNetworking() override;
void DeferMediaLoad(content::RenderFrame* render_frame,
const base::Closure& closure) override;
+ protected:
+ CastContentRendererClient();
+
private:
scoped_ptr<network_hints::PrescientNetworkingDispatcher>
prescient_networking_dispatcher_;
diff --git a/chromium/chromecast/renderer/cast_content_renderer_client_simple.cc b/chromium/chromecast/renderer/cast_content_renderer_client_simple.cc
index 5ad4fccb261..5f94e08e7ac 100644
--- a/chromium/chromecast/renderer/cast_content_renderer_client_simple.cc
+++ b/chromium/chromecast/renderer/cast_content_renderer_client_simple.cc
@@ -4,17 +4,15 @@
#include "chromecast/renderer/cast_content_renderer_client.h"
+#include "base/memory/scoped_ptr.h"
#include "ipc/message_filter.h"
namespace chromecast {
namespace shell {
-void PlatformAddRendererNativeBindings(blink::WebLocalFrame* frame) {
-}
-
-std::vector<scoped_refptr<IPC::MessageFilter>>
-CastContentRendererClient::PlatformGetRendererMessageFilters() {
- return std::vector<scoped_refptr<IPC::MessageFilter>>();
+// static
+scoped_ptr<CastContentRendererClient> CastContentRendererClient::Create() {
+ return make_scoped_ptr(new CastContentRendererClient());
}
} // namespace shell
diff --git a/chromium/chromecast/renderer/key_systems_cast.cc b/chromium/chromecast/renderer/key_systems_cast.cc
index bede01890c5..bb27a6f11a2 100644
--- a/chromium/chromecast/renderer/key_systems_cast.cc
+++ b/chromium/chromecast/renderer/key_systems_cast.cc
@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "build/build_config.h"
#include "chromecast/media/base/key_systems_common.h"
#include "components/cdm/renderer/widevine_key_systems.h"
#include "media/base/eme_constants.h"
@@ -31,8 +32,13 @@ void AddKeySystemWithCodecs(
::media::EME_CODEC_MP4_AAC | ::media::EME_CODEC_MP4_AVC1;
info.max_audio_robustness = ::media::EmeRobustness::EMPTY;
info.max_video_robustness = ::media::EmeRobustness::EMPTY;
+#if defined(OS_ANDROID)
info.persistent_license_support =
::media::EmeSessionTypeSupport::NOT_SUPPORTED;
+#else
+ info.persistent_license_support =
+ ::media::EmeSessionTypeSupport::SUPPORTED;
+#endif
info.persistent_release_message_support =
::media::EmeSessionTypeSupport::NOT_SUPPORTED;
info.persistent_state_support = ::media::EmeFeatureSupport::ALWAYS_ENABLED;
diff --git a/chromium/chromecast/renderer/key_systems_cast.h b/chromium/chromecast/renderer/key_systems_cast.h
index c64eb1db708..d59993f131d 100644
--- a/chromium/chromecast/renderer/key_systems_cast.h
+++ b/chromium/chromecast/renderer/key_systems_cast.h
@@ -22,10 +22,6 @@ void AddKeySystemWithCodecs(
void AddChromecastKeySystems(
std::vector<::media::KeySystemInfo>* key_systems_info);
-// TODO(gunsch): Remove when prefixed EME is removed.
-void AddChromecastPlatformKeySystems(
- std::vector<::media::KeySystemInfo>* key_systems_info);
-
} // namespace shell
} // namespace chromecast
diff --git a/chromium/chromecast/renderer/key_systems_cast_simple.cc b/chromium/chromecast/renderer/key_systems_cast_simple.cc
deleted file mode 100644
index e5ca3783c3e..00000000000
--- a/chromium/chromecast/renderer/key_systems_cast_simple.cc
+++ /dev/null
@@ -1,16 +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/renderer/key_systems_cast.h"
-
-namespace chromecast {
-namespace shell {
-
-void AddChromecastPlatformKeySystems(
- std::vector< ::media::KeySystemInfo>* key_systems_info) {
- // Intentional no-op for public build.
-}
-
-} // namespace shell
-} // namespace chromecast
diff --git a/chromium/chromecast/renderer/media/audio_pipeline_proxy.cc b/chromium/chromecast/renderer/media/audio_pipeline_proxy.cc
index 30297a8a549..0193232d6f2 100644
--- a/chromium/chromecast/renderer/media/audio_pipeline_proxy.cc
+++ b/chromium/chromecast/renderer/media/audio_pipeline_proxy.cc
@@ -195,22 +195,20 @@ void AudioPipelineProxyInternal::OnStateChanged(
base::ResetAndReturn(&status_cb_).Run(status);
}
-
-// A macro runs current member function on |io_message_loop_proxy_| thread.
-#define FORWARD_ON_IO_THREAD(param_fn, ...) \
- io_message_loop_proxy_->PostTask( \
- FROM_HERE, \
- base::Bind(&AudioPipelineProxyInternal::param_fn, \
- base::Unretained(proxy_.get()), ##__VA_ARGS__))
+// A macro runs current member function on |io_task_runner_| thread.
+#define FORWARD_ON_IO_THREAD(param_fn, ...) \
+ io_task_runner_->PostTask( \
+ FROM_HERE, base::Bind(&AudioPipelineProxyInternal::param_fn, \
+ base::Unretained(proxy_.get()), ##__VA_ARGS__))
AudioPipelineProxy::AudioPipelineProxy(
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<MediaChannelProxy> media_channel_proxy)
- : io_message_loop_proxy_(io_message_loop_proxy),
+ : io_task_runner_(io_task_runner),
proxy_(new AudioPipelineProxyInternal(media_channel_proxy)),
audio_streamer_(new AvStreamerProxy()),
weak_factory_(this) {
- DCHECK(io_message_loop_proxy_.get());
+ DCHECK(io_task_runner_.get());
weak_this_ = weak_factory_.GetWeakPtr();
thread_checker_.DetachFromThread();
}
@@ -218,7 +216,7 @@ AudioPipelineProxy::AudioPipelineProxy(
AudioPipelineProxy::~AudioPipelineProxy() {
DCHECK(thread_checker_.CalledOnValidThread());
// Release the underlying object on the right thread.
- io_message_loop_proxy_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&AudioPipelineProxyInternal::Release, base::Passed(&proxy_)));
}
diff --git a/chromium/chromecast/renderer/media/audio_pipeline_proxy.h b/chromium/chromecast/renderer/media/audio_pipeline_proxy.h
index b319ee1b8a7..7bcc6852e6a 100644
--- a/chromium/chromecast/renderer/media/audio_pipeline_proxy.h
+++ b/chromium/chromecast/renderer/media/audio_pipeline_proxy.h
@@ -15,7 +15,7 @@
#include "media/base/pipeline_status.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
class SharedMemory;
}
@@ -33,9 +33,8 @@ class MediaChannelProxy;
class AudioPipelineProxy : public AudioPipeline {
public:
- AudioPipelineProxy(
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy,
- scoped_refptr<MediaChannelProxy> media_channel_proxy);
+ AudioPipelineProxy(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ scoped_refptr<MediaChannelProxy> media_channel_proxy);
~AudioPipelineProxy() override;
void Initialize(
@@ -60,7 +59,7 @@ class AudioPipelineProxy : public AudioPipeline {
void OnPipeWrite();
void OnPipeRead();
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// |proxy_| main goal is to convert function calls to IPC messages.
scoped_ptr<AudioPipelineProxyInternal> proxy_;
diff --git a/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.cc b/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.cc
index 62fe7716a3d..f2c9bfbd973 100644
--- a/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.cc
+++ b/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.cc
@@ -18,9 +18,11 @@ namespace chromecast {
namespace media {
ChromecastMediaRendererFactory::ChromecastMediaRendererFactory(
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories,
const scoped_refptr<::media::MediaLog>& media_log,
int render_frame_id)
: render_frame_id_(render_frame_id),
+ gpu_factories_(gpu_factories),
media_log_(media_log) {
}
@@ -46,11 +48,12 @@ scoped_ptr<::media::Renderer> ChromecastMediaRendererFactory::CreateRenderer(
::media::CHANNEL_LAYOUT_STEREO,
kDefaultSamplingRate, kDefaultBitsPerSample,
buffer_size, ::media::AudioParameters::NO_EFFECTS);
- ::media::AudioHardwareConfig audio_config(input_audio_params,
- output_audio_params);
+
+ audio_config_.reset(new ::media::AudioHardwareConfig(input_audio_params,
+ output_audio_params));
default_render_factory_.reset(new ::media::DefaultRendererFactory(
- media_log_, /*gpu_factories*/ nullptr, audio_config));
+ media_log_, /*gpu_factories*/ nullptr, *audio_config_));
}
DCHECK(default_render_factory_);
@@ -61,8 +64,8 @@ scoped_ptr<::media::Renderer> ChromecastMediaRendererFactory::CreateRenderer(
render_frame_id_,
content::RenderThread::Get()->GetIOMessageLoopProxy(),
cma_load_type));
- scoped_ptr<CmaRenderer> cma_renderer(
- new CmaRenderer(cma_media_pipeline.Pass(), video_renderer_sink));
+ scoped_ptr<CmaRenderer> cma_renderer(new CmaRenderer(
+ cma_media_pipeline.Pass(), video_renderer_sink, gpu_factories_));
scoped_ptr<::media::Renderer> default_media_render(
default_render_factory_->CreateRenderer(media_task_runner,
audio_renderer_sink,
diff --git a/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.h b/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.h
index 820609478fa..ab2b078edad 100644
--- a/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.h
+++ b/chromium/chromecast/renderer/media/chromecast_media_renderer_factory.h
@@ -10,6 +10,8 @@
#include "media/base/renderer_factory.h"
namespace media {
+class AudioHardwareConfig;
+class GpuVideoAcceleratorFactories;
class MediaLog;
class DefaultRendererFactory;
}
@@ -20,6 +22,7 @@ namespace media {
class ChromecastMediaRendererFactory : public ::media::RendererFactory {
public:
ChromecastMediaRendererFactory(
+ const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories,
const scoped_refptr<::media::MediaLog>& media_log,
int render_frame_id);
~ChromecastMediaRendererFactory() final;
@@ -32,9 +35,13 @@ class ChromecastMediaRendererFactory : public ::media::RendererFactory {
private:
int render_frame_id_;
+ scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_;
scoped_refptr<::media::MediaLog> media_log_;
scoped_ptr<::media::DefaultRendererFactory> default_render_factory_;
+ // Audio config for the default media renderer.
+ scoped_ptr<::media::AudioHardwareConfig> audio_config_;
+
DISALLOW_COPY_AND_ASSIGN(ChromecastMediaRendererFactory);
};
diff --git a/chromium/chromecast/renderer/media/cma_message_filter_proxy.cc b/chromium/chromecast/renderer/media/cma_message_filter_proxy.cc
index f2701a98725..c502ea2cafb 100644
--- a/chromium/chromecast/renderer/media/cma_message_filter_proxy.cc
+++ b/chromium/chromecast/renderer/media/cma_message_filter_proxy.cc
@@ -5,7 +5,7 @@
#include "chromecast/renderer/media/cma_message_filter_proxy.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "chromecast/common/media/cma_messages.h"
#include "ipc/ipc_logging.h"
@@ -46,22 +46,21 @@ CmaMessageFilterProxy* CmaMessageFilterProxy::Get() {
}
CmaMessageFilterProxy::CmaMessageFilterProxy(
- const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
- : sender_(NULL),
- io_message_loop_(io_message_loop) {
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+ : sender_(NULL), io_task_runner_(io_task_runner) {
DCHECK(!filter_);
filter_ = this;
}
int CmaMessageFilterProxy::CreateChannel() {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
DelegateEntry* entry = new DelegateEntry();
int id = delegates_.Add(entry);
return id;
}
void CmaMessageFilterProxy::DestroyChannel(int id) {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
DelegateEntry* entry = delegates_.Lookup(id);
if (!entry)
return;
@@ -71,7 +70,7 @@ void CmaMessageFilterProxy::DestroyChannel(int id) {
bool CmaMessageFilterProxy::SetMediaDelegate(
int id, const MediaDelegate& media_delegate) {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
DelegateEntry* entry = delegates_.Lookup(id);
if (!entry)
return false;
@@ -81,7 +80,7 @@ bool CmaMessageFilterProxy::SetMediaDelegate(
bool CmaMessageFilterProxy::SetAudioDelegate(
int id, const AudioDelegate& audio_delegate) {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
DelegateEntry* entry = delegates_.Lookup(id);
if (!entry)
return false;
@@ -91,7 +90,7 @@ bool CmaMessageFilterProxy::SetAudioDelegate(
bool CmaMessageFilterProxy::SetVideoDelegate(
int id, const VideoDelegate& video_delegate) {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
DelegateEntry* entry = delegates_.Lookup(id);
if (!entry)
return false;
@@ -100,7 +99,7 @@ bool CmaMessageFilterProxy::SetVideoDelegate(
}
bool CmaMessageFilterProxy::Send(scoped_ptr<IPC::Message> message) {
- DCHECK(io_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
if (!sender_)
return false;
bool status = sender_->Send(message.release());
@@ -269,4 +268,4 @@ void CmaMessageFilterProxy::OnNaturalSizeChanged(
}
} // namespace media
-} // namespace chromecast \ No newline at end of file
+} // namespace chromecast
diff --git a/chromium/chromecast/renderer/media/cma_message_filter_proxy.h b/chromium/chromecast/renderer/media/cma_message_filter_proxy.h
index 0930f19938e..ab007118e17 100644
--- a/chromium/chromecast/renderer/media/cma_message_filter_proxy.h
+++ b/chromium/chromecast/renderer/media/cma_message_filter_proxy.h
@@ -19,7 +19,7 @@
#include "media/base/pipeline_status.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace chromecast {
@@ -59,7 +59,7 @@ class CmaMessageFilterProxy : public IPC::MessageFilter {
};
explicit CmaMessageFilterProxy(
- const scoped_refptr<base::MessageLoopProxy>& io_message_loop);
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
// Getter for the one CmaMessageFilterHost object.
static CmaMessageFilterProxy* Get();
@@ -124,7 +124,7 @@ class CmaMessageFilterProxy : public IPC::MessageFilter {
IPC::Sender* sender_;
- scoped_refptr<base::MessageLoopProxy> const io_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> const io_task_runner_;
DISALLOW_COPY_AND_ASSIGN(CmaMessageFilterProxy);
};
diff --git a/chromium/chromecast/renderer/media/cma_renderer_unittest.cc b/chromium/chromecast/renderer/media/cma_renderer_unittest.cc
deleted file mode 100644
index 19ff6ecec62..00000000000
--- a/chromium/chromecast/renderer/media/cma_renderer_unittest.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2015 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 "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/shared_memory.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-#include "chromecast/common/media/cma_messages.h"
-#include "chromecast/common/media/shared_memory_chunk.h"
-#include "chromecast/media/cma/base/buffering_defs.h"
-#include "chromecast/media/cma/filters/cma_renderer.h"
-#include "chromecast/media/cma/ipc/media_memory_chunk.h"
-#include "chromecast/media/cma/ipc/media_message_fifo.h"
-#include "chromecast/media/cma/pipeline/media_pipeline.h"
-#include "chromecast/renderer/media/cma_message_filter_proxy.h"
-#include "chromecast/renderer/media/media_pipeline_proxy.h"
-#include "ipc/ipc_test_sink.h"
-#include "media/base/demuxer_stream_provider.h"
-#include "media/base/fake_demuxer_stream.h"
-#include "media/base/null_video_sink.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromecast {
-namespace media {
-
-namespace {
-
-class CmaRendererTest : public testing::Test {
- public:
- CmaRendererTest() {
- demuxer_stream_provider_.reset(
- new ::media::FakeDemuxerStreamProvider(1, 1, false));
- null_sink_.reset(new ::media::NullVideoSink(
- false,
- base::TimeDelta::FromSecondsD(1.0 / 60),
- base::Bind(&MockCB::OnFrameReceived, base::Unretained(&mock_)),
- message_loop_.task_runner()));
-
- cma_proxy_ = new CmaMessageFilterProxy(message_loop_.message_loop_proxy());
- cma_proxy_->OnFilterAdded(&ipc_sink_);
-
- renderer_.reset(new CmaRenderer(
- scoped_ptr<MediaPipelineProxy>(
- new MediaPipelineProxy(0, message_loop_.message_loop_proxy(),
- LoadType::kLoadTypeMediaSource)),
- null_sink_.get()));
- }
-
- ~CmaRendererTest() override {
- cma_proxy_->OnFilterRemoved();
- }
-
- protected:
- base::MessageLoop message_loop_;
- scoped_ptr<::media::FakeDemuxerStreamProvider> demuxer_stream_provider_;
- IPC::TestSink ipc_sink_;
- scoped_refptr<CmaMessageFilterProxy> cma_proxy_;
- scoped_ptr<CmaRenderer> renderer_;
-
- class MockCB {
- public:
- MOCK_METHOD1(OnInitialized, void(::media::PipelineStatus));
- MOCK_METHOD1(OnFrameReceived,
- void(const scoped_refptr<::media::VideoFrame>&));
- MOCK_METHOD1(OnStatistics, void(const ::media::PipelineStatistics&));
- MOCK_METHOD1(OnBufferingState, void(::media::BufferingState));
- MOCK_METHOD0(OnEnded, void());
- MOCK_METHOD1(OnError, void(::media::PipelineStatus));
- MOCK_METHOD0(OnWaitingForDecryptionKey, void());
- };
- MockCB mock_;
-
- private:
- scoped_ptr<::media::NullVideoSink> null_sink_;
-
- DISALLOW_COPY_AND_ASSIGN(CmaRendererTest);
-};
-
-} // namespace
-
-TEST_F(CmaRendererTest, TestInitialization) {
- renderer_->Initialize(
- demuxer_stream_provider_.get(),
- base::Bind(&MockCB::OnInitialized, base::Unretained(&mock_)),
- base::Bind(&MockCB::OnStatistics, base::Unretained(&mock_)),
- base::Bind(&MockCB::OnBufferingState, base::Unretained(&mock_)),
- base::Bind(&MockCB::OnEnded, base::Unretained(&mock_)),
- base::Bind(&MockCB::OnError, base::Unretained(&mock_)),
- base::Bind(&MockCB::OnWaitingForDecryptionKey, base::Unretained(&mock_)));
- message_loop_.RunUntilIdle();
-
- EXPECT_TRUE(ipc_sink_.GetUniqueMessageMatching(CmaHostMsg_CreateAvPipe::ID));
- base::SharedMemory* shared_memory = new base::SharedMemory();
- EXPECT_TRUE(shared_memory->CreateAndMapAnonymous(kAppVideoBufferSize));
-
- // Renderer MediaMessageFifo instance expects the first bytes of the shared
- // memory blob to describe how much space is available for writing.
- *(static_cast<size_t*>(shared_memory->memory())) =
- shared_memory->requested_size() - MediaMessageFifo::kDescriptorSize;
-
- base::FileDescriptor foreign_socket_handle;
- cma_proxy_->OnMessageReceived(CmaMsg_AvPipeCreated(
- 1, kVideoTrackId, true,
- shared_memory->handle(), foreign_socket_handle));
- message_loop_.RunUntilIdle();
-
- EXPECT_FALSE(
- ipc_sink_.GetUniqueMessageMatching(CmaHostMsg_AudioInitialize::ID));
- EXPECT_TRUE(
- ipc_sink_.GetUniqueMessageMatching(CmaHostMsg_VideoInitialize::ID));
-
- EXPECT_CALL(mock_, OnInitialized(::media::PIPELINE_OK));
- cma_proxy_->OnMessageReceived(
- CmaMsg_TrackStateChanged(1, kVideoTrackId, ::media::PIPELINE_OK));
- message_loop_.RunUntilIdle();
-}
-
-
-} // namespace media
-} // namespace chromecast
diff --git a/chromium/chromecast/renderer/media/media_pipeline_proxy.cc b/chromium/chromecast/renderer/media/media_pipeline_proxy.cc
index 830ac0fe134..38a69980c6b 100644
--- a/chromium/chromecast/renderer/media/media_pipeline_proxy.cc
+++ b/chromium/chromecast/renderer/media/media_pipeline_proxy.cc
@@ -8,7 +8,7 @@
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "chromecast/common/media/cma_messages.h"
#include "chromecast/media/cma/base/coded_frame_provider.h"
#include "chromecast/renderer/media/audio_pipeline_proxy.h"
@@ -149,44 +149,40 @@ void MediaPipelineProxyInternal::OnStateChanged(
base::ResetAndReturn(&status_cb_).Run(status);
}
-
-// A macro runs current member function on |io_message_loop_proxy_| thread.
-#define FORWARD_ON_IO_THREAD(param_fn, ...) \
- io_message_loop_proxy_->PostTask( \
- FROM_HERE, \
- base::Bind(&MediaPipelineProxyInternal::param_fn, \
- base::Unretained(proxy_.get()), ##__VA_ARGS__))
+// A macro runs current member function on |io_task_runner_| thread.
+#define FORWARD_ON_IO_THREAD(param_fn, ...) \
+ io_task_runner_->PostTask( \
+ FROM_HERE, base::Bind(&MediaPipelineProxyInternal::param_fn, \
+ base::Unretained(proxy_.get()), ##__VA_ARGS__))
MediaPipelineProxy::MediaPipelineProxy(
int render_frame_id,
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
LoadType load_type)
- : io_message_loop_proxy_(io_message_loop_proxy),
+ : io_task_runner_(io_task_runner),
render_frame_id_(render_frame_id),
media_channel_proxy_(new MediaChannelProxy),
proxy_(new MediaPipelineProxyInternal(media_channel_proxy_)),
has_audio_(false),
has_video_(false),
- audio_pipeline_(new AudioPipelineProxy(
- io_message_loop_proxy, media_channel_proxy_)),
- video_pipeline_(new VideoPipelineProxy(
- io_message_loop_proxy, media_channel_proxy_)),
+ audio_pipeline_(
+ new AudioPipelineProxy(io_task_runner, media_channel_proxy_)),
+ video_pipeline_(
+ new VideoPipelineProxy(io_task_runner, media_channel_proxy_)),
weak_factory_(this) {
weak_this_ = weak_factory_.GetWeakPtr();
- io_message_loop_proxy_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&MediaChannelProxy::Open, media_channel_proxy_,
- load_type));
+ base::Bind(&MediaChannelProxy::Open, media_channel_proxy_, load_type));
thread_checker_.DetachFromThread();
}
MediaPipelineProxy::~MediaPipelineProxy() {
- io_message_loop_proxy_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&MediaPipelineProxyInternal::Release, base::Passed(&proxy_)));
- io_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&MediaChannelProxy::Close, media_channel_proxy_));
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&MediaChannelProxy::Close, media_channel_proxy_));
}
void MediaPipelineProxy::SetClient(
@@ -218,12 +214,12 @@ void MediaPipelineProxy::InitializeAudio(
}
void MediaPipelineProxy::InitializeVideo(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
has_video_ = true;
- video_pipeline_->Initialize(config, frame_provider.Pass(), status_cb);
+ video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb);
}
void MediaPipelineProxy::StartPlayingFrom(base::TimeDelta time) {
@@ -250,7 +246,7 @@ void MediaPipelineProxy::Flush(const ::media::PipelineStatusCB& status_cb) {
}
::media::PipelineStatusCB cb =
base::Bind(&MediaPipelineProxy::OnProxyFlushDone, weak_this_, status_cb);
- pending_callbacks_ = ::media::SerialRunner::Run(bound_fns, cb);
+ pending_flush_callbacks_ = ::media::SerialRunner::Run(bound_fns, cb);
}
void MediaPipelineProxy::OnProxyFlushDone(
@@ -258,7 +254,7 @@ void MediaPipelineProxy::OnProxyFlushDone(
::media::PipelineStatus status) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(status, ::media::PIPELINE_OK);
- pending_callbacks_.reset();
+ pending_flush_callbacks_.reset();
FORWARD_ON_IO_THREAD(Flush, status_cb);
}
@@ -266,6 +262,11 @@ void MediaPipelineProxy::Stop() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_audio_ || has_video_);
+ // Cancel pending flush callbacks since we are about to stop/shutdown
+ // audio/video pipelines. This will ensure A/V Flush won't happen in
+ // stopped state.
+ pending_flush_callbacks_.reset();
+
if (has_audio_)
audio_pipeline_->Stop();
if (has_video_)
@@ -280,4 +281,4 @@ void MediaPipelineProxy::SetPlaybackRate(double playback_rate) {
}
} // namespace cma
-} // namespace chromecast \ No newline at end of file
+} // namespace chromecast
diff --git a/chromium/chromecast/renderer/media/media_pipeline_proxy.h b/chromium/chromecast/renderer/media/media_pipeline_proxy.h
index decec653b86..1e8e9e6b7ab 100644
--- a/chromium/chromecast/renderer/media/media_pipeline_proxy.h
+++ b/chromium/chromecast/renderer/media/media_pipeline_proxy.h
@@ -16,7 +16,7 @@
#include "media/base/serial_runner.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
}
namespace chromecast {
@@ -28,10 +28,9 @@ class VideoPipelineProxy;
class MediaPipelineProxy : public MediaPipeline {
public:
- MediaPipelineProxy(
- int render_frame_id,
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
- LoadType load_type);
+ MediaPipelineProxy(int render_frame_id,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ LoadType load_type);
~MediaPipelineProxy() override;
// MediaPipeline implementation.
@@ -44,7 +43,7 @@ class MediaPipelineProxy : public MediaPipeline {
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) override;
void InitializeVideo(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) override;
void StartPlayingFrom(base::TimeDelta time) override;
@@ -58,7 +57,7 @@ class MediaPipelineProxy : public MediaPipeline {
base::ThreadChecker thread_checker_;
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
const int render_frame_id_;
@@ -71,7 +70,7 @@ class MediaPipelineProxy : public MediaPipeline {
bool has_video_;
scoped_ptr<AudioPipelineProxy> audio_pipeline_;
scoped_ptr<VideoPipelineProxy> video_pipeline_;
- scoped_ptr< ::media::SerialRunner> pending_callbacks_;
+ scoped_ptr< ::media::SerialRunner> pending_flush_callbacks_;
base::WeakPtr<MediaPipelineProxy> weak_this_;
base::WeakPtrFactory<MediaPipelineProxy> weak_factory_;
@@ -82,4 +81,4 @@ class MediaPipelineProxy : public MediaPipeline {
} // namespace media
} // namespace chromecast
-#endif // CHROMECAST_RENDERER_MEDIA_MEDIA_PIPELINE_PROXY_H_ \ No newline at end of file
+#endif // CHROMECAST_RENDERER_MEDIA_MEDIA_PIPELINE_PROXY_H_
diff --git a/chromium/chromecast/renderer/media/video_pipeline_proxy.cc b/chromium/chromecast/renderer/media/video_pipeline_proxy.cc
index 6c924cd4e2e..bcef0838d26 100644
--- a/chromium/chromecast/renderer/media/video_pipeline_proxy.cc
+++ b/chromium/chromecast/renderer/media/video_pipeline_proxy.cc
@@ -56,7 +56,7 @@ class VideoPipelineProxyInternal {
void SetClient(const base::Closure& pipe_read_cb,
const VideoPipelineClient& client);
void CreateAvPipe(const SharedMemCB& shared_mem_cb);
- void Initialize(const ::media::VideoDecoderConfig& config,
+ void Initialize(const std::vector<::media::VideoDecoderConfig>& configs,
const ::media::PipelineStatusCB& status_cb);
private:
@@ -166,12 +166,12 @@ void VideoPipelineProxyInternal::OnAvPipeCreated(
}
void VideoPipelineProxyInternal::Initialize(
- const ::media::VideoDecoderConfig& arg1,
+ const std::vector<::media::VideoDecoderConfig>& configs,
const ::media::PipelineStatusCB& status_cb) {
DCHECK(thread_checker_.CalledOnValidThread());
bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>(
new CmaHostMsg_VideoInitialize(media_channel_proxy_->GetId(),
- kVideoTrackId, arg1)));
+ kVideoTrackId, configs)));
if (!success) {
status_cb.Run( ::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
return;
@@ -187,22 +187,20 @@ void VideoPipelineProxyInternal::OnStateChanged(
base::ResetAndReturn(&status_cb_).Run(status);
}
-
-// A macro runs current member function on |io_message_loop_proxy_| thread.
-#define FORWARD_ON_IO_THREAD(param_fn, ...) \
- io_message_loop_proxy_->PostTask( \
- FROM_HERE, \
- base::Bind(&VideoPipelineProxyInternal::param_fn, \
- base::Unretained(proxy_.get()), ##__VA_ARGS__))
+// A macro runs current member function on |io_task_runner_| thread.
+#define FORWARD_ON_IO_THREAD(param_fn, ...) \
+ io_task_runner_->PostTask( \
+ FROM_HERE, base::Bind(&VideoPipelineProxyInternal::param_fn, \
+ base::Unretained(proxy_.get()), ##__VA_ARGS__))
VideoPipelineProxy::VideoPipelineProxy(
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<MediaChannelProxy> media_channel_proxy)
- : io_message_loop_proxy_(io_message_loop_proxy),
+ : io_task_runner_(io_task_runner),
proxy_(new VideoPipelineProxyInternal(media_channel_proxy)),
video_streamer_(new AvStreamerProxy()),
weak_factory_(this) {
- DCHECK(io_message_loop_proxy_.get());
+ DCHECK(io_task_runner_.get());
weak_this_ = weak_factory_.GetWeakPtr();
thread_checker_.DetachFromThread();
}
@@ -210,7 +208,7 @@ VideoPipelineProxy::VideoPipelineProxy(
VideoPipelineProxy::~VideoPipelineProxy() {
DCHECK(thread_checker_.CalledOnValidThread());
// Release the underlying object on the right thread.
- io_message_loop_proxy_->PostTask(
+ io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&VideoPipelineProxyInternal::Release, base::Passed(&proxy_)));
}
@@ -225,7 +223,7 @@ void VideoPipelineProxy::SetClient(
}
void VideoPipelineProxy::Initialize(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb) {
CMALOG(kLogControl) << "VideoPipelineProxy::Initialize";
@@ -235,12 +233,12 @@ void VideoPipelineProxy::Initialize(
VideoPipelineProxyInternal::SharedMemCB shared_mem_cb =
::media::BindToCurrentLoop(base::Bind(
&VideoPipelineProxy::OnAvPipeCreated, weak_this_,
- config, status_cb));
+ configs, status_cb));
FORWARD_ON_IO_THREAD(CreateAvPipe, shared_mem_cb);
}
void VideoPipelineProxy::OnAvPipeCreated(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
const ::media::PipelineStatusCB& status_cb,
scoped_ptr<base::SharedMemory> shared_memory) {
CMALOG(kLogControl) << "VideoPipelineProxy::OnAvPipeCreated";
@@ -262,7 +260,7 @@ void VideoPipelineProxy::OnAvPipeCreated(
video_streamer_->SetMediaMessageFifo(video_pipe.Pass());
// Now proceed to the decoder/renderer initialization.
- FORWARD_ON_IO_THREAD(Initialize, config, status_cb);
+ FORWARD_ON_IO_THREAD(Initialize, configs, status_cb);
}
void VideoPipelineProxy::StartFeeding() {
diff --git a/chromium/chromecast/renderer/media/video_pipeline_proxy.h b/chromium/chromecast/renderer/media/video_pipeline_proxy.h
index 88745525091..1dbf13ec0b8 100644
--- a/chromium/chromecast/renderer/media/video_pipeline_proxy.h
+++ b/chromium/chromecast/renderer/media/video_pipeline_proxy.h
@@ -14,7 +14,7 @@
#include "media/base/pipeline_status.h"
namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
class SharedMemory;
}
@@ -32,12 +32,11 @@ class MediaChannelProxy;
class VideoPipelineProxy : public VideoPipeline {
public:
- VideoPipelineProxy(
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy,
- scoped_refptr<MediaChannelProxy> media_channel_proxy);
+ VideoPipelineProxy(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ scoped_refptr<MediaChannelProxy> media_channel_proxy);
~VideoPipelineProxy() override;
- void Initialize(const ::media::VideoDecoderConfig& config,
+ void Initialize(const std::vector<::media::VideoDecoderConfig>& configs,
scoped_ptr<CodedFrameProvider> frame_provider,
const ::media::PipelineStatusCB& status_cb);
void StartFeeding();
@@ -51,13 +50,13 @@ class VideoPipelineProxy : public VideoPipeline {
base::ThreadChecker thread_checker_;
void OnAvPipeCreated(
- const ::media::VideoDecoderConfig& config,
+ const std::vector<::media::VideoDecoderConfig>& configs,
const ::media::PipelineStatusCB& status_cb,
scoped_ptr<base::SharedMemory> shared_memory);
void OnPipeWrite();
void OnPipeRead();
- scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// |proxy_| main goal is to convert function calls to IPC messages.
scoped_ptr<VideoPipelineProxyInternal> proxy_;