Commit 6ad356d3 authored by timav's avatar timav Committed by Commit bot

Propagate audible state from player to the containing tab.

This is part 1 (chromium),
part 2 (clank) is https://chrome-internal-review.googlesource.com/#/c/195455/

This CL is only about propagation/plumbing.
Neither the reporting of audible state my players nor the consumption
(UI notification) are implemented.

This patch creates a new object AudioMonitorAndroid and
attaches it to MediaWebContentsObserver. The AudioMonitorAndroid
maintains the audible state for the tab. It receives notifications
from MediaPlayerAndroid objects and sends the resulting
notification to the WebContents.

BUG=414810

Review URL: https://codereview.chromium.org/896673003

Cr-Commit-Position: refs/heads/master@{#318823}
parent 1f67ef5a
...@@ -71,4 +71,5 @@ public class ChromeWebContentsDelegateAndroid extends WebContentsDelegateAndroid ...@@ -71,4 +71,5 @@ public class ChromeWebContentsDelegateAndroid extends WebContentsDelegateAndroid
protected static native boolean nativeIsCapturingAudio(WebContents webContents); protected static native boolean nativeIsCapturingAudio(WebContents webContents);
protected static native boolean nativeIsCapturingVideo(WebContents webContents); protected static native boolean nativeIsCapturingVideo(WebContents webContents);
protected static native boolean nativeHasAudibleAudio(WebContents webContents);
} }
...@@ -371,3 +371,10 @@ jboolean IsCapturingVideo(JNIEnv* env, ...@@ -371,3 +371,10 @@ jboolean IsCapturingVideo(JNIEnv* env,
return indicator->IsCapturingVideo(web_contents); return indicator->IsCapturingVideo(web_contents);
} }
jboolean HasAudibleAudio(JNIEnv* env,
jclass clazz,
jobject java_web_contents) {
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(java_web_contents);
return web_contents->WasRecentlyAudible();
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/media_players_observer.h"
#include <climits>
#include "base/logging.h"
#include "content/public/browser/web_contents.h"
namespace content {
MediaPlayersObserver::MediaPlayersObserver(WebContents* web_contents)
: AudioStateProvider(web_contents) {
}
MediaPlayersObserver::~MediaPlayersObserver() {}
bool MediaPlayersObserver::IsAudioStateAvailable() const {
return true;
}
// This audio state provider does not have a monitor
AudioStreamMonitor* MediaPlayersObserver::audio_stream_monitor() {
return nullptr;
}
void MediaPlayersObserver::OnAudibleStateChanged(RenderFrameHost* rfh,
int player_id,
bool is_audible) {
audio_status_map_[Key(rfh, player_id)] = is_audible;
UpdateStatusAndNotify();
}
void MediaPlayersObserver::RemovePlayer(RenderFrameHost* rfh, int player_id) {
size_t num_erased_entries = audio_status_map_.erase(Key(rfh, player_id));
DCHECK_EQ(1u, num_erased_entries);
UpdateStatusAndNotify();
}
void MediaPlayersObserver::RenderFrameDeleted(RenderFrameHost* rfh) {
StatusMap::iterator begin = audio_status_map_.lower_bound(Key(rfh, 0));
StatusMap::iterator end = audio_status_map_.upper_bound(Key(rfh, INT_MAX));
audio_status_map_.erase(begin, end);
UpdateStatusAndNotify();
}
void MediaPlayersObserver::UpdateStatusAndNotify() {
for (const auto& player_status : audio_status_map_) {
if (player_status.second) {
Notify(true); // at least one player is making noise
return;
}
}
Notify(false);
}
} // namespace content
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
#define CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
#include <map>
#include "base/macros.h"
#include "content/browser/media/audio_state_provider.h"
namespace content {
class RenderFrameHost;
// On Android the MediaPlayerAndroid objects report
// the audible state to us.
class MediaPlayersObserver : public AudioStateProvider {
public:
explicit MediaPlayersObserver(WebContents* web_contents);
~MediaPlayersObserver() override;
bool IsAudioStateAvailable() const override;
// This audio state provider does not have a monitor,
// the method returns nullptr.
AudioStreamMonitor* audio_stream_monitor() override;
// These methods constitute the observer pattern, should
// be called when corresponding event happens. They will notify
// WebContents whenever its audible state as a whole changes.
void OnAudibleStateChanged(RenderFrameHost* rfh, int player_id,
bool is_audible);
void RemovePlayer(RenderFrameHost* rfh, int player_id);
void RenderFrameDeleted(RenderFrameHost* rfh);
private:
void UpdateStatusAndNotify();
// Audible status per player ID and frame
typedef std::pair<RenderFrameHost*, int> Key;
typedef std::map<Key, bool> StatusMap;
StatusMap audio_status_map_;
DISALLOW_COPY_AND_ASSIGN(MediaPlayersObserver);
};
} // namespace content
#endif // CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "content/browser/android/content_view_core_impl.h" #include "content/browser/android/content_view_core_impl.h"
#include "content/browser/android/media_players_observer.h"
#include "content/browser/media/android/browser_demuxer_android.h" #include "content/browser/media/android/browser_demuxer_android.h"
#include "content/browser/media/android/media_resource_getter_impl.h" #include "content/browser/media/android/media_resource_getter_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h"
...@@ -57,10 +58,11 @@ void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor( ...@@ -57,10 +58,11 @@ void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
// static // static
BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create( BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
RenderFrameHost* rfh) { RenderFrameHost* rfh,
MediaPlayersObserver* audio_monitor) {
if (g_factory) if (g_factory)
return g_factory(rfh); return g_factory(rfh, audio_monitor);
return new BrowserMediaPlayerManager(rfh); return new BrowserMediaPlayerManager(rfh, audio_monitor);
} }
ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const { ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
...@@ -121,8 +123,10 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer( ...@@ -121,8 +123,10 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
} }
BrowserMediaPlayerManager::BrowserMediaPlayerManager( BrowserMediaPlayerManager::BrowserMediaPlayerManager(
RenderFrameHost* render_frame_host) RenderFrameHost* render_frame_host,
MediaPlayersObserver* audio_monitor)
: render_frame_host_(render_frame_host), : render_frame_host_(render_frame_host),
audio_monitor_(audio_monitor),
fullscreen_player_id_(kInvalidMediaPlayerId), fullscreen_player_id_(kInvalidMediaPlayerId),
fullscreen_player_is_released_(false), fullscreen_player_is_released_(false),
web_contents_(WebContents::FromRenderFrameHost(render_frame_host)), web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
...@@ -254,6 +258,12 @@ void BrowserMediaPlayerManager::OnVideoSizeChanged( ...@@ -254,6 +258,12 @@ void BrowserMediaPlayerManager::OnVideoSizeChanged(
video_view_->OnVideoSizeChanged(width, height); video_view_->OnVideoSizeChanged(width, height);
} }
void BrowserMediaPlayerManager::OnAudibleStateChanged(
int player_id, bool is_audible) {
audio_monitor_->OnAudibleStateChanged(
render_frame_host_, player_id, is_audible);
}
media::MediaResourceGetter* media::MediaResourceGetter*
BrowserMediaPlayerManager::GetMediaResourceGetter() { BrowserMediaPlayerManager::GetMediaResourceGetter() {
if (!media_resource_getter_.get()) { if (!media_resource_getter_.get()) {
...@@ -518,6 +528,7 @@ void BrowserMediaPlayerManager::RemovePlayer(int player_id) { ...@@ -518,6 +528,7 @@ void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
if ((*it)->player_id() == player_id) { if ((*it)->player_id() == player_id) {
ReleaseMediaResources(player_id); ReleaseMediaResources(player_id);
players_.erase(it); players_.erase(it);
audio_monitor_->RemovePlayer(render_frame_host_, player_id);
break; break;
} }
} }
......
...@@ -30,6 +30,7 @@ namespace content { ...@@ -30,6 +30,7 @@ namespace content {
class BrowserDemuxerAndroid; class BrowserDemuxerAndroid;
class ContentViewCoreImpl; class ContentViewCoreImpl;
class ExternalVideoSurfaceContainer; class ExternalVideoSurfaceContainer;
class MediaPlayersObserver;
class RenderFrameHost; class RenderFrameHost;
class WebContents; class WebContents;
...@@ -42,7 +43,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager ...@@ -42,7 +43,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
: public media::MediaPlayerManager { : public media::MediaPlayerManager {
public: public:
// Permits embedders to provide an extended version of the class. // Permits embedders to provide an extended version of the class.
typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*); typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*,
MediaPlayersObserver*);
static void RegisterFactory(Factory factory); static void RegisterFactory(Factory factory);
// Permits embedders to handle custom urls. // Permits embedders to handle custom urls.
...@@ -50,7 +52,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager ...@@ -50,7 +52,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
media::MediaUrlInterceptor* media_url_interceptor); media::MediaUrlInterceptor* media_url_interceptor);
// Returns a new instance using the registered factory if available. // Returns a new instance using the registered factory if available.
static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh); static BrowserMediaPlayerManager* Create(
RenderFrameHost* rfh,
MediaPlayersObserver* audio_monitor);
ContentViewCoreImpl* GetContentViewCore() const; ContentViewCoreImpl* GetContentViewCore() const;
...@@ -83,6 +87,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager ...@@ -83,6 +87,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
const base::TimeDelta& current_time) override; const base::TimeDelta& current_time) override;
void OnError(int player_id, int error) override; void OnError(int player_id, int error) override;
void OnVideoSizeChanged(int player_id, int width, int height) override; void OnVideoSizeChanged(int player_id, int width, int height) override;
void OnAudibleStateChanged(
int player_id, bool is_audible_now) override;
media::MediaResourceGetter* GetMediaResourceGetter() override; media::MediaResourceGetter* GetMediaResourceGetter() override;
media::MediaUrlInterceptor* GetMediaUrlInterceptor() override; media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
media::MediaPlayerAndroid* GetFullscreenPlayer() override; media::MediaPlayerAndroid* GetFullscreenPlayer() override;
...@@ -118,7 +125,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager ...@@ -118,7 +125,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
protected: protected:
// Clients must use Create() or subclass constructor. // Clients must use Create() or subclass constructor.
explicit BrowserMediaPlayerManager(RenderFrameHost* render_frame_host); BrowserMediaPlayerManager(RenderFrameHost* render_frame_host,
MediaPlayersObserver* audio_monitor);
WebContents* web_contents() const { return web_contents_; } WebContents* web_contents() const { return web_contents_; }
...@@ -168,6 +176,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager ...@@ -168,6 +176,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
RenderFrameHost* const render_frame_host_; RenderFrameHost* const render_frame_host_;
MediaPlayersObserver* audio_monitor_;
// An array of managed players. // An array of managed players.
ScopedVector<media::MediaPlayerAndroid> players_; ScopedVector<media::MediaPlayerAndroid> players_;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/media/audio_state_provider.h"
#include "base/logging.h"
#include "content/browser/media/audio_stream_monitor.h"
#include "content/public/browser/web_contents.h"
namespace content {
AudioStateProvider::AudioStateProvider(WebContents* contents)
: web_contents_(contents),
was_recently_audible_(false) {
DCHECK(web_contents_);
}
bool AudioStateProvider::WasRecentlyAudible() const {
return was_recently_audible_;
}
void AudioStateProvider::Notify(bool new_state) {
if (was_recently_audible_ != new_state) {
was_recently_audible_ = new_state;
web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
}
}
} // namespace content
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
#define CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
#include "content/common/content_export.h"
namespace content {
class WebContents;
class AudioStreamMonitor;
// This class is associated with a WebContents, and maintains the audible
// state regarding all the players in it.
// The audible state is true if at least one player is playing a sound.
// Whenever the audible state of the WebContents as a whole changes, this
// class sends a notification to it.
//
// Each WebContentsImpl owns an AudioStateProvider
class CONTENT_EXPORT AudioStateProvider {
public:
explicit AudioStateProvider(WebContents* web_contents);
virtual ~AudioStateProvider() {}
// Indicates whether this service is available on the system.
virtual bool IsAudioStateAvailable() const = 0;
// If this provider uses monitoring (i.e. measure the signal),
// return its monitor.
virtual AudioStreamMonitor* audio_stream_monitor() = 0;
// Returns true if the WebContents is playing or has recently been
// playing the sound.
virtual bool WasRecentlyAudible() const;
void set_was_recently_audible_for_testing(bool value) {
was_recently_audible_ = value;
}
protected:
// Notify WebContents that the audio state has changed.
void Notify(bool new_state);
// The WebContents instance instance to receive indicator toggle
// notifications. This pointer should be valid for the lifetime of
// AudioStreamMonitor.
WebContents* const web_contents_;
// The audio state that is being maintained
bool was_recently_audible_;
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
...@@ -21,23 +21,36 @@ AudioStreamMonitor* AudioStreamMonitorFromRenderFrame(int render_process_id, ...@@ -21,23 +21,36 @@ AudioStreamMonitor* AudioStreamMonitorFromRenderFrame(int render_process_id,
WebContentsImpl* const web_contents = WebContentsImpl* const web_contents =
static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost( static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(
RenderFrameHost::FromID(render_process_id, render_frame_id))); RenderFrameHost::FromID(render_process_id, render_frame_id)));
return web_contents ? web_contents->audio_stream_monitor() : NULL;
if (!web_contents)
return nullptr;
AudioStateProvider* audio_provider = web_contents->audio_state_provider();
return audio_provider ? audio_provider->audio_stream_monitor() : nullptr;
} }
} // namespace } // namespace
AudioStreamMonitor::AudioStreamMonitor(WebContents* contents) AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
: web_contents_(contents), : AudioStateProvider(contents),
clock_(&default_tick_clock_), clock_(&default_tick_clock_)
was_recently_audible_(false) { {
DCHECK(web_contents_);
} }
AudioStreamMonitor::~AudioStreamMonitor() {} AudioStreamMonitor::~AudioStreamMonitor() {}
bool AudioStreamMonitor::IsAudioStateAvailable() const {
return media::AudioOutputController::will_monitor_audio_levels();
}
// This provider is the monitor.
AudioStreamMonitor* AudioStreamMonitor::audio_stream_monitor() {
return this;
}
bool AudioStreamMonitor::WasRecentlyAudible() const { bool AudioStreamMonitor::WasRecentlyAudible() const {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
return was_recently_audible_; return AudioStateProvider::WasRecentlyAudible();
} }
// static // static
...@@ -46,7 +59,7 @@ void AudioStreamMonitor::StartMonitoringStream( ...@@ -46,7 +59,7 @@ void AudioStreamMonitor::StartMonitoringStream(
int render_frame_id, int render_frame_id,
int stream_id, int stream_id,
const ReadPowerAndClipCallback& read_power_callback) { const ReadPowerAndClipCallback& read_power_callback) {
if (!monitoring_available()) if (!media::AudioOutputController::will_monitor_audio_levels())
return; return;
BrowserThread::PostTask(BrowserThread::UI, BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE, FROM_HERE,
...@@ -61,7 +74,7 @@ void AudioStreamMonitor::StartMonitoringStream( ...@@ -61,7 +74,7 @@ void AudioStreamMonitor::StartMonitoringStream(
void AudioStreamMonitor::StopMonitoringStream(int render_process_id, void AudioStreamMonitor::StopMonitoringStream(int render_process_id,
int render_frame_id, int render_frame_id,
int stream_id) { int stream_id) {
if (!monitoring_available()) if (!media::AudioOutputController::will_monitor_audio_levels())
return; return;
BrowserThread::PostTask(BrowserThread::UI, BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE, FROM_HERE,
...@@ -138,16 +151,12 @@ void AudioStreamMonitor::Poll() { ...@@ -138,16 +151,12 @@ void AudioStreamMonitor::Poll() {
} }
void AudioStreamMonitor::MaybeToggle() { void AudioStreamMonitor::MaybeToggle() {
const bool indicator_was_on = was_recently_audible_;
const base::TimeTicks off_time = const base::TimeTicks off_time =
last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds); last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
const base::TimeTicks now = clock_->NowTicks(); const base::TimeTicks now = clock_->NowTicks();
const bool should_indicator_be_on = now < off_time; const bool should_indicator_be_on = now < off_time;
if (should_indicator_be_on != indicator_was_on) { Notify(should_indicator_be_on);
was_recently_audible_ = should_indicator_be_on;
web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
}
if (!should_indicator_be_on) { if (!should_indicator_be_on) {
off_timer_.Stop(); off_timer_.Stop();
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/browser/media/audio_state_provider.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "media/audio/audio_output_controller.h" #include "media/audio/audio_output_controller.h"
...@@ -22,7 +23,6 @@ class TickClock; ...@@ -22,7 +23,6 @@ class TickClock;
} }
namespace content { namespace content {
class WebContents;
// Repeatedly polls audio streams for their power levels, and "debounces" the // Repeatedly polls audio streams for their power levels, and "debounces" the
// information into a simple, binary "was recently audible" result for the audio // information into a simple, binary "was recently audible" result for the audio
...@@ -32,23 +32,23 @@ class WebContents; ...@@ -32,23 +32,23 @@ class WebContents;
// to turn on/off repeatedly and annoy the user. AudioStreamMonitor sends UI // to turn on/off repeatedly and annoy the user. AudioStreamMonitor sends UI
// update notifications only when needed, but may be queried at any time. // update notifications only when needed, but may be queried at any time.
// //
// Each WebContentsImpl owns an AudioStreamMonitor. class CONTENT_EXPORT AudioStreamMonitor : public AudioStateProvider {
class CONTENT_EXPORT AudioStreamMonitor {
public: public:
explicit AudioStreamMonitor(WebContents* contents); explicit AudioStreamMonitor(WebContents* contents);
~AudioStreamMonitor(); ~AudioStreamMonitor() override;
// Indicates if audio stream monitoring is available. It's only available if // Indicates if audio stream monitoring is available. It's only available if
// AudioOutputController can and will monitor output power levels. // AudioOutputController can and will monitor output power levels.
static bool monitoring_available() { bool IsAudioStateAvailable() const override;
return media::AudioOutputController::will_monitor_audio_levels();
} // This provider is a monitor, the method returns |this|.
AudioStreamMonitor* audio_stream_monitor() override;
// Returns true if audio has recently been audible from the tab. This is // Returns true if audio has recently been audible from the tab. This is
// usually called whenever the tab data model is refreshed; but there are // usually called whenever the tab data model is refreshed; but there are
// other use cases as well (e.g., the OOM killer uses this to de-prioritize // other use cases as well (e.g., the OOM killer uses this to de-prioritize
// the killing of tabs making sounds). // the killing of tabs making sounds).
bool WasRecentlyAudible() const; bool WasRecentlyAudible() const override;
// Starts or stops audio level monitoring respectively for the stream owned by // Starts or stops audio level monitoring respectively for the stream owned by
// the specified renderer. Safe to call from any thread. // the specified renderer. Safe to call from any thread.
...@@ -66,10 +66,6 @@ class CONTENT_EXPORT AudioStreamMonitor { ...@@ -66,10 +66,6 @@ class CONTENT_EXPORT AudioStreamMonitor {
int render_frame_id, int render_frame_id,
int stream_id); int stream_id);
void set_was_recently_audible_for_testing(bool value) {
was_recently_audible_ = value;
}
private: private:
friend class AudioStreamMonitorTest; friend class AudioStreamMonitorTest;
...@@ -112,11 +108,6 @@ class CONTENT_EXPORT AudioStreamMonitor { ...@@ -112,11 +108,6 @@ class CONTENT_EXPORT AudioStreamMonitor {
// on, |off_timer_| is started to re-invoke this method in the future. // on, |off_timer_| is started to re-invoke this method in the future.
void MaybeToggle(); void MaybeToggle();
// The WebContents instance instance to receive indicator toggle
// notifications. This pointer should be valid for the lifetime of
// AudioStreamMonitor.
WebContents* const web_contents_;
// Note: |clock_| is always |&default_tick_clock_|, except during unit // Note: |clock_| is always |&default_tick_clock_|, except during unit
// testing. // testing.
base::DefaultTickClock default_tick_clock_; base::DefaultTickClock default_tick_clock_;
...@@ -134,10 +125,6 @@ class CONTENT_EXPORT AudioStreamMonitor { ...@@ -134,10 +125,6 @@ class CONTENT_EXPORT AudioStreamMonitor {
// Records the last time at which sound was audible from any stream. // Records the last time at which sound was audible from any stream.
base::TimeTicks last_blurt_time_; base::TimeTicks last_blurt_time_;
// Set to true if the last call to MaybeToggle() determined the indicator
// should be turned on.
bool was_recently_audible_;
// Calls Poll() at regular intervals while |poll_callbacks_| is non-empty. // Calls Poll() at regular intervals while |poll_callbacks_| is non-empty.
base::RepeatingTimer<AudioStreamMonitor> poll_timer_; base::RepeatingTimer<AudioStreamMonitor> poll_timer_;
......
...@@ -52,7 +52,13 @@ class AudioStreamMonitorTest : public RenderViewHostTestHarness { ...@@ -52,7 +52,13 @@ class AudioStreamMonitorTest : public RenderViewHostTestHarness {
WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>( WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>(
RenderViewHostTestHarness::web_contents()); RenderViewHostTestHarness::web_contents());
web_contents->SetDelegate(&mock_web_contents_delegate_); web_contents->SetDelegate(&mock_web_contents_delegate_);
monitor_ = web_contents->audio_stream_monitor();
AudioStateProvider* provider = web_contents->audio_state_provider();
ASSERT_TRUE(provider);
monitor_ = provider->audio_stream_monitor();
ASSERT_TRUE(monitor_);
const_cast<base::TickClock*&>(monitor_->clock_) = &clock_; const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
} }
......
...@@ -8,11 +8,13 @@ ...@@ -8,11 +8,13 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "content/browser/media/cdm/browser_cdm_manager.h" #include "content/browser/media/cdm/browser_cdm_manager.h"
#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_macros.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "content/browser/android/media_players_observer.h"
#include "content/browser/media/android/browser_media_player_manager.h" #include "content/browser/media/android/browser_media_player_manager.h"
#include "content/common/media/media_player_messages_android.h" #include "content/common/media/media_player_messages_android.h"
#include "media/base/android/media_player_android.h" #include "media/base/android/media_player_android.h"
...@@ -22,7 +24,8 @@ namespace content { ...@@ -22,7 +24,8 @@ namespace content {
MediaWebContentsObserver::MediaWebContentsObserver( MediaWebContentsObserver::MediaWebContentsObserver(
WebContents* web_contents) WebContents* web_contents)
: WebContentsObserver(web_contents) { : WebContentsObserver(web_contents)
{
} }
MediaWebContentsObserver::~MediaWebContentsObserver() { MediaWebContentsObserver::~MediaWebContentsObserver() {
...@@ -35,6 +38,10 @@ void MediaWebContentsObserver::RenderFrameDeleted( ...@@ -35,6 +38,10 @@ void MediaWebContentsObserver::RenderFrameDeleted(
// Always destroy the media players before CDMs because we do not support // Always destroy the media players before CDMs because we do not support
// detaching CDMs from media players yet. See http://crbug.com/330324 // detaching CDMs from media players yet. See http://crbug.com/330324
media_player_managers_.erase(key); media_player_managers_.erase(key);
MediaPlayersObserver* audio_observer = GetMediaPlayersObserver();
if (audio_observer)
audio_observer->RenderFrameDeleted(render_frame_host);
#endif #endif
// TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
// and BrowserCdmManager all run on browser UI thread. So this call is okay. // and BrowserCdmManager all run on browser UI thread. So this call is okay.
...@@ -161,11 +168,24 @@ BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager( ...@@ -161,11 +168,24 @@ BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager(
if (!media_player_managers_.contains(key)) { if (!media_player_managers_.contains(key)) {
media_player_managers_.set( media_player_managers_.set(
key, key,
make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host))); make_scoped_ptr(BrowserMediaPlayerManager::Create(
render_frame_host, GetMediaPlayersObserver())));
} }
return media_player_managers_.get(key); return media_player_managers_.get(key);
} }
MediaPlayersObserver*
MediaWebContentsObserver::GetMediaPlayersObserver() const {
AudioStateProvider* provider =
static_cast<WebContentsImpl*>(web_contents())->audio_state_provider();
MediaPlayersObserver* audio_observer =
static_cast<MediaPlayersObserver*>(provider);
DCHECK(audio_observer);
return audio_observer;
}
#if defined(VIDEO_HOLE) #if defined(VIDEO_HOLE)
void MediaWebContentsObserver::OnFrameInfoUpdated() { void MediaWebContentsObserver::OnFrameInfoUpdated() {
for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin(); for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
......
...@@ -7,11 +7,16 @@ ...@@ -7,11 +7,16 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/containers/scoped_ptr_hash_map.h" #include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
namespace content { namespace content {
#if defined(OS_ANDROID)
class MediaPlayersObserver;
#endif // defined(OS_ANDROID)
class BrowserCdmManager; class BrowserCdmManager;
class BrowserMediaPlayerManager; class BrowserMediaPlayerManager;
...@@ -45,6 +50,8 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver { ...@@ -45,6 +50,8 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id); void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
MediaPlayersObserver* GetMediaPlayersObserver() const;
#if defined(VIDEO_HOLE) #if defined(VIDEO_HOLE)
void OnFrameInfoUpdated(); void OnFrameInfoUpdated();
#endif // defined(VIDEO_HOLE) #endif // defined(VIDEO_HOLE)
......
...@@ -108,6 +108,7 @@ ...@@ -108,6 +108,7 @@
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "content/browser/android/content_video_view.h" #include "content/browser/android/content_video_view.h"
#include "content/browser/android/date_time_chooser_android.h" #include "content/browser/android/date_time_chooser_android.h"
#include "content/browser/android/media_players_observer.h"
#include "content/browser/media/android/browser_media_player_manager.h" #include "content/browser/media/android/browser_media_player_manager.h"
#include "content/browser/web_contents/web_contents_android.h" #include "content/browser/web_contents/web_contents_android.h"
#endif #endif
...@@ -358,7 +359,6 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context, ...@@ -358,7 +359,6 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
geolocation_service_context_(new GeolocationServiceContext()), geolocation_service_context_(new GeolocationServiceContext()),
accessibility_mode_( accessibility_mode_(
BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()), BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
audio_stream_monitor_(this),
virtual_keyboard_requested_(false), virtual_keyboard_requested_(false),
loading_weak_factory_(this) { loading_weak_factory_(this) {
frame_tree_.SetFrameRemoveListener( frame_tree_.SetFrameRemoveListener(
...@@ -367,6 +367,12 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context, ...@@ -367,6 +367,12 @@ WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
#if defined(ENABLE_BROWSER_CDMS) #if defined(ENABLE_BROWSER_CDMS)
media_web_contents_observer_.reset(new MediaWebContentsObserver(this)); media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
#endif #endif
#if defined(OS_ANDROID)
audio_state_provider_.reset(new MediaPlayersObserver(this));
#else
audio_state_provider_.reset(new AudioStreamMonitor(this));
#endif
} }
WebContentsImpl::~WebContentsImpl() { WebContentsImpl::~WebContentsImpl() {
...@@ -1041,7 +1047,7 @@ void WebContentsImpl::NotifyNavigationStateChanged( ...@@ -1041,7 +1047,7 @@ void WebContentsImpl::NotifyNavigationStateChanged(
// Create and release the audio power save blocker depending on whether the // Create and release the audio power save blocker depending on whether the
// tab is actively producing audio or not. // tab is actively producing audio or not.
if ((changed_flags & INVALIDATE_TYPE_TAB) && if ((changed_flags & INVALIDATE_TYPE_TAB) &&
AudioStreamMonitor::monitoring_available()) { audio_state_provider_->IsAudioStateAvailable()) {
if (WasRecentlyAudible()) { if (WasRecentlyAudible()) {
if (!audio_power_save_blocker_) if (!audio_power_save_blocker_)
CreateAudioPowerSaveBlocker(); CreateAudioPowerSaveBlocker();
...@@ -2523,7 +2529,7 @@ void WebContentsImpl::InsertCSS(const std::string& css) { ...@@ -2523,7 +2529,7 @@ void WebContentsImpl::InsertCSS(const std::string& css) {
} }
bool WebContentsImpl::WasRecentlyAudible() { bool WebContentsImpl::WasRecentlyAudible() {
return audio_stream_monitor_.WasRecentlyAudible(); return audio_state_provider_->WasRecentlyAudible();
} }
void WebContentsImpl::GetManifest(const GetManifestCallback& callback) { void WebContentsImpl::GetManifest(const GetManifestCallback& callback) {
...@@ -3210,7 +3216,7 @@ void WebContentsImpl::MaybeReleasePowerSaveBlockers() { ...@@ -3210,7 +3216,7 @@ void WebContentsImpl::MaybeReleasePowerSaveBlockers() {
// monitoring, release the audio power save blocker here instead of during // monitoring, release the audio power save blocker here instead of during
// NotifyNavigationStateChanged(). // NotifyNavigationStateChanged().
if (active_audio_players_.empty() && if (active_audio_players_.empty() &&
!AudioStreamMonitor::monitoring_available()) { !audio_state_provider_->IsAudioStateAvailable()) {
audio_power_save_blocker_.reset(); audio_power_save_blocker_.reset();
} }
...@@ -3233,7 +3239,7 @@ void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie, ...@@ -3233,7 +3239,7 @@ void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
// If we don't have audio stream monitoring, allocate the audio power save // If we don't have audio stream monitoring, allocate the audio power save
// blocker here instead of during NotifyNavigationStateChanged(). // blocker here instead of during NotifyNavigationStateChanged().
if (!audio_power_save_blocker_ && if (!audio_power_save_blocker_ &&
!AudioStreamMonitor::monitoring_available()) { !audio_state_provider_->IsAudioStateAvailable()) {
CreateAudioPowerSaveBlocker(); CreateAudioPowerSaveBlocker();
} }
} }
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "content/browser/frame_host/navigator_delegate.h" #include "content/browser/frame_host/navigator_delegate.h"
#include "content/browser/frame_host/render_frame_host_delegate.h" #include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_manager.h" #include "content/browser/frame_host/render_frame_host_manager.h"
#include "content/browser/media/audio_stream_monitor.h" #include "content/browser/media/audio_state_provider.h"
#include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h" #include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/common/accessibility_mode_enums.h" #include "content/common/accessibility_mode_enums.h"
...@@ -669,8 +669,8 @@ class CONTENT_EXPORT WebContentsImpl ...@@ -669,8 +669,8 @@ class CONTENT_EXPORT WebContentsImpl
// Forces overscroll to be disabled (used by touch emulation). // Forces overscroll to be disabled (used by touch emulation).
void SetForceDisableOverscrollContent(bool force_disable); void SetForceDisableOverscrollContent(bool force_disable);
AudioStreamMonitor* audio_stream_monitor() { AudioStateProvider* audio_state_provider() {
return &audio_stream_monitor_; return audio_state_provider_.get();
} }
bool has_audio_power_save_blocker_for_testing() const { bool has_audio_power_save_blocker_for_testing() const {
...@@ -1025,6 +1025,11 @@ class CONTENT_EXPORT WebContentsImpl ...@@ -1025,6 +1025,11 @@ class CONTENT_EXPORT WebContentsImpl
scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_; scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_;
scoped_ptr<PowerSaveBlocker> video_power_save_blocker_; scoped_ptr<PowerSaveBlocker> video_power_save_blocker_;
// Tells whether this WebContents is actively producing sound.
// Order is important: the |frame_tree_| destruction uses
// |audio_state_provider_|.
scoped_ptr<AudioStateProvider> audio_state_provider_;
// Manages the frame tree of the page and process swaps in each node. // Manages the frame tree of the page and process swaps in each node.
FrameTree frame_tree_; FrameTree frame_tree_;
...@@ -1239,9 +1244,6 @@ class CONTENT_EXPORT WebContentsImpl ...@@ -1239,9 +1244,6 @@ class CONTENT_EXPORT WebContentsImpl
// is created, and broadcast to all frames when it changes. // is created, and broadcast to all frames when it changes.
AccessibilityMode accessibility_mode_; AccessibilityMode accessibility_mode_;
// Monitors power levels for audio streams associated with this WebContents.
AudioStreamMonitor audio_stream_monitor_;
// Created on-demand to mute all audio output from this WebContents. // Created on-demand to mute all audio output from this WebContents.
scoped_ptr<WebContentsAudioMuter> audio_muter_; scoped_ptr<WebContentsAudioMuter> audio_muter_;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "content/browser/frame_host/interstitial_page_impl.h" #include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/media/audio_stream_monitor.h" #include "content/browser/media/audio_state_provider.h"
#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h" #include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h" #include "content/browser/webui/web_ui_controller_factory_registry.h"
...@@ -2891,20 +2891,20 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2891,20 +2891,20 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
TestRenderFrameHost* rfh = contents()->GetMainFrame(); TestRenderFrameHost* rfh = contents()->GetMainFrame();
AudioStreamMonitor* monitor = contents()->audio_stream_monitor(); AudioStateProvider* audio_state = contents()->audio_state_provider();
// The audio power save blocker should not be based on having a media player // The audio power save blocker should not be based on having a media player
// when audio stream monitoring is available. // when audio stream monitoring is available.
if (AudioStreamMonitor::monitoring_available()) { if (audio_state->IsAudioStateAvailable()) {
// Send a fake audio stream monitor notification. The audio power save // Send a fake audio stream monitor notification. The audio power save
// blocker should be created. // blocker should be created.
monitor->set_was_recently_audible_for_testing(true); audio_state->set_was_recently_audible_for_testing(true);
contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing()); EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
// Send another fake notification, this time when WasRecentlyAudible() will // Send another fake notification, this time when WasRecentlyAudible() will
// be false. The power save blocker should be released. // be false. The power save blocker should be released.
monitor->set_was_recently_audible_for_testing(false); audio_state->set_was_recently_audible_for_testing(false);
contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing()); EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
} }
...@@ -2916,7 +2916,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2916,7 +2916,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
0, kPlayerAudioVideoId, true, true, false)); 0, kPlayerAudioVideoId, true, true, false));
EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
!AudioStreamMonitor::monitoring_available()); !audio_state->IsAudioStateAvailable());
// Upon hiding the video power save blocker should be released. // Upon hiding the video power save blocker should be released.
contents()->WasHidden(); contents()->WasHidden();
...@@ -2929,7 +2929,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2929,7 +2929,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
0, kPlayerVideoOnlyId, true, false, false)); 0, kPlayerVideoOnlyId, true, false, false));
EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
!AudioStreamMonitor::monitoring_available()); !audio_state->IsAudioStateAvailable());
// Showing the WebContents should result in the creation of the blocker. // Showing the WebContents should result in the creation of the blocker.
contents()->WasShown(); contents()->WasShown();
...@@ -2941,7 +2941,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2941,7 +2941,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
0, kPlayerAudioOnlyId, false, true, false)); 0, kPlayerAudioOnlyId, false, true, false));
EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
!AudioStreamMonitor::monitoring_available()); !audio_state->IsAudioStateAvailable());
// Start a remote player. There should be no change in the power save // Start a remote player. There should be no change in the power save
// blockers. // blockers.
...@@ -2949,7 +2949,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2949,7 +2949,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
0, kPlayerRemoteId, true, true, true)); 0, kPlayerRemoteId, true, true, true));
EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
!AudioStreamMonitor::monitoring_available()); !audio_state->IsAudioStateAvailable());
// Destroy the original audio video player. Both power save blockers should // Destroy the original audio video player. Both power save blockers should
// remain. // remain.
...@@ -2957,7 +2957,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2957,7 +2957,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId)); FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
!AudioStreamMonitor::monitoring_available()); !audio_state->IsAudioStateAvailable());
// Destroy the audio only player. The video power save blocker should remain. // Destroy the audio only player. The video power save blocker should remain.
rfh->OnMessageReceived( rfh->OnMessageReceived(
...@@ -2984,7 +2984,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) { ...@@ -2984,7 +2984,7 @@ TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
0, kPlayerAudioVideoId, true, true, false)); 0, kPlayerAudioVideoId, true, true, false));
EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing()); EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(), EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
!AudioStreamMonitor::monitoring_available()); !audio_state->IsAudioStateAvailable());
// Crash the renderer. // Crash the renderer.
contents()->GetMainFrame()->OnMessageReceived( contents()->GetMainFrame()->OnMessageReceived(
......
...@@ -355,6 +355,8 @@ ...@@ -355,6 +355,8 @@
'browser/android/interstitial_page_delegate_android.h', 'browser/android/interstitial_page_delegate_android.h',
'browser/android/load_url_params.cc', 'browser/android/load_url_params.cc',
'browser/android/load_url_params.h', 'browser/android/load_url_params.h',
'browser/android/media_players_observer.cc',
'browser/android/media_players_observer.h',
'browser/android/overscroll_controller_android.cc', 'browser/android/overscroll_controller_android.cc',
'browser/android/overscroll_controller_android.h', 'browser/android/overscroll_controller_android.h',
'browser/android/overscroll_glow.cc', 'browser/android/overscroll_glow.cc',
...@@ -928,6 +930,8 @@ ...@@ -928,6 +930,8 @@
'browser/media/android/media_drm_credential_manager.h', 'browser/media/android/media_drm_credential_manager.h',
'browser/media/android/media_resource_getter_impl.cc', 'browser/media/android/media_resource_getter_impl.cc',
'browser/media/android/media_resource_getter_impl.h', 'browser/media/android/media_resource_getter_impl.h',
'browser/media/audio_state_provider.cc',
'browser/media/audio_state_provider.h',
'browser/media/audio_stream_monitor.cc', 'browser/media/audio_stream_monitor.cc',
'browser/media/audio_stream_monitor.h', 'browser/media/audio_stream_monitor.h',
'browser/media/capture/audio_mirroring_manager.cc', 'browser/media/capture/audio_mirroring_manager.cc',
......
...@@ -1120,6 +1120,7 @@ ...@@ -1120,6 +1120,7 @@
'sources!': [ 'sources!': [
'browser/geolocation/network_location_provider_unittest.cc', 'browser/geolocation/network_location_provider_unittest.cc',
'browser/geolocation/wifi_data_provider_common_unittest.cc', 'browser/geolocation/wifi_data_provider_common_unittest.cc',
'browser/media/audio_stream_monitor_unittest.cc',
'browser/webui/url_data_manager_backend_unittest.cc', 'browser/webui/url_data_manager_backend_unittest.cc',
], ],
'dependencies': [ 'dependencies': [
......
...@@ -21,6 +21,7 @@ MediaPlayerAndroid::MediaPlayerAndroid( ...@@ -21,6 +21,7 @@ MediaPlayerAndroid::MediaPlayerAndroid(
player_id_(player_id), player_id_(player_id),
manager_(manager), manager_(manager),
frame_url_(frame_url), frame_url_(frame_url),
is_audible_(false),
weak_factory_(this) { weak_factory_(this) {
listener_.reset(new MediaPlayerListener(base::MessageLoopProxy::current(), listener_.reset(new MediaPlayerListener(base::MessageLoopProxy::current(),
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
...@@ -79,5 +80,11 @@ void MediaPlayerAndroid::DetachListener() { ...@@ -79,5 +80,11 @@ void MediaPlayerAndroid::DetachListener() {
listener_->ReleaseMediaPlayerListenerResources(); listener_->ReleaseMediaPlayerListenerResources();
} }
void MediaPlayerAndroid::SetAudible(bool is_audible) {
if (is_audible_ != is_audible) {
is_audible_ = is_audible;
manager_->OnAudibleStateChanged(player_id(), is_audible_);
}
}
} // namespace media } // namespace media
...@@ -102,6 +102,7 @@ class MEDIA_EXPORT MediaPlayerAndroid { ...@@ -102,6 +102,7 @@ class MEDIA_EXPORT MediaPlayerAndroid {
// events. Otherwise, it also listens to the events from |j_media_player|. // events. Otherwise, it also listens to the events from |j_media_player|.
void AttachListener(jobject j_media_player); void AttachListener(jobject j_media_player);
void DetachListener(); void DetachListener();
void SetAudible(bool is_audible);
MediaPlayerManager* manager() { return manager_; } MediaPlayerManager* manager() { return manager_; }
...@@ -122,6 +123,9 @@ class MEDIA_EXPORT MediaPlayerAndroid { ...@@ -122,6 +123,9 @@ class MEDIA_EXPORT MediaPlayerAndroid {
// Listener object that listens to all the media player events. // Listener object that listens to all the media player events.
scoped_ptr<MediaPlayerListener> listener_; scoped_ptr<MediaPlayerListener> listener_;
// Maintains the audible state of the player, true if it is playing sound.
bool is_audible_;
// Weak pointer passed to |listener_| for callbacks. // Weak pointer passed to |listener_| for callbacks.
// NOTE: Weak pointers must be invalidated before all other member variables. // NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<MediaPlayerAndroid> weak_factory_; base::WeakPtrFactory<MediaPlayerAndroid> weak_factory_;
......
...@@ -355,6 +355,8 @@ void MediaPlayerBridge::Release() { ...@@ -355,6 +355,8 @@ void MediaPlayerBridge::Release() {
if (j_media_player_bridge_.is_null()) if (j_media_player_bridge_.is_null())
return; return;
SetAudible(false);
time_update_timer_.Stop(); time_update_timer_.Stop();
if (prepared_) { if (prepared_) {
pending_seek_ = GetCurrentTime(); pending_seek_ = GetCurrentTime();
...@@ -371,15 +373,22 @@ void MediaPlayerBridge::Release() { ...@@ -371,15 +373,22 @@ void MediaPlayerBridge::Release() {
} }
void MediaPlayerBridge::SetVolume(double volume) { void MediaPlayerBridge::SetVolume(double volume) {
if (j_media_player_bridge_.is_null()) { volume_ = volume;
volume_ = volume;
if (j_media_player_bridge_.is_null())
return; return;
}
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env); CHECK(env);
// Update the audible state if we are playing.
jboolean is_playing = Java_MediaPlayerBridge_isPlaying(
env, j_media_player_bridge_.obj());
if (is_playing)
SetAudible(volume_ > 0);
Java_MediaPlayerBridge_setVolume( Java_MediaPlayerBridge_setVolume(
env, j_media_player_bridge_.obj(), volume); env, j_media_player_bridge_.obj(), volume_);
} }
void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) { void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
...@@ -389,11 +398,13 @@ void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) { ...@@ -389,11 +398,13 @@ void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
} }
void MediaPlayerBridge::OnPlaybackComplete() { void MediaPlayerBridge::OnPlaybackComplete() {
SetAudible(false);
time_update_timer_.Stop(); time_update_timer_.Stop();
MediaPlayerAndroid::OnPlaybackComplete(); MediaPlayerAndroid::OnPlaybackComplete();
} }
void MediaPlayerBridge::OnMediaInterrupted() { void MediaPlayerBridge::OnMediaInterrupted() {
SetAudible(false);
time_update_timer_.Stop(); time_update_timer_.Stop();
MediaPlayerAndroid::OnMediaInterrupted(); MediaPlayerAndroid::OnMediaInterrupted();
} }
...@@ -453,9 +464,13 @@ void MediaPlayerBridge::StartInternal() { ...@@ -453,9 +464,13 @@ void MediaPlayerBridge::StartInternal() {
base::TimeDelta::FromMilliseconds(kTimeUpdateInterval), base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
this, &MediaPlayerBridge::OnTimeUpdateTimerFired); this, &MediaPlayerBridge::OnTimeUpdateTimerFired);
} }
SetAudible(volume_ > 0);
} }
void MediaPlayerBridge::PauseInternal() { void MediaPlayerBridge::PauseInternal() {
SetAudible(false);
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj()); Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj());
time_update_timer_.Stop(); time_update_timer_.Stop();
......
...@@ -63,6 +63,9 @@ class MEDIA_EXPORT MediaPlayerManager { ...@@ -63,6 +63,9 @@ class MEDIA_EXPORT MediaPlayerManager {
// Called when video size has changed. Args: player ID, width, height. // Called when video size has changed. Args: player ID, width, height.
virtual void OnVideoSizeChanged(int player_id, int width, int height) = 0; virtual void OnVideoSizeChanged(int player_id, int width, int height) = 0;
// Called when the player thinks it stopped or started making sound.
virtual void OnAudibleStateChanged(int player_id, bool is_audible_now) = 0;
// Returns the player that's in the fullscreen mode currently. // Returns the player that's in the fullscreen mode currently.
virtual MediaPlayerAndroid* GetFullscreenPlayer() = 0; virtual MediaPlayerAndroid* GetFullscreenPlayer() = 0;
......
...@@ -75,6 +75,7 @@ class MockMediaPlayerManager : public MediaPlayerManager { ...@@ -75,6 +75,7 @@ class MockMediaPlayerManager : public MediaPlayerManager {
const base::TimeDelta& current_time) override {} const base::TimeDelta& current_time) override {}
void OnError(int player_id, int error) override {} void OnError(int player_id, int error) override {}
void OnVideoSizeChanged(int player_id, int width, int height) override {} void OnVideoSizeChanged(int player_id, int width, int height) override {}
void OnAudibleStateChanged(int player_id, bool is_audible_now) override {}
MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; } MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; }
MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; } MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; }
void RequestFullScreen(int player_id) override {} void RequestFullScreen(int player_id) override {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment