| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "content/browser/media/audio_stream_monitor.h" | 
|  | 6 | 
|  | 7 #include "base/bind.h" | 
|  | 8 #include "base/bind_helpers.h" | 
|  | 9 #include "content/browser/web_contents/web_contents_impl.h" | 
|  | 10 #include "content/public/browser/browser_thread.h" | 
|  | 11 #include "content/public/browser/invalidate_type.h" | 
|  | 12 #include "content/public/browser/render_frame_host.h" | 
|  | 13 | 
|  | 14 namespace content { | 
|  | 15 | 
|  | 16 namespace { | 
|  | 17 | 
|  | 18 AudioStreamMonitor* AudioStreamMonitorFromRenderFrame(int render_process_id, | 
|  | 19                                                       int render_frame_id) { | 
|  | 20   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  | 21   WebContentsImpl* const web_contents = | 
|  | 22       static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost( | 
|  | 23           RenderFrameHost::FromID(render_process_id, render_frame_id))); | 
|  | 24   return web_contents ? web_contents->audio_stream_monitor() : NULL; | 
|  | 25 } | 
|  | 26 | 
|  | 27 }  // namespace | 
|  | 28 | 
|  | 29 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents) | 
|  | 30     : web_contents_(contents), | 
|  | 31       clock_(&default_tick_clock_), | 
|  | 32       was_recently_audible_(false) { | 
|  | 33   DCHECK(web_contents_); | 
|  | 34 } | 
|  | 35 | 
|  | 36 AudioStreamMonitor::~AudioStreamMonitor() {} | 
|  | 37 | 
|  | 38 bool AudioStreamMonitor::WasRecentlyAudible() const { | 
|  | 39   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 40   return was_recently_audible_; | 
|  | 41 } | 
|  | 42 | 
|  | 43 // static | 
|  | 44 void AudioStreamMonitor::StartMonitoringStream( | 
|  | 45     int render_process_id, | 
|  | 46     int render_frame_id, | 
|  | 47     int stream_id, | 
|  | 48     const ReadPowerAndClipCallback& read_power_callback) { | 
|  | 49   if (!monitoring_available()) | 
|  | 50     return; | 
|  | 51   BrowserThread::PostTask(BrowserThread::UI, | 
|  | 52                           FROM_HERE, | 
|  | 53                           base::Bind(&StartMonitoringHelper, | 
|  | 54                                      render_process_id, | 
|  | 55                                      render_frame_id, | 
|  | 56                                      stream_id, | 
|  | 57                                      read_power_callback)); | 
|  | 58 } | 
|  | 59 | 
|  | 60 // static | 
|  | 61 void AudioStreamMonitor::StopMonitoringStream(int render_process_id, | 
|  | 62                                               int render_frame_id, | 
|  | 63                                               int stream_id) { | 
|  | 64   if (!monitoring_available()) | 
|  | 65     return; | 
|  | 66   BrowserThread::PostTask(BrowserThread::UI, | 
|  | 67                           FROM_HERE, | 
|  | 68                           base::Bind(&StopMonitoringHelper, | 
|  | 69                                      render_process_id, | 
|  | 70                                      render_frame_id, | 
|  | 71                                      stream_id)); | 
|  | 72 } | 
|  | 73 | 
|  | 74 // static | 
|  | 75 void AudioStreamMonitor::StartMonitoringHelper( | 
|  | 76     int render_process_id, | 
|  | 77     int render_frame_id, | 
|  | 78     int stream_id, | 
|  | 79     const ReadPowerAndClipCallback& read_power_callback) { | 
|  | 80   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  | 81   AudioStreamMonitor* const monitor = | 
|  | 82       AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id); | 
|  | 83   if (monitor) { | 
|  | 84     monitor->StartMonitoringStreamOnUIThread( | 
|  | 85         render_process_id, stream_id, read_power_callback); | 
|  | 86   } | 
|  | 87 } | 
|  | 88 | 
|  | 89 // static | 
|  | 90 void AudioStreamMonitor::StopMonitoringHelper(int render_process_id, | 
|  | 91                                               int render_frame_id, | 
|  | 92                                               int stream_id) { | 
|  | 93   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  | 94   AudioStreamMonitor* const monitor = | 
|  | 95       AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id); | 
|  | 96   if (monitor) | 
|  | 97     monitor->StopMonitoringStreamOnUIThread(render_process_id, stream_id); | 
|  | 98 } | 
|  | 99 | 
|  | 100 void AudioStreamMonitor::StartMonitoringStreamOnUIThread( | 
|  | 101     int render_process_id, | 
|  | 102     int stream_id, | 
|  | 103     const ReadPowerAndClipCallback& read_power_callback) { | 
|  | 104   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 105   DCHECK(!read_power_callback.is_null()); | 
|  | 106   poll_callbacks_[StreamID(render_process_id, stream_id)] = read_power_callback; | 
|  | 107   if (!poll_timer_.IsRunning()) { | 
|  | 108     poll_timer_.Start( | 
|  | 109         FROM_HERE, | 
|  | 110         base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond, | 
|  | 111         base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this))); | 
|  | 112   } | 
|  | 113 } | 
|  | 114 | 
|  | 115 void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id, | 
|  | 116                                                         int stream_id) { | 
|  | 117   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 118   poll_callbacks_.erase(StreamID(render_process_id, stream_id)); | 
|  | 119   if (poll_callbacks_.empty()) | 
|  | 120     poll_timer_.Stop(); | 
|  | 121 } | 
|  | 122 | 
|  | 123 void AudioStreamMonitor::Poll() { | 
|  | 124   for (StreamPollCallbackMap::const_iterator it = poll_callbacks_.begin(); | 
|  | 125        it != poll_callbacks_.end(); | 
|  | 126        ++it) { | 
|  | 127     // TODO(miu): A new UI for delivering specific power level and clipping | 
|  | 128     // information is still in the works.  For now, we throw away all | 
|  | 129     // information except for "is it audible?" | 
|  | 130     const float power_dbfs = it->second.Run().first; | 
|  | 131     const float kSilenceThresholdDBFS = -72.24719896f; | 
|  | 132     if (power_dbfs >= kSilenceThresholdDBFS) { | 
|  | 133       last_blurt_time_ = clock_->NowTicks(); | 
|  | 134       MaybeToggle(); | 
|  | 135       break;  // No need to poll remaining streams. | 
|  | 136     } | 
|  | 137   } | 
|  | 138 } | 
|  | 139 | 
|  | 140 void AudioStreamMonitor::MaybeToggle() { | 
|  | 141   const bool indicator_was_on = was_recently_audible_; | 
|  | 142   const base::TimeTicks off_time = | 
|  | 143       last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds); | 
|  | 144   const base::TimeTicks now = clock_->NowTicks(); | 
|  | 145   const bool should_indicator_be_on = now < off_time; | 
|  | 146 | 
|  | 147   if (should_indicator_be_on != indicator_was_on) { | 
|  | 148     was_recently_audible_ = should_indicator_be_on; | 
|  | 149     web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); | 
|  | 150   } | 
|  | 151 | 
|  | 152   if (!should_indicator_be_on) { | 
|  | 153     off_timer_.Stop(); | 
|  | 154   } else if (!off_timer_.IsRunning()) { | 
|  | 155     off_timer_.Start( | 
|  | 156         FROM_HERE, | 
|  | 157         off_time - now, | 
|  | 158         base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this))); | 
|  | 159   } | 
|  | 160 } | 
|  | 161 | 
|  | 162 }  // namespace content | 
| OLD | NEW | 
|---|