| Index: content/browser/media/session/media_session.cc
 | 
| diff --git a/content/browser/media/session/media_session.cc b/content/browser/media/session/media_session.cc
 | 
| index ea25caad4df7d8adeb230f46523aa00d64e6c3d1..72e3b86e9f872f798a05b971ccb6433bd8aedc9e 100644
 | 
| --- a/content/browser/media/session/media_session.cc
 | 
| +++ b/content/browser/media/session/media_session.cc
 | 
| @@ -5,12 +5,17 @@
 | 
|  #include "content/browser/media/session/media_session.h"
 | 
|  
 | 
|  #include "content/browser/media/session/audio_focus_delegate.h"
 | 
| +#include "content/browser/media/session/media_session_observer.h"
 | 
|  #include "content/browser/media/session/media_session_player_observer.h"
 | 
|  #include "content/browser/web_contents/web_contents_impl.h"
 | 
|  #include "content/public/browser/web_contents.h"
 | 
|  #include "content/public/browser/web_contents_delegate.h"
 | 
|  #include "media/base/media_content_type.h"
 | 
|  
 | 
| +#if defined(OS_ANDROID)
 | 
| +#include "content/browser/media/session/media_session_android.h"
 | 
| +#endif  // defined(OS_ANDROID
 | 
| +
 | 
|  namespace content {
 | 
|  
 | 
|  namespace {
 | 
| @@ -57,6 +62,20 @@ MediaSession* MediaSession::Get(WebContents* web_contents) {
 | 
|  MediaSession::~MediaSession() {
 | 
|    DCHECK(players_.empty());
 | 
|    DCHECK(audio_focus_state_ == State::INACTIVE);
 | 
| +  for (auto& observer : observers_)
 | 
| +    observer.MediaSessionDestroyed();
 | 
| +#if defined(OS_ANDROID)
 | 
| +  // Reset session_android to prevent further messages from Java.
 | 
| +  session_android_.reset();
 | 
| +#endif  // defined(OS_ANDROID)
 | 
| +}
 | 
| +
 | 
| +void MediaSession::AddObserver(MediaSessionObserver* observer) {
 | 
| +  observers_.AddObserver(observer);
 | 
| +}
 | 
| +
 | 
| +void MediaSession::RemoveObserver(MediaSessionObserver* observer) {
 | 
| +  observers_.RemoveObserver(observer);
 | 
|  }
 | 
|  
 | 
|  void MediaSession::WebContentsDestroyed() {
 | 
| @@ -74,8 +93,9 @@ void MediaSession::WebContentsDestroyed() {
 | 
|  
 | 
|  void MediaSession::SetMetadata(const base::Optional<MediaMetadata>& metadata) {
 | 
|    metadata_ = metadata;
 | 
| -  static_cast<WebContentsImpl*>(web_contents())
 | 
| -      ->OnMediaSessionMetadataChanged();
 | 
| +
 | 
| +  for (auto& observer : observers_)
 | 
| +    observer.MediaSessionMetadataChanged(metadata_);
 | 
|  }
 | 
|  
 | 
|  bool MediaSession::AddPlayer(MediaSessionPlayerObserver* observer,
 | 
| @@ -379,7 +399,11 @@ MediaSession::MediaSession(WebContents* web_contents)
 | 
|        audio_focus_state_(State::INACTIVE),
 | 
|        audio_focus_type_(
 | 
|            AudioFocusManager::AudioFocusType::GainTransientMayDuck),
 | 
| -      is_ducking_(false) {}
 | 
| +      is_ducking_(false) {
 | 
| +#if defined(OS_ANDROID)
 | 
| +  session_android_.reset(new MediaSessionAndroid(this));
 | 
| +#endif  // defined(OS_ANDROID)
 | 
| +}
 | 
|  
 | 
|  void MediaSession::Initialize() {
 | 
|    delegate_ = AudioFocusDelegate::Create(this);
 | 
| @@ -410,7 +434,8 @@ void MediaSession::AbandonSystemAudioFocusIfNeeded() {
 | 
|  
 | 
|  void MediaSession::UpdateWebContents() {
 | 
|    media_session_state_listeners_.Notify(audio_focus_state_);
 | 
| -  static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
 | 
| +  for (auto& observer : observers_)
 | 
| +    observer.MediaSessionStateChanged(IsControllable(), IsSuspended());
 | 
|  }
 | 
|  
 | 
|  void MediaSession::SetAudioFocusState(State audio_focus_state) {
 | 
| 
 |