Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: content/browser/renderer_host/media/audio_renderer_host.cc

Issue 2443573003: Factor out AudioOutputDelegate from AudioRendererHost. (Closed)
Patch Set: . Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 // The audio streams tracker isn't automatically decremented since the
236 // Note: OnCloseStream() removes the entries from audio_entries_. 142 // removal isn't done through OnCloseStream.
o1ka 2016/11/22 21:48:16 OnCloseStream won't be called because ...; so decr
Max Morin 2016/11/25 15:32:35 Not sure what you mean. OnCloseStream won't be cal
237 OnCloseStream(audio_entries_.begin()->first); 143 g_audio_streams_tracker.Get().DecreaseStreamCount(delegates_.size());
238 } 144 delegates_.clear();
239 145
240 // Remove any authorizations for streams that were not yet created 146 // Remove any authorizations for streams that were not yet created
241 authorizations_.clear(); 147 authorizations_.clear();
242 } 148 }
243 149
244 void AudioRendererHost::OnDestruct() const { 150 void AudioRendererHost::OnDestruct() const {
245 BrowserThread::DeleteOnIOThread::Destruct(this); 151 BrowserThread::DeleteOnIOThread::Destruct(this);
246 } 152 }
247 153
248 void AudioRendererHost::AudioEntry::OnCreated() { 154 void AudioRendererHost::OnStreamCreated(
249 BrowserThread::PostTask( 155 int stream_id,
250 BrowserThread::IO, 156 base::SharedMemory* shared_memory,
251 FROM_HERE, 157 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); 158 DCHECK_CURRENTLY_ON(BrowserThread::IO);
276 159
277 if (!PeerHandle()) { 160 if (!PeerHandle()) {
278 DLOG(WARNING) << "Renderer process handle is invalid."; 161 DLOG(WARNING) << "Renderer process handle is invalid.";
279 ReportErrorAndClose(stream_id); 162 OnStreamError(stream_id);
280 return; 163 return;
281 } 164 }
282 165
283 AudioEntry* const entry = LookupById(stream_id); 166 if (!LookupById(stream_id)) {
284 if (!entry) { 167 SendErrorMessage(stream_id);
285 ReportErrorAndClose(stream_id);
286 return; 168 return;
287 } 169 }
288 170
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; 171 base::SharedMemoryHandle foreign_memory_handle;
296 base::SyncSocket::TransitDescriptor socket_descriptor; 172 base::SyncSocket::TransitDescriptor socket_descriptor;
297 size_t shared_memory_size = shared_memory->requested_size(); 173 size_t shared_memory_size = shared_memory->requested_size();
298 174
175 // TODO(maxmorin): Figure out how/if this is safe, since shared_memory is also
176 // accessed on the audio thread.
299 if (!(shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle) && 177 if (!(shared_memory->ShareToProcess(PeerHandle(), &foreign_memory_handle) &&
300 foreign_socket->PrepareTransitDescriptor(PeerHandle(), 178 foreign_socket->PrepareTransitDescriptor(PeerHandle(),
301 &socket_descriptor))) { 179 &socket_descriptor))) {
302 // Something went wrong in preparing the IPC handles. 180 // Something went wrong in preparing the IPC handles.
303 ReportErrorAndClose(entry->stream_id()); 181 OnStreamError(stream_id);
304 return; 182 return;
305 } 183 }
306 184
307 Send(new AudioMsg_NotifyStreamCreated( 185 Send(new AudioMsg_NotifyStreamCreated(
308 stream_id, foreign_memory_handle, socket_descriptor, 186 stream_id, foreign_memory_handle, socket_descriptor,
309 base::checked_cast<uint32_t>(shared_memory_size))); 187 base::checked_cast<uint32_t>(shared_memory_size)));
310 } 188 }
311 189
190 void AudioRendererHost::OnStreamStateChanged(bool is_playing) {
191 DCHECK_CURRENTLY_ON(BrowserThread::IO);
192 if (is_playing) {
193 base::AtomicRefCountInc(&num_playing_streams_);
194
195 // Inform the RenderProcessHost when audio starts playing for the first
196 // time. The nonatomic increment-and-read is ok since this is the only
197 // thread that |num_plaing_streams| may be updated on.
198 if (base::AtomicRefCountIsOne(&num_playing_streams_))
199 NotifyRenderProcessHostThatAudioStateChanged(render_process_id_);
200 } else {
201 // Inform the RenderProcessHost when there is no more audio playing.
202 if (!base::AtomicRefCountDec(&num_playing_streams_))
203 NotifyRenderProcessHostThatAudioStateChanged(render_process_id_);
204 }
205 }
206
207 void AudioRendererHost::OnStreamError(int stream_id) {
208 DCHECK_CURRENTLY_ON(BrowserThread::IO);
209
210 SendErrorMessage(stream_id);
211
212 OnCloseStream(stream_id);
213 }
214
312 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { 215 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) {
313 DCHECK_CURRENTLY_ON(BrowserThread::IO); 216 DCHECK_CURRENTLY_ON(BrowserThread::IO);
314 217
315 if (!is_valid) { 218 if (!is_valid) {
316 DLOG(WARNING) << "Render frame for stream (id=" << stream_id 219 DLOG(WARNING) << "Render frame for stream (id=" << stream_id
317 << ") no longer exists."; 220 << ") no longer exists.";
318 ReportErrorAndClose(stream_id); 221 OnStreamError(stream_id);
319 } 222 }
320 } 223 }
321 224
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 225 RenderProcessHost::AudioOutputControllerList
344 AudioRendererHost::DoGetOutputControllers() const { 226 AudioRendererHost::DoGetOutputControllers() const {
345 DCHECK_CURRENTLY_ON(BrowserThread::IO); 227 DCHECK_CURRENTLY_ON(BrowserThread::IO);
346 228
347 RenderProcessHost::AudioOutputControllerList controllers; 229 RenderProcessHost::AudioOutputControllerList controllers;
348 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); 230 for (const auto& delegate : delegates_)
349 it != audio_entries_.end(); 231 controllers.push_back(delegate->controller());
350 ++it) {
351 controllers.push_back(it->second->controller());
352 }
353 232
354 return controllers; 233 return controllers;
355 } 234 }
356 235
357 /////////////////////////////////////////////////////////////////////////////// 236 ///////////////////////////////////////////////////////////////////////////////
358 // IPC Messages handler 237 // IPC Messages handler
359 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { 238 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
360 bool handled = true; 239 bool handled = true;
361 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) 240 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
362 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, 241 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization,
(...skipping 15 matching lines...) Expand all
378 int session_id, 257 int session_id,
379 const std::string& device_id, 258 const std::string& device_id,
380 const url::Origin& security_origin) { 259 const url::Origin& security_origin) {
381 DCHECK_CURRENTLY_ON(BrowserThread::IO); 260 DCHECK_CURRENTLY_ON(BrowserThread::IO);
382 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); 261 const base::TimeTicks auth_start_time = base::TimeTicks::Now();
383 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" 262 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization"
384 << "(stream_id=" << stream_id 263 << "(stream_id=" << stream_id
385 << ", render_frame_id=" << render_frame_id 264 << ", render_frame_id=" << render_frame_id
386 << ", session_id=" << session_id << ", device_id=" << device_id 265 << ", session_id=" << session_id << ", device_id=" << device_id
387 << ", security_origin=" << security_origin << ")"; 266 << ", security_origin=" << security_origin << ")";
267
388 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) 268 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id))
389 return; 269 return;
390 authorizations_.insert(MakeAuthorizationData(stream_id, false, device_id)); 270 authorizations_.insert(MakeAuthorizationData(stream_id, false, device_id));
391 // Unretained is ok here since |this| owns |authorization_handler_| and 271 // Unretained is ok here since |this| owns |authorization_handler_| and
392 // |authorization_handler_| owns the callback. 272 // |authorization_handler_| owns the callback.
393 authorization_handler_.RequestDeviceAuthorization( 273 authorization_handler_.RequestDeviceAuthorization(
394 render_frame_id, session_id, device_id, security_origin, 274 render_frame_id, session_id, device_id, security_origin,
395 base::Bind(&AudioRendererHost::AuthorizationCompleted, 275 base::Bind(&AudioRendererHost::AuthorizationCompleted,
396 base::Unretained(this), stream_id, security_origin, 276 base::Unretained(this), stream_id, security_origin,
397 auth_start_time)); 277 auth_start_time));
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 // to create it now. 329 // to create it now.
450 content::bad_message::ReceivedBadMessage( 330 content::bad_message::ReceivedBadMessage(
451 this, bad_message::ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION); 331 this, bad_message::ARH_CREATED_STREAM_WITHOUT_AUTHORIZATION);
452 return; 332 return;
453 } 333 }
454 device_unique_id.swap(auth_data->second.second); 334 device_unique_id.swap(auth_data->second.second);
455 authorizations_.erase(auth_data); 335 authorizations_.erase(auth_data);
456 } 336 }
457 337
458 // Fail early if either of two sanity-checks fail: 338 // Fail early if either of two sanity-checks fail:
459 // 1. There should not yet exist an AudioEntry for the given |stream_id| 339 // 1. There should not yet exist an AudioOutputDelegate for the given
460 // since the renderer may not create two streams with the same ID. 340 // |stream_id| since the renderer may not create two streams with the
341 // same ID.
461 // 2. An out-of-range render frame ID was provided. Renderers must *always* 342 // 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 343 // 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 344 // several browser-level features depend on this (e.g., OOM manager, UI
464 // audio indicator, muting, audio capture). 345 // audio indicator, muting, audio capture).
465 // Note: media::AudioParameters is validated in the deserializer, so there is 346 // Note: media::AudioParameters is validated in the deserializer, so there is
466 // no need to check that here. 347 // no need to check that here.
467 if (LookupById(stream_id)) { 348 if (LookupById(stream_id)) {
468 SendErrorMessage(stream_id); 349 SendErrorMessage(stream_id);
469 return; 350 return;
470 } 351 }
471 if (render_frame_id <= 0) { 352 if (render_frame_id <= 0) {
472 SendErrorMessage(stream_id); 353 SendErrorMessage(stream_id);
473 return; 354 return;
474 } 355 }
475 356
476 // Post a task to the UI thread to check that the |render_frame_id| references 357 // 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 358 // 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 359 // stated in the comments above. This does not block stream creation, but will
479 // force-close the stream later if validation fails. 360 // force-close the stream later if validation fails.
480 BrowserThread::PostTask( 361 BrowserThread::PostTask(
481 BrowserThread::UI, FROM_HERE, 362 BrowserThread::UI, FROM_HERE,
482 base::Bind(validate_render_frame_id_function_, render_process_id_, 363 base::Bind(validate_render_frame_id_function_, render_process_id_,
483 render_frame_id, 364 render_frame_id,
484 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, 365 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this,
485 stream_id))); 366 stream_id)));
486 367
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 = 368 MediaObserver* const media_observer =
495 GetContentClient()->browser()->GetMediaObserver(); 369 GetContentClient()->browser()->GetMediaObserver();
496 if (media_observer)
497 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
498 370
499 if (mirroring_manager_) { 371 MediaInternals* const media_internals = MediaInternals::GetInstance();
500 mirroring_manager_->AddDiverter( 372 std::unique_ptr<media::AudioLog> audio_log = media_internals->CreateAudioLog(
501 render_process_id_, entry->render_frame_id(), entry->controller()); 373 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER);
502 } 374 media_internals->SetWebContentsTitleForAudioLogEntry(
503 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 375 stream_id, render_process_id_, render_frame_id, audio_log.get());
376 delegates_.push_back(AudioOutputDelegate::Create(
377 this, audio_manager_, std::move(audio_log), mirroring_manager_,
378 media_observer, stream_id, render_frame_id, render_process_id_, params,
379 device_unique_id));
380
504 g_audio_streams_tracker.Get().IncreaseStreamCount(); 381 g_audio_streams_tracker.Get().IncreaseStreamCount();
505 382
506 audio_log_->OnCreated(stream_id, params, device_unique_id); 383 if (delegates_.size() > max_simultaneous_streams_)
507 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( 384 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 } 385 }
513 386
514 void AudioRendererHost::OnPlayStream(int stream_id) { 387 void AudioRendererHost::OnPlayStream(int stream_id) {
515 DCHECK_CURRENTLY_ON(BrowserThread::IO); 388 DCHECK_CURRENTLY_ON(BrowserThread::IO);
516 389
517 AudioEntry* entry = LookupById(stream_id); 390 AudioOutputDelegate* delegate = LookupById(stream_id);
518 if (!entry) { 391 if (!delegate) {
519 SendErrorMessage(stream_id); 392 SendErrorMessage(stream_id);
520 return; 393 return;
521 } 394 }
522 395
523 entry->controller()->Play(); 396 delegate->OnPlayStream();
524 audio_log_->OnStarted(stream_id);
525 } 397 }
526 398
527 void AudioRendererHost::OnPauseStream(int stream_id) { 399 void AudioRendererHost::OnPauseStream(int stream_id) {
528 DCHECK_CURRENTLY_ON(BrowserThread::IO); 400 DCHECK_CURRENTLY_ON(BrowserThread::IO);
529 401
530 AudioEntry* entry = LookupById(stream_id); 402 AudioOutputDelegate* delegate = LookupById(stream_id);
531 if (!entry) { 403 if (!delegate) {
532 SendErrorMessage(stream_id); 404 SendErrorMessage(stream_id);
533 return; 405 return;
534 } 406 }
535 407
536 entry->controller()->Pause(); 408 delegate->OnPauseStream();
537 audio_log_->OnStopped(stream_id);
538 } 409 }
539 410
540 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { 411 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
541 DCHECK_CURRENTLY_ON(BrowserThread::IO); 412 DCHECK_CURRENTLY_ON(BrowserThread::IO);
542 413
543 AudioEntry* entry = LookupById(stream_id); 414 AudioOutputDelegate* delegate = LookupById(stream_id);
544 if (!entry) { 415 if (!delegate) {
545 SendErrorMessage(stream_id); 416 SendErrorMessage(stream_id);
546 return; 417 return;
547 } 418 }
548 419
549 // Make sure the volume is valid. 420 // Make sure the volume is valid.
550 if (volume < 0 || volume > 1.0) 421 if (volume < 0 || volume > 1.0)
551 return; 422 return;
552 entry->controller()->SetVolume(volume); 423 delegate->OnSetVolume(volume);
553 audio_log_->OnSetVolume(stream_id, volume);
554 } 424 }
555 425
556 void AudioRendererHost::SendErrorMessage(int stream_id) { 426 void AudioRendererHost::SendErrorMessage(int stream_id) {
557 Send(new AudioMsg_NotifyStreamError(stream_id)); 427 Send(new AudioMsg_NotifyStreamError(stream_id));
558 } 428 }
559 429
560 void AudioRendererHost::OnCloseStream(int stream_id) { 430 void AudioRendererHost::OnCloseStream(int stream_id) {
561 DCHECK_CURRENTLY_ON(BrowserThread::IO); 431 DCHECK_CURRENTLY_ON(BrowserThread::IO);
562 authorizations_.erase(stream_id); 432 authorizations_.erase(stream_id);
563 433
434 auto i = LookupIteratorById(stream_id);
435
564 // Prevent oustanding callbacks from attempting to close/delete the same 436 // Prevent oustanding callbacks from attempting to close/delete the same
565 // AudioEntry twice. 437 // AudioOutputDelegate twice.
566 AudioEntryMap::iterator i = audio_entries_.find(stream_id); 438 if (i == delegates_.end())
567 if (i == audio_entries_.end())
568 return; 439 return;
569 std::unique_ptr<AudioEntry> entry(i->second); 440
570 audio_entries_.erase(i); 441 std::swap(*i, delegates_.back());
442 delegates_.pop_back();
443
571 g_audio_streams_tracker.Get().DecreaseStreamCount(); 444 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 } 445 }
578 446
579 void AudioRendererHost::DeleteEntry(std::unique_ptr<AudioEntry> entry) { 447 AudioRendererHost::AudioOutputDelegateList::iterator
448 AudioRendererHost::LookupIteratorById(int stream_id) {
580 DCHECK_CURRENTLY_ON(BrowserThread::IO); 449 DCHECK_CURRENTLY_ON(BrowserThread::IO);
581 450
582 // De-register the controller from the AudioMirroringManager now that the 451 return std::find_if(delegates_.begin(), delegates_.end(),
583 // controller has closed the AudioOutputStream and shut itself down. This 452 [stream_id](const AudioOutputDelegate::UniquePtr& d) {
584 // ensures that calling RemoveDiverter() here won't trigger the controller to 453 return d->stream_id() == stream_id;
585 // re-start the default AudioOutputStream and cause a brief audio blip to come 454 });
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 } 455 }
594 456
595 void AudioRendererHost::ReportErrorAndClose(int stream_id) { 457 AudioOutputDelegate* AudioRendererHost::LookupById(int stream_id) {
596 DCHECK_CURRENTLY_ON(BrowserThread::IO); 458 DCHECK_CURRENTLY_ON(BrowserThread::IO);
597 459
598 // Make sure this isn't a stray callback executing after the stream has been 460 auto i = LookupIteratorById(stream_id);
599 // closed, so error notifications aren't sent after clients believe the stream 461 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 } 462 }
646 463
647 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { 464 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) {
648 DCHECK_CURRENTLY_ON(BrowserThread::IO); 465 DCHECK_CURRENTLY_ON(BrowserThread::IO);
649 return authorizations_.find(stream_id) != authorizations_.end(); 466 return authorizations_.find(stream_id) != authorizations_.end();
650 } 467 }
651 468
652 bool AudioRendererHost::HasActiveAudio() { 469 bool AudioRendererHost::HasActiveAudio() {
653 return !base::AtomicRefCountIsZero(&num_playing_streams_); 470 return !base::AtomicRefCountIsZero(&num_playing_streams_);
654 } 471 }
655 472
656 void AudioRendererHost::OverrideDevicePermissionsForTesting(bool has_access) { 473 void AudioRendererHost::OverrideDevicePermissionsForTesting(bool has_access) {
657 authorization_handler_.OverridePermissionsForTesting(has_access); 474 authorization_handler_.OverridePermissionsForTesting(has_access);
658 } 475 }
659 } // namespace content 476 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698