OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/memory/shared_memory.h" | |
15 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
16 #include "content/browser/bad_message.h" | 14 #include "content/browser/bad_message.h" |
17 #include "content/browser/browser_main_loop.h" | 15 #include "content/browser/browser_main_loop.h" |
18 #include "content/browser/media/audio_stream_monitor.h" | 16 #include "content/browser/media/audio_stream_monitor.h" |
19 #include "content/browser/media/capture/audio_mirroring_manager.h" | 17 #include "content/browser/media/capture/audio_mirroring_manager.h" |
20 #include "content/browser/media/media_internals.h" | 18 #include "content/browser/media/media_internals.h" |
21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 19 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
22 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 20 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
23 #include "content/browser/renderer_host/media/media_stream_manager.h" | 21 #include "content/browser/renderer_host/media/media_stream_manager.h" |
24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | 22 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
(...skipping 22 matching lines...) Expand all Loading... | |
47 std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData( | 45 std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData( |
48 int stream_id, | 46 int stream_id, |
49 bool authorized, | 47 bool authorized, |
50 const std::string& device_unique_id) { | 48 const std::string& device_unique_id) { |
51 return std::make_pair(stream_id, | 49 return std::make_pair(stream_id, |
52 std::make_pair(authorized, device_unique_id)); | 50 std::make_pair(authorized, device_unique_id)); |
53 } | 51 } |
54 | 52 |
55 | 53 |
56 void NotifyRenderProcessHostThatAudioStateChanged(int render_process_id) { | 54 void NotifyRenderProcessHostThatAudioStateChanged(int render_process_id) { |
57 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 55 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
56 BrowserThread::PostTask( | |
57 BrowserThread::UI, FROM_HERE, | |
58 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | |
59 render_process_id)); | |
60 return; | |
61 } | |
58 | 62 |
59 RenderProcessHost* render_process_host = | 63 RenderProcessHost* render_process_host = |
60 RenderProcessHost::FromID(render_process_id); | 64 RenderProcessHost::FromID(render_process_id); |
61 | 65 |
62 if (render_process_host) | 66 if (render_process_host) |
63 render_process_host->AudioStateChanged(); | 67 render_process_host->AudioStateChanged(); |
64 } | 68 } |
65 | 69 |
66 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { | 70 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { |
67 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", | 71 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", |
68 base::TimeTicks::Now() - auth_start_time, | 72 base::TimeTicks::Now() - auth_start_time, |
69 base::TimeDelta::FromMilliseconds(1), | 73 base::TimeDelta::FromMilliseconds(1), |
70 base::TimeDelta::FromMilliseconds(5000), 50); | 74 base::TimeDelta::FromMilliseconds(5000), 50); |
71 } | 75 } |
72 | 76 |
73 // Check that the routing ID references a valid RenderFrameHost, and run | 77 // Check that the routing ID references a valid RenderFrameHost, and run |
74 // |callback| on the IO thread with true if the ID is valid. | 78 // |callback| on the IO thread with true if the ID is valid. |
75 void ValidateRenderFrameId(int render_process_id, | 79 void ValidateRenderFrameId(int render_process_id, |
76 int render_frame_id, | 80 int render_frame_id, |
77 const base::Callback<void(bool)>& callback) { | 81 const base::Callback<void(bool)>& callback) { |
78 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 82 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
79 const bool frame_exists = | 83 const bool frame_exists = |
80 !!RenderFrameHost::FromID(render_process_id, render_frame_id); | 84 !!RenderFrameHost::FromID(render_process_id, render_frame_id); |
81 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 85 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
82 base::Bind(callback, frame_exists)); | 86 base::Bind(callback, frame_exists)); |
83 } | 87 } |
84 | 88 |
85 } // namespace | 89 } // namespace |
86 | 90 |
87 class AudioRendererHost::AudioEntry | |
88 : public media::AudioOutputController::EventHandler { | |
89 public: | |
90 ~AudioEntry() override; | |
91 | |
92 // Returns nullptr on failure. | |
93 static std::unique_ptr<AudioRendererHost::AudioEntry> Create( | |
94 AudioRendererHost* host, | |
95 int stream_id, | |
96 int render_frame_id, | |
97 const media::AudioParameters& params, | |
98 const std::string& output_device_id); | |
99 | |
100 int stream_id() const { | |
101 return stream_id_; | |
102 } | |
103 | |
104 int render_frame_id() const { return render_frame_id_; } | |
105 | |
106 media::AudioOutputController* controller() const { return controller_.get(); } | |
107 | |
108 AudioSyncReader* reader() const { return reader_.get(); } | |
109 | |
110 // Used by ARH to track the number of active streams for UMA stats. | |
111 bool playing() const { return playing_; } | |
112 void set_playing(bool playing) { playing_ = playing; } | |
113 | |
114 private: | |
115 AudioEntry(AudioRendererHost* host, | |
116 int stream_id, | |
117 int render_frame_id, | |
118 const media::AudioParameters& params, | |
119 const std::string& output_device_id, | |
120 std::unique_ptr<AudioSyncReader> reader); | |
121 | |
122 // media::AudioOutputController::EventHandler implementation. | |
123 void OnCreated() override; | |
124 void OnPlaying() override; | |
125 void OnPaused() override; | |
126 void OnError() override; | |
127 | |
128 AudioRendererHost* const host_; | |
129 const int stream_id_; | |
130 | |
131 // The routing ID of the source RenderFrame. | |
132 const int render_frame_id_; | |
133 | |
134 // The synchronous reader to be used by |controller_|. | |
135 const std::unique_ptr<AudioSyncReader> reader_; | |
136 | |
137 // The AudioOutputController that manages the audio stream. | |
138 const scoped_refptr<media::AudioOutputController> controller_; | |
139 | |
140 bool playing_; | |
141 | |
142 DISALLOW_COPY_AND_ASSIGN(AudioEntry); | |
143 }; | |
144 | |
145 AudioRendererHost::AudioEntry::AudioEntry( | |
146 AudioRendererHost* host, | |
147 int stream_id, | |
148 int render_frame_id, | |
149 const media::AudioParameters& params, | |
150 const std::string& output_device_id, | |
151 std::unique_ptr<AudioSyncReader> reader) | |
152 : host_(host), | |
153 stream_id_(stream_id), | |
154 render_frame_id_(render_frame_id), | |
155 reader_(std::move(reader)), | |
156 controller_(media::AudioOutputController::Create(host->audio_manager_, | |
157 this, | |
158 params, | |
159 output_device_id, | |
160 reader_.get())), | |
161 playing_(false) { | |
162 DCHECK(controller_); | |
163 } | |
164 | |
165 AudioRendererHost::AudioEntry::~AudioEntry() {} | |
166 | |
167 // static | |
168 std::unique_ptr<AudioRendererHost::AudioEntry> | |
169 AudioRendererHost::AudioEntry::Create(AudioRendererHost* host, | |
170 int stream_id, | |
171 int render_frame_id, | |
172 const media::AudioParameters& params, | |
173 const std::string& output_device_id) { | |
174 std::unique_ptr<AudioSyncReader> reader(AudioSyncReader::Create(params)); | |
175 if (!reader) { | |
176 return nullptr; | |
177 } | |
178 return base::WrapUnique(new AudioEntry(host, stream_id, render_frame_id, | |
179 params, output_device_id, | |
180 std::move(reader))); | |
181 } | |
182 | |
183 /////////////////////////////////////////////////////////////////////////////// | 91 /////////////////////////////////////////////////////////////////////////////// |
184 // AudioRendererHost implementations. | 92 // AudioRendererHost implementations. |
185 | 93 |
186 AudioRendererHost::AudioRendererHost(int render_process_id, | 94 AudioRendererHost::AudioRendererHost(int render_process_id, |
187 media::AudioManager* audio_manager, | 95 media::AudioManager* audio_manager, |
188 AudioMirroringManager* mirroring_manager, | 96 AudioMirroringManager* mirroring_manager, |
189 MediaInternals* media_internals, | |
190 MediaStreamManager* media_stream_manager, | 97 MediaStreamManager* media_stream_manager, |
191 const std::string& salt) | 98 const std::string& salt) |
192 : BrowserMessageFilter(AudioMsgStart), | 99 : BrowserMessageFilter(AudioMsgStart), |
193 render_process_id_(render_process_id), | 100 render_process_id_(render_process_id), |
194 audio_manager_(audio_manager), | 101 audio_manager_(audio_manager), |
195 mirroring_manager_(mirroring_manager), | 102 mirroring_manager_(mirroring_manager), |
196 audio_log_(media_internals->CreateAudioLog( | 103 media_stream_manager_(media_stream_manager), |
197 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | |
198 num_playing_streams_(0), | 104 num_playing_streams_(0), |
199 salt_(salt), | 105 salt_(salt), |
200 validate_render_frame_id_function_(&ValidateRenderFrameId), | 106 validate_render_frame_id_function_(&ValidateRenderFrameId), |
201 max_simultaneous_streams_(0), | 107 max_simultaneous_streams_(0), |
202 authorization_handler_(media_stream_manager, render_process_id_, salt) { | 108 authorization_handler_(media_stream_manager, render_process_id_, salt) { |
203 DCHECK(audio_manager_); | 109 DCHECK(audio_manager_); |
204 } | 110 } |
205 | 111 |
206 AudioRendererHost::~AudioRendererHost() { | 112 AudioRendererHost::~AudioRendererHost() { |
207 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 113 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
208 CHECK(audio_entries_.empty()); | 114 CHECK(delegates_.empty()); |
209 | 115 |
210 // If we had any streams, report UMA stats for the maximum number of | 116 // If we had any streams, report UMA stats for the maximum number of |
211 // simultaneous streams for this render process and for the whole browser | 117 // simultaneous streams for this render process and for the whole browser |
212 // process since last reported. | 118 // process since last reported. |
213 if (max_simultaneous_streams_ > 0) { | 119 if (max_simultaneous_streams_ > 0) { |
214 UMA_HISTOGRAM_CUSTOM_COUNTS("Media.AudioRendererIpcStreams", | 120 UMA_HISTOGRAM_CUSTOM_COUNTS("Media.AudioRendererIpcStreams", |
215 max_simultaneous_streams_, 1, 50, 51); | 121 max_simultaneous_streams_, 1, 50, 51); |
216 UMA_HISTOGRAM_CUSTOM_COUNTS( | 122 UMA_HISTOGRAM_CUSTOM_COUNTS( |
217 "Media.AudioRendererIpcStreamsTotal", | 123 "Media.AudioRendererIpcStreamsTotal", |
218 g_audio_streams_tracker.Get().max_stream_count(), | 124 g_audio_streams_tracker.Get().max_stream_count(), |
219 1, 100, 101); | 125 1, 100, 101); |
220 g_audio_streams_tracker.Get().ResetMaxStreamCount(); | 126 g_audio_streams_tracker.Get().ResetMaxStreamCount(); |
221 } | 127 } |
222 } | 128 } |
223 | 129 |
224 void AudioRendererHost::GetOutputControllers( | 130 void AudioRendererHost::GetOutputControllers( |
225 const RenderProcessHost::GetAudioOutputControllersCallback& | 131 const RenderProcessHost::GetAudioOutputControllersCallback& |
226 callback) const { | 132 callback) const { |
227 BrowserThread::PostTaskAndReplyWithResult( | 133 BrowserThread::PostTaskAndReplyWithResult( |
228 BrowserThread::IO, FROM_HERE, | 134 BrowserThread::IO, FROM_HERE, |
229 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); | 135 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); |
230 } | 136 } |
231 | 137 |
232 void AudioRendererHost::OnChannelClosing() { | 138 void AudioRendererHost::OnChannelClosing() { |
233 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 139 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
234 // Since the IPC sender is gone, close all requested audio streams. | 140 // Since the IPC sender is gone, close all requested audio streams. |
235 while (!audio_entries_.empty()) { | 141 g_audio_streams_tracker.Get().DecreaseStreamCount(delegates_.size()); |
o1ka
2016/11/22 13:24:04
Comment that OnCloseStream won't be called, and th
Max Morin
2016/11/22 16:04:29
Done.
| |
236 // Note: OnCloseStream() removes the entries from audio_entries_. | 142 delegates_.clear(); |
237 OnCloseStream(audio_entries_.begin()->first); | |
238 } | |
239 | 143 |
240 // Remove any authorizations for streams that were not yet created | 144 // Remove any authorizations for streams that were not yet created |
241 authorizations_.clear(); | 145 authorizations_.clear(); |
242 } | 146 } |
243 | 147 |
244 void AudioRendererHost::OnDestruct() const { | 148 void AudioRendererHost::OnDestruct() const { |
245 BrowserThread::DeleteOnIOThread::Destruct(this); | 149 BrowserThread::DeleteOnIOThread::Destruct(this); |
246 } | 150 } |
247 | 151 |
248 void AudioRendererHost::AudioEntry::OnCreated() { | 152 void AudioRendererHost::OnStreamCreated( |
249 BrowserThread::PostTask( | 153 int stream_id, |
250 BrowserThread::IO, | 154 base::SharedMemory* shared_memory, |
251 FROM_HERE, | 155 base::CancelableSyncSocket* foreign_socket) { |
252 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_)); | |
253 } | |
254 | |
255 void AudioRendererHost::AudioEntry::OnPlaying() { | |
256 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
257 base::Bind(&AudioRendererHost::StreamStateChanged, | |
258 host_, stream_id_, true)); | |
259 } | |
260 | |
261 void AudioRendererHost::AudioEntry::OnPaused() { | |
262 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
263 base::Bind(&AudioRendererHost::StreamStateChanged, | |
264 host_, stream_id_, false)); | |
265 } | |
266 | |
267 void AudioRendererHost::AudioEntry::OnError() { | |
268 BrowserThread::PostTask( | |
269 BrowserThread::IO, | |
270 FROM_HERE, | |
271 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_)); | |
272 } | |
273 | |
274 void AudioRendererHost::DoCompleteCreation(int stream_id) { | |
275 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 156 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
276 | 157 |
277 if (!PeerHandle()) { | 158 if (!PeerHandle()) { |
278 DLOG(WARNING) << "Renderer process handle is invalid."; | 159 DLOG(WARNING) << "Renderer process handle is invalid."; |
279 ReportErrorAndClose(stream_id); | 160 OnStreamError(stream_id); |
280 return; | 161 return; |
281 } | 162 } |
282 | 163 |
283 AudioEntry* const entry = LookupById(stream_id); | 164 if (!LookupById(stream_id)) { |
284 if (!entry) { | 165 SendErrorMessage(stream_id); |
285 ReportErrorAndClose(stream_id); | |
286 return; | 166 return; |
287 } | 167 } |
288 | 168 |
289 // Now construction is done and we are ready to send the shared memory and the | |
290 // sync socket to the renderer. | |
291 base::SharedMemory* shared_memory = entry->reader()->shared_memory(); | |
292 base::CancelableSyncSocket* foreign_socket = | |
293 entry->reader()->foreign_socket(); | |
294 | |
295 base::SharedMemoryHandle foreign_memory_handle; | 169 base::SharedMemoryHandle foreign_memory_handle; |
296 base::SyncSocket::TransitDescriptor socket_descriptor; | 170 base::SyncSocket::TransitDescriptor socket_descriptor; |
297 size_t shared_memory_size = shared_memory->requested_size(); | 171 size_t shared_memory_size = shared_memory->requested_size(); |
298 | 172 |
173 // TODO(maxmorin): Figure out how/if this is safe, since shared_memory is also | |
174 // accessed on the audio thread. | |
299 if (!(shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle) && | 175 if (!(shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle) && |
300 foreign_socket->PrepareTransitDescriptor(PeerHandle(), | 176 foreign_socket->PrepareTransitDescriptor(PeerHandle(), |
301 &socket_descriptor))) { | 177 &socket_descriptor))) { |
302 // Something went wrong in preparing the IPC handles. | 178 // Something went wrong in preparing the IPC handles. |
303 ReportErrorAndClose(entry->stream_id()); | 179 OnStreamError(stream_id); |
304 return; | 180 return; |
305 } | 181 } |
306 | 182 |
307 Send(new AudioMsg_NotifyStreamCreated( | 183 Send(new AudioMsg_NotifyStreamCreated( |
308 stream_id, foreign_memory_handle, socket_descriptor, | 184 stream_id, foreign_memory_handle, socket_descriptor, |
309 base::checked_cast<uint32_t>(shared_memory_size))); | 185 base::checked_cast<uint32_t>(shared_memory_size))); |
310 } | 186 } |
311 | 187 |
188 void AudioRendererHost::OnStreamStateChanged(bool is_playing) { | |
189 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
190 if (is_playing) { | |
191 base::AtomicRefCountInc(&num_playing_streams_); | |
192 | |
193 // Inform the RenderProcessHost when audio starts playing for the first | |
194 // time. The nonatomic increment-and-read is ok since this is the only | |
195 // thread that |num_plaing_streams| may be updated on. | |
196 if (base::AtomicRefCountIsOne(&num_playing_streams_)) | |
197 NotifyRenderProcessHostThatAudioStateChanged(render_process_id_); | |
198 } else { | |
199 // Inform the RenderProcessHost when there is no more audio playing. | |
200 if (!base::AtomicRefCountDec(&num_playing_streams_)) | |
201 NotifyRenderProcessHostThatAudioStateChanged(render_process_id_); | |
202 } | |
203 } | |
204 | |
205 void AudioRendererHost::OnStreamError(int stream_id) { | |
206 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
207 | |
208 SendErrorMessage(stream_id); | |
209 | |
210 OnCloseStream(stream_id); | |
211 } | |
212 | |
312 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { | 213 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { |
313 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 214 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
314 | 215 |
315 if (!is_valid) { | 216 if (!is_valid) { |
316 DLOG(WARNING) << "Render frame for stream (id=" << stream_id | 217 DLOG(WARNING) << "Render frame for stream (id=" << stream_id |
317 << ") no longer exists."; | 218 << ") no longer exists."; |
318 ReportErrorAndClose(stream_id); | 219 OnStreamError(stream_id); |
319 } | 220 } |
320 } | 221 } |
321 | 222 |
322 void AudioRendererHost::StreamStateChanged(int stream_id, bool is_playing) { | |
323 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
324 | |
325 AudioEntry* const entry = LookupById(stream_id); | |
326 if (!entry) | |
327 return; | |
328 | |
329 if (is_playing) { | |
330 AudioStreamMonitor::StartMonitoringStream( | |
331 render_process_id_, | |
332 entry->render_frame_id(), | |
333 entry->stream_id(), | |
334 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, | |
335 entry->controller())); | |
336 } else { | |
337 AudioStreamMonitor::StopMonitoringStream( | |
338 render_process_id_, entry->render_frame_id(), entry->stream_id()); | |
339 } | |
340 UpdateNumPlayingStreams(entry, is_playing); | |
341 } | |
342 | |
343 RenderProcessHost::AudioOutputControllerList | 223 RenderProcessHost::AudioOutputControllerList |
344 AudioRendererHost::DoGetOutputControllers() const { | 224 AudioRendererHost::DoGetOutputControllers() const { |
345 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 225 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
346 | 226 |
347 RenderProcessHost::AudioOutputControllerList controllers; | 227 RenderProcessHost::AudioOutputControllerList controllers; |
348 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); | 228 for (const auto& delegate : delegates_) |
349 it != audio_entries_.end(); | 229 controllers.push_back(delegate->controller()); |
350 ++it) { | |
351 controllers.push_back(it->second->controller()); | |
352 } | |
353 | 230 |
354 return controllers; | 231 return controllers; |
355 } | 232 } |
356 | 233 |
357 /////////////////////////////////////////////////////////////////////////////// | 234 /////////////////////////////////////////////////////////////////////////////// |
358 // IPC Messages handler | 235 // IPC Messages handler |
359 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { | 236 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { |
360 bool handled = true; | 237 bool handled = true; |
361 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) | 238 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) |
362 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, | 239 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, |
(...skipping 15 matching lines...) Expand all Loading... | |
378 int session_id, | 255 int session_id, |
379 const std::string& device_id, | 256 const std::string& device_id, |
380 const url::Origin& security_origin) { | 257 const url::Origin& security_origin) { |
381 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 258 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
382 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); | 259 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); |
383 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" | 260 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" |
384 << "(stream_id=" << stream_id | 261 << "(stream_id=" << stream_id |
385 << ", render_frame_id=" << render_frame_id | 262 << ", render_frame_id=" << render_frame_id |
386 << ", session_id=" << session_id << ", device_id=" << device_id | 263 << ", session_id=" << session_id << ", device_id=" << device_id |
387 << ", security_origin=" << security_origin << ")"; | 264 << ", security_origin=" << security_origin << ")"; |
265 | |
388 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) | 266 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) |
389 return; | 267 return; |
390 authorizations_.insert(MakeAuthorizationData(stream_id, false, device_id)); | 268 authorizations_.insert(MakeAuthorizationData(stream_id, false, device_id)); |
391 // Unretained is ok here since |this| owns |authorization_handler_| and | 269 // Unretained is ok here since |this| owns |authorization_handler_| and |
392 // |authorization_handler_| owns the callback. | 270 // |authorization_handler_| owns the callback. |
393 authorization_handler_.RequestDeviceAuthorization( | 271 authorization_handler_.RequestDeviceAuthorization( |
394 render_frame_id, session_id, device_id, security_origin, | 272 render_frame_id, session_id, device_id, security_origin, |
395 base::Bind(&AudioRendererHost::AuthorizationCompleted, | 273 base::Bind(&AudioRendererHost::AuthorizationCompleted, |
396 base::Unretained(this), stream_id, security_origin, | 274 base::Unretained(this), stream_id, security_origin, |
397 auth_start_time)); | 275 auth_start_time)); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
449 // to create it now. | 327 // to create it now. |
450 content::bad_message::ReceivedBadMessage( | 328 content::bad_message::ReceivedBadMessage( |
451 this, bad_message::ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION); | 329 this, bad_message::ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION); |
452 return; | 330 return; |
453 } | 331 } |
454 device_unique_id.swap(auth_data->second.second); | 332 device_unique_id.swap(auth_data->second.second); |
455 authorizations_.erase(auth_data); | 333 authorizations_.erase(auth_data); |
456 } | 334 } |
457 | 335 |
458 // Fail early if either of two sanity-checks fail: | 336 // Fail early if either of two sanity-checks fail: |
459 // 1. There should not yet exist an AudioEntry for the given |stream_id| | 337 // 1. There should not yet exist an AudioOutputDelegate for the given |
460 // since the renderer may not create two streams with the same ID. | 338 // |stream_id| since the renderer may not create two streams with the |
339 // same ID. | |
461 // 2. An out-of-range render frame ID was provided. Renderers must *always* | 340 // 2. An out-of-range render frame ID was provided. Renderers must *always* |
462 // specify a valid render frame ID for each audio output they create, as | 341 // specify a valid render frame ID for each audio output they create, as |
463 // several browser-level features depend on this (e.g., OOM manager, UI | 342 // several browser-level features depend on this (e.g., OOM manager, UI |
464 // audio indicator, muting, audio capture). | 343 // audio indicator, muting, audio capture). |
465 // Note: media::AudioParameters is validated in the deserializer, so there is | 344 // Note: media::AudioParameters is validated in the deserializer, so there is |
466 // no need to check that here. | 345 // no need to check that here. |
467 if (LookupById(stream_id)) { | 346 if (LookupById(stream_id)) { |
468 SendErrorMessage(stream_id); | 347 SendErrorMessage(stream_id); |
469 return; | 348 return; |
470 } | 349 } |
471 if (render_frame_id <= 0) { | 350 if (render_frame_id <= 0) { |
472 SendErrorMessage(stream_id); | 351 SendErrorMessage(stream_id); |
473 return; | 352 return; |
474 } | 353 } |
475 | 354 |
476 // Post a task to the UI thread to check that the |render_frame_id| references | 355 // Post a task to the UI thread to check that the |render_frame_id| references |
477 // a valid render frame. This validation is important for all the reasons | 356 // a valid render frame. This validation is important for all the reasons |
478 // stated in the comments above. This does not block stream creation, but will | 357 // stated in the comments above. This does not block stream creation, but will |
479 // force-close the stream later if validation fails. | 358 // force-close the stream later if validation fails. |
480 BrowserThread::PostTask( | 359 BrowserThread::PostTask( |
481 BrowserThread::UI, FROM_HERE, | 360 BrowserThread::UI, FROM_HERE, |
482 base::Bind(validate_render_frame_id_function_, render_process_id_, | 361 base::Bind(validate_render_frame_id_function_, render_process_id_, |
483 render_frame_id, | 362 render_frame_id, |
484 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, | 363 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, |
485 stream_id))); | 364 stream_id))); |
486 | 365 |
487 std::unique_ptr<AudioEntry> entry = AudioEntry::Create( | |
488 this, stream_id, render_frame_id, params, device_unique_id); | |
489 if (!entry) { | |
490 SendErrorMessage(stream_id); | |
491 return; | |
492 } | |
493 | |
494 MediaObserver* const media_observer = | 366 MediaObserver* const media_observer = |
495 GetContentClient()->browser()->GetMediaObserver(); | 367 GetContentClient()->browser()->GetMediaObserver(); |
496 if (media_observer) | |
497 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); | |
498 | 368 |
499 if (mirroring_manager_) { | 369 MediaInternals* const media_internals = MediaInternals::GetInstance(); |
500 mirroring_manager_->AddDiverter( | 370 std::unique_ptr<media::AudioLog> audio_log = media_internals->CreateAudioLog( |
501 render_process_id_, entry->render_frame_id(), entry->controller()); | 371 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER); |
502 } | 372 media_internals->SetWebContentsTitleForAudioLogEntry( |
503 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 373 stream_id, render_process_id_, render_frame_id, audio_log.get()); |
374 delegates_.push_back(AudioOutputDelegate::Create( | |
375 this, audio_manager_, std::move(audio_log), mirroring_manager_, | |
376 media_observer, stream_id, render_frame_id, render_process_id_, params, | |
377 device_unique_id)); | |
378 | |
504 g_audio_streams_tracker.Get().IncreaseStreamCount(); | 379 g_audio_streams_tracker.Get().IncreaseStreamCount(); |
505 | 380 |
506 audio_log_->OnCreated(stream_id, params, device_unique_id); | 381 if (delegates_.size() > max_simultaneous_streams_) |
507 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( | 382 max_simultaneous_streams_ = delegates_.size(); |
508 stream_id, render_process_id_, render_frame_id, audio_log_.get()); | |
509 | |
510 if (audio_entries_.size() > max_simultaneous_streams_) | |
511 max_simultaneous_streams_ = audio_entries_.size(); | |
512 } | 383 } |
513 | 384 |
514 void AudioRendererHost::OnPlayStream(int stream_id) { | 385 void AudioRendererHost::OnPlayStream(int stream_id) { |
515 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 386 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
516 | 387 |
517 AudioEntry* entry = LookupById(stream_id); | 388 AudioOutputDelegate* delegate = LookupById(stream_id); |
518 if (!entry) { | 389 if (!delegate) { |
519 SendErrorMessage(stream_id); | 390 SendErrorMessage(stream_id); |
520 return; | 391 return; |
521 } | 392 } |
522 | 393 |
523 entry->controller()->Play(); | 394 delegate->OnPlayStream(); |
524 audio_log_->OnStarted(stream_id); | |
525 } | 395 } |
526 | 396 |
527 void AudioRendererHost::OnPauseStream(int stream_id) { | 397 void AudioRendererHost::OnPauseStream(int stream_id) { |
528 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 398 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
529 | 399 |
530 AudioEntry* entry = LookupById(stream_id); | 400 AudioOutputDelegate* delegate = LookupById(stream_id); |
531 if (!entry) { | 401 if (!delegate) { |
532 SendErrorMessage(stream_id); | 402 SendErrorMessage(stream_id); |
533 return; | 403 return; |
534 } | 404 } |
535 | 405 |
536 entry->controller()->Pause(); | 406 delegate->OnPauseStream(); |
537 audio_log_->OnStopped(stream_id); | |
538 } | 407 } |
539 | 408 |
540 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { | 409 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { |
541 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 410 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
542 | 411 |
543 AudioEntry* entry = LookupById(stream_id); | 412 AudioOutputDelegate* delegate = LookupById(stream_id); |
544 if (!entry) { | 413 if (!delegate) { |
545 SendErrorMessage(stream_id); | 414 SendErrorMessage(stream_id); |
546 return; | 415 return; |
547 } | 416 } |
548 | 417 |
549 // Make sure the volume is valid. | 418 // Make sure the volume is valid. |
550 if (volume < 0 || volume > 1.0) | 419 if (volume < 0 || volume > 1.0) |
551 return; | 420 return; |
552 entry->controller()->SetVolume(volume); | 421 delegate->OnSetVolume(volume); |
553 audio_log_->OnSetVolume(stream_id, volume); | |
554 } | 422 } |
555 | 423 |
556 void AudioRendererHost::SendErrorMessage(int stream_id) { | 424 void AudioRendererHost::SendErrorMessage(int stream_id) { |
557 Send(new AudioMsg_NotifyStreamError(stream_id)); | 425 Send(new AudioMsg_NotifyStreamError(stream_id)); |
558 } | 426 } |
559 | 427 |
560 void AudioRendererHost::OnCloseStream(int stream_id) { | 428 void AudioRendererHost::OnCloseStream(int stream_id) { |
561 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 429 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
562 authorizations_.erase(stream_id); | 430 authorizations_.erase(stream_id); |
563 | 431 |
432 auto i = LookupIteratorById(stream_id); | |
433 | |
564 // Prevent oustanding callbacks from attempting to close/delete the same | 434 // Prevent oustanding callbacks from attempting to close/delete the same |
565 // AudioEntry twice. | 435 // AudioOutputDelegate twice. |
566 AudioEntryMap::iterator i = audio_entries_.find(stream_id); | 436 if (i == delegates_.end()) |
567 if (i == audio_entries_.end()) | |
568 return; | 437 return; |
569 std::unique_ptr<AudioEntry> entry(i->second); | 438 |
570 audio_entries_.erase(i); | 439 std::swap(*i, delegates_.back()); |
440 delegates_.pop_back(); | |
441 | |
571 g_audio_streams_tracker.Get().DecreaseStreamCount(); | 442 g_audio_streams_tracker.Get().DecreaseStreamCount(); |
572 | |
573 media::AudioOutputController* const controller = entry->controller(); | |
574 controller->Close( | |
575 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry))); | |
576 audio_log_->OnClosed(stream_id); | |
577 } | 443 } |
578 | 444 |
579 void AudioRendererHost::DeleteEntry(std::unique_ptr<AudioEntry> entry) { | 445 AudioRendererHost::AudioOutputDelegateList::iterator |
446 AudioRendererHost::LookupIteratorById(int stream_id) { | |
580 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 447 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
581 | 448 |
582 // De-register the controller from the AudioMirroringManager now that the | 449 return std::find_if(delegates_.begin(), delegates_.end(), |
583 // controller has closed the AudioOutputStream and shut itself down. This | 450 [stream_id](const AudioOutputDelegate::UniquePtr& d) { |
584 // ensures that calling RemoveDiverter() here won't trigger the controller to | 451 return d->stream_id() == stream_id; |
585 // re-start the default AudioOutputStream and cause a brief audio blip to come | 452 }); |
586 // out the user's speakers. http://crbug.com/474432 | |
587 if (mirroring_manager_) | |
588 mirroring_manager_->RemoveDiverter(entry->controller()); | |
589 | |
590 AudioStreamMonitor::StopMonitoringStream( | |
591 render_process_id_, entry->render_frame_id(), entry->stream_id()); | |
592 UpdateNumPlayingStreams(entry.get(), false); | |
593 } | 453 } |
594 | 454 |
595 void AudioRendererHost::ReportErrorAndClose(int stream_id) { | 455 AudioOutputDelegate* AudioRendererHost::LookupById(int stream_id) { |
596 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 456 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
597 | 457 |
598 // Make sure this isn't a stray callback executing after the stream has been | 458 auto i = LookupIteratorById(stream_id); |
599 // closed, so error notifications aren't sent after clients believe the stream | 459 return i != delegates_.end() ? i->get() : nullptr; |
600 // is closed. | |
601 if (!LookupById(stream_id)) | |
602 return; | |
603 | |
604 SendErrorMessage(stream_id); | |
605 | |
606 audio_log_->OnError(stream_id); | |
607 OnCloseStream(stream_id); | |
608 } | |
609 | |
610 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { | |
611 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
612 | |
613 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id); | |
614 return i != audio_entries_.end() ? i->second : NULL; | |
615 } | |
616 | |
617 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry, | |
618 bool is_playing) { | |
619 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
620 if (entry->playing() == is_playing) | |
621 return; | |
622 | |
623 if (is_playing) { | |
624 entry->set_playing(true); | |
625 base::AtomicRefCountInc(&num_playing_streams_); | |
626 | |
627 // Inform the RenderProcessHost when audio starts playing for the first | |
628 // time. | |
629 if (base::AtomicRefCountIsOne(&num_playing_streams_)) { | |
630 BrowserThread::PostTask( | |
631 BrowserThread::UI, FROM_HERE, | |
632 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | |
633 render_process_id_)); | |
634 } | |
635 } else { | |
636 entry->set_playing(false); | |
637 // Inform the RenderProcessHost when there is no more audio playing. | |
638 if (!base::AtomicRefCountDec(&num_playing_streams_)) { | |
639 BrowserThread::PostTask( | |
640 BrowserThread::UI, FROM_HERE, | |
641 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | |
642 render_process_id_)); | |
643 } | |
644 } | |
645 } | 460 } |
646 | 461 |
647 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 462 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { |
648 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 463 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
649 return authorizations_.find(stream_id) != authorizations_.end(); | 464 return authorizations_.find(stream_id) != authorizations_.end(); |
650 } | 465 } |
651 | 466 |
652 bool AudioRendererHost::HasActiveAudio() { | 467 bool AudioRendererHost::HasActiveAudio() { |
653 return !base::AtomicRefCountIsZero(&num_playing_streams_); | 468 return !base::AtomicRefCountIsZero(&num_playing_streams_); |
654 } | 469 } |
655 | 470 |
656 void AudioRendererHost::OverrideDevicePermissionsForTesting(bool has_access) { | 471 void AudioRendererHost::OverrideDevicePermissionsForTesting(bool has_access) { |
657 authorization_handler_.OverridePermissionsForTesting(has_access); | 472 authorization_handler_.OverridePermissionsForTesting(has_access); |
658 } | 473 } |
659 } // namespace content | 474 } // namespace content |
OLD | NEW |