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