Retry: Win Video Capture: Create an STA |video_capture_thread_| from MediaStreamManager.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host.cc
blob43555fcdb199dc73592b7e48f748d4cb73d16585
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/common/media/audio_messages.h"
22 #include "content/public/browser/content_browser_client.h"
23 #include "content/public/browser/media_observer.h"
24 #include "content/public/common/content_switches.h"
25 #include "media/audio/audio_manager_base.h"
26 #include "media/base/audio_bus.h"
27 #include "media/base/limits.h"
29 using media::AudioBus;
30 using media::AudioManager;
32 namespace content {
34 class AudioRendererHost::AudioEntry
35 : public media::AudioOutputController::EventHandler {
36 public:
37 AudioEntry(AudioRendererHost* host,
38 int stream_id,
39 int render_view_id,
40 int render_frame_id,
41 const media::AudioParameters& params,
42 const std::string& output_device_id,
43 scoped_ptr<base::SharedMemory> shared_memory,
44 scoped_ptr<media::AudioOutputController::SyncReader> reader);
45 ~AudioEntry() override;
47 int stream_id() const {
48 return stream_id_;
51 int render_view_id() const {
52 return render_view_id_;
55 int render_frame_id() const { return render_frame_id_; }
57 media::AudioOutputController* controller() const { return controller_.get(); }
59 base::SharedMemory* shared_memory() {
60 return shared_memory_.get();
63 media::AudioOutputController::SyncReader* reader() const {
64 return reader_.get();
67 bool playing() const { return playing_; }
68 void set_playing(bool playing) { playing_ = playing; }
70 private:
71 // media::AudioOutputController::EventHandler implementation.
72 void OnCreated() override;
73 void OnPlaying() override;
74 void OnPaused() override;
75 void OnError() override;
76 void OnDeviceChange(int new_buffer_size, int new_sample_rate) override;
78 AudioRendererHost* const host_;
79 const int stream_id_;
81 // The routing ID of the source render view/frame.
82 const int render_view_id_;
83 const int render_frame_id_;
85 // Shared memory for transmission of the audio data. Used by |reader_|.
86 const scoped_ptr<base::SharedMemory> shared_memory_;
88 // The synchronous reader to be used by |controller_|.
89 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
91 // The AudioOutputController that manages the audio stream.
92 const scoped_refptr<media::AudioOutputController> controller_;
94 bool playing_;
97 AudioRendererHost::AudioEntry::AudioEntry(
98 AudioRendererHost* host,
99 int stream_id,
100 int render_view_id,
101 int render_frame_id,
102 const media::AudioParameters& params,
103 const std::string& output_device_id,
104 scoped_ptr<base::SharedMemory> shared_memory,
105 scoped_ptr<media::AudioOutputController::SyncReader> reader)
106 : host_(host),
107 stream_id_(stream_id),
108 render_view_id_(render_view_id),
109 render_frame_id_(render_frame_id),
110 shared_memory_(shared_memory.Pass()),
111 reader_(reader.Pass()),
112 controller_(media::AudioOutputController::Create(host->audio_manager_,
113 this,
114 params,
115 output_device_id,
116 reader_.get())),
117 playing_(false) {
118 DCHECK(controller_.get());
121 AudioRendererHost::AudioEntry::~AudioEntry() {}
123 ///////////////////////////////////////////////////////////////////////////////
124 // AudioRendererHost implementations.
126 AudioRendererHost::AudioRendererHost(
127 int render_process_id,
128 media::AudioManager* audio_manager,
129 AudioMirroringManager* mirroring_manager,
130 MediaInternals* media_internals,
131 MediaStreamManager* media_stream_manager)
132 : BrowserMessageFilter(AudioMsgStart),
133 render_process_id_(render_process_id),
134 audio_manager_(audio_manager),
135 mirroring_manager_(mirroring_manager),
136 audio_log_(media_internals->CreateAudioLog(
137 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
138 media_stream_manager_(media_stream_manager),
139 num_playing_streams_(0) {
140 DCHECK(audio_manager_);
141 DCHECK(media_stream_manager_);
144 AudioRendererHost::~AudioRendererHost() {
145 DCHECK(audio_entries_.empty());
148 void AudioRendererHost::GetOutputControllers(
149 int render_view_id,
150 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
151 BrowserThread::PostTaskAndReplyWithResult(
152 BrowserThread::IO,
153 FROM_HERE,
154 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
155 render_view_id),
156 callback);
159 void AudioRendererHost::OnChannelClosing() {
160 // Since the IPC sender is gone, close all requested audio streams.
161 while (!audio_entries_.empty()) {
162 // Note: OnCloseStream() removes the entries from audio_entries_.
163 OnCloseStream(audio_entries_.begin()->first);
167 void AudioRendererHost::OnDestruct() const {
168 BrowserThread::DeleteOnIOThread::Destruct(this);
171 void AudioRendererHost::AudioEntry::OnCreated() {
172 BrowserThread::PostTask(
173 BrowserThread::IO,
174 FROM_HERE,
175 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
178 void AudioRendererHost::AudioEntry::OnPlaying() {
179 BrowserThread::PostTask(
180 BrowserThread::IO,
181 FROM_HERE,
182 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
183 host_,
184 stream_id_,
185 true));
188 void AudioRendererHost::AudioEntry::OnPaused() {
189 BrowserThread::PostTask(
190 BrowserThread::IO,
191 FROM_HERE,
192 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
193 host_,
194 stream_id_,
195 false));
198 void AudioRendererHost::AudioEntry::OnError() {
199 BrowserThread::PostTask(
200 BrowserThread::IO,
201 FROM_HERE,
202 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
205 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
206 int new_sample_rate) {
207 BrowserThread::PostTask(
208 BrowserThread::IO,
209 FROM_HERE,
210 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
211 new AudioMsg_NotifyDeviceChanged(
212 stream_id_, new_buffer_size, new_sample_rate)));
215 void AudioRendererHost::DoCompleteCreation(int stream_id) {
216 DCHECK_CURRENTLY_ON(BrowserThread::IO);
218 if (!PeerHandle()) {
219 DLOG(WARNING) << "Renderer process handle is invalid.";
220 ReportErrorAndClose(stream_id);
221 return;
224 AudioEntry* const entry = LookupById(stream_id);
225 if (!entry) {
226 ReportErrorAndClose(stream_id);
227 return;
230 // Once the audio stream is created then complete the creation process by
231 // mapping shared memory and sharing with the renderer process.
232 base::SharedMemoryHandle foreign_memory_handle;
233 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
234 &foreign_memory_handle)) {
235 // If we failed to map and share the shared memory then close the audio
236 // stream and send an error message.
237 ReportErrorAndClose(entry->stream_id());
238 return;
241 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
243 base::SyncSocket::TransitDescriptor socket_descriptor;
245 // If we failed to prepare the sync socket for the renderer then we fail
246 // the construction of audio stream.
247 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
248 ReportErrorAndClose(entry->stream_id());
249 return;
252 Send(new AudioMsg_NotifyStreamCreated(
253 entry->stream_id(), foreign_memory_handle, socket_descriptor,
254 entry->shared_memory()->requested_size()));
257 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
258 bool is_playing) {
259 DCHECK_CURRENTLY_ON(BrowserThread::IO);
261 AudioEntry* const entry = LookupById(stream_id);
262 if (!entry)
263 return;
265 Send(new AudioMsg_NotifyStreamStateChanged(
266 stream_id,
267 is_playing ? media::AudioOutputIPCDelegate::kPlaying
268 : media::AudioOutputIPCDelegate::kPaused));
270 if (is_playing) {
271 AudioStreamMonitor::StartMonitoringStream(
272 render_process_id_,
273 entry->render_frame_id(),
274 entry->stream_id(),
275 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
276 entry->controller()));
277 } else {
278 AudioStreamMonitor::StopMonitoringStream(
279 render_process_id_, entry->render_frame_id(), entry->stream_id());
281 UpdateNumPlayingStreams(entry, is_playing);
284 RenderViewHost::AudioOutputControllerList
285 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
286 DCHECK_CURRENTLY_ON(BrowserThread::IO);
288 RenderViewHost::AudioOutputControllerList controllers;
289 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
290 it != audio_entries_.end();
291 ++it) {
292 AudioEntry* entry = it->second;
293 if (entry->render_view_id() == render_view_id)
294 controllers.push_back(entry->controller());
297 return controllers;
300 ///////////////////////////////////////////////////////////////////////////////
301 // IPC Messages handler
302 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
303 bool handled = true;
304 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
305 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
306 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
307 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
308 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
309 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
310 IPC_MESSAGE_UNHANDLED(handled = false)
311 IPC_END_MESSAGE_MAP()
313 return handled;
316 void AudioRendererHost::OnCreateStream(
317 int stream_id, int render_view_id, int render_frame_id, int session_id,
318 const media::AudioParameters& params) {
319 DCHECK_CURRENTLY_ON(BrowserThread::IO);
321 DVLOG(1) << "AudioRendererHost@" << this
322 << "::OnCreateStream(stream_id=" << stream_id
323 << ", render_view_id=" << render_view_id
324 << ", session_id=" << session_id << ")";
325 DCHECK_GT(render_view_id, 0);
326 DCHECK_GT(render_frame_id, 0);
328 // media::AudioParameters is validated in the deserializer.
329 if (LookupById(stream_id) != NULL) {
330 SendErrorMessage(stream_id);
331 return;
334 // Initialize the |output_device_id| to an empty string which indicates that
335 // the default device should be used. If a StreamDeviceInfo instance was found
336 // though, then we use the matched output device.
337 std::string output_device_id;
338 const StreamDeviceInfo* info = media_stream_manager_->
339 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
340 if (info)
341 output_device_id = info->device.matched_output_device_id;
343 // Create the shared memory and share with the renderer process.
344 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
345 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
346 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
347 SendErrorMessage(stream_id);
348 return;
351 scoped_ptr<AudioSyncReader> reader(
352 new AudioSyncReader(shared_memory.get(), params));
353 if (!reader->Init()) {
354 SendErrorMessage(stream_id);
355 return;
358 MediaObserver* const media_observer =
359 GetContentClient()->browser()->GetMediaObserver();
360 if (media_observer)
361 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
363 scoped_ptr<AudioEntry> entry(new AudioEntry(this,
364 stream_id,
365 render_view_id,
366 render_frame_id,
367 params,
368 output_device_id,
369 shared_memory.Pass(),
370 reader.Pass()));
371 if (mirroring_manager_) {
372 mirroring_manager_->AddDiverter(
373 render_process_id_, entry->render_frame_id(), entry->controller());
375 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
376 audio_log_->OnCreated(stream_id, params, output_device_id);
379 void AudioRendererHost::OnPlayStream(int stream_id) {
380 DCHECK_CURRENTLY_ON(BrowserThread::IO);
382 AudioEntry* entry = LookupById(stream_id);
383 if (!entry) {
384 SendErrorMessage(stream_id);
385 return;
388 entry->controller()->Play();
389 audio_log_->OnStarted(stream_id);
392 void AudioRendererHost::OnPauseStream(int stream_id) {
393 DCHECK_CURRENTLY_ON(BrowserThread::IO);
395 AudioEntry* entry = LookupById(stream_id);
396 if (!entry) {
397 SendErrorMessage(stream_id);
398 return;
401 entry->controller()->Pause();
402 audio_log_->OnStopped(stream_id);
405 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
406 DCHECK_CURRENTLY_ON(BrowserThread::IO);
408 AudioEntry* entry = LookupById(stream_id);
409 if (!entry) {
410 SendErrorMessage(stream_id);
411 return;
414 // Make sure the volume is valid.
415 if (volume < 0 || volume > 1.0)
416 return;
417 entry->controller()->SetVolume(volume);
418 audio_log_->OnSetVolume(stream_id, volume);
421 void AudioRendererHost::SendErrorMessage(int stream_id) {
422 Send(new AudioMsg_NotifyStreamStateChanged(
423 stream_id, media::AudioOutputIPCDelegate::kError));
426 void AudioRendererHost::OnCloseStream(int stream_id) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO);
429 // Prevent oustanding callbacks from attempting to close/delete the same
430 // AudioEntry twice.
431 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
432 if (i == audio_entries_.end())
433 return;
434 scoped_ptr<AudioEntry> entry(i->second);
435 audio_entries_.erase(i);
437 media::AudioOutputController* const controller = entry->controller();
438 if (mirroring_manager_)
439 mirroring_manager_->RemoveDiverter(controller);
440 controller->Close(
441 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
442 audio_log_->OnClosed(stream_id);
445 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
446 DCHECK_CURRENTLY_ON(BrowserThread::IO);
447 AudioStreamMonitor::StopMonitoringStream(
448 render_process_id_, entry->render_frame_id(), entry->stream_id());
449 UpdateNumPlayingStreams(entry.get(), false);
452 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
453 DCHECK_CURRENTLY_ON(BrowserThread::IO);
455 // Make sure this isn't a stray callback executing after the stream has been
456 // closed, so error notifications aren't sent after clients believe the stream
457 // is closed.
458 if (!LookupById(stream_id))
459 return;
461 SendErrorMessage(stream_id);
463 audio_log_->OnError(stream_id);
464 OnCloseStream(stream_id);
467 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
468 DCHECK_CURRENTLY_ON(BrowserThread::IO);
470 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
471 return i != audio_entries_.end() ? i->second : NULL;
474 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
475 bool is_playing) {
476 DCHECK_CURRENTLY_ON(BrowserThread::IO);
477 if (entry->playing() == is_playing)
478 return;
480 bool should_alert_resource_scheduler;
481 if (is_playing) {
482 should_alert_resource_scheduler =
483 !RenderViewHasActiveAudio(entry->render_view_id());
484 entry->set_playing(true);
485 base::AtomicRefCountInc(&num_playing_streams_);
486 } else {
487 entry->set_playing(false);
488 should_alert_resource_scheduler =
489 !RenderViewHasActiveAudio(entry->render_view_id());
490 base::AtomicRefCountDec(&num_playing_streams_);
493 if (should_alert_resource_scheduler && ResourceDispatcherHostImpl::Get()) {
494 ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
495 render_process_id_, entry->render_view_id(), is_playing);
499 bool AudioRendererHost::HasActiveAudio() {
500 return !base::AtomicRefCountIsZero(&num_playing_streams_);
503 bool AudioRendererHost::RenderViewHasActiveAudio(int render_view_id) const {
504 for (AudioEntryMap::const_iterator it = audio_entries_.begin();
505 it != audio_entries_.end();
506 ++it) {
507 AudioEntry* entry = it->second;
508 if (entry->render_view_id() == render_view_id && entry->playing())
509 return true;
511 return false;
514 } // namespace content