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

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

Powered by Google App Engine
This is Rietveld 408576698