Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host.cc
blob5f140ac2b8ff7c4c301552632c5c0b8b9fc5c22a
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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/audio_renderer_host.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/metrics/histogram.h"
12 #include "base/process/process.h"
13 #include "content/browser/browser_main_loop.h"
14 #include "content/browser/loader/resource_dispatcher_host_impl.h"
15 #include "content/browser/media/audio_stream_monitor.h"
16 #include "content/browser/media/capture/audio_mirroring_manager.h"
17 #include "content/browser/media/media_internals.h"
18 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
19 #include "content/browser/renderer_host/media/audio_sync_reader.h"
20 #include "content/browser/renderer_host/media/media_stream_manager.h"
21 #include "content/browser/renderer_host/render_widget_host_impl.h"
22 #include "content/common/media/audio_messages.h"
23 #include "content/public/browser/content_browser_client.h"
24 #include "content/public/browser/media_observer.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/common/content_switches.h"
28 #include "media/audio/audio_manager_base.h"
29 #include "media/base/audio_bus.h"
30 #include "media/base/limits.h"
32 using media::AudioBus;
33 using media::AudioManager;
35 namespace content {
37 namespace {
38 // TODO(aiolos): This is a temporary hack until the resource scheduler is
39 // migrated to RenderFrames for the Site Isolation project. It's called in
40 // response to low frequency playback state changes. http://crbug.com/472869
41 int RenderFrameIdToRenderViewId(int render_process_id, int render_frame_id) {
42 DCHECK_CURRENTLY_ON(BrowserThread::UI);
43 RenderFrameHost* const frame =
44 RenderFrameHost::FromID(render_process_id, render_frame_id);
45 return frame ? frame->GetRenderViewHost()->GetRoutingID() : MSG_ROUTING_NONE;
48 void NotifyResourceDispatcherOfAudioStateChange(int render_process_id,
49 bool is_playing,
50 int render_view_id) {
51 DCHECK_CURRENTLY_ON(BrowserThread::IO);
52 if (render_view_id == MSG_ROUTING_NONE || !ResourceDispatcherHostImpl::Get())
53 return;
55 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
56 render_process_id, render_view_id, is_playing);
59 } // namespace
61 class AudioRendererHost::AudioEntry
62 : public media::AudioOutputController::EventHandler {
63 public:
64 AudioEntry(AudioRendererHost* host,
65 int stream_id,
66 int render_frame_id,
67 const media::AudioParameters& params,
68 const std::string& output_device_id,
69 scoped_ptr<base::SharedMemory> shared_memory,
70 scoped_ptr<media::AudioOutputController::SyncReader> reader);
71 ~AudioEntry() override;
73 int stream_id() const {
74 return stream_id_;
77 int render_frame_id() const { return render_frame_id_; }
79 media::AudioOutputController* controller() const { return controller_.get(); }
81 base::SharedMemory* shared_memory() {
82 return shared_memory_.get();
85 media::AudioOutputController::SyncReader* reader() const {
86 return reader_.get();
89 bool playing() const { return playing_; }
90 void set_playing(bool playing) { playing_ = playing; }
92 private:
93 // media::AudioOutputController::EventHandler implementation.
94 void OnCreated() override;
95 void OnPlaying() override;
96 void OnPaused() override;
97 void OnError() override;
99 AudioRendererHost* const host_;
100 const int stream_id_;
102 // The routing ID of the source RenderFrame.
103 const int render_frame_id_;
105 // Shared memory for transmission of the audio data. Used by |reader_|.
106 const scoped_ptr<base::SharedMemory> shared_memory_;
108 // The synchronous reader to be used by |controller_|.
109 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
111 // The AudioOutputController that manages the audio stream.
112 const scoped_refptr<media::AudioOutputController> controller_;
114 bool playing_;
117 AudioRendererHost::AudioEntry::AudioEntry(
118 AudioRendererHost* host,
119 int stream_id,
120 int render_frame_id,
121 const media::AudioParameters& params,
122 const std::string& output_device_id,
123 scoped_ptr<base::SharedMemory> shared_memory,
124 scoped_ptr<media::AudioOutputController::SyncReader> reader)
125 : host_(host),
126 stream_id_(stream_id),
127 render_frame_id_(render_frame_id),
128 shared_memory_(shared_memory.Pass()),
129 reader_(reader.Pass()),
130 controller_(media::AudioOutputController::Create(host->audio_manager_,
131 this,
132 params,
133 output_device_id,
134 reader_.get())),
135 playing_(false) {
136 DCHECK(controller_.get());
139 AudioRendererHost::AudioEntry::~AudioEntry() {}
141 ///////////////////////////////////////////////////////////////////////////////
142 // AudioRendererHost implementations.
144 AudioRendererHost::AudioRendererHost(
145 int render_process_id,
146 media::AudioManager* audio_manager,
147 AudioMirroringManager* mirroring_manager,
148 MediaInternals* media_internals,
149 MediaStreamManager* media_stream_manager)
150 : BrowserMessageFilter(AudioMsgStart),
151 render_process_id_(render_process_id),
152 audio_manager_(audio_manager),
153 mirroring_manager_(mirroring_manager),
154 audio_log_(media_internals->CreateAudioLog(
155 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
156 media_stream_manager_(media_stream_manager),
157 num_playing_streams_(0) {
158 DCHECK(audio_manager_);
159 DCHECK(media_stream_manager_);
162 AudioRendererHost::~AudioRendererHost() {
163 DCHECK(audio_entries_.empty());
166 void AudioRendererHost::GetOutputControllers(
167 const RenderProcessHost::GetAudioOutputControllersCallback&
168 callback) const {
169 BrowserThread::PostTaskAndReplyWithResult(
170 BrowserThread::IO, FROM_HERE,
171 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
174 void AudioRendererHost::OnChannelClosing() {
175 // Since the IPC sender is gone, close all requested audio streams.
176 while (!audio_entries_.empty()) {
177 // Note: OnCloseStream() removes the entries from audio_entries_.
178 OnCloseStream(audio_entries_.begin()->first);
182 void AudioRendererHost::OnDestruct() const {
183 BrowserThread::DeleteOnIOThread::Destruct(this);
186 void AudioRendererHost::AudioEntry::OnCreated() {
187 BrowserThread::PostTask(
188 BrowserThread::IO,
189 FROM_HERE,
190 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
193 void AudioRendererHost::AudioEntry::OnPlaying() {
194 BrowserThread::PostTask(
195 BrowserThread::IO,
196 FROM_HERE,
197 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
198 host_,
199 stream_id_,
200 true));
203 void AudioRendererHost::AudioEntry::OnPaused() {
204 BrowserThread::PostTask(
205 BrowserThread::IO,
206 FROM_HERE,
207 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
208 host_,
209 stream_id_,
210 false));
213 void AudioRendererHost::AudioEntry::OnError() {
214 BrowserThread::PostTask(
215 BrowserThread::IO,
216 FROM_HERE,
217 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
220 void AudioRendererHost::DoCompleteCreation(int stream_id) {
221 DCHECK_CURRENTLY_ON(BrowserThread::IO);
223 if (!PeerHandle()) {
224 DLOG(WARNING) << "Renderer process handle is invalid.";
225 ReportErrorAndClose(stream_id);
226 return;
229 AudioEntry* const entry = LookupById(stream_id);
230 if (!entry) {
231 ReportErrorAndClose(stream_id);
232 return;
235 // Once the audio stream is created then complete the creation process by
236 // mapping shared memory and sharing with the renderer process.
237 base::SharedMemoryHandle foreign_memory_handle;
238 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
239 &foreign_memory_handle)) {
240 // If we failed to map and share the shared memory then close the audio
241 // stream and send an error message.
242 ReportErrorAndClose(entry->stream_id());
243 return;
246 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
248 base::SyncSocket::TransitDescriptor socket_descriptor;
250 // If we failed to prepare the sync socket for the renderer then we fail
251 // the construction of audio stream.
252 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
253 ReportErrorAndClose(entry->stream_id());
254 return;
257 Send(new AudioMsg_NotifyStreamCreated(
258 entry->stream_id(), foreign_memory_handle, socket_descriptor,
259 entry->shared_memory()->requested_size()));
262 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
263 bool is_playing) {
264 DCHECK_CURRENTLY_ON(BrowserThread::IO);
266 AudioEntry* const entry = LookupById(stream_id);
267 if (!entry)
268 return;
270 Send(new AudioMsg_NotifyStreamStateChanged(
271 stream_id,
272 is_playing ? media::AudioOutputIPCDelegate::kPlaying
273 : media::AudioOutputIPCDelegate::kPaused));
275 if (is_playing) {
276 AudioStreamMonitor::StartMonitoringStream(
277 render_process_id_,
278 entry->render_frame_id(),
279 entry->stream_id(),
280 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
281 entry->controller()));
282 } else {
283 AudioStreamMonitor::StopMonitoringStream(
284 render_process_id_, entry->render_frame_id(), entry->stream_id());
286 UpdateNumPlayingStreams(entry, is_playing);
289 RenderProcessHost::AudioOutputControllerList
290 AudioRendererHost::DoGetOutputControllers() const {
291 DCHECK_CURRENTLY_ON(BrowserThread::IO);
293 RenderProcessHost::AudioOutputControllerList controllers;
294 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
295 it != audio_entries_.end();
296 ++it) {
297 controllers.push_back(it->second->controller());
300 return controllers;
303 ///////////////////////////////////////////////////////////////////////////////
304 // IPC Messages handler
305 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
306 bool handled = true;
307 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
308 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
309 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
310 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
311 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
312 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
313 IPC_MESSAGE_UNHANDLED(handled = false)
314 IPC_END_MESSAGE_MAP()
316 return handled;
319 void AudioRendererHost::OnCreateStream(int stream_id,
320 int render_frame_id,
321 int session_id,
322 const media::AudioParameters& params) {
323 DCHECK_CURRENTLY_ON(BrowserThread::IO);
325 DVLOG(1) << "AudioRendererHost@" << this
326 << "::OnCreateStream(stream_id=" << stream_id
327 << ", render_frame_id=" << render_frame_id
328 << ", session_id=" << session_id << ")";
329 DCHECK_GT(render_frame_id, 0);
331 // media::AudioParameters is validated in the deserializer.
332 if (LookupById(stream_id) != NULL) {
333 SendErrorMessage(stream_id);
334 return;
337 // Initialize the |output_device_id| to an empty string which indicates that
338 // the default device should be used. If a StreamDeviceInfo instance was found
339 // though, then we use the matched output device.
340 std::string output_device_id;
341 const StreamDeviceInfo* info = media_stream_manager_->
342 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
343 if (info)
344 output_device_id = info->device.matched_output_device_id;
346 // Create the shared memory and share with the renderer process.
347 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
348 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
349 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
350 SendErrorMessage(stream_id);
351 return;
354 scoped_ptr<AudioSyncReader> reader(
355 new AudioSyncReader(shared_memory.get(), params));
356 if (!reader->Init()) {
357 SendErrorMessage(stream_id);
358 return;
361 MediaObserver* const media_observer =
362 GetContentClient()->browser()->GetMediaObserver();
363 if (media_observer)
364 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
366 scoped_ptr<AudioEntry> entry(new AudioEntry(this,
367 stream_id,
368 render_frame_id,
369 params,
370 output_device_id,
371 shared_memory.Pass(),
372 reader.Pass()));
373 if (mirroring_manager_) {
374 mirroring_manager_->AddDiverter(
375 render_process_id_, entry->render_frame_id(), entry->controller());
377 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
378 audio_log_->OnCreated(stream_id, params, output_device_id);
379 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
380 stream_id, render_process_id_, render_frame_id, audio_log_.get());
383 void AudioRendererHost::OnPlayStream(int stream_id) {
384 DCHECK_CURRENTLY_ON(BrowserThread::IO);
386 AudioEntry* entry = LookupById(stream_id);
387 if (!entry) {
388 SendErrorMessage(stream_id);
389 return;
392 entry->controller()->Play();
393 audio_log_->OnStarted(stream_id);
396 void AudioRendererHost::OnPauseStream(int stream_id) {
397 DCHECK_CURRENTLY_ON(BrowserThread::IO);
399 AudioEntry* entry = LookupById(stream_id);
400 if (!entry) {
401 SendErrorMessage(stream_id);
402 return;
405 entry->controller()->Pause();
406 audio_log_->OnStopped(stream_id);
409 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
410 DCHECK_CURRENTLY_ON(BrowserThread::IO);
412 AudioEntry* entry = LookupById(stream_id);
413 if (!entry) {
414 SendErrorMessage(stream_id);
415 return;
418 // Make sure the volume is valid.
419 if (volume < 0 || volume > 1.0)
420 return;
421 entry->controller()->SetVolume(volume);
422 audio_log_->OnSetVolume(stream_id, volume);
425 void AudioRendererHost::SendErrorMessage(int stream_id) {
426 Send(new AudioMsg_NotifyStreamStateChanged(
427 stream_id, media::AudioOutputIPCDelegate::kError));
430 void AudioRendererHost::OnCloseStream(int stream_id) {
431 DCHECK_CURRENTLY_ON(BrowserThread::IO);
433 // Prevent oustanding callbacks from attempting to close/delete the same
434 // AudioEntry twice.
435 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
436 if (i == audio_entries_.end())
437 return;
438 scoped_ptr<AudioEntry> entry(i->second);
439 audio_entries_.erase(i);
441 media::AudioOutputController* const controller = entry->controller();
442 if (mirroring_manager_)
443 mirroring_manager_->RemoveDiverter(controller);
444 controller->Close(
445 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
446 audio_log_->OnClosed(stream_id);
449 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
450 DCHECK_CURRENTLY_ON(BrowserThread::IO);
451 AudioStreamMonitor::StopMonitoringStream(
452 render_process_id_, entry->render_frame_id(), entry->stream_id());
453 UpdateNumPlayingStreams(entry.get(), false);
456 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
457 DCHECK_CURRENTLY_ON(BrowserThread::IO);
459 // Make sure this isn't a stray callback executing after the stream has been
460 // closed, so error notifications aren't sent after clients believe the stream
461 // is closed.
462 if (!LookupById(stream_id))
463 return;
465 SendErrorMessage(stream_id);
467 audio_log_->OnError(stream_id);
468 OnCloseStream(stream_id);
471 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
472 DCHECK_CURRENTLY_ON(BrowserThread::IO);
474 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
475 return i != audio_entries_.end() ? i->second : NULL;
478 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
479 bool is_playing) {
480 DCHECK_CURRENTLY_ON(BrowserThread::IO);
481 if (entry->playing() == is_playing)
482 return;
484 bool should_alert_resource_scheduler;
485 if (is_playing) {
486 should_alert_resource_scheduler =
487 !RenderFrameHasActiveAudio(entry->render_frame_id());
488 entry->set_playing(true);
489 base::AtomicRefCountInc(&num_playing_streams_);
490 } else {
491 entry->set_playing(false);
492 should_alert_resource_scheduler =
493 !RenderFrameHasActiveAudio(entry->render_frame_id());
494 base::AtomicRefCountDec(&num_playing_streams_);
497 if (should_alert_resource_scheduler && ResourceDispatcherHostImpl::Get()) {
498 BrowserThread::PostTaskAndReplyWithResult(
499 BrowserThread::UI, FROM_HERE,
500 base::Bind(&RenderFrameIdToRenderViewId, render_process_id_,
501 entry->render_frame_id()),
502 base::Bind(&NotifyResourceDispatcherOfAudioStateChange,
503 render_process_id_, is_playing));
507 bool AudioRendererHost::HasActiveAudio() {
508 return !base::AtomicRefCountIsZero(&num_playing_streams_);
511 bool AudioRendererHost::RenderFrameHasActiveAudio(int render_frame_id) const {
512 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
513 it != audio_entries_.end();
514 ++it) {
515 AudioEntry* entry = it->second;
516 if (entry->render_frame_id() == render_frame_id && entry->playing())
517 return true;
519 return false;
522 } // namespace content