Import Cobalt 11.153049
diff --git a/src/base/message_pump_io_starboard.cc b/src/base/message_pump_io_starboard.cc
index 2ef146d..45e8215 100644
--- a/src/base/message_pump_io_starboard.cc
+++ b/src/base/message_pump_io_starboard.cc
@@ -28,7 +28,8 @@
 namespace base {
 
 MessagePumpIOStarboard::SocketWatcher::SocketWatcher()
-    : socket_(kSbSocketInvalid),
+    : interests_(kSbSocketWaiterInterestNone),
+      socket_(kSbSocketInvalid),
       pump_(NULL),
       watcher_(NULL),
       ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}
@@ -48,6 +49,7 @@
   }
   pump_ = NULL;
   watcher_ = NULL;
+  interests_ = kSbSocketWaiterInterestNone;
   return result;
 }
 
@@ -147,6 +149,7 @@
   controller->Init(socket, persistent);
   controller->set_watcher(delegate);
   controller->set_pump(this);
+  controller->set_interests(interests);
 
   return true;
 }
diff --git a/src/base/message_pump_io_starboard.h b/src/base/message_pump_io_starboard.h
index c840181..028115f 100644
--- a/src/base/message_pump_io_starboard.h
+++ b/src/base/message_pump_io_starboard.h
@@ -83,6 +83,7 @@
     SbSocket Release();
 
     int interests() const { return interests_; }
+    void set_interests(int interests) { interests_ = interests; }
 
     void set_pump(MessagePumpIOStarboard* pump) { pump_ = pump; }
     MessagePumpIOStarboard* pump() const { return pump_; }
diff --git a/src/cobalt/audio/audio_buffer_source_node.cc b/src/cobalt/audio/audio_buffer_source_node.cc
index 55aff8c..03b7199 100644
--- a/src/cobalt/audio/audio_buffer_source_node.cc
+++ b/src/cobalt/audio/audio_buffer_source_node.cc
@@ -111,35 +111,38 @@
   size_t channels = static_cast<size_t>(buffer_->number_of_channels());
 
   if (sample_type == kSampleTypeFloat32) {
-    std::vector<float*> audio_buffer(channels, NULL);
+    std::vector<scoped_refptr<dom::Float32Array>> audio_buffer_storages(
+        channels);
+    std::vector<float*> audio_buffers(channels, NULL);
     for (size_t i = 0; i < channels; ++i) {
       scoped_refptr<dom::Float32Array> buffer_data =
           buffer_->GetChannelData(static_cast<uint32>(i), NULL);
-      scoped_refptr<dom::Float32Array> sub_array = buffer_data->Subarray(
+      audio_buffer_storages[i] = buffer_data->Subarray(
           NULL, read_index_, read_index_ + number_of_frames);
-      audio_buffer[i] = sub_array->data();
+      audio_buffers[i] = audio_buffer_storages[i]->data();
     }
 
     read_index_ += number_of_frames;
 
-    scoped_ptr<ShellAudioBus> audio_bus(
-        new ShellAudioBus(static_cast<size_t>(number_of_frames), audio_buffer));
+    scoped_ptr<ShellAudioBus> audio_bus(new ShellAudioBus(
+        static_cast<size_t>(number_of_frames), audio_buffers));
 
     return audio_bus.Pass();
   } else if (sample_type == kSampleTypeInt16) {
-    std::vector<int16*> audio_buffer(channels, NULL);
+    std::vector<scoped_refptr<dom::Int16Array>> audio_buffer_storages(channels);
+    std::vector<int16*> audio_buffers(channels, NULL);
     for (size_t i = 0; i < channels; ++i) {
       scoped_refptr<dom::Int16Array> buffer_data =
           buffer_->GetChannelDataInt16(static_cast<uint32>(i), NULL);
-      scoped_refptr<dom::Int16Array> sub_array = buffer_data->Subarray(
+      audio_buffer_storages[i] = buffer_data->Subarray(
           NULL, read_index_, read_index_ + number_of_frames);
-      audio_buffer[i] = sub_array->data();
+      audio_buffers[i] = audio_buffer_storages[i]->data();
     }
 
     read_index_ += number_of_frames;
 
-    scoped_ptr<ShellAudioBus> audio_bus(
-        new ShellAudioBus(static_cast<size_t>(number_of_frames), audio_buffer));
+    scoped_ptr<ShellAudioBus> audio_bus(new ShellAudioBus(
+        static_cast<size_t>(number_of_frames), audio_buffers));
 
     return audio_bus.Pass();
   }
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc
index 5d740ab..535c784 100644
--- a/src/cobalt/audio/audio_device.cc
+++ b/src/cobalt/audio/audio_device.cc
@@ -170,14 +170,14 @@
   *frames_in_buffer = static_cast<int>(frames_rendered_ - frames_consumed_);
 
   if ((kFramesPerChannel - *frames_in_buffer) >= kRenderBufferSizeFrames) {
-    bool silence = false;
-
     // If there was silence last time we were called, then the buffer has
     // already been zeroed out and we don't need to do it again.
     if (!was_silence_last_update_) {
       input_audio_bus_.ZeroAllFrames();
     }
 
+    bool silence = true;
+
     // Fill our temporary buffer with planar PCM float samples.
     render_callback_->FillAudioBus(&input_audio_bus_, &silence);
 
@@ -345,7 +345,7 @@
 
   if ((kFramesPerChannel - *total_frames) >= kRenderBufferSizeFrames) {
     // Fill our temporary buffer with PCM float samples.
-    bool silence = false;
+    bool silence = true;
     render_callback_->FillAudioBus(&audio_bus_, &silence);
 
     if (!silence) {
diff --git a/src/cobalt/audio/audio_device.h b/src/cobalt/audio/audio_device.h
index fec6cea..dd5f898 100644
--- a/src/cobalt/audio/audio_device.h
+++ b/src/cobalt/audio/audio_device.h
@@ -38,6 +38,10 @@
     typedef ::media::ShellAudioBus ShellAudioBus;
 #endif  // defined(COBALT_MEDIA_SOURCE_2016)
 
+    // |silence| will be set to true before calling if |audio_buffer| contains
+    // only silence samples, it will be set to |false| otherwise.  On return
+    // FillAudioBus() will set |silence| to |false| if it has modified
+    // |audio_buffer|.
     virtual void FillAudioBus(ShellAudioBus* audio_buffer, bool* silence) = 0;
 
    protected:
diff --git a/src/cobalt/audio/audio_node_input.cc b/src/cobalt/audio/audio_node_input.cc
index 2e76dcf..529986d 100644
--- a/src/cobalt/audio/audio_node_input.cc
+++ b/src/cobalt/audio/audio_node_input.cc
@@ -231,8 +231,6 @@
   // This is called by Audio thread.
   owner_node_->audio_lock()->AssertLocked();
 
-  *silence = true;
-
   // TODO: Consider computing computedNumberOfChannels and do up-mix or
   // down-mix base on computedNumberOfChannels. The current implementation
   // is based on the fact that the channelCountMode is max.
@@ -251,8 +249,12 @@
         output_audio_bus->sample_type());
 
     if (audio_bus) {
-      MixAudioBuffer(owner_node_->channel_interpretation(), audio_bus.get(),
-                     output_audio_bus);
+      if (*silence && audio_bus->channels() == output_audio_bus->channels()) {
+        output_audio_bus->Assign(*audio_bus);
+      } else {
+        MixAudioBuffer(owner_node_->channel_interpretation(), audio_bus.get(),
+                       output_audio_bus);
+      }
       *silence = false;
     }
   }
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index ab3ce08..feed93d 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -139,7 +139,7 @@
     // is actually occupied by JS objects, and the part that is not yet.
     base::CVal<base::cval::SizeInBytes, base::CValPublic> js_reserved_memory;
 
-    base::CVal<int64> app_start_time;
+    base::CVal<int64, base::CValPublic> app_start_time;
     base::CVal<base::TimeDelta, base::CValPublic> app_lifetime;
   };
 
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index db86c6d..7d0debb 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -444,10 +444,10 @@
 
   // The time when a URL navigation starts. This is recorded after the previous
   // WebModule is destroyed.
-  base::CVal<int64> navigate_time_;
+  base::CVal<int64, base::CValPublic> navigate_time_;
 
   // The time when the WebModule's Window.onload event is fired.
-  base::CVal<int64> on_load_event_time_;
+  base::CVal<int64, base::CValPublic> on_load_event_time_;
 
 #if defined(ENABLE_DEBUG_CONSOLE)
   // Possibly null, but if not, will contain a reference to an instance of
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 87cfbf3..9d6ff51 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -263,6 +263,9 @@
   // Initializes the ResourceProvider and dependent resources.
   void SetResourceProvider(render_tree::ResourceProvider* resource_provider);
 
+  void OnStartDispatchEvent(const scoped_refptr<dom::Event>& event);
+  void OnStopDispatchEvent(const scoped_refptr<dom::Event>& event);
+
   // Thread checker ensures all calls to the WebModule are made from the same
   // thread that it is created in.
   base::ThreadChecker thread_checker_;
@@ -556,6 +559,9 @@
                  base::Unretained(this)),
       data.window_close_callback, data.window_minimize_callback,
       data.options.camera_3d, media_session_client_->GetMediaSession(),
+      base::Bind(&WebModule::Impl::OnStartDispatchEvent,
+                 base::Unretained(this)),
+      base::Bind(&WebModule::Impl::OnStopDispatchEvent, base::Unretained(this)),
       data.options.csp_insecure_allowed_token, data.dom_max_element_depth,
       data.options.video_playback_rate_multiplier,
 #if defined(ENABLE_TEST_RUNNER)
@@ -679,17 +685,11 @@
   DCHECK(is_running_);
   DCHECK(window_);
 
-  web_module_stat_tracker_->OnStartInjectEvent(event);
-
   if (element) {
     element->DispatchEvent(event);
   } else {
     window_->InjectEvent(event);
   }
-
-  web_module_stat_tracker_->OnEndInjectEvent(
-      window_->HasPendingAnimationFrameCallbacks(),
-      layout_manager_->IsRenderTreePending());
 }
 
 void WebModule::Impl::InjectKeyboardEvent(scoped_refptr<dom::Element> element,
@@ -905,6 +905,18 @@
   }
 }
 
+void WebModule::Impl::OnStartDispatchEvent(
+    const scoped_refptr<dom::Event>& event) {
+  web_module_stat_tracker_->OnStartDispatchEvent(event);
+}
+
+void WebModule::Impl::OnStopDispatchEvent(
+    const scoped_refptr<dom::Event>& event) {
+  web_module_stat_tracker_->OnStopDispatchEvent(
+      event, window_->HasPendingAnimationFrameCallbacks(),
+      layout_manager_->IsRenderTreePending());
+}
+
 void WebModule::Impl::Start(render_tree::ResourceProvider* resource_provider) {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Start()");
   SetResourceProvider(resource_provider);
diff --git a/src/cobalt/browser/web_module_stat_tracker.cc b/src/cobalt/browser/web_module_stat_tracker.cc
index 187c076..59a4c2a 100644
--- a/src/cobalt/browser/web_module_stat_tracker.cc
+++ b/src/cobalt/browser/web_module_stat_tracker.cc
@@ -34,6 +34,7 @@
       layout_stat_tracker_(new layout::LayoutStatTracker(name)),
       should_track_event_stats_(should_track_event_stats),
       current_event_type_(kEventTypeInvalid),
+      current_event_dispatched_event_(NULL),
       name_(name),
       event_is_processing_(StringPrintf("Event.%s.IsProcessing", name.c_str()),
                            false, "Nonzero when an event is being processed.") {
@@ -56,7 +57,7 @@
 
 WebModuleStatTracker::~WebModuleStatTracker() { EndCurrentEvent(false); }
 
-void WebModuleStatTracker::OnStartInjectEvent(
+void WebModuleStatTracker::OnStartDispatchEvent(
     const scoped_refptr<dom::Event>& event) {
   if (!should_track_event_stats_) {
     return;
@@ -85,28 +86,30 @@
   if (current_event_type_ != kEventTypeInvalid) {
     event_is_processing_ = true;
     event_start_time_ = base::TimeTicks::Now();
+    current_event_dispatched_event_ = event;
 
     dom_stat_tracker_->OnStartEvent();
     layout_stat_tracker_->OnStartEvent();
 
     stop_watch_durations_[kStopWatchTypeEvent] = base::TimeDelta();
-    stop_watch_durations_[kStopWatchTypeInjectEvent] = base::TimeDelta();
+    stop_watch_durations_[kStopWatchTypeDispatchEvent] = base::TimeDelta();
 
     stop_watches_[kStopWatchTypeEvent].Start();
-    stop_watches_[kStopWatchTypeInjectEvent].Start();
+    stop_watches_[kStopWatchTypeDispatchEvent].Start();
   }
 }
 
-void WebModuleStatTracker::OnEndInjectEvent(
+void WebModuleStatTracker::OnStopDispatchEvent(
+    const scoped_refptr<dom::Event>& event,
     bool are_animation_frame_callbacks_pending,
     bool is_new_render_tree_pending) {
-  // If the injection isn't currently being timed, then this event injection
-  // isn't being tracked. Simply return.
-  if (!stop_watches_[kStopWatchTypeInjectEvent].IsCounting()) {
+  // Verify that this dispatched event is the one currently being tracked.
+  if (event != current_event_dispatched_event_) {
     return;
   }
 
-  stop_watches_[kStopWatchTypeInjectEvent].Stop();
+  current_event_dispatched_event_ = NULL;
+  stop_watches_[kStopWatchTypeDispatchEvent].Stop();
 
   if (!are_animation_frame_callbacks_pending && !is_new_render_tree_pending) {
     EndCurrentEvent(false);
@@ -123,7 +126,9 @@
 void WebModuleStatTracker::OnRenderTreeProduced() { EndCurrentEvent(true); }
 
 WebModuleStatTracker::EventStats::EventStats(const std::string& name)
-    : produced_render_tree_(
+    : start_time(StringPrintf("Event.Time.%s.Start", name.c_str()), 0,
+          "The time that the event started."),
+      produced_render_tree(
           StringPrintf("Event.%s.ProducedRenderTree", name.c_str()), false,
           "Nonzero when the event produced a render tree."),
       count_dom_html_elements_created(
@@ -179,12 +184,12 @@
       duration_total(StringPrintf("Event.Duration.%s", name.c_str()),
                      base::TimeDelta(),
                      "Total duration of the event (in microseconds). This is "
-                     "the time elapsed from the event injection until the "
+                     "the time elapsed from the event dispatch until the "
                      "render tree is produced."),
-      duration_dom_inject_event(
-          StringPrintf("Event.Duration.%s.DOM.InjectEvent", name.c_str()),
+      duration_dom_dispatch_event(
+          StringPrintf("Event.Duration.%s.DOM.DispatchEvent", name.c_str()),
           base::TimeDelta(),
-          "Injection duration, which includes JS, for event (in "
+          "Dispatch duration, which includes JS, for event (in "
           "microseconds). This does not include subsequent DOM and Layout "
           "processing."),
       duration_dom_run_animation_frame_callbacks(
@@ -246,7 +251,8 @@
   stop_watches_[kStopWatchTypeEvent].Stop();
 
   EventStats* event_stats = event_stats_[current_event_type_];
-  event_stats->produced_render_tree_ = was_render_tree_produced;
+  event_stats->start_time = event_start_time_.ToInternalValue();
+  event_stats->produced_render_tree = was_render_tree_produced;
 
   // Update event counts
   event_stats->count_dom_html_elements_created =
@@ -278,8 +284,8 @@
 
   // Update event durations
   event_stats->duration_total = stop_watch_durations_[kStopWatchTypeEvent];
-  event_stats->duration_dom_inject_event =
-      stop_watch_durations_[kStopWatchTypeInjectEvent];
+  event_stats->duration_dom_dispatch_event =
+      stop_watch_durations_[kStopWatchTypeDispatchEvent];
   event_stats->duration_dom_run_animation_frame_callbacks =
       dom_stat_tracker_->GetStopWatchTypeDuration(
           dom::DomStatTracker::kStopWatchTypeRunAnimationFrameCallbacks);
@@ -349,7 +355,7 @@
       << "\"DurTotalUs\":"
       << stop_watch_durations_[kStopWatchTypeEvent].InMicroseconds() << ", "
       << "\"DurDomInjectEventUs\":"
-      << stop_watch_durations_[kStopWatchTypeInjectEvent].InMicroseconds()
+      << stop_watch_durations_[kStopWatchTypeDispatchEvent].InMicroseconds()
       << ", "
       << "\"DurDomRunAnimationFrameCallbacksUs\":"
       << dom_stat_tracker_
diff --git a/src/cobalt/browser/web_module_stat_tracker.h b/src/cobalt/browser/web_module_stat_tracker.h
index 79045e3..594f1c6 100644
--- a/src/cobalt/browser/web_module_stat_tracker.h
+++ b/src/cobalt/browser/web_module_stat_tracker.h
@@ -34,7 +34,7 @@
 class WebModuleStatTracker : public base::StopWatchOwner {
  public:
   WebModuleStatTracker(const std::string& name,
-                       bool should_track_injected_events);
+                       bool should_track_dispatched_events);
   ~WebModuleStatTracker();
 
   dom::DomStatTracker* dom_stat_tracker() const {
@@ -45,15 +45,16 @@
     return layout_stat_tracker_.get();
   }
 
-  // |OnStartInjectEvent| starts event stat tracking if
-  // |should_track_injected_events_| is true. Otherwise, it does nothing.
-  void OnStartInjectEvent(const scoped_refptr<dom::Event>& event);
+  // |OnStartDispatchEvent| starts event stat tracking if
+  // |should_track_dispatched_events_| is true. Otherwise, it does nothing.
+  void OnStartDispatchEvent(const scoped_refptr<dom::Event>& event);
 
-  // |OnEndInjectEvent| notifies the event stat tracking that the event has
-  // finished being injected. If no animation frame callbacks and also no render
-  // tree is pending, it also ends tracking of the event.
-  void OnEndInjectEvent(bool are_animation_frame_callbacks_pending,
-                        bool is_new_render_tree_pending);
+  // |OnStopDispatchEvent| notifies the event stat tracking that |event| has
+  // finished being dispatched. If this is the event currently being tracked
+  // and nothing is pending, then it also ends tracking of the event.
+  void OnStopDispatchEvent(const scoped_refptr<dom::Event>& event,
+                           bool are_animation_frame_callbacks_pending,
+                           bool is_new_render_tree_pending);
 
   // |OnRanAnimationFrameCallbacks| ends stat tracking for the current event
   // if no render tree is pending.
@@ -74,14 +75,15 @@
 
   enum StopWatchType {
     kStopWatchTypeEvent,
-    kStopWatchTypeInjectEvent,
+    kStopWatchTypeDispatchEvent,
     kNumStopWatchTypes,
   };
 
   struct EventStats {
     explicit EventStats(const std::string& name);
 
-    base::CVal<bool, base::CValPublic> produced_render_tree_;
+    base::CVal<int64, base::CValPublic> start_time;
+    base::CVal<bool, base::CValPublic> produced_render_tree;
 
     // Count-related
     base::CVal<int, base::CValPublic> count_dom_html_elements_created;
@@ -102,7 +104,7 @@
 
     // Duration-related
     base::CVal<base::TimeDelta, base::CValPublic> duration_total;
-    base::CVal<base::TimeDelta, base::CValPublic> duration_dom_inject_event;
+    base::CVal<base::TimeDelta, base::CValPublic> duration_dom_dispatch_event;
     base::CVal<base::TimeDelta, base::CValPublic>
         duration_dom_run_animation_frame_callbacks;
     base::CVal<base::TimeDelta, base::CValPublic>
@@ -140,6 +142,10 @@
   // Event-related
   const bool should_track_event_stats_;
   EventType current_event_type_;
+  // Raw pointer to the current event. This is used to verify that the event in
+  // |OnStopDispatchEvent| is the dispatched event being tracked.
+  dom::Event* current_event_dispatched_event_;
+
   // Each individual |EventType| has its own entry in the vector.
   ScopedVector<EventStats> event_stats_;
 
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index ad8eeb1..d31d97a 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-132145
\ No newline at end of file
+153049
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index ec59efe..6af95d4 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -65,38 +65,22 @@
     # Contains the current font package selection.  This can be used to trade
     # font quality, coverage, and latency for different font package sizes.
     # The font package can be one of the following options:
-    #   'expanded' -- The largest package. It includes everything in the
-    #                 'standard' package, along with 'bold' weight CJK. It is
-    #                 recommended that 'local_font_cache_size_in_bytes' be
-    #                 increased to 24MB when using this package to account for
-    #                 the extra memory required by bold CJK. This package is
-    #                 ~48.7MB.
     #   'standard' -- The default package. It includes all sans-serif, serif,
     #                 and FCC fonts, non-CJK fallback fonts in both 'normal' and
-    #                 'bold' weights, and 'normal' weight CJK ('bold' weight CJK
-    #                 is synthesized from it). This package is ~29.4MB.
-    #   'limited_with_jp' -- A significantly smaller package than 'standard'.
-    #                 This package removes all but 'normal' and 'bold' weighted
+    #                 'bold' weights, and 'normal' weight CJK ('bold' weight
+    #                 CJK is synthesized from it). This package is ~29.4MB.
+    #   'limited'  -- A significantly smaller package than 'standard'. This
+    #                 package removes all but 'normal' and 'bold' weighted
     #                 sans-serif and serif, removes the FCC fonts (which must be
     #                 provided by the system or downloaded from the web),
-    #                 removes the 'bold' weighted non-CJK fallback fonts (the
-    #                 'normal' weight is still included and is used to
-    #                 synthesize bold), and replaces standard CJK with low
-    #                 quality CJK. However, higher quality Japanese is still
-    #                 included. Because low quality CJK cannot synthesize bold,
-    #                 bold glyphs are unavailable in Chinese and Korean. This
-    #                 package is ~10.9MB.
-    #   'limited'  -- A smaller package than 'limited_with_jp'. The two packages
-    #                 are identical with the exception that 'limited' does not
-    #                 include the higher quality Japanese font; instead it
-    #                 relies on low quality CJK for all CJK characters. Because
+    #                 and replaces standard CJK with low quality CJK. Because
     #                 low quality CJK cannot synthesize bold, bold glyphs are
-    #                 unavailable in Chinese, Japanese, and Korean. This package
+    #                 unavailable in Chinese, Japanese and Korean. This package
     #                 is ~7.7MB.
     #   'minimal'  -- The smallest possible font package. It only includes
     #                 Roboto's Basic Latin characters. Everything else must be
     #                 provided by the system or downloaded from the web. This
-    #                 package is ~16.4KB.
+    #                 package is ~35.4KB.
     # NOTE: When bold is needed, but unavailable, it is typically synthesized,
     #       resulting in lower quality glyphs than those generated directly from
     #       a bold font. However, this does not occur with low quality CJK,
@@ -129,7 +113,6 @@
     'cobalt_font_package_override_fallback_lang_non_cjk%': -1,
     'cobalt_font_package_override_fallback_lang_cjk%': -1,
     'cobalt_font_package_override_fallback_lang_cjk_low_quality%': -1,
-    'cobalt_font_package_override_fallback_lang_jp%': -1,
     'cobalt_font_package_override_fallback_emoji%': -1,
     'cobalt_font_package_override_fallback_symbols%': -1,
 
@@ -559,6 +542,17 @@
     # re-download video data.  Note that the JavaScript app may experience
     # significant difficulty if this value is too low.
     'cobalt_media_buffer_video_budget_4k%': 60 * 1024 * 1024,
+
+    # Specifies the duration threshold of media source garbage collection.  When
+    # the accumulated duration in a source buffer exceeds this value, the media
+    # source implementation will try to eject existing buffers from the cache.
+    # This is usually triggered when the video being played has a simple content
+    # and the encoded data is small.  In such case this can limit how much is
+    # allocated for the book keeping data of the media buffers and avoid OOM of
+    # system heap.
+    # This should be set to 170 for most of the platforms.  But it can be
+    # further reduced on systems with extremely low memory.
+    'cobalt_media_source_garbage_collection_duration_threshold_in_seconds%': 170,
   },
 
   'target_defaults': {
@@ -585,6 +579,7 @@
       'COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET=<(cobalt_media_buffer_non_video_budget)',
       'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P=<(cobalt_media_buffer_video_budget_1080p)',
       'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K=<(cobalt_media_buffer_video_budget_4k)',
+      'COBALT_MEDIA_SOURCE_GARBAGE_COLLECTION_DURATION_THRESHOLD_IN_SECONDS=<(cobalt_media_source_garbage_collection_duration_threshold_in_seconds)',
     ],
     'cflags': [ '<@(compiler_flags)' ],
     'ldflags': [ '<@(linker_flags)' ],
diff --git a/src/cobalt/build/copy_icu_data.gypi b/src/cobalt/build/copy_icu_data.gypi
index c2bfac3..9b9ba27 100644
--- a/src/cobalt/build/copy_icu_data.gypi
+++ b/src/cobalt/build/copy_icu_data.gypi
@@ -39,15 +39,21 @@
         'little_endian%': '<(little_endian)',
         'use_icu_dat_file%': '<(use_icu_dat_file)',
       },
+      'little_endian%': '<(little_endian)',
     },
 
-    #'inputs_icu%': [ '<(inputs_icu)' ],
-    'inputs_icu%': [ '<(static_contents_source_dir)/icu/' ],
+    'conditions': [
+      ['little_endian==1', {
+        'inputs_icu%': [ '<(static_contents_source_dir)/icu/icudt56l' ],
+      }, {
+        'inputs_icu%': [ '<(static_contents_source_dir)/icu/icudt56b' ],
+      }],
+    ],
   },
 
   'copies': [
     {
-      'destination': '<(static_contents_output_data_dir)/',
+      'destination': '<(static_contents_output_data_dir)/icu/',
       'files': [ '<(inputs_icu)' ],
     },
   ],
diff --git a/src/cobalt/content/fonts/README.md b/src/cobalt/content/fonts/README.md
index 1181646..0c2edfc 100644
--- a/src/cobalt/content/fonts/README.md
+++ b/src/cobalt/content/fonts/README.md
@@ -41,23 +41,6 @@
     }
 
 ### Package Profiles
-*  'expanded' -- The largest package. It includes everything in the 'standard'
-                 package, along with 'bold' weight CJK. It is recommended that
-                 'local_font_cache_size_in_bytes' be increased to 24MB when
-                 using this package to account for the extra memory required by
-                 bold CJK. This package is ~48.7MB.
-
-                 Package category values:
-                   'package_named_sans_serif': 4,
-                   'package_named_serif': 3,
-                   'package_named_fcc_fonts': 2,
-                   'package_fallback_lang_non_cjk': 2,
-                   'package_fallback_lang_cjk': 2,
-                   'package_fallback_lang_cjk_low_quality': 0,
-                   'package_fallback_lang_jp': 0,
-                   'package_fallback_emoji': 1,
-                   'package_fallback_symbols': 1,
-
 *  'standard' -- The default package. It includes all sans-serif, serif, and FCC
                  fonts, non-CJK fallback fonts in both 'normal' and 'bold'
                  weights, and 'normal' weight CJK ('bold' weight CJK is
@@ -70,20 +53,16 @@
                   'package_fallback_lang_non_cjk': 2,
                   'package_fallback_lang_cjk': 1,
                   'package_fallback_lang_cjk_low_quality': 0,
-                  'package_fallback_lang_jp': 0,
                   'package_fallback_emoji': 1,
                   'package_fallback_symbols': 1,
 
-*  'limited_with_jp' -- A significantly smaller package than 'standard'. This
-                 package removes all but 'normal' and 'bold' weighted sans-serif
-                 and serif, removes the FCC fonts (which must be provided by the
-                 system or downloaded from the web), removes the 'bold' weighted
-                 non-CJK fallback fonts (the 'normal' weight is still included
-                 and is used to synthesize bold), and replaces standard CJK with
-                 low quality CJK. However, higher quality Japanese is still
-                 included. Because low quality CJK cannot synthesize bold, bold
-                 glyphs are unavailable in Chinese and Korean. This package is
-                 ~10.9MB.
+*  'limited'  -- A significantly smaller package than 'standard'. This package
+                 removes all but 'normal' and 'bold' weighted sans-serif and
+                 serif, removes the FCC fonts (which must be provided by the
+                 system or downloaded from the web), and replaces standard CJK
+                 with low quality CJK. Because low quality CJK cannot synthesize
+                 bold, bold glyphs are unavailable in Chinese, Japanese and
+                 Korean. This package is ~7.7MB.
 
                  Package category values:
                   'package_named_sans_serif': 2,
@@ -92,31 +71,12 @@
                   'package_fallback_lang_non_cjk': 1,
                   'package_fallback_lang_cjk': 0,
                   'package_fallback_lang_cjk_low_quality': 1,
-                  'package_fallback_lang_jp': 1,
-                  'package_fallback_emoji': 1,
-                  'package_fallback_symbols': 1,
-
-*  'limited'  -- A smaller package than 'limited_with_jp'. The two packages are
-                 identical with the exception that 'limited' does not include
-                 the higher quality Japanese font; instead it relies on low
-                 quality CJK for all CJK characters. Because low quality CJK
-                 cannot synthesize bold, bold glyphs are unavailable in Chinese,
-                 Japanese, and Korean. This package is ~7.7MB.
-
-                 Package category values:
-                  'package_named_sans_serif': 2,
-                  'package_named_serif': 0,
-                  'package_named_fcc_fonts': 0,
-                  'package_fallback_lang_non_cjk': 1,
-                  'package_fallback_lang_cjk': 0,
-                  'package_fallback_lang_cjk_low_quality': 1,
-                  'package_fallback_lang_jp': 0,
                   'package_fallback_emoji': 1,
                   'package_fallback_symbols': 1,
 
 *  'minimal'  -- The smallest possible font package. It only includes Roboto's
                  Basic Latin characters. Everything else must be provided by the
-                 system or downloaded from the web. This package is ~16.4KB.
+                 system or downloaded from the web. This package is ~35.4KB.
 
                  Package category values:
                   'package_named_sans_serif': 0,
@@ -125,7 +85,6 @@
                   'package_fallback_lang_non_cjk': 0,
                   'package_fallback_lang_cjk': 0,
                   'package_fallback_lang_cjk_low_quality': 0,
-                  'package_fallback_lang_jp': 0,
                   'package_fallback_emoji': 0,
                   'package_fallback_symbols': 0,
 
@@ -160,10 +119,6 @@
        included when 'package_fallback_lang_cjk' has a value of '0'. This is the
        only category of fonts that is not synthetically boldable.
 
-  *  'package_fallback_lang_jp':
-       Higher quality Japanese language-specific fallback fonts. These should
-       only be included when 'package_fallback_lang_cjk' has a value of '0'.
-
   *  'package_fallback_emoji':
        Emoji-related fallback fonts.
 
@@ -219,8 +174,6 @@
        'package_fallback_lang_cjk'
   *  'cobalt_font_package_override_fallback_lang_cjk_low_quality' ==>
        'package_fallback_lang_cjk_low_quality'
-  *  'cobalt_font_package_override_fallback_lang_jp' ==>
-       'package_fallback_lang_jp'
   *  'cobalt_font_package_override_fallback_emoji' ==>
        'package_fallback_emoji'
   *  'cobalt_font_package_override_fallback_symbols' ==>
diff --git a/src/cobalt/content/fonts/config/common/fonts.xml b/src/cobalt/content/fonts/config/common/fonts.xml
index b60cc92..fc579cc 100644
--- a/src/cobalt/content/fonts/config/common/fonts.xml
+++ b/src/cobalt/content/fonts/config/common/fonts.xml
@@ -346,9 +346,6 @@
     <family lang="ko" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
         <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
     </family>
-    <family lang="ja" pages="0,32,34-35,46-159,249-250,254-255,498,512-523,525-527,530-538,540-543,545-547,550,552,554-559,561,563-568,570,572-573,575-579,582-584,586-594,596-608,610-612,614-618,620,622-625,627-628,630-631,633-638,640,642-646,649-655,658,660-664,666,669-678,681,695-696,760-761">
-        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
-    </family>
     <family pages="0,32-33,35-39,41,43,48,50,254,496-502,4068,4072">
         <font weight="400" style="normal">NotoEmoji-Regular.ttf</font>
     </family>
diff --git a/src/cobalt/content/fonts/font_files/NotoSansCJK-Bold.ttc b/src/cobalt/content/fonts/font_files/NotoSansCJK-Bold.ttc
deleted file mode 100644
index 09707f9..0000000
--- a/src/cobalt/content/fonts/font_files/NotoSansCJK-Bold.ttc
+++ /dev/null
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/NotoSansJP-Regular.otf b/src/cobalt/content/fonts/font_files/NotoSansJP-Regular.otf
deleted file mode 100644
index 40b064a..0000000
--- a/src/cobalt/content/fonts/font_files/NotoSansJP-Regular.otf
+++ /dev/null
Binary files differ
diff --git a/src/cobalt/cssom/css_declared_style_data.h b/src/cobalt/cssom/css_declared_style_data.h
index 0ac19c7..3263fa2 100644
--- a/src/cobalt/cssom/css_declared_style_data.h
+++ b/src/cobalt/cssom/css_declared_style_data.h
@@ -17,10 +17,11 @@
 
 #include <bitset>
 #include <functional>
+#include <map>
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "base/hash_tables.h"
+#include "base/containers/small_map.h"
 #include "base/memory/ref_counted.h"
 #include "cobalt/base/unused.h"
 #include "cobalt/cssom/css_declaration_data.h"
@@ -36,7 +37,10 @@
  public:
   CSSDeclaredStyleData();
 
-  typedef base::hash_map<PropertyKey, scoped_refptr<PropertyValue> >
+  // NOTE: The array size of base::SmallMap is based on extensive testing. Do
+  // not change it unless additional profiling data justifies it.
+  typedef base::SmallMap<std::map<PropertyKey, scoped_refptr<PropertyValue> >,
+                         8, std::equal_to<PropertyKey> >
       PropertyValues;
 
   // The length attribute must return the number of CSS declarations in the
diff --git a/src/cobalt/dom/custom_event_test.cc b/src/cobalt/dom/custom_event_test.cc
index 6a834a1..316de78 100644
--- a/src/cobalt/dom/custom_event_test.cc
+++ b/src/cobalt/dom/custom_event_test.cc
@@ -72,7 +72,9 @@
             base::Closure() /* csp_policy_changed */,
             base::Closure() /* ran_animation_frame_callbacks */,
             dom::Window::CloseCallback() /* window_close */,
-            base::Closure() /* window_minimize */, NULL, NULL)) {
+            base::Closure() /* window_minimize */, NULL, NULL,
+            dom::Window::OnStartDispatchEventCallback(),
+            dom::Window::OnStopDispatchEventCallback())) {
     engine_ = script::JavaScriptEngine::CreateEngine(
         script::JavaScriptEngine::Options());
     global_environment_ = engine_->CreateGlobalEnvironment();
diff --git a/src/cobalt/dom/dom_stat_tracker.h b/src/cobalt/dom/dom_stat_tracker.h
index 35cedb7..e967385 100644
--- a/src/cobalt/dom/dom_stat_tracker.h
+++ b/src/cobalt/dom/dom_stat_tracker.h
@@ -104,11 +104,11 @@
 
   // Tracking of videos produced by an event.
   base::StopWatch event_video_start_delay_stop_watch_;
-  base::CVal<base::TimeDelta> event_video_start_delay_;
+  base::CVal<base::TimeDelta, base::CValPublic> event_video_start_delay_;
 
   // Count of HtmlScriptElement::Execute() calls and time of last call.
-  base::CVal<int> script_element_execute_count_;
-  base::CVal<int64> script_element_execute_time_;
+  base::CVal<int, base::CValPublic> script_element_execute_count_;
+  base::CVal<int64, base::CValPublic> script_element_execute_time_;
 
   // Periodic counts. The counts are cleared after the CVals are updated in
   // |FlushPeriodicTracking|.
diff --git a/src/cobalt/dom/element.cc b/src/cobalt/dom/element.cc
index 30330d9..6c6a07e 100644
--- a/src/cobalt/dom/element.cc
+++ b/src/cobalt/dom/element.cc
@@ -242,7 +242,7 @@
     named_node_map_->SetAttributeInternal(attr_name, value);
   }
 
-  if (document) {
+  if (document && GetRootNode() == document) {
     document->OnDOMMutation();
   }
   OnSetAttribute(name, value);
@@ -307,7 +307,7 @@
     named_node_map_->RemoveAttributeInternal(attr_name);
   }
 
-  if (document) {
+  if (document && GetRootNode() == document) {
     document->OnDOMMutation();
   }
   OnRemoveAttribute(name);
diff --git a/src/cobalt/dom/error_event_test.cc b/src/cobalt/dom/error_event_test.cc
index 105ec2e..28b8e88 100644
--- a/src/cobalt/dom/error_event_test.cc
+++ b/src/cobalt/dom/error_event_test.cc
@@ -72,7 +72,9 @@
             base::Closure() /* csp_policy_changed */,
             base::Closure() /* ran_animation_frame_callbacks */,
             dom::Window::CloseCallback() /* window_close */,
-            base::Closure() /* window_minimize */, NULL, NULL)) {
+            base::Closure() /* window_minimize */, NULL, NULL,
+            dom::Window::OnStartDispatchEventCallback(),
+            dom::Window::OnStopDispatchEventCallback())) {
     engine_ = script::JavaScriptEngine::CreateEngine(
         script::JavaScriptEngine::Options());
     global_environment_ = engine_->CreateGlobalEnvironment();
diff --git a/src/cobalt/dom/html_link_element.cc b/src/cobalt/dom/html_link_element.cc
index ab3dfb6..5381bc9 100644
--- a/src/cobalt/dom/html_link_element.cc
+++ b/src/cobalt/dom/html_link_element.cc
@@ -144,15 +144,16 @@
       base::Bind(&HTMLLinkElement::OnLoadingError, base::Unretained(this))));
 }
 
-void HTMLLinkElement::OnLoadingDone(const std::string& content) {
-  TRACK_MEMORY_SCOPE("DOM");
+void HTMLLinkElement::OnLoadingDone(scoped_ptr<std::string> content) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(content);
+  TRACK_MEMORY_SCOPE("DOM");
   TRACE_EVENT0("cobalt::dom", "HTMLLinkElement::OnLoadingDone()");
   Document* document = node_document();
   if (rel() == "stylesheet") {
-    OnStylesheetLoaded(document, content);
+    OnStylesheetLoaded(document, *content);
   } else if (rel() == "splashscreen") {
-    OnSplashscreenLoaded(document, content);
+    OnSplashscreenLoaded(document, *content);
   } else {
     NOTIMPLEMENTED();
     return;
diff --git a/src/cobalt/dom/html_link_element.h b/src/cobalt/dom/html_link_element.h
index 1390480..1f20ffe 100644
--- a/src/cobalt/dom/html_link_element.h
+++ b/src/cobalt/dom/html_link_element.h
@@ -70,7 +70,7 @@
   // From the spec: HTMLLinkElement.
   void Obtain();
 
-  void OnLoadingDone(const std::string& content);
+  void OnLoadingDone(scoped_ptr<std::string> content);
   void OnLoadingError(const std::string& error);
   void OnSplashscreenLoaded(Document* document, const std::string& content);
   void OnStylesheetLoaded(Document* document, const std::string& content);
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 380491c..2eece7e 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -125,7 +125,6 @@
       paused_(true),
       seeking_(false),
       controls_(false),
-      last_time_update_event_wall_time_(0),
       last_time_update_event_movie_time_(std::numeric_limits<float>::max()),
       processing_media_player_callback_(0),
       media_source_url_(std::string(kMediaSourceUrlProtocol) + ':' +
@@ -1106,20 +1105,14 @@
 }
 
 void HTMLMediaElement::ScheduleTimeupdateEvent(bool periodic_event) {
-  double now = base::Time::Now().ToDoubleT();
-  double time_delta = now - last_time_update_event_wall_time_;
-
-  // throttle the periodic events
-  if (periodic_event && time_delta < kMaxTimeupdateEventFrequency) {
-    return;
-  }
-
   // Some media engines make multiple "time changed" callbacks at the same time,
   // but we only want one event at a given time so filter here
   float movie_time = current_time(NULL);
   if (movie_time != last_time_update_event_movie_time_) {
+    if (!periodic_event && playback_progress_timer_.IsRunning()) {
+      playback_progress_timer_.Reset();
+    }
     ScheduleOwnEvent(base::Tokens::timeupdate());
-    last_time_update_event_wall_time_ = now;
     last_time_update_event_movie_time_ = movie_time;
   }
 }
@@ -1593,10 +1586,15 @@
 
   ScheduleOwnEvent(base::Tokens::durationchange());
 
-  float now = current_time(NULL);
-  float dur = duration();
-  if (now > dur) {
-    Seek(dur);
+  double now = current_time(NULL);
+  // Reset and update |duration_|.
+  duration_ = std::numeric_limits<double>::quiet_NaN();
+  if (player_ && ready_state_ >= WebMediaPlayer::kReadyStateHaveMetadata) {
+    duration_ = player_->GetDuration();
+  }
+
+  if (now > duration_) {
+    Seek(static_cast<float>(duration_));
   }
 
   EndProcessingMediaPlayerCallback();
diff --git a/src/cobalt/dom/html_media_element.h b/src/cobalt/dom/html_media_element.h
index dc0fdaa..0c6f554 100644
--- a/src/cobalt/dom/html_media_element.h
+++ b/src/cobalt/dom/html_media_element.h
@@ -298,8 +298,6 @@
   bool seeking_;
   bool controls_;
 
-  // The last time a timeupdate event was sent (wall clock).
-  double last_time_update_event_wall_time_;
   // The last time a timeupdate event was sent in movie time.
   double last_time_update_event_movie_time_;
 
diff --git a/src/cobalt/dom/html_script_element.cc b/src/cobalt/dom/html_script_element.cc
index 652c504..ee3def5 100644
--- a/src/cobalt/dom/html_script_element.cc
+++ b/src/cobalt/dom/html_script_element.cc
@@ -15,6 +15,7 @@
 #include "cobalt/dom/html_script_element.h"
 
 #include <deque>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
@@ -265,6 +266,8 @@
         PreventGarbageCollection();
         ExecuteExternal();
         AllowGarbageCollection();
+        // Release the content string now that we're finished with it.
+        content_.reset();
       } else {
         // Executing the script block must just consist of firing a simple event
         // named error at the element.
@@ -347,9 +350,9 @@
   }
 }
 
-void HTMLScriptElement::OnSyncLoadingDone(const std::string& content) {
+void HTMLScriptElement::OnSyncLoadingDone(scoped_ptr<std::string> content) {
   TRACE_EVENT0("cobalt::dom", "HTMLScriptElement::OnSyncLoadingDone()");
-  content_ = content;
+  content_ = content.Pass();
   is_sync_load_successful_ = true;
 }
 
@@ -360,16 +363,18 @@
 
 // Algorithm for OnLoadingDone:
 //   https://www.w3.org/TR/html5/scripting-1.html#prepare-a-script
-void HTMLScriptElement::OnLoadingDone(const std::string& content) {
+void HTMLScriptElement::OnLoadingDone(scoped_ptr<std::string> content) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(load_option_ == 4 || load_option_ == 5);
+  DCHECK(content);
   TRACE_EVENT0("cobalt::dom", "HTMLScriptElement::OnLoadingDone()");
   if (!document_) {
     AllowGarbageCollection();
     return;
   }
 
-  content_ = content;
+  content_ = content.Pass();
+
   switch (load_option_) {
     case 4: {
       // If the element has a src attribute, does not have an async attribute,
@@ -446,6 +451,13 @@
       document_->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
     } break;
   }
+
+  // Release the content string now that we're finished with it.
+  content_.reset();
+
+  // Post a task to release the loader.
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&HTMLScriptElement::ReleaseLoader, this));
 }
 
 // Algorithm for OnLoadingError:
@@ -490,6 +502,19 @@
   // document until the task that is queued by the networking task source
   // once the resource has been fetched (defined above) has been run.
   document_->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
+
+  // Post a task to release the loader.
+  MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&HTMLScriptElement::ReleaseLoader, this));
+}
+
+void HTMLScriptElement::ExecuteExternal() {
+  DCHECK(content_);
+  Execute(*content_, base::SourceLocation(url_.spec(), 1, 1), true);
+}
+
+void HTMLScriptElement::ExecuteInternal() {
+  Execute(text_content().value(), inline_script_location_, false);
 }
 
 // Algorithm for Execute:
@@ -586,5 +611,11 @@
   }
 }
 
+void HTMLScriptElement::ReleaseLoader() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(loader_);
+  loader_.reset();
+}
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/html_script_element.h b/src/cobalt/dom/html_script_element.h
index 8307158..d121d34 100644
--- a/src/cobalt/dom/html_script_element.h
+++ b/src/cobalt/dom/html_script_element.h
@@ -89,18 +89,14 @@
   //
   void Prepare();
 
-  void OnSyncLoadingDone(const std::string& content);
+  void OnSyncLoadingDone(scoped_ptr<std::string> content);
   void OnSyncLoadingError(const std::string& error);
 
-  void OnLoadingDone(const std::string& content);
+  void OnLoadingDone(scoped_ptr<std::string> content);
   void OnLoadingError(const std::string& error);
 
-  void ExecuteExternal() {
-    Execute(content_, base::SourceLocation(url_.spec(), 1, 1), true);
-  }
-  void ExecuteInternal() {
-    Execute(text_content().value(), inline_script_location_, false);
-  }
+  void ExecuteExternal();
+  void ExecuteInternal();
   void Execute(const std::string& content,
                const base::SourceLocation& script_location, bool is_external);
 
@@ -108,6 +104,7 @@
       const tracked_objects::Location& location, const base::Token& token);
   void PreventGarbageCollection();
   void AllowGarbageCollection();
+  void ReleaseLoader();
 
   // Whether the script has been started.
   bool is_already_started_;
@@ -131,8 +128,8 @@
   bool is_sync_load_successful_;
   // Resolved URL of the script.
   GURL url_;
-  // Content of the script.
-  std::string content_;
+  // Content of the script. Released after Execute is called.
+  scoped_ptr<std::string> content_;
   // Active requests disabling garbage collection.
   int prevent_garbage_collection_count_;
 
diff --git a/src/cobalt/dom/html_video_element.cc b/src/cobalt/dom/html_video_element.cc
index 8b63f37..a5b806e 100644
--- a/src/cobalt/dom/html_video_element.cc
+++ b/src/cobalt/dom/html_video_element.cc
@@ -16,6 +16,9 @@
 
 #include "base/logging.h"
 #include "base/string_number_conversions.h"
+#include "cobalt/dom/dom_settings.h"
+#include "cobalt/dom/performance.h"
+#include "cobalt/dom/window.h"
 #include "cobalt/math/size_f.h"
 
 namespace cobalt {
@@ -76,15 +79,18 @@
   return static_cast<uint32>(player()->GetNaturalSize().height());
 }
 
-scoped_refptr<VideoPlaybackQuality> HTMLVideoElement::GetVideoPlaybackQuality()
-    const {
-  // TODO: Provide all attributes with valid values.
+scoped_refptr<VideoPlaybackQuality> HTMLVideoElement::GetVideoPlaybackQuality(
+    script::EnvironmentSettings* environment_settings) const {
+  DOMSettings* dom_settings =
+      base::polymorphic_downcast<DOMSettings*>(environment_settings);
+  DCHECK(dom_settings);
+  DCHECK(dom_settings->window());
+  DCHECK(dom_settings->window()->performance());
+
   return new VideoPlaybackQuality(
-      0.,   // creation_time
+      dom_settings->window()->performance()->Now(),
       player() ? static_cast<uint32>(player()->GetDecodedFrameCount()) : 0,
-      player() ? static_cast<uint32>(player()->GetDroppedFrameCount()) : 0,
-      0,    // corrupted_video_frames
-      0.);  // total_frame_delay
+      player() ? static_cast<uint32>(player()->GetDroppedFrameCount()) : 0);
 }
 
 scoped_refptr<ShellVideoFrameProvider>
diff --git a/src/cobalt/dom/html_video_element.h b/src/cobalt/dom/html_video_element.h
index 45396d1..2fe480e 100644
--- a/src/cobalt/dom/html_video_element.h
+++ b/src/cobalt/dom/html_video_element.h
@@ -21,6 +21,7 @@
 #include "cobalt/dom/video_playback_quality.h"
 #include "cobalt/math/rect.h"
 #include "cobalt/math/size_f.h"
+#include "cobalt/script/environment_settings.h"
 #if !defined(COBALT_MEDIA_SOURCE_2016)
 #include "media/base/shell_video_frame_provider.h"
 #endif  // !defined(COBALT_MEDIA_SOURCE_2016)
@@ -50,7 +51,8 @@
   void set_height(uint32 height);
   uint32 video_width() const;
   uint32 video_height() const;
-  scoped_refptr<VideoPlaybackQuality> GetVideoPlaybackQuality() const;
+  scoped_refptr<VideoPlaybackQuality> GetVideoPlaybackQuality(
+      script::EnvironmentSettings* environment_settings) const;
 
   // Custom, not in any spec
   //
diff --git a/src/cobalt/dom/html_video_element.idl b/src/cobalt/dom/html_video_element.idl
index 53259ab..d73e064 100644
--- a/src/cobalt/dom/html_video_element.idl
+++ b/src/cobalt/dom/html_video_element.idl
@@ -21,5 +21,5 @@
   readonly attribute unsigned long videoHeight;
 
   // https://www.w3.org/TR/media-source/#widl-HTMLVideoElement-getVideoPlaybackQuality-VideoPlaybackQuality
-  VideoPlaybackQuality getVideoPlaybackQuality();
+  [CallWith=EnvironmentSettings] VideoPlaybackQuality getVideoPlaybackQuality();
 };
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index 50376b2..40705ee 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -109,6 +109,10 @@
     window = node_document()->default_view();
   }
 
+  if (window) {
+    window->OnStartDispatchEvent(event);
+  }
+
   typedef std::vector<scoped_refptr<Node> > Ancestors;
   Ancestors ancestors;
   for (Node* current = this->parent_node(); current != NULL;
@@ -159,6 +163,10 @@
 
   event->set_event_phase(Event::kNone);
 
+  if (window) {
+    window->OnStopDispatchEvent(event);
+  }
+
   // The event has completed being dispatched. Stop tracking it in the global
   // stats.
   GlobalStats::GetInstance()->StopJavaScriptEvent();
diff --git a/src/cobalt/dom/testing/stub_window.h b/src/cobalt/dom/testing/stub_window.h
index 53f53bd..a12c934 100644
--- a/src/cobalt/dom/testing/stub_window.h
+++ b/src/cobalt/dom/testing/stub_window.h
@@ -60,7 +60,9 @@
         base::Closure() /* csp_policy_changed */,
         base::Closure() /* ran_animation_frame_callbacks */,
         dom::Window::CloseCallback() /* window_close */,
-        base::Closure() /* window_minimize */, NULL, NULL);
+        base::Closure() /* window_minimize */, NULL, NULL,
+        dom::Window::OnStartDispatchEventCallback(),
+        dom::Window::OnStopDispatchEventCallback());
     global_environment_->CreateGlobalObject(window_, &environment_settings_);
   }
 
diff --git a/src/cobalt/dom/video_playback_quality.h b/src/cobalt/dom/video_playback_quality.h
index 471b929..d3e0e9b 100644
--- a/src/cobalt/dom/video_playback_quality.h
+++ b/src/cobalt/dom/video_playback_quality.h
@@ -27,21 +27,19 @@
 class VideoPlaybackQuality : public script::Wrappable {
  public:
   VideoPlaybackQuality(double creation_time, uint32 total_video_frames,
-                       uint32 dropped_video_frames,
-                       uint32 corrupted_video_frames, double total_frame_delay)
+                       uint32 dropped_video_frames)
       : creation_time_(creation_time),
         total_video_frames_(total_video_frames),
-        dropped_video_frames_(dropped_video_frames),
-        corrupted_video_frames_(corrupted_video_frames),
-        total_frame_delay_(total_frame_delay) {}
+        dropped_video_frames_(dropped_video_frames) {}
 
   // Web API: VideoPlaybackQuality
   //
   double creation_time() const { return creation_time_; }
   uint32 total_video_frames() const { return total_video_frames_; }
   uint32 dropped_video_frames() const { return dropped_video_frames_; }
-  uint32 corrupted_video_frames() const { return corrupted_video_frames_; }
-  double total_frame_delay() const { return total_frame_delay_; }
+  // Always returns 0 as Cobalt simply stops the playback on encountering
+  // corrupted video frames.
+  uint32 corrupted_video_frames() const { return 0; }
 
   DEFINE_WRAPPABLE_TYPE(VideoPlaybackQuality);
 
@@ -49,8 +47,6 @@
   double creation_time_;
   uint32 total_video_frames_;
   uint32 dropped_video_frames_;
-  uint32 corrupted_video_frames_;
-  double total_frame_delay_;
 };
 
 }  // namespace dom
diff --git a/src/cobalt/dom/video_playback_quality.idl b/src/cobalt/dom/video_playback_quality.idl
index acc06c0..146f170 100644
--- a/src/cobalt/dom/video_playback_quality.idl
+++ b/src/cobalt/dom/video_playback_quality.idl
@@ -19,7 +19,6 @@
   readonly attribute unsigned long totalVideoFrames;
   readonly attribute unsigned long droppedVideoFrames;
   readonly attribute unsigned long corruptedVideoFrames;
-  readonly attribute double totalFrameDelay;
 };
 
 typedef double DOMHighResTimeStamp;
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 66dadf7..b68d8ba 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -82,42 +82,45 @@
 const int64_t kPerformanceTimerMinResolutionInMicroseconds = 20;
 }  // namespace
 
-Window::Window(int width, int height, float device_pixel_ratio,
-               base::ApplicationState initial_application_state,
-               cssom::CSSParser* css_parser, Parser* dom_parser,
-               loader::FetcherFactory* fetcher_factory,
-               render_tree::ResourceProvider** resource_provider,
-               loader::image::AnimatedImageTracker* animated_image_tracker,
-               loader::image::ImageCache* image_cache,
-               loader::image::ReducedCacheCapacityManager*
-                   reduced_image_cache_capacity_manager,
-               loader::font::RemoteTypefaceCache* remote_typeface_cache,
-               loader::mesh::MeshCache* mesh_cache,
-               LocalStorageDatabase* local_storage_database,
-               media::CanPlayTypeHandler* can_play_type_handler,
-               media::WebMediaPlayerFactory* web_media_player_factory,
-               script::ExecutionState* execution_state,
-               script::ScriptRunner* script_runner,
-               script::ScriptValueFactory* script_value_factory,
-               MediaSource::Registry* media_source_registry,
-               DomStatTracker* dom_stat_tracker, const GURL& url,
-               const std::string& user_agent, const std::string& language,
-               const std::string& font_language_script,
-               const base::Callback<void(const GURL&)> navigation_callback,
-               const base::Callback<void(const std::string&)>& error_callback,
-               network_bridge::CookieJar* cookie_jar,
-               const network_bridge::PostSender& post_sender,
-               const std::string& default_security_policy,
-               CspEnforcementType csp_enforcement_mode,
-               const base::Closure& csp_policy_changed_callback,
-               const base::Closure& ran_animation_frame_callbacks_callback,
-               const CloseCallback& window_close_callback,
-               const base::Closure& window_minimize_callback,
-               const scoped_refptr<input::Camera3D>& camera_3d,
-               const scoped_refptr<MediaSession>& media_session,
-               int csp_insecure_allowed_token, int dom_max_element_depth,
-               float video_playback_rate_multiplier, ClockType clock_type,
-               const CacheCallback& splash_screen_cache_callback)
+Window::Window(
+    int width, int height, float device_pixel_ratio,
+    base::ApplicationState initial_application_state,
+    cssom::CSSParser* css_parser, Parser* dom_parser,
+    loader::FetcherFactory* fetcher_factory,
+    render_tree::ResourceProvider** resource_provider,
+    loader::image::AnimatedImageTracker* animated_image_tracker,
+    loader::image::ImageCache* image_cache,
+    loader::image::ReducedCacheCapacityManager*
+        reduced_image_cache_capacity_manager,
+    loader::font::RemoteTypefaceCache* remote_typeface_cache,
+    loader::mesh::MeshCache* mesh_cache,
+    LocalStorageDatabase* local_storage_database,
+    media::CanPlayTypeHandler* can_play_type_handler,
+    media::WebMediaPlayerFactory* web_media_player_factory,
+    script::ExecutionState* execution_state,
+    script::ScriptRunner* script_runner,
+    script::ScriptValueFactory* script_value_factory,
+    MediaSource::Registry* media_source_registry,
+    DomStatTracker* dom_stat_tracker, const GURL& url,
+    const std::string& user_agent, const std::string& language,
+    const std::string& font_language_script,
+    const base::Callback<void(const GURL&)> navigation_callback,
+    const base::Callback<void(const std::string&)>& error_callback,
+    network_bridge::CookieJar* cookie_jar,
+    const network_bridge::PostSender& post_sender,
+    const std::string& default_security_policy,
+    CspEnforcementType csp_enforcement_mode,
+    const base::Closure& csp_policy_changed_callback,
+    const base::Closure& ran_animation_frame_callbacks_callback,
+    const CloseCallback& window_close_callback,
+    const base::Closure& window_minimize_callback,
+    const scoped_refptr<input::Camera3D>& camera_3d,
+    const scoped_refptr<MediaSession>& media_session,
+    const OnStartDispatchEventCallback& on_start_dispatch_event_callback,
+    const OnStopDispatchEventCallback& on_stop_dispatch_event_callback,
+    int csp_insecure_allowed_token, int dom_max_element_depth,
+    float video_playback_rate_multiplier, ClockType clock_type,
+    const CacheCallback& splash_screen_cache_callback)
     : width_(width),
       height_(height),
       device_pixel_ratio_(device_pixel_ratio),
@@ -176,7 +179,9 @@
           ran_animation_frame_callbacks_callback),
       window_close_callback_(window_close_callback),
       window_minimize_callback_(window_minimize_callback),
-      splash_screen_cache_callback_(splash_screen_cache_callback) {
+      splash_screen_cache_callback_(splash_screen_cache_callback),
+      on_start_dispatch_event_callback_(on_start_dispatch_event_callback),
+      on_stop_dispatch_event_callback_(on_stop_dispatch_event_callback) {
 #if !defined(ENABLE_TEST_RUNNER)
   UNREFERENCED_PARAMETER(clock_type);
 #endif
@@ -578,6 +583,18 @@
   }
 }
 
+void Window::OnStartDispatchEvent(const scoped_refptr<dom::Event>& event) {
+  if (!on_start_dispatch_event_callback_.is_null()) {
+    on_start_dispatch_event_callback_.Run(event);
+  }
+}
+
+void Window::OnStopDispatchEvent(const scoped_refptr<dom::Event>& event) {
+  if (!on_stop_dispatch_event_callback_.is_null()) {
+    on_stop_dispatch_event_callback_.Run(event);
+  }
+}
+
 void Window::TraceMembers(script::Tracer* tracer) {
   tracer->Trace(performance_);
   tracer->Trace(document_);
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index 335353f..3e16727 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -98,11 +98,11 @@
   typedef AnimationFrameRequestCallbackList::FrameRequestCallback
       FrameRequestCallback;
   typedef WindowTimers::TimerCallback TimerCallback;
-  typedef base::Callback<scoped_ptr<loader::Decoder>(
-      HTMLElementContext*, const scoped_refptr<Document>&,
-      const base::SourceLocation&, const base::Closure&,
-      const base::Callback<void(const std::string&)>&)>
-      HTMLDecoderCreatorCallback;
+  typedef base::Callback<void(const scoped_refptr<dom::Event>& event)>
+      OnStartDispatchEventCallback;
+  typedef base::Callback<void(const scoped_refptr<dom::Event>& event)>
+      OnStopDispatchEventCallback;
+
   // Callback that will be called when window.close() is called.  The
   // base::TimeDelta parameter will contain the document's timeline time when
   // close() was called.
@@ -148,6 +148,9 @@
       const base::Closure& window_minimize_callback,
       const scoped_refptr<input::Camera3D>& camera_3d,
       const scoped_refptr<cobalt::media_session::MediaSession>& media_session,
+      const OnStartDispatchEventCallback&
+          start_tracking_dispatch_event_callback,
+      const OnStopDispatchEventCallback& stop_tracking_dispatch_event_callback,
       int csp_insecure_allowed_token = 0, int dom_max_element_depth = 0,
       float video_playback_rate_multiplier = 1.f,
       ClockType clock_type = kClockTypeSystemTime,
@@ -335,6 +338,9 @@
   // Cache the passed in splash screen content for the window.location URL.
   void CacheSplashScreen(const std::string& content);
 
+  void OnStartDispatchEvent(const scoped_refptr<dom::Event>& event);
+  void OnStopDispatchEvent(const scoped_refptr<dom::Event>& event);
+
   DEFINE_WRAPPABLE_TYPE(Window);
 
  private:
@@ -396,6 +402,9 @@
 
   CacheCallback splash_screen_cache_callback_;
 
+  OnStartDispatchEventCallback on_start_dispatch_event_callback_;
+  OnStopDispatchEventCallback on_stop_dispatch_event_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(Window);
 };
 
diff --git a/src/cobalt/dom/window_test.cc b/src/cobalt/dom/window_test.cc
index 845c319..60989f1 100644
--- a/src/cobalt/dom/window_test.cc
+++ b/src/cobalt/dom/window_test.cc
@@ -61,7 +61,9 @@
             base::Closure() /* csp_policy_changed */,
             base::Closure() /* ran_animation_frame_callbacks */,
             dom::Window::CloseCallback() /* window_close */,
-            base::Closure() /* window_minimize */, NULL, NULL)) {}
+            base::Closure() /* window_minimize */, NULL, NULL,
+            dom::Window::OnStartDispatchEventCallback(),
+            dom::Window::OnStopDispatchEventCallback())) {}
 
   ~WindowTest() OVERRIDE {}
 
diff --git a/src/cobalt/loader/loader_test.cc b/src/cobalt/loader/loader_test.cc
index 1e7872a..570d839 100644
--- a/src/cobalt/loader/loader_test.cc
+++ b/src/cobalt/loader/loader_test.cc
@@ -16,6 +16,7 @@
 
 #include "base/bind.h"
 #include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
@@ -40,8 +41,8 @@
  public:
   explicit TextDecoderCallback(base::RunLoop* run_loop) : run_loop_(run_loop) {}
 
-  void OnDone(const std::string& text) {
-    text_ = text;
+  void OnDone(scoped_ptr<std::string> text) {
+    text_ = *text;
     MessageLoop::current()->PostTask(FROM_HERE, run_loop_->QuitClosure());
   }
 
diff --git a/src/cobalt/loader/resource_cache.h b/src/cobalt/loader/resource_cache.h
index ab01730..12993ee 100644
--- a/src/cobalt/loader/resource_cache.h
+++ b/src/cobalt/loader/resource_cache.h
@@ -585,12 +585,13 @@
   base::CVal<base::cval::SizeInBytes, base::CValPublic> memory_size_in_bytes_;
   base::CVal<base::cval::SizeInBytes, base::CValPublic>
       memory_capacity_in_bytes_;
-  base::CVal<base::cval::SizeInBytes> memory_resources_loaded_in_bytes_;
+  base::CVal<base::cval::SizeInBytes, base::CValPublic>
+      memory_resources_loaded_in_bytes_;
 
-  base::CVal<int> count_resources_requested_;
-  base::CVal<int> count_resources_loading_;
-  base::CVal<int> count_resources_loaded_;
-  base::CVal<int> count_pending_callbacks_;
+  base::CVal<int, base::CValPublic> count_resources_requested_;
+  base::CVal<int, base::CValPublic> count_resources_loading_;
+  base::CVal<int, base::CValPublic> count_resources_loaded_;
+  base::CVal<int, base::CValPublic> count_pending_callbacks_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourceCache);
 };
diff --git a/src/cobalt/loader/text_decoder.h b/src/cobalt/loader/text_decoder.h
index 11b78d4..2c1761c 100644
--- a/src/cobalt/loader/text_decoder.h
+++ b/src/cobalt/loader/text_decoder.h
@@ -17,6 +17,7 @@
 
 #include <algorithm>
 #include <string>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
@@ -32,13 +33,14 @@
 // results.
 class TextDecoder : public Decoder {
  public:
-  explicit TextDecoder(base::Callback<void(const std::string&)> done_callback)
+  explicit TextDecoder(
+      base::Callback<void(scoped_ptr<std::string>)> done_callback)
       : done_callback_(done_callback), suspended_(false) {}
   ~TextDecoder() OVERRIDE {}
 
   // This function is used for binding callback for creating TextDecoder.
   static scoped_ptr<Decoder> Create(
-      base::Callback<void(const std::string&)> done_callback) {
+      base::Callback<void(scoped_ptr<std::string>)> done_callback) {
     return scoped_ptr<Decoder>(new TextDecoder(done_callback));
   }
 
@@ -48,7 +50,10 @@
     if (suspended_) {
       return;
     }
-    text_.append(data, size);
+    if (!text_) {
+      text_.reset(new std::string);
+    }
+    text_->append(data, size);
   }
 
   void DecodeChunkPassed(scoped_ptr<std::string> data) OVERRIDE {
@@ -58,10 +63,10 @@
       return;
     }
 
-    if (text_.empty()) {
-      std::swap(*data, text_);
+    if (!text_) {
+      text_ = data.Pass();
     } else {
-      text_.append(*data);
+      text_->append(*data);
     }
   }
 
@@ -70,11 +75,14 @@
     if (suspended_) {
       return;
     }
-    done_callback_.Run(text_);
+    if (!text_) {
+      text_.reset(new std::string);
+    }
+    done_callback_.Run(text_.Pass());
   }
   bool Suspend() OVERRIDE {
     suspended_ = true;
-    text_.clear();
+    text_.reset();
     return true;
   }
   void Resume(render_tree::ResourceProvider* /*resource_provider*/) OVERRIDE {
@@ -83,8 +91,8 @@
 
  private:
   base::ThreadChecker thread_checker_;
-  std::string text_;
-  base::Callback<void(const std::string&)> done_callback_;
+  base::Callback<void(scoped_ptr<std::string>)> done_callback_;
+  scoped_ptr<std::string> text_;
   bool suspended_;
 };
 
diff --git a/src/cobalt/loader/text_decoder_test.cc b/src/cobalt/loader/text_decoder_test.cc
index 7c62696..29402dd 100644
--- a/src/cobalt/loader/text_decoder_test.cc
+++ b/src/cobalt/loader/text_decoder_test.cc
@@ -15,6 +15,7 @@
 #include "cobalt/loader/text_decoder.h"
 
 #include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -23,7 +24,7 @@
 namespace {
 
 struct TextDecoderCallback {
-  void Callback(const std::string& value) { text = value; }
+  void Callback(scoped_ptr<std::string> value) { text = *value; }
   std::string text;
 };
 
diff --git a/src/cobalt/media/base/shell_audio_bus.cc b/src/cobalt/media/base/shell_audio_bus.cc
index aea8fb0..81b569d 100644
--- a/src/cobalt/media/base/shell_audio_bus.cc
+++ b/src/cobalt/media/base/shell_audio_bus.cc
@@ -53,6 +53,31 @@
   }
 }
 
+void Sum(const float* source, float* destination, size_t size) {
+  while (size > 0) {
+    *destination += *source;
+    ++source;
+    ++destination;
+    --size;
+  }
+}
+
+void Sum(const int16* source, int16* destination, size_t size) {
+  while (size > 0) {
+    int sample_in_int32 = *destination + static_cast<int>(*source);
+    if (sample_in_int32 > std::numeric_limits<int16>::max()) {
+      *destination = std::numeric_limits<int16>::max();
+    } else if (sample_in_int32 < std::numeric_limits<int16>::min()) {
+      *destination = std::numeric_limits<int16>::min();
+    } else {
+      *destination = static_cast<int16>(sample_in_int32);
+    }
+    ++source;
+    ++destination;
+    --size;
+  }
+}
+
 }  // namespace
 
 ShellAudioBus::ShellAudioBus(size_t channels, size_t frames,
@@ -148,6 +173,17 @@
   return channel_data_[channel];
 }
 
+uint8* ShellAudioBus::interleaved_data() {
+  DCHECK_EQ(storage_type_, kInterleaved);
+  return channel_data_[0];
+}
+
+uint8* ShellAudioBus::planar_data(size_t channel) {
+  DCHECK_LT(channel, channels_);
+  DCHECK_EQ(storage_type_, kPlanar);
+  return channel_data_[channel];
+}
+
 void ShellAudioBus::ZeroFrames(size_t start_frame, size_t end_frame) {
   DCHECK_LE(start_frame, end_frame);
   DCHECK_LE(end_frame, frames_);
@@ -223,84 +259,103 @@
   }
 }
 
-template <typename SourceSampleType, typename DestSampleType,
-          StorageType SourceStorageType, StorageType DestStorageType>
-void ShellAudioBus::MixForTypes(const ShellAudioBus& source) {
+template <StorageType SourceStorageType, StorageType DestStorageType>
+void ShellAudioBus::MixFloatSamples(const ShellAudioBus& source) {
   const size_t frames = std::min(frames_, source.frames_);
 
+  if (SourceStorageType == DestStorageType) {
+    if (SourceStorageType == kInterleaved) {
+      Sum(reinterpret_cast<const float*>(source.interleaved_data()),
+          reinterpret_cast<float*>(interleaved_data()), frames * channels_);
+      return;
+    }
+    for (size_t channel = 0; channel < channels_; ++channel) {
+      Sum(reinterpret_cast<const float*>(source.planar_data(channel)),
+          reinterpret_cast<float*>(planar_data(channel)), frames);
+    }
+    return;
+  }
+
   for (size_t channel = 0; channel < channels_; ++channel) {
     for (size_t frame = 0; frame < frames; ++frame) {
-      *reinterpret_cast<DestSampleType*>(
-          GetSamplePtrForType<DestSampleType, DestStorageType>(channel,
-                                                               frame)) +=
-          source.GetSampleForType<SourceSampleType, SourceStorageType>(channel,
-                                                                       frame);
+      *reinterpret_cast<float*>(
+          GetSamplePtrForType<float, DestStorageType>(channel, frame)) +=
+          source.GetSampleForType<float, SourceStorageType>(channel, frame);
+    }
+  }
+}
+
+template <StorageType SourceStorageType, StorageType DestStorageType>
+void ShellAudioBus::MixInt16Samples(const ShellAudioBus& source) {
+  const size_t frames = std::min(frames_, source.frames_);
+
+  if (SourceStorageType == DestStorageType) {
+    if (SourceStorageType == kInterleaved) {
+      Sum(reinterpret_cast<const int16*>(source.interleaved_data()),
+          reinterpret_cast<int16*>(interleaved_data()), frames * channels_);
+      return;
+    }
+    for (size_t channel = 0; channel < channels_; ++channel) {
+      Sum(reinterpret_cast<const int16*>(source.planar_data(channel)),
+          reinterpret_cast<int16*>(planar_data(channel)), frames);
+    }
+    return;
+  }
+
+  for (size_t channel = 0; channel < channels_; ++channel) {
+    for (size_t frame = 0; frame < frames; ++frame) {
+      auto& dest_sample = *reinterpret_cast<int16*>(
+          GetSamplePtrForType<int16, DestStorageType>(channel, frame));
+      int source_sample =
+          source.GetSampleForType<int16, SourceStorageType>(channel, frame);
+      if (dest_sample + source_sample > std::numeric_limits<int16>::max()) {
+        dest_sample = std::numeric_limits<int16>::max();
+      } else if (dest_sample + source_sample <
+                 std::numeric_limits<int16>::min()) {
+        dest_sample = std::numeric_limits<int16>::min();
+      } else {
+        dest_sample += source_sample;
+      }
     }
   }
 }
 
 void ShellAudioBus::Mix(const ShellAudioBus& source) {
   DCHECK_EQ(channels_, source.channels_);
+  DCHECK_EQ(sample_type_, source.sample_type_);
 
-  if (channels_ != source.channels_) {
+  if (channels_ != source.channels_ || sample_type_ != source.sample_type_) {
     ZeroAllFrames();
     return;
   }
 
   // Profiling has identified this area of code as hot, so instead of calling
-  // GetSamplePtr, which branches each time it is called, we branch once
-  // before we loop and inline the branch of the function we want.
-  if (source.sample_type_ == kInt16 && sample_type_ == kInt16 &&
-      source.storage_type_ == kInterleaved && storage_type_ == kInterleaved) {
-    MixForTypes<int16, int16, kInterleaved, kInterleaved>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kInt16 &&
-             source.storage_type_ == kInterleaved && storage_type_ == kPlanar) {
-    MixForTypes<int16, int16, kInterleaved, kPlanar>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kInt16 &&
-             source.storage_type_ == kPlanar && storage_type_ == kInterleaved) {
-    MixForTypes<int16, int16, kPlanar, kInterleaved>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kInt16 &&
-             source.storage_type_ == kPlanar && storage_type_ == kPlanar) {
-    MixForTypes<int16, int16, kPlanar, kPlanar>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kInterleaved &&
+  // GetSamplePtr, which branches each time it is called, we branch once before
+  // we loop and inline the branch of the function we want.
+  if (source.sample_type_ == kInt16 && source.storage_type_ == kInterleaved &&
+      storage_type_ == kInterleaved) {
+    MixInt16Samples<kInterleaved, kInterleaved>(source);
+  } else if (sample_type_ == kInt16 && source.storage_type_ == kInterleaved &&
+             storage_type_ == kPlanar) {
+    MixInt16Samples<kInterleaved, kPlanar>(source);
+  } else if (sample_type_ == kInt16 && source.storage_type_ == kPlanar &&
              storage_type_ == kInterleaved) {
-    MixForTypes<int16, float, kInterleaved, kInterleaved>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kInterleaved && storage_type_ == kPlanar) {
-    MixForTypes<int16, float, kInterleaved, kPlanar>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kPlanar && storage_type_ == kInterleaved) {
-    MixForTypes<int16, float, kPlanar, kInterleaved>(source);
-  } else if (source.sample_type_ == kInt16 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kPlanar && storage_type_ == kPlanar) {
-    MixForTypes<int16, float, kPlanar, kPlanar>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kInt16 &&
-             source.storage_type_ == kInterleaved &&
+    MixInt16Samples<kPlanar, kInterleaved>(source);
+  } else if (sample_type_ == kInt16 && source.storage_type_ == kPlanar &&
+             storage_type_ == kPlanar) {
+    MixInt16Samples<kPlanar, kPlanar>(source);
+  } else if (sample_type_ == kFloat32 && source.storage_type_ == kInterleaved &&
              storage_type_ == kInterleaved) {
-    MixForTypes<float, int16, kInterleaved, kInterleaved>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kInt16 &&
-             source.storage_type_ == kInterleaved && storage_type_ == kPlanar) {
-    MixForTypes<float, int16, kInterleaved, kPlanar>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kInt16 &&
-             source.storage_type_ == kPlanar && storage_type_ == kInterleaved) {
-    MixForTypes<float, int16, kPlanar, kInterleaved>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kInt16 &&
-             source.storage_type_ == kPlanar && storage_type_ == kPlanar) {
-    MixForTypes<float, int16, kPlanar, kPlanar>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kInterleaved &&
+    MixFloatSamples<kInterleaved, kInterleaved>(source);
+  } else if (sample_type_ == kFloat32 && source.storage_type_ == kInterleaved &&
+             storage_type_ == kPlanar) {
+    MixFloatSamples<kInterleaved, kPlanar>(source);
+  } else if (sample_type_ == kFloat32 && source.storage_type_ == kPlanar &&
              storage_type_ == kInterleaved) {
-    MixForTypes<float, float, kInterleaved, kInterleaved>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kInterleaved && storage_type_ == kPlanar) {
-    MixForTypes<float, float, kInterleaved, kPlanar>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kPlanar && storage_type_ == kInterleaved) {
-    MixForTypes<float, float, kPlanar, kInterleaved>(source);
-  } else if (source.sample_type_ == kFloat32 && sample_type_ == kFloat32 &&
-             source.storage_type_ == kPlanar && storage_type_ == kPlanar) {
-    MixForTypes<float, float, kPlanar, kPlanar>(source);
+    MixFloatSamples<kPlanar, kInterleaved>(source);
+  } else if (sample_type_ == kFloat32 && source.storage_type_ == kPlanar &&
+             storage_type_ == kPlanar) {
+    MixFloatSamples<kPlanar, kPlanar>(source);
   } else {
     NOTREACHED();
   }
diff --git a/src/cobalt/media/base/shell_audio_bus.h b/src/cobalt/media/base/shell_audio_bus.h
index c9ef550..833d2dc 100644
--- a/src/cobalt/media/base/shell_audio_bus.h
+++ b/src/cobalt/media/base/shell_audio_bus.h
@@ -63,6 +63,8 @@
   size_t GetSampleSizeInBytes() const;
   const uint8* interleaved_data() const;
   const uint8* planar_data(size_t channel) const;
+  uint8* interleaved_data();
+  uint8* planar_data(size_t channel);
 
   int16 GetInt16Sample(size_t channel, size_t frame) const {
     DCHECK_EQ(sample_type_, kInt16);
@@ -130,9 +132,11 @@
         GetSamplePtrForType<SampleTypeName, T>(channel, frame));
   }
 
-  template <typename SourceSampleType, typename DestSampleType,
-            StorageType SourceStorageType, StorageType DestStorageType>
-  void MixForTypes(const ShellAudioBus& source);
+  template <StorageType SourceStorageType, StorageType DestStorageType>
+  void MixFloatSamples(const ShellAudioBus& source);
+
+  template <StorageType SourceStorageType, StorageType DestStorageType>
+  void MixInt16Samples(const ShellAudioBus& source);
 
  private:
   void SetFloat32Sample(size_t channel, size_t frame, float sample) {
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc
index e17dd70..3810a3f 100644
--- a/src/cobalt/media/base/starboard_player.cc
+++ b/src/cobalt/media/base/starboard_player.cc
@@ -204,15 +204,16 @@
 }
 
 void StarboardPlayer::SetBounds(int z_index, const gfx::Rect& rect) {
+  base::AutoLock auto_lock(lock_);
+
+  set_bounds_z_index_ = z_index;
+  set_bounds_rect_ = rect;
+
   if (state_ == kSuspended) {
-    pending_set_bounds_z_index_ = z_index;
-    pending_set_bounds_rect_ = rect;
     return;
   }
 
-  DCHECK(SbPlayerIsValid(player_));
-  SbPlayerSetBounds(player_, z_index, rect.x(), rect.y(), rect.width(),
-                    rect.height());
+  UpdateBounds_Locked();
 }
 
 void StarboardPlayer::PrepareForSeek() {
@@ -363,6 +364,7 @@
 
   base::AutoLock auto_lock(lock_);
   state_ = kResuming;
+  UpdateBounds_Locked();
 }
 
 namespace {
@@ -441,14 +443,10 @@
   }
   ShellMediaPlatform::Instance()->GetVideoFrameProvider()->SetOutputMode(
       ToVideoFrameProviderOutputMode(output_mode_));
-
   set_bounds_helper_->SetPlayer(this);
 
-  if (pending_set_bounds_z_index_ && pending_set_bounds_rect_) {
-    SetBounds(*pending_set_bounds_z_index_, *pending_set_bounds_rect_);
-    pending_set_bounds_z_index_ = base::nullopt_t();
-    pending_set_bounds_rect_ = base::nullopt_t();
-  }
+  base::AutoLock auto_lock(lock_);
+  UpdateBounds_Locked();
 }
 
 SbDecodeTarget StarboardPlayer::GetCurrentSbDecodeTarget() {
@@ -459,6 +457,19 @@
   return output_mode_;
 }
 
+void StarboardPlayer::UpdateBounds_Locked() {
+  lock_.AssertAcquired();
+  DCHECK(SbPlayerIsValid(player_));
+
+  if (!set_bounds_z_index_ || !set_bounds_rect_) {
+    return;
+  }
+
+  auto& rect = *set_bounds_rect_;
+  SbPlayerSetBounds(player_, *set_bounds_z_index_, rect.x(), rect.y(),
+                    rect.width(), rect.height());
+}
+
 void StarboardPlayer::ClearDecoderBufferCache() {
   DCHECK(message_loop_->BelongsToCurrentThread());
 
diff --git a/src/cobalt/media/base/starboard_player.h b/src/cobalt/media/base/starboard_player.h
index a2c9dc5..a15255d 100644
--- a/src/cobalt/media/base/starboard_player.h
+++ b/src/cobalt/media/base/starboard_player.h
@@ -114,6 +114,8 @@
 
   void WriteNextBufferFromCache(DemuxerStream::Type type);
 
+  void UpdateBounds_Locked();
+
   void ClearDecoderBufferCache();
 
   void OnDecoderStatus(SbPlayer player, SbMediaType type,
@@ -156,15 +158,14 @@
   bool paused_;
   bool seek_pending_;
   DecoderBufferCache decoder_buffer_cache_;
-  // If |SetBounds| is called while we are in a suspended state, then the
-  // |z_index| and |rect| that we are passed will be saved to here, and then
-  // immediately set on the new player that we construct when we are resumed.
-  base::optional<int> pending_set_bounds_z_index_;
-  base::optional<gfx::Rect> pending_set_bounds_rect_;
 
   // The following variables can be accessed from GetInfo(), which can be called
   // from any threads.  So some of their usages have to be guarded by |lock_|.
   base::Lock lock_;
+
+  // Stores the |z_index| and |rect| parameters of the latest SetBounds() call.
+  base::optional<int> set_bounds_z_index_;
+  base::optional<gfx::Rect> set_bounds_rect_;
   State state_;
   SbPlayer player_;
   uint32 cached_video_frames_decoded_;
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/filters/shell_demuxer.cc
index 45e3af5..20472aa 100644
--- a/src/cobalt/media/filters/shell_demuxer.cc
+++ b/src/cobalt/media/filters/shell_demuxer.cc
@@ -195,8 +195,7 @@
       stopped_(false),
       flushing_(false),
       audio_reached_eos_(false),
-      video_reached_eos_(false),
-      ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+      video_reached_eos_(false) {
   DCHECK(message_loop_);
   DCHECK(buffer_allocator_);
   DCHECK(data_source_);
@@ -236,19 +235,12 @@
     return;
   }
 
-  base::PostTaskAndReplyWithResult(
-      blocking_thread_.message_loop_proxy(), FROM_HERE,
-      base::Bind(&ShellDemuxer::ParseConfigBlocking, base::Unretained(this),
-                 status_cb),
-      // ParseConfigDone() will run on the current thread.  Use a WeakPtr to
-      // ensure that ParseConfigDone() won't run if the current instance is
-      // destroyed.
-      base::Bind(&ShellDemuxer::ParseConfigDone, weak_ptr_factory_.GetWeakPtr(),
-                 status_cb));
+  blocking_thread_.message_loop_proxy()->PostTask(
+      FROM_HERE, base::Bind(&ShellDemuxer::ParseConfigBlocking,
+                            base::Unretained(this), status_cb));
 }
 
-PipelineStatus ShellDemuxer::ParseConfigBlocking(
-    const PipelineStatusCB& status_cb) {
+void ShellDemuxer::ParseConfigBlocking(const PipelineStatusCB& status_cb) {
   DCHECK(blocking_thread_.message_loop_proxy()->BelongsToCurrentThread());
   DCHECK(!parser_);
 
@@ -263,17 +255,20 @@
     if (status == PIPELINE_OK) {
       status = DEMUXER_ERROR_COULD_NOT_PARSE;
     }
-    return status;
+    ParseConfigDone(status_cb, status);
+    return;
   }
 
   // instruct the parser to extract audio and video config from the file
   if (!parser_->ParseConfig()) {
-    return DEMUXER_ERROR_COULD_NOT_PARSE;
+    ParseConfigDone(status_cb, DEMUXER_ERROR_COULD_NOT_PARSE);
+    return;
   }
 
   // make sure we got a valid and complete configuration
   if (!parser_->IsConfigComplete()) {
-    return DEMUXER_ERROR_COULD_NOT_PARSE;
+    ParseConfigDone(status_cb, DEMUXER_ERROR_COULD_NOT_PARSE);
+    return;
   }
 
   // IsConfigComplete() should guarantee we know the duration
@@ -287,14 +282,14 @@
 
   // successful parse of config data, inform the nonblocking demuxer thread
   DCHECK_EQ(status, PIPELINE_OK);
-  return PIPELINE_OK;
+  ParseConfigDone(status_cb, PIPELINE_OK);
 }
 
 void ShellDemuxer::ParseConfigDone(const PipelineStatusCB& status_cb,
                                    PipelineStatus status) {
-  DCHECK(MessageLoopBelongsToCurrentThread());
+  DCHECK(blocking_thread_.message_loop_proxy()->BelongsToCurrentThread());
 
-  if (stopped_) {
+  if (HasStopCalled()) {
     return;
   }
 
@@ -324,7 +319,7 @@
   scoped_refptr<ShellAU> au = parser_->GetNextAU(type);
   // fatal parsing error returns NULL or malformed AU
   if (!au || !au->IsValid()) {
-    if (!stopped_) {
+    if (!HasStopCalled()) {
       DLOG(ERROR) << "got back bad AU from parser";
       host_->OnDemuxerError(DEMUXER_ERROR_COULD_NOT_PARSE);
     }
@@ -364,7 +359,11 @@
 void ShellDemuxer::AllocateBuffer() {
   DCHECK(requested_au_);
 
-  if (requested_au_ && !stopped_) {
+  if (HasStopCalled()) {
+    return;
+  }
+
+  if (requested_au_) {
     size_t total_buffer_size = audio_demuxer_stream_->GetTotalBufferSize() +
                                video_demuxer_stream_->GetTotalBufferSize();
     if (total_buffer_size >= COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET) {
@@ -407,7 +406,7 @@
   TRACE_EVENT2("media_stack", "ShellDemuxer::Download()", "type", event_type,
                "timestamp", requested_au_->GetTimestamp().InMicroseconds());
   // do nothing if stopped
-  if (stopped_) {
+  if (HasStopCalled()) {
     DLOG(INFO) << "aborting download task, stopped";
     return;
   }
@@ -464,10 +463,11 @@
 void ShellDemuxer::IssueNextRequest() {
   DCHECK(!requested_au_);
   // if we're stopped don't download anymore
-  if (stopped_) {
+  if (HasStopCalled()) {
     DLOG(INFO) << "stopped so request loop is stopping";
     return;
   }
+
   DemuxerStream::Type type = DemuxerStream::UNKNOWN;
   // if we have eos in one or both buffers the decision is easy
   if (audio_reached_eos_ || video_reached_eos_) {
@@ -516,7 +516,11 @@
   DCHECK(MessageLoopBelongsToCurrentThread());
   // set our internal stop flag, to not treat read failures as
   // errors anymore but as a natural part of stopping
-  stopped_ = true;
+  {
+    base::AutoLock auto_lock(lock_for_stopped_);
+    stopped_ = true;
+  }
+
   // stop the reader, which will stop the datasource and call back
   reader_->Stop();
 }
@@ -534,6 +538,11 @@
   callback.Run();
 }
 
+bool ShellDemuxer::HasStopCalled() {
+  base::AutoLock auto_lock(lock_for_stopped_);
+  return stopped_;
+}
+
 void ShellDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
   blocking_thread_.message_loop()->PostTask(
       FROM_HERE, base::Bind(&ShellDemuxer::SeekTask, base::Unretained(this),
diff --git a/src/cobalt/media/filters/shell_demuxer.h b/src/cobalt/media/filters/shell_demuxer.h
index ca8ea29..5fde5c6 100644
--- a/src/cobalt/media/filters/shell_demuxer.h
+++ b/src/cobalt/media/filters/shell_demuxer.h
@@ -20,7 +20,6 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "base/memory/weak_ptr.h"
 #include "base/message_loop.h"
 #include "base/threading/thread.h"
 #include "cobalt/media/base/decoder_buffer.h"
@@ -150,12 +149,11 @@
   void ParseConfigDone(const PipelineStatusCB& status_cb,
                        PipelineStatus status);
   void DataSourceStopped(const base::Closure& callback);
+  bool HasStopCalled();
 
   // methods that perform blocking I/O, and are therefore run on the
-  // blocking_thread_
-  // download enough of the stream to parse the configuration. returns
-  // false on error.
-  PipelineStatus ParseConfigBlocking(const PipelineStatusCB& status_cb);
+  // blocking_thread_ download enough of the stream to parse the configuration.
+  void ParseConfigBlocking(const PipelineStatusCB& status_cb);
   void AllocateBuffer();
   void Download(scoped_refptr<DecoderBuffer> buffer);
   void IssueNextRequest();
@@ -171,6 +169,7 @@
   scoped_refptr<MediaLog> media_log_;
   scoped_refptr<ShellDataSourceReader> reader_;
 
+  base::Lock lock_for_stopped_;
   bool stopped_;
   bool flushing_;
 
@@ -181,8 +180,6 @@
   scoped_refptr<ShellAU> requested_au_;
   bool audio_reached_eos_;
   bool video_reached_eos_;
-
-  base::WeakPtrFactory<ShellDemuxer> weak_ptr_factory_;
 };
 
 }  // namespace media
diff --git a/src/cobalt/media/filters/source_buffer_stream.cc b/src/cobalt/media/filters/source_buffer_stream.cc
index 4f9ffb0..6327853 100644
--- a/src/cobalt/media/filters/source_buffer_stream.cc
+++ b/src/cobalt/media/filters/source_buffer_stream.cc
@@ -731,10 +731,29 @@
     return false;
   }
 
-  // Return if we're under or at the memory limit.
-  if (ranges_size + newDataSize <= memory_limit_) return true;
+  base::TimeDelta duration = GetBufferedDurationForGarbageCollection();
 
-  size_t bytes_to_free = ranges_size + newDataSize - memory_limit_;
+  size_t bytes_to_free = 0;
+
+  // Check if we're under or at the memory/duration limit.
+  const auto kGcDurationThresholdInMilliseconds =
+      COBALT_MEDIA_SOURCE_GARBAGE_COLLECTION_DURATION_THRESHOLD_IN_SECONDS *
+      1000;
+
+  if (ranges_size + newDataSize > memory_limit_) {
+    bytes_to_free = ranges_size + newDataSize - memory_limit_;
+  } else if (duration.InMilliseconds() > kGcDurationThresholdInMilliseconds) {
+    // Estimate the size to free.
+    auto duration_to_free =
+        duration.InMilliseconds() - kGcDurationThresholdInMilliseconds;
+    bytes_to_free = ranges_size * duration_to_free / duration.InMilliseconds();
+  }
+
+  if (bytes_to_free == 0) {
+    return true;
+  }
+
+  DCHECK_GT(bytes_to_free, 0);
 
   DVLOG(2) << __func__ << " " << GetStreamTypeName()
            << ": Before GC media_time=" << media_time.InSecondsF()
@@ -1834,5 +1853,14 @@
   return true;
 }
 
+base::TimeDelta SourceBufferStream::GetBufferedDurationForGarbageCollection()
+    const {
+  base::TimeDelta duration;
+  for (auto range : ranges_) {
+    duration += range->GetEndTimestamp() - range->GetStartTimestamp();
+  }
+  return duration;
+}
+
 }  // namespace media
 }  // namespace cobalt
diff --git a/src/cobalt/media/filters/source_buffer_stream.h b/src/cobalt/media/filters/source_buffer_stream.h
index edeac1a..de9d343 100644
--- a/src/cobalt/media/filters/source_buffer_stream.h
+++ b/src/cobalt/media/filters/source_buffer_stream.h
@@ -471,6 +471,10 @@
   // appropriately and returns true.  Otherwise returns false.
   bool SetPendingBuffer(scoped_refptr<StreamParserBuffer>* out_buffer);
 
+  // Returns the accumulated duration of all ranges.  This is solely used by
+  // garbage collection.
+  base::TimeDelta GetBufferedDurationForGarbageCollection() const;
+
   // Used to report log messages that can help the web developer figure out what
   // is wrong with the content.
   scoped_refptr<MediaLog> media_log_;
diff --git a/src/cobalt/renderer/copy_font_data.gypi b/src/cobalt/renderer/copy_font_data.gypi
index b62574e..0102e42 100644
--- a/src/cobalt/renderer/copy_font_data.gypi
+++ b/src/cobalt/renderer/copy_font_data.gypi
@@ -21,22 +21,9 @@
     'source_font_files_dir': '<(static_contents_source_dir)/fonts/font_files',
 
     'conditions': [
-      [ 'cobalt_font_package == "expanded"', {
-        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
-
-        'package_named_sans_serif': 4,
-        'package_named_serif': 3,
-        'package_named_fcc_fonts': 2,
-        'package_fallback_lang_non_cjk': 2,
-        'package_fallback_lang_cjk': 2,
-        'package_fallback_lang_cjk_low_quality': 0,
-        'package_fallback_lang_jp': 0,
-        'package_fallback_emoji': 1,
-        'package_fallback_symbols': 1,
-      }],
-
       # 'unlimited' is deprecated but is mapped to 'standard'
-      [ 'cobalt_font_package == "standard" or cobalt_font_package == "unlimited"', {
+      # 'expanded' also currently maps to 'standard' but this may change in the future
+      [ 'cobalt_font_package == "standard" or cobalt_font_package == "unlimited" or cobalt_font_package == "expanded"', {
         'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
         'package_named_sans_serif': 4,
@@ -45,13 +32,12 @@
         'package_fallback_lang_non_cjk': 2,
         'package_fallback_lang_cjk': 1,
         'package_fallback_lang_cjk_low_quality': 0,
-        'package_fallback_lang_jp': 0,
         'package_fallback_emoji': 1,
         'package_fallback_symbols': 1,
       }],
 
-      # '10megabytes' is deprecated but is mapped to 'limited_with_jp'
-      [ 'cobalt_font_package == "limited_with_jp" or cobalt_font_package == "10megabytes"', {
+      # '10megabytes' and 'limited_with_jp' are deprecated but map to 'limited'
+      [ 'cobalt_font_package == "limited" or cobalt_font_package == "limited_with_jp" or cobalt_font_package == "10megabytes"', {
         'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
         'package_named_sans_serif': 2,
@@ -60,21 +46,6 @@
         'package_fallback_lang_non_cjk': 1,
         'package_fallback_lang_cjk': 0,
         'package_fallback_lang_cjk_low_quality': 1,
-        'package_fallback_lang_jp': 1,
-        'package_fallback_emoji': 1,
-        'package_fallback_symbols': 1,
-      }],
-
-      [ 'cobalt_font_package == "limited"', {
-        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
-
-        'package_named_sans_serif': 2,
-        'package_named_serif': 0,
-        'package_named_fcc_fonts': 0,
-        'package_fallback_lang_non_cjk': 1,
-        'package_fallback_lang_cjk': 0,
-        'package_fallback_lang_cjk_low_quality': 1,
-        'package_fallback_lang_jp': 0,
         'package_fallback_emoji': 1,
         'package_fallback_symbols': 1,
       }],
@@ -88,7 +59,6 @@
         'package_fallback_lang_non_cjk': 0,
         'package_fallback_lang_cjk': 0,
         'package_fallback_lang_cjk_low_quality': 0,
-        'package_fallback_lang_jp': 0,
         'package_fallback_emoji': 0,
         'package_fallback_symbols': 0,
       }],
@@ -108,7 +78,6 @@
         'package_fallback_lang_non_cjk': 0,
         'package_fallback_lang_cjk': 0,
         'package_fallback_lang_cjk_low_quality': 0,
-        'package_fallback_lang_jp': 0,
         'package_fallback_emoji': 1,
         'package_fallback_symbols': 0,
       }],
@@ -131,9 +100,6 @@
       [ 'cobalt_font_package_override_fallback_lang_cjk_low_quality >= 0', {
         'package_fallback_lang_cjk_low_quality': '<(cobalt_font_package_override_fallback_lang_cjk_low_quality)',
       }],
-      [ 'cobalt_font_package_override_fallback_lang_jp >= 0', {
-        'package_fallback_lang_jp': '<(cobalt_font_package_override_fallback_lang_jp)',
-      }],
       [ 'cobalt_font_package_override_fallback_emoji >= 0', {
         'package_fallback_emoji': '<(cobalt_font_package_override_fallback_emoji)',
       }],
@@ -309,21 +275,11 @@
             '<(source_font_files_dir)/NotoSansCJK-Regular.ttc',
           ],
         }],
-        [ 'package_fallback_lang_cjk >= 2', {
-          'files+': [
-            '<(source_font_files_dir)/NotoSansCJK-Bold.ttc',
-          ],
-        }],
         [ 'package_fallback_lang_cjk_low_quality >= 1', {
           'files+': [
             '<(source_font_files_dir)/DroidSansFallback.ttf',
           ],
         }],
-        [ 'package_fallback_lang_jp >= 1', {
-          'files+': [
-            '<(source_font_files_dir)/NotoSansJP-Regular.otf',
-          ],
-        }],
         [ 'package_fallback_emoji >= 1', {
           'files+': [
             '<(source_font_files_dir)/NotoEmoji-Regular.ttf',
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index f41aea3..98ca265 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -80,9 +80,6 @@
       last_did_rasterize_(false),
       last_animations_expired_(true),
       last_stat_tracked_animations_expired_(true),
-      rasterize_periodic_timer_("Renderer.Rasterize.Duration",
-                                kRasterizePeriodicTimerEntriesPerUpdate,
-                                false /*enable_entry_list_c_val*/),
       rasterize_animations_timer_("Renderer.Rasterize.Animations",
                                   kRasterizeAnimationsTimerMaxEntries,
                                   true /*enable_entry_list_c_val*/),
@@ -352,14 +349,6 @@
   bool animations_active =
       !are_stat_tracked_animations_expired && did_rasterize;
 
-  // The rasterization is only timed with the periodic timer when the render
-  // tree has changed. This ensures that the frames being timed are consistent
-  // between platforms that submit unchanged trees and those that don't.
-  if (did_rasterize) {
-    rasterize_periodic_timer_.Start(start_time);
-    rasterize_periodic_timer_.Stop(end_time);
-  }
-
   if (last_animations_active || animations_active) {
     // The rasterization is only timed with the animations timer when there are
     // animations to track. This applies when animations were active during
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index 366ef0d..965035c 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -245,13 +245,9 @@
   bool last_did_rasterize_;
 
   // Timer tracking the amount of time spent in
-  // |RasterizeSubmissionToRenderTarget| when the render tree has changed.
-  // The tracking is flushed when the max count is hit.
-  base::CValCollectionTimerStats<base::CValPublic> rasterize_periodic_timer_;
-  // Timer tracking the amount of time spent in
   // |RasterizeSubmissionToRenderTarget| while animations are active. The
   // tracking is flushed when the animations expire.
-  base::CValCollectionTimerStats<base::CValDebug> rasterize_animations_timer_;
+  base::CValCollectionTimerStats<base::CValPublic> rasterize_animations_timer_;
 
   // Accumulates render tree rasterization interval times but does not flush
   // them until the maximum number of samples is gathered.
@@ -265,16 +261,16 @@
       rasterize_animations_interval_timer_;
 
   // The total number of new render trees that have been rasterized.
-  base::CVal<int> new_render_tree_rasterize_count_;
+  base::CVal<int, base::CValPublic> new_render_tree_rasterize_count_;
   // The last time that a newly encountered render tree was first rasterized.
-  base::CVal<int64> new_render_tree_rasterize_time_;
+  base::CVal<int64, base::CValPublic> new_render_tree_rasterize_time_;
 
   // Whether or not animations are currently playing.
-  base::CVal<bool> has_active_animations_c_val_;
+  base::CVal<bool, base::CValPublic> has_active_animations_c_val_;
   // The most recent time animations started playing.
-  base::CVal<int64> animations_start_time_;
+  base::CVal<int64, base::CValPublic> animations_start_time_;
   // The most recent time animations ended playing.
-  base::CVal<int64> animations_end_time_;
+  base::CVal<int64, base::CValPublic> animations_end_time_;
 
 #if defined(ENABLE_DEBUG_CONSOLE)
   // Dumps the current render tree to the console.
diff --git a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
index 1c5e2d4..2dd5667 100644
--- a/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/cached_software_rasterizer.cc
@@ -234,6 +234,7 @@
       // This surface may have already been in the cache if it was in there
       // with a different scale.  In that case, replace the old one.
       cache_memory_usage_ -= found->second.GetEstimatedMemoryUsage();
+      SbBlitterDestroySurface(found->second.surface);
       surface_map_.erase(found);
     }
 
diff --git a/src/cobalt/script/mozjs-45/mozjs_engine.cc b/src/cobalt/script/mozjs-45/mozjs_engine.cc
index ea0f726..656553a 100644
--- a/src/cobalt/script/mozjs-45/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_engine.cc
@@ -144,7 +144,16 @@
     : accumulated_extra_memory_cost_(0), options_(options) {
   TRACE_EVENT0("cobalt::script", "MozjsEngine::MozjsEngine()");
   SbOnce(&g_js_init_once_control, CallInitAndRegisterShutDownOnce);
-  runtime_ = JS_NewRuntime(options_.js_options.gc_threshold_bytes);
+
+  // Set the nursery size to half of the GC threshold size. Analysis has shown
+  // that allocating less than this does not reduce the total amount of JS
+  // memory used, and allocating more does not provide performance improvements.
+  constexpr size_t kMinMaxNurseryBytes = 1 * 1024 * 1024;
+  uint32_t max_nursery_bytes =
+      std::max(options_.js_options.gc_threshold_bytes / 2, kMinMaxNurseryBytes);
+
+  runtime_ =
+      JS_NewRuntime(options_.js_options.gc_threshold_bytes, max_nursery_bytes);
   CHECK(runtime_);
 
   // Sets the size of the native stack that should not be exceeded.
diff --git a/src/starboard/nplb/socket_resolve_test.cc b/src/starboard/nplb/socket_resolve_test.cc
index ebca117..bf96ac3 100644
--- a/src/starboard/nplb/socket_resolve_test.cc
+++ b/src/starboard/nplb/socket_resolve_test.cc
@@ -37,7 +37,7 @@
 const void* kNull = NULL;
 
 // A random host name to use to test DNS resolution.
-const char* kTestHostName = "www.yahoo.com";
+const char kTestHostName[] = "www.example.com";
 
 #define LOG_ADDRESS(i) "In returned address #" << (i)
 
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
index 850838f..6ccf433 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
@@ -231,10 +231,23 @@
 
   codec_context_->channels = audio_header_.number_of_channels;
   codec_context_->sample_rate = audio_header_.samples_per_second;
-
   codec_context_->extradata = NULL;
   codec_context_->extradata_size = 0;
 
+  if (codec_context_->codec_id == AV_CODEC_ID_OPUS &&
+      audio_header_.audio_specific_config_size > 0) {
+    // AV_INPUT_BUFFER_PADDING_SIZE is not defined in ancient avcodec.h.  Use a
+    // large enough padding here explicitly.
+    const int kAvInputBufferPaddingSize = 256;
+    codec_context_->extradata_size = audio_header_.audio_specific_config_size;
+    codec_context_->extradata = static_cast<uint8_t*>(
+        av_malloc(codec_context_->extradata_size + kAvInputBufferPaddingSize));
+    SbMemoryCopy(codec_context_->extradata, audio_header_.audio_specific_config,
+                 codec_context_->extradata_size);
+    SbMemorySet(codec_context_->extradata + codec_context_->extradata_size, 0,
+                kAvInputBufferPaddingSize);
+  }
+
   AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
 
   if (codec == NULL) {
@@ -264,13 +277,10 @@
 void AudioDecoder::TeardownCodec() {
   if (codec_context_) {
     CloseCodec(codec_context_);
-    av_free(codec_context_);
-    codec_context_ = NULL;
+    av_freep(&codec_context_->extradata);
+    av_freep(&codec_context_);
   }
-  if (av_frame_) {
-    av_free(av_frame_);
-    av_frame_ = NULL;
-  }
+  av_freep(&av_frame_);
 }
 
 }  // namespace ffmpeg
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc b/src/starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc
index 3892b04..9df9cdf 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc
@@ -115,7 +115,7 @@
 AudioResampler::~AudioResampler() {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
   avresample_close(context_);
-  av_free(context_);
+  av_freep(&context_);
 }
 
 scoped_refptr<AudioResampler::DecodedAudio> AudioResampler::Resample(
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index e1e9129..6d8981b 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -382,13 +382,9 @@
 void VideoDecoder::TeardownCodec() {
   if (codec_context_) {
     CloseCodec(codec_context_);
-    av_free(codec_context_);
-    codec_context_ = NULL;
+    av_freep(&codec_context_);
   }
-  if (av_frame_) {
-    av_free(av_frame_);
-    av_frame_ = NULL;
-  }
+  av_freep(&av_frame_);
 
   if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
     ScopedLock lock(decode_target_mutex_);
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
index 0b81764..58d48ad 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -64,9 +64,14 @@
 
 }  // namespace
 
-AudioRendererImpl::AudioRendererImpl(scoped_ptr<AudioDecoder> decoder,
-                                     const SbMediaAudioHeader& audio_header)
-    : eos_state_(kEOSNotReceived),
+AudioRendererImpl::AudioRendererImpl(
+    scoped_ptr<AudioDecoder> decoder,
+    const SbMediaAudioHeader& audio_header,
+    size_t max_cached_frames /*= kDefaultMaxCachedFrames*/,
+    size_t max_frames_per_append /* = kDefaultMaxFramesPerAppend*/)
+    : max_cached_frames_(max_cached_frames),
+      max_frames_per_append_(max_frames_per_append),
+      eos_state_(kEOSNotReceived),
       channels_(audio_header.number_of_channels),
       sink_sample_type_(GetSinkAudioSampleType()),
       bytes_per_frame_(media::GetBytesPerSample(sink_sample_type_) * channels_),
@@ -76,7 +81,7 @@
       consume_frames_called_(false),
       seeking_(false),
       seeking_to_pts_(0),
-      frame_buffer_(kMaxCachedFrames * bytes_per_frame_),
+      frame_buffer_(max_cached_frames_ * bytes_per_frame_),
       frames_sent_to_sink_(0),
       pending_decoder_outputs_(0),
       frames_consumed_by_sink_(0),
@@ -89,6 +94,8 @@
           Bind(&AudioRendererImpl::ProcessAudioData, this)),
       decoder_needs_full_reset_(false) {
   SB_DCHECK(decoder_ != NULL);
+  SB_DCHECK(max_frames_per_append_ > 0);
+  SB_DCHECK(max_cached_frames_ >= max_frames_per_append_ * 2);
 
   frame_buffers_[0] = &frame_buffer_[0];
 
@@ -316,7 +323,7 @@
       channels_, destination_sample_rate, sink_sample_type_,
       kSbMediaAudioFrameStorageTypeInterleaved,
       reinterpret_cast<SbAudioSinkFrameBuffers>(frame_buffers_),
-      kMaxCachedFrames, &AudioRendererImpl::UpdateSourceStatusFunc,
+      max_cached_frames_, &AudioRendererImpl::UpdateSourceStatusFunc,
       &AudioRendererImpl::ConsumeFramesFunc, this);
   SB_DCHECK(SbAudioSinkIsValid(audio_sink_));
 
@@ -337,7 +344,7 @@
   if (*is_playing) {
     *frames_in_buffer = static_cast<int>(frames_sent_to_sink_.load() -
                                          frames_consumed_by_sink_.load());
-    *offset_in_frames = frames_consumed_by_sink_.load() % kMaxCachedFrames;
+    *offset_in_frames = frames_consumed_by_sink_.load() % max_cached_frames_;
   } else {
     *frames_in_buffer = *offset_in_frames = 0;
   }
@@ -398,14 +405,15 @@
 
   // Loop until no audio is appended, i.e. AppendAudioToFrameBuffer() returns
   // false.
-  while (AppendAudioToFrameBuffer()) {
+  bool is_frame_buffer_full = false;
+  while (AppendAudioToFrameBuffer(&is_frame_buffer_full)) {
   }
 
   while (pending_decoder_outputs_ > 0) {
     if (time_stretcher_.IsQueueFull()) {
       // There is no room to do any further processing, schedule the function
       // again for a later time.  The delay time is 1/4 of the buffer size.
-      const SbTimeMonotonic delay = kMaxCachedFrames * kSbTimeSecond /
+      const SbTimeMonotonic delay = max_cached_frames_ * kSbTimeSecond /
                                     decoder_->GetSamplesPerSecond() / 4;
       process_audio_data_scheduled_ = true;
       Schedule(process_audio_data_closure_, delay);
@@ -439,7 +447,7 @@
 
     // Loop until no audio is appended, i.e. AppendAudioToFrameBuffer() returns
     // false.
-    while (AppendAudioToFrameBuffer()) {
+    while (AppendAudioToFrameBuffer(&is_frame_buffer_full)) {
     }
   }
 
@@ -449,15 +457,14 @@
     return;
   }
 
-  int64_t frames_in_buffer =
-      frames_sent_to_sink_.load() - frames_consumed_by_sink_.load();
-  if (kMaxCachedFrames - frames_in_buffer < kFrameAppendUnit &&
-      eos_state_.load() < kEOSSentToSink) {
+  if (is_frame_buffer_full) {
     // There are still audio data not appended so schedule a callback later.
     SbTimeMonotonic delay = 0;
-    if (kMaxCachedFrames - frames_in_buffer < kMaxCachedFrames / 4) {
+    int64_t frames_in_buffer =
+        frames_sent_to_sink_.load() - frames_consumed_by_sink_.load();
+    if (max_cached_frames_ - frames_in_buffer < max_cached_frames_ / 4) {
       int frames_to_delay = static_cast<int>(
-          kMaxCachedFrames / 4 - (kMaxCachedFrames - frames_in_buffer));
+          max_cached_frames_ / 4 - (max_cached_frames_ - frames_in_buffer));
       delay = frames_to_delay * kSbTimeSecond / decoder_->GetSamplesPerSecond();
     }
     process_audio_data_scheduled_ = true;
@@ -465,8 +472,11 @@
   }
 }
 
-bool AudioRendererImpl::AppendAudioToFrameBuffer() {
+bool AudioRendererImpl::AppendAudioToFrameBuffer(bool* is_frame_buffer_full) {
   SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(is_frame_buffer_full);
+
+  *is_frame_buffer_full = false;
 
   if (seeking_.load() && time_stretcher_.IsQueueFull()) {
     seeking_.store(false);
@@ -479,14 +489,15 @@
   int frames_in_buffer = static_cast<int>(frames_sent_to_sink_.load() -
                                           frames_consumed_by_sink_.load());
 
-  if (kMaxCachedFrames - frames_in_buffer < kFrameAppendUnit) {
+  if (max_cached_frames_ - frames_in_buffer < max_frames_per_append_) {
+    *is_frame_buffer_full = true;
     return false;
   }
 
-  int offset_to_append = frames_sent_to_sink_.load() % kMaxCachedFrames;
+  int offset_to_append = frames_sent_to_sink_.load() % max_cached_frames_;
 
   scoped_refptr<DecodedAudio> decoded_audio =
-      time_stretcher_.Read(kFrameAppendUnit, playback_rate_.load());
+      time_stretcher_.Read(max_frames_per_append_, playback_rate_.load());
   SB_DCHECK(decoded_audio);
   if (decoded_audio->frames() == 0 && eos_state_.load() == kEOSDecoded) {
     eos_state_.store(kEOSSentToSink);
@@ -500,13 +511,13 @@
   int frames_to_append = decoded_audio->frames();
   int frames_appended = 0;
 
-  if (frames_to_append > kMaxCachedFrames - offset_to_append) {
+  if (frames_to_append > max_cached_frames_ - offset_to_append) {
     SbMemoryCopy(&frame_buffer_[offset_to_append * bytes_per_frame_],
                  source_buffer,
-                 (kMaxCachedFrames - offset_to_append) * bytes_per_frame_);
-    source_buffer += (kMaxCachedFrames - offset_to_append) * bytes_per_frame_;
-    frames_to_append -= kMaxCachedFrames - offset_to_append;
-    frames_appended += kMaxCachedFrames - offset_to_append;
+                 (max_cached_frames_ - offset_to_append) * bytes_per_frame_);
+    source_buffer += (max_cached_frames_ - offset_to_append) * bytes_per_frame_;
+    frames_to_append -= max_cached_frames_ - offset_to_append;
+    frames_appended += max_cached_frames_ - offset_to_append;
     offset_to_append = 0;
   }
 
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
index 7ab3a0a..c602812 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
@@ -44,8 +44,20 @@
 // |AudioDecoder| interface, rather than a platform specific implementation.
 class AudioRendererImpl : public AudioRenderer, private JobQueue::JobOwner {
  public:
+  static const size_t kDefaultMaxCachedFrames = 256 * 1024;
+  static const size_t kDefaultMaxFramesPerAppend = 16384;
+
+  // |max_cached_frames| is a soft limit for the max audio frames this class can
+  // cache so it can:
+  // 1. Avoid using too much memory.
+  // 2. Have the audio cache full to simulate the state that the renderer can no
+  //    longer accept more data.
+  // |max_frames_per_append| is the max number of frames that the audio renderer
+  // tries to append to the sink buffer at once.
   AudioRendererImpl(scoped_ptr<AudioDecoder> decoder,
-                    const SbMediaAudioHeader& audio_header);
+                    const SbMediaAudioHeader& audio_header,
+                    size_t max_cached_frames = kDefaultMaxCachedFrames,
+                    size_t max_frames_per_append = kDefaultMaxFramesPerAppend);
   ~AudioRendererImpl() SB_OVERRIDE;
 
   void Initialize(const Closure& error_cb) SB_OVERRIDE;
@@ -69,6 +81,16 @@
   SbMediaTime GetCurrentTime() SB_OVERRIDE;
 
  protected:
+  enum EOSState {
+    kEOSNotReceived,
+    kEOSWrittenToDecoder,
+    kEOSDecoded,
+    kEOSSentToSink
+  };
+
+  const size_t max_cached_frames_;
+  const size_t max_frames_per_append_;
+
   atomic_bool paused_;
   atomic_bool consume_frames_called_;
   atomic_bool seeking_;
@@ -85,22 +107,6 @@
   atomic_double playback_rate_;
 
  private:
-  enum EOSState {
-    kEOSNotReceived,
-    kEOSWrittenToDecoder,
-    kEOSDecoded,
-    kEOSSentToSink
-  };
-
-  // Set a soft limit for the max audio frames we can cache so we can:
-  // 1. Avoid using too much memory.
-  // 2. Have the audio cache full to simulate the state that the renderer can no
-  //    longer accept more data.
-  static const size_t kMaxCachedFrames = 256 * 1024;
-  // The audio renderer tries to append |kAppendFrameUnit| frames every time to
-  // the sink buffer.
-  static const size_t kFrameAppendUnit = 16384;
-
   void CreateAudioSinkAndResampler();
   void UpdateSourceStatus(int* frames_in_buffer,
                           int* offset_in_frames,
@@ -113,7 +119,7 @@
   void OnDecoderOutput();
   void ProcessAudioData();
   void FillResamplerAndTimeStretcher();
-  bool AppendAudioToFrameBuffer();
+  bool AppendAudioToFrameBuffer(bool* is_frame_buffer_full);
 
   // SbAudioSink callbacks
   static void UpdateSourceStatusFunc(int* frames_in_buffer,