Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host.cc
blobea633c06f1bd719cfa1b31329e931410708afdb4
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/memory/shared_memory.h"
10 #include "base/metrics/histogram.h"
11 #include "base/process/process.h"
12 #include "content/browser/browser_main_loop.h"
13 #include "content/browser/media/capture/audio_mirroring_manager.h"
14 #include "content/browser/media/media_internals.h"
15 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
16 #include "content/browser/renderer_host/media/audio_sync_reader.h"
17 #include "content/browser/renderer_host/media/media_stream_manager.h"
18 #include "content/common/media/audio_messages.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/browser/media_observer.h"
21 #include "content/public/common/content_switches.h"
22 #include "media/audio/audio_manager_base.h"
23 #include "media/base/audio_bus.h"
24 #include "media/base/limits.h"
26 using media::AudioBus;
27 using media::AudioManager;
29 namespace content {
31 class AudioRendererHost::AudioEntry
32 : public media::AudioOutputController::EventHandler {
33 public:
34 AudioEntry(AudioRendererHost* host,
35 int stream_id,
36 int render_view_id,
37 int render_frame_id,
38 const media::AudioParameters& params,
39 const std::string& output_device_id,
40 scoped_ptr<base::SharedMemory> shared_memory,
41 scoped_ptr<media::AudioOutputController::SyncReader> reader);
42 virtual ~AudioEntry();
44 int stream_id() const {
45 return stream_id_;
48 int render_view_id() const {
49 return render_view_id_;
52 int render_frame_id() const { return render_frame_id_; }
54 media::AudioOutputController* controller() const { return controller_.get(); }
56 base::SharedMemory* shared_memory() {
57 return shared_memory_.get();
60 media::AudioOutputController::SyncReader* reader() const {
61 return reader_.get();
64 private:
65 // media::AudioOutputController::EventHandler implementation.
66 virtual void OnCreated() OVERRIDE;
67 virtual void OnPlaying() OVERRIDE;
68 virtual void OnPaused() OVERRIDE;
69 virtual void OnError() OVERRIDE;
70 virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate)
71 OVERRIDE;
73 AudioRendererHost* const host_;
74 const int stream_id_;
76 // The routing ID of the source render view/frame.
77 const int render_view_id_;
78 const int render_frame_id_;
80 // Shared memory for transmission of the audio data. Used by |reader_|.
81 const scoped_ptr<base::SharedMemory> shared_memory_;
83 // The synchronous reader to be used by |controller_|.
84 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
86 // The AudioOutputController that manages the audio stream.
87 const scoped_refptr<media::AudioOutputController> controller_;
90 AudioRendererHost::AudioEntry::AudioEntry(
91 AudioRendererHost* host,
92 int stream_id,
93 int render_view_id,
94 int render_frame_id,
95 const media::AudioParameters& params,
96 const std::string& output_device_id,
97 scoped_ptr<base::SharedMemory> shared_memory,
98 scoped_ptr<media::AudioOutputController::SyncReader> reader)
99 : host_(host),
100 stream_id_(stream_id),
101 render_view_id_(render_view_id),
102 render_frame_id_(render_frame_id),
103 shared_memory_(shared_memory.Pass()),
104 reader_(reader.Pass()),
105 controller_(media::AudioOutputController::Create(host->audio_manager_,
106 this,
107 params,
108 output_device_id,
109 reader_.get())) {
110 DCHECK(controller_.get());
113 AudioRendererHost::AudioEntry::~AudioEntry() {}
115 ///////////////////////////////////////////////////////////////////////////////
116 // AudioRendererHost implementations.
118 AudioRendererHost::AudioRendererHost(
119 int render_process_id,
120 media::AudioManager* audio_manager,
121 AudioMirroringManager* mirroring_manager,
122 MediaInternals* media_internals,
123 MediaStreamManager* media_stream_manager)
124 : BrowserMessageFilter(AudioMsgStart),
125 render_process_id_(render_process_id),
126 audio_manager_(audio_manager),
127 mirroring_manager_(mirroring_manager),
128 audio_log_(media_internals->CreateAudioLog(
129 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
130 media_stream_manager_(media_stream_manager) {
131 DCHECK(audio_manager_);
132 DCHECK(media_stream_manager_);
135 AudioRendererHost::~AudioRendererHost() {
136 DCHECK(audio_entries_.empty());
139 void AudioRendererHost::GetOutputControllers(
140 int render_view_id,
141 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
142 BrowserThread::PostTaskAndReplyWithResult(
143 BrowserThread::IO,
144 FROM_HERE,
145 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
146 render_view_id),
147 callback);
150 void AudioRendererHost::OnChannelClosing() {
151 // Since the IPC channel is gone, close all requested audio streams.
152 while (!audio_entries_.empty()) {
153 // Note: OnCloseStream() removes the entries from audio_entries_.
154 OnCloseStream(audio_entries_.begin()->first);
158 void AudioRendererHost::OnDestruct() const {
159 BrowserThread::DeleteOnIOThread::Destruct(this);
162 void AudioRendererHost::AudioEntry::OnCreated() {
163 BrowserThread::PostTask(
164 BrowserThread::IO,
165 FROM_HERE,
166 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
169 void AudioRendererHost::AudioEntry::OnPlaying() {
170 BrowserThread::PostTask(
171 BrowserThread::IO,
172 FROM_HERE,
173 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
174 host_,
175 stream_id_,
176 true));
179 void AudioRendererHost::AudioEntry::OnPaused() {
180 BrowserThread::PostTask(
181 BrowserThread::IO,
182 FROM_HERE,
183 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
184 host_,
185 stream_id_,
186 false));
189 void AudioRendererHost::AudioEntry::OnError() {
190 BrowserThread::PostTask(
191 BrowserThread::IO,
192 FROM_HERE,
193 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
196 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
197 int new_sample_rate) {
198 BrowserThread::PostTask(
199 BrowserThread::IO,
200 FROM_HERE,
201 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
202 new AudioMsg_NotifyDeviceChanged(
203 stream_id_, new_buffer_size, new_sample_rate)));
206 void AudioRendererHost::DoCompleteCreation(int stream_id) {
207 DCHECK_CURRENTLY_ON(BrowserThread::IO);
209 if (!PeerHandle()) {
210 DLOG(WARNING) << "Renderer process handle is invalid.";
211 ReportErrorAndClose(stream_id);
212 return;
215 AudioEntry* const entry = LookupById(stream_id);
216 if (!entry) {
217 ReportErrorAndClose(stream_id);
218 return;
221 // Once the audio stream is created then complete the creation process by
222 // mapping shared memory and sharing with the renderer process.
223 base::SharedMemoryHandle foreign_memory_handle;
224 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
225 &foreign_memory_handle)) {
226 // If we failed to map and share the shared memory then close the audio
227 // stream and send an error message.
228 ReportErrorAndClose(entry->stream_id());
229 return;
232 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
234 #if defined(OS_WIN)
235 base::SyncSocket::Handle foreign_socket_handle;
236 #else
237 base::FileDescriptor foreign_socket_handle;
238 #endif
240 // If we failed to prepare the sync socket for the renderer then we fail
241 // the construction of audio stream.
242 if (!reader->PrepareForeignSocketHandle(PeerHandle(),
243 &foreign_socket_handle)) {
244 ReportErrorAndClose(entry->stream_id());
245 return;
248 Send(new AudioMsg_NotifyStreamCreated(
249 entry->stream_id(),
250 foreign_memory_handle,
251 foreign_socket_handle,
252 entry->shared_memory()->requested_size()));
255 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
256 bool is_playing) {
257 DCHECK_CURRENTLY_ON(BrowserThread::IO);
259 AudioEntry* const entry = LookupById(stream_id);
260 if (!entry)
261 return;
263 Send(new AudioMsg_NotifyStreamStateChanged(
264 stream_id,
265 is_playing ? media::AudioOutputIPCDelegate::kPlaying
266 : media::AudioOutputIPCDelegate::kPaused));
268 MediaObserver* const media_observer =
269 GetContentClient()->browser()->GetMediaObserver();
270 if (media_observer) {
271 if (is_playing) {
272 media_observer->OnAudioStreamPlaying(
273 render_process_id_,
274 entry->render_frame_id(),
275 entry->stream_id(),
276 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
277 entry->controller()));
278 } else {
279 media_observer->OnAudioStreamStopped(render_process_id_,
280 entry->render_frame_id(),
281 entry->stream_id());
286 RenderViewHost::AudioOutputControllerList
287 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
288 DCHECK_CURRENTLY_ON(BrowserThread::IO);
290 RenderViewHost::AudioOutputControllerList controllers;
291 AudioEntryMap::const_iterator it = audio_entries_.begin();
292 for (; it != audio_entries_.end(); ++it) {
293 AudioEntry* entry = it->second;
294 if (entry->render_view_id() == render_view_id)
295 controllers.push_back(entry->controller());
298 return controllers;
301 ///////////////////////////////////////////////////////////////////////////////
302 // IPC Messages handler
303 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
304 bool* message_was_ok) {
305 bool handled = true;
306 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok)
307 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
308 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
309 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
310 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
311 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
312 IPC_MESSAGE_UNHANDLED(handled = false)
313 IPC_END_MESSAGE_MAP_EX()
315 return handled;
318 void AudioRendererHost::OnCreateStream(
319 int stream_id, int render_view_id, int render_frame_id, int session_id,
320 const media::AudioParameters& params) {
321 DCHECK_CURRENTLY_ON(BrowserThread::IO);
323 DVLOG(1) << "AudioRendererHost@" << this
324 << "::OnCreateStream(stream_id=" << stream_id
325 << ", render_view_id=" << render_view_id
326 << ", session_id=" << session_id << ")";
327 DCHECK_GT(render_view_id, 0);
328 DCHECK_GT(render_frame_id, 0);
330 // media::AudioParameters is validated in the deserializer.
331 if (LookupById(stream_id) != NULL) {
332 SendErrorMessage(stream_id);
333 return;
336 // Initialize the |output_device_id| to an empty string which indicates that
337 // the default device should be used. If a StreamDeviceInfo instance was found
338 // though, then we use the matched output device.
339 std::string output_device_id;
340 const StreamDeviceInfo* info = media_stream_manager_->
341 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
342 if (info)
343 output_device_id = info->device.matched_output_device_id;
345 // Create the shared memory and share with the renderer process.
346 // For synchronized I/O (if input_channels > 0) then we allocate
347 // extra memory after the output data for the input data.
348 uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
349 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
350 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
351 SendErrorMessage(stream_id);
352 return;
355 scoped_ptr<AudioSyncReader> reader(
356 new AudioSyncReader(shared_memory.get(), params));
357 if (!reader->Init()) {
358 SendErrorMessage(stream_id);
359 return;
362 MediaObserver* const media_observer =
363 GetContentClient()->browser()->GetMediaObserver();
364 if (media_observer)
365 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
367 scoped_ptr<AudioEntry> entry(new AudioEntry(
368 this,
369 stream_id,
370 render_view_id,
371 render_frame_id,
372 params,
373 output_device_id,
374 shared_memory.Pass(),
375 reader.PassAs<media::AudioOutputController::SyncReader>()));
376 if (mirroring_manager_) {
377 mirroring_manager_->AddDiverter(
378 render_process_id_, entry->render_view_id(), entry->controller());
380 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
381 audio_log_->OnCreated(stream_id, params, output_device_id);
384 void AudioRendererHost::OnPlayStream(int stream_id) {
385 DCHECK_CURRENTLY_ON(BrowserThread::IO);
387 AudioEntry* entry = LookupById(stream_id);
388 if (!entry) {
389 SendErrorMessage(stream_id);
390 return;
393 entry->controller()->Play();
394 audio_log_->OnStarted(stream_id);
397 void AudioRendererHost::OnPauseStream(int stream_id) {
398 DCHECK_CURRENTLY_ON(BrowserThread::IO);
400 AudioEntry* entry = LookupById(stream_id);
401 if (!entry) {
402 SendErrorMessage(stream_id);
403 return;
406 entry->controller()->Pause();
407 audio_log_->OnStopped(stream_id);
410 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
411 DCHECK_CURRENTLY_ON(BrowserThread::IO);
413 AudioEntry* entry = LookupById(stream_id);
414 if (!entry) {
415 SendErrorMessage(stream_id);
416 return;
419 // Make sure the volume is valid.
420 if (volume < 0 || volume > 1.0)
421 return;
422 entry->controller()->SetVolume(volume);
423 audio_log_->OnSetVolume(stream_id, volume);
426 void AudioRendererHost::SendErrorMessage(int stream_id) {
427 Send(new AudioMsg_NotifyStreamStateChanged(
428 stream_id, media::AudioOutputIPCDelegate::kError));
431 void AudioRendererHost::OnCloseStream(int stream_id) {
432 DCHECK_CURRENTLY_ON(BrowserThread::IO);
434 // Prevent oustanding callbacks from attempting to close/delete the same
435 // AudioEntry twice.
436 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
437 if (i == audio_entries_.end())
438 return;
439 scoped_ptr<AudioEntry> entry(i->second);
440 audio_entries_.erase(i);
442 media::AudioOutputController* const controller = entry->controller();
443 if (mirroring_manager_) {
444 mirroring_manager_->RemoveDiverter(
445 render_process_id_, entry->render_view_id(), controller);
447 controller->Close(
448 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
449 audio_log_->OnClosed(stream_id);
452 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
453 DCHECK_CURRENTLY_ON(BrowserThread::IO);
455 // At this point, make the final "say" in audio playback state.
456 MediaObserver* const media_observer =
457 GetContentClient()->browser()->GetMediaObserver();
458 if (media_observer) {
459 media_observer->OnAudioStreamStopped(render_process_id_,
460 entry->render_frame_id(),
461 entry->stream_id());
465 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
466 DCHECK_CURRENTLY_ON(BrowserThread::IO);
468 // Make sure this isn't a stray callback executing after the stream has been
469 // closed, so error notifications aren't sent after clients believe the stream
470 // is closed.
471 if (!LookupById(stream_id))
472 return;
474 SendErrorMessage(stream_id);
476 audio_log_->OnError(stream_id);
477 OnCloseStream(stream_id);
480 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
481 DCHECK_CURRENTLY_ON(BrowserThread::IO);
483 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
484 return i != audio_entries_.end() ? i->second : NULL;
487 } // namespace content