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.
4
5 #include "content/browser/renderer_host/media/audio_renderer_host.h"
6
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/media_internals.h"
14 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
15 #include "content/browser/renderer_host/media/audio_mirroring_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"
25
26 using media::AudioBus;
27 using media::AudioManager;
28
29 namespace content {
30
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 const media::AudioParameters& params,
38 const std::string& output_device_id,
39 const std::string& input_device_id,
40 scoped_ptr<base::SharedMemory> shared_memory,
41 scoped_ptr<media::AudioOutputController::SyncReader> reader);
42 virtual ~AudioEntry();
43
stream_id() const44 int stream_id() const {
45 return stream_id_;
46 }
47
render_view_id() const48 int render_view_id() const {
49 return render_view_id_;
50 }
51
controller() const52 media::AudioOutputController* controller() const { return controller_.get(); }
53
shared_memory()54 base::SharedMemory* shared_memory() {
55 return shared_memory_.get();
56 }
57
reader() const58 media::AudioOutputController::SyncReader* reader() const {
59 return reader_.get();
60 }
61
62 private:
63 // media::AudioOutputController::EventHandler implementation.
64 virtual void OnCreated() OVERRIDE;
65 virtual void OnPlaying() OVERRIDE;
66 virtual void OnPowerMeasured(float power_dbfs, bool clipped) OVERRIDE;
67 virtual void OnPaused() OVERRIDE;
68 virtual void OnError() OVERRIDE;
69 virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate)
70 OVERRIDE;
71
72 AudioRendererHost* const host_;
73 const int stream_id_;
74
75 // The routing ID of the source render view.
76 const int render_view_id_;
77
78 // The AudioOutputController that manages the audio stream.
79 const scoped_refptr<media::AudioOutputController> controller_;
80
81 // Shared memory for transmission of the audio data.
82 const scoped_ptr<base::SharedMemory> shared_memory_;
83
84 // The synchronous reader to be used by the controller.
85 const scoped_ptr<media::AudioOutputController::SyncReader> reader_;
86 };
87
AudioEntry(AudioRendererHost * host,int stream_id,int render_view_id,const media::AudioParameters & params,const std::string & output_device_id,const std::string & input_device_id,scoped_ptr<base::SharedMemory> shared_memory,scoped_ptr<media::AudioOutputController::SyncReader> reader)88 AudioRendererHost::AudioEntry::AudioEntry(
89 AudioRendererHost* host, int stream_id, int render_view_id,
90 const media::AudioParameters& params,
91 const std::string& output_device_id,
92 const std::string& input_device_id,
93 scoped_ptr<base::SharedMemory> shared_memory,
94 scoped_ptr<media::AudioOutputController::SyncReader> reader)
95 : host_(host),
96 stream_id_(stream_id),
97 render_view_id_(render_view_id),
98 controller_(media::AudioOutputController::Create(
99 host->audio_manager_, this, params, output_device_id,
100 input_device_id, reader.get())),
101 shared_memory_(shared_memory.Pass()),
102 reader_(reader.Pass()) {
103 DCHECK(controller_.get());
104 }
105
~AudioEntry()106 AudioRendererHost::AudioEntry::~AudioEntry() {}
107
108 ///////////////////////////////////////////////////////////////////////////////
109 // AudioRendererHost implementations.
110
AudioRendererHost(int render_process_id,media::AudioManager * audio_manager,AudioMirroringManager * mirroring_manager,MediaInternals * media_internals,MediaStreamManager * media_stream_manager)111 AudioRendererHost::AudioRendererHost(
112 int render_process_id,
113 media::AudioManager* audio_manager,
114 AudioMirroringManager* mirroring_manager,
115 MediaInternals* media_internals,
116 MediaStreamManager* media_stream_manager)
117 : render_process_id_(render_process_id),
118 audio_manager_(audio_manager),
119 mirroring_manager_(mirroring_manager),
120 audio_log_(media_internals->CreateAudioLog(
121 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
122 media_stream_manager_(media_stream_manager) {
123 DCHECK(audio_manager_);
124 DCHECK(media_stream_manager_);
125 }
126
~AudioRendererHost()127 AudioRendererHost::~AudioRendererHost() {
128 DCHECK(audio_entries_.empty());
129 }
130
GetOutputControllers(int render_view_id,const RenderViewHost::GetAudioOutputControllersCallback & callback) const131 void AudioRendererHost::GetOutputControllers(
132 int render_view_id,
133 const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
134 BrowserThread::PostTaskAndReplyWithResult(
135 BrowserThread::IO,
136 FROM_HERE,
137 base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
138 render_view_id),
139 callback);
140 }
141
OnChannelClosing()142 void AudioRendererHost::OnChannelClosing() {
143 // Since the IPC channel is gone, close all requested audio streams.
144 while (!audio_entries_.empty()) {
145 // Note: OnCloseStream() removes the entries from audio_entries_.
146 OnCloseStream(audio_entries_.begin()->first);
147 }
148 }
149
OnDestruct() const150 void AudioRendererHost::OnDestruct() const {
151 BrowserThread::DeleteOnIOThread::Destruct(this);
152 }
153
OnCreated()154 void AudioRendererHost::AudioEntry::OnCreated() {
155 BrowserThread::PostTask(
156 BrowserThread::IO,
157 FROM_HERE,
158 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
159 }
160
OnPlaying()161 void AudioRendererHost::AudioEntry::OnPlaying() {
162 BrowserThread::PostTask(
163 BrowserThread::IO,
164 FROM_HERE,
165 base::Bind(
166 base::IgnoreResult(&AudioRendererHost::Send), host_,
167 new AudioMsg_NotifyStreamStateChanged(
168 stream_id_, media::AudioOutputIPCDelegate::kPlaying)));
169 }
170
OnPowerMeasured(float power_dbfs,bool clipped)171 void AudioRendererHost::AudioEntry::OnPowerMeasured(float power_dbfs,
172 bool clipped) {
173 BrowserThread::PostTask(
174 BrowserThread::IO,
175 FROM_HERE,
176 base::Bind(&AudioRendererHost::DoNotifyAudioPowerLevel, host_,
177 stream_id_, power_dbfs, clipped));
178 }
179
OnPaused()180 void AudioRendererHost::AudioEntry::OnPaused() {
181 BrowserThread::PostTask(
182 BrowserThread::IO,
183 FROM_HERE,
184 base::Bind(
185 base::IgnoreResult(&AudioRendererHost::Send), host_,
186 new AudioMsg_NotifyStreamStateChanged(
187 stream_id_, media::AudioOutputIPCDelegate::kPaused)));
188 }
189
OnError()190 void AudioRendererHost::AudioEntry::OnError() {
191 BrowserThread::PostTask(
192 BrowserThread::IO,
193 FROM_HERE,
194 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
195 }
196
OnDeviceChange(int new_buffer_size,int new_sample_rate)197 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
198 int new_sample_rate) {
199 BrowserThread::PostTask(
200 BrowserThread::IO,
201 FROM_HERE,
202 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
203 new AudioMsg_NotifyDeviceChanged(
204 stream_id_, new_buffer_size, new_sample_rate)));
205 }
206
DoCompleteCreation(int stream_id)207 void AudioRendererHost::DoCompleteCreation(int stream_id) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209
210 if (!PeerHandle()) {
211 DLOG(WARNING) << "Renderer process handle is invalid.";
212 ReportErrorAndClose(stream_id);
213 return;
214 }
215
216 AudioEntry* const entry = LookupById(stream_id);
217 if (!entry) {
218 ReportErrorAndClose(stream_id);
219 return;
220 }
221
222 // Once the audio stream is created then complete the creation process by
223 // mapping shared memory and sharing with the renderer process.
224 base::SharedMemoryHandle foreign_memory_handle;
225 if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
226 &foreign_memory_handle)) {
227 // If we failed to map and share the shared memory then close the audio
228 // stream and send an error message.
229 ReportErrorAndClose(entry->stream_id());
230 return;
231 }
232
233 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
234
235 #if defined(OS_WIN)
236 base::SyncSocket::Handle foreign_socket_handle;
237 #else
238 base::FileDescriptor foreign_socket_handle;
239 #endif
240
241 // If we failed to prepare the sync socket for the renderer then we fail
242 // the construction of audio stream.
243 if (!reader->PrepareForeignSocketHandle(PeerHandle(),
244 &foreign_socket_handle)) {
245 ReportErrorAndClose(entry->stream_id());
246 return;
247 }
248
249 Send(new AudioMsg_NotifyStreamCreated(
250 entry->stream_id(),
251 foreign_memory_handle,
252 foreign_socket_handle,
253 entry->shared_memory()->requested_size()));
254 }
255
256 RenderViewHost::AudioOutputControllerList
DoGetOutputControllers(int render_view_id) const257 AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
258 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
259
260 RenderViewHost::AudioOutputControllerList controllers;
261 AudioEntryMap::const_iterator it = audio_entries_.begin();
262 for (; it != audio_entries_.end(); ++it) {
263 AudioEntry* entry = it->second;
264 if (entry->render_view_id() == render_view_id)
265 controllers.push_back(entry->controller());
266 }
267
268 return controllers;
269 }
270
DoNotifyAudioPowerLevel(int stream_id,float power_dbfs,bool clipped)271 void AudioRendererHost::DoNotifyAudioPowerLevel(int stream_id,
272 float power_dbfs,
273 bool clipped) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
275
276 MediaObserver* const media_observer =
277 GetContentClient()->browser()->GetMediaObserver();
278 if (media_observer) {
279 AudioEntry* const entry = LookupById(stream_id);
280 if (entry) {
281 media_observer->OnAudioStreamPlayingChanged(
282 render_process_id_, entry->render_view_id(), entry->stream_id(),
283 true, power_dbfs, clipped);
284 }
285 }
286 }
287
288 ///////////////////////////////////////////////////////////////////////////////
289 // IPC Messages handler
OnMessageReceived(const IPC::Message & message,bool * message_was_ok)290 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
291 bool* message_was_ok) {
292 bool handled = true;
293 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok)
294 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
295 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
296 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
297 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
298 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
299 IPC_MESSAGE_UNHANDLED(handled = false)
300 IPC_END_MESSAGE_MAP_EX()
301
302 return handled;
303 }
304
OnCreateStream(int stream_id,int render_view_id,int session_id,const media::AudioParameters & params)305 void AudioRendererHost::OnCreateStream(
306 int stream_id, int render_view_id, int session_id,
307 const media::AudioParameters& params) {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309
310 DVLOG(1) << "AudioRendererHost@" << this
311 << "::OnCreateStream(stream_id=" << stream_id
312 << ", render_view_id=" << render_view_id
313 << ", session_id=" << session_id << ")";
314 DCHECK_GT(render_view_id, 0);
315
316 // media::AudioParameters is validated in the deserializer.
317 int input_channels = params.input_channels();
318 if (input_channels < 0 ||
319 input_channels > media::limits::kMaxChannels ||
320 LookupById(stream_id) != NULL) {
321 SendErrorMessage(stream_id);
322 return;
323 }
324
325 // When the |input_channels| is valid, clients are trying to create a unified
326 // IO stream which opens an input device mapping to the |session_id|.
327 // Initialize the |output_device_id| to an empty string which indicates that
328 // the default device should be used. If a StreamDeviceInfo instance was found
329 // though, then we use the matched output device.
330 std::string input_device_id, output_device_id;
331 const StreamDeviceInfo* info = media_stream_manager_->
332 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
333 if (info)
334 output_device_id = info->device.matched_output_device_id;
335
336 if (input_channels > 0) {
337 if (!info) {
338 SendErrorMessage(stream_id);
339 DLOG(WARNING) << "No permission has been granted to input stream with "
340 << "session_id=" << session_id;
341 return;
342 }
343
344 input_device_id = info->device.id;
345 }
346
347 // Calculate output and input memory size.
348 int output_memory_size = AudioBus::CalculateMemorySize(params);
349 int frames = params.frames_per_buffer();
350 int input_memory_size = AudioBus::CalculateMemorySize(input_channels, frames);
351
352 // Create the shared memory and share with the renderer process.
353 // For synchronized I/O (if input_channels > 0) then we allocate
354 // extra memory after the output data for the input data.
355 uint32 shared_memory_size = output_memory_size + input_memory_size;
356 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
357 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
358 SendErrorMessage(stream_id);
359 return;
360 }
361
362 scoped_ptr<AudioSyncReader> reader(
363 new AudioSyncReader(shared_memory.get(), params, input_channels));
364 if (!reader->Init()) {
365 SendErrorMessage(stream_id);
366 return;
367 }
368
369 MediaObserver* const media_observer =
370 GetContentClient()->browser()->GetMediaObserver();
371 if (media_observer)
372 media_observer->OnCreatingAudioStream(render_process_id_, render_view_id);
373
374 scoped_ptr<AudioEntry> entry(new AudioEntry(
375 this, stream_id, render_view_id, params, output_device_id,
376 input_device_id, shared_memory.Pass(),
377 reader.PassAs<media::AudioOutputController::SyncReader>()));
378 if (mirroring_manager_) {
379 mirroring_manager_->AddDiverter(
380 render_process_id_, entry->render_view_id(), entry->controller());
381 }
382 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
383 audio_log_->OnCreated(stream_id, params, input_device_id, output_device_id);
384 }
385
OnPlayStream(int stream_id)386 void AudioRendererHost::OnPlayStream(int stream_id) {
387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
388
389 AudioEntry* entry = LookupById(stream_id);
390 if (!entry) {
391 SendErrorMessage(stream_id);
392 return;
393 }
394
395 entry->controller()->Play();
396 audio_log_->OnStarted(stream_id);
397 }
398
OnPauseStream(int stream_id)399 void AudioRendererHost::OnPauseStream(int stream_id) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
401
402 AudioEntry* entry = LookupById(stream_id);
403 if (!entry) {
404 SendErrorMessage(stream_id);
405 return;
406 }
407
408 entry->controller()->Pause();
409 audio_log_->OnStopped(stream_id);
410 }
411
OnSetVolume(int stream_id,double volume)412 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
414
415 AudioEntry* entry = LookupById(stream_id);
416 if (!entry) {
417 SendErrorMessage(stream_id);
418 return;
419 }
420
421 // Make sure the volume is valid.
422 if (volume < 0 || volume > 1.0)
423 return;
424 entry->controller()->SetVolume(volume);
425 audio_log_->OnSetVolume(stream_id, volume);
426 }
427
SendErrorMessage(int stream_id)428 void AudioRendererHost::SendErrorMessage(int stream_id) {
429 Send(new AudioMsg_NotifyStreamStateChanged(
430 stream_id, media::AudioOutputIPCDelegate::kError));
431 }
432
OnCloseStream(int stream_id)433 void AudioRendererHost::OnCloseStream(int stream_id) {
434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
435
436 // Prevent oustanding callbacks from attempting to close/delete the same
437 // AudioEntry twice.
438 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
439 if (i == audio_entries_.end())
440 return;
441 scoped_ptr<AudioEntry> entry(i->second);
442 audio_entries_.erase(i);
443
444 media::AudioOutputController* const controller = entry->controller();
445 if (mirroring_manager_) {
446 mirroring_manager_->RemoveDiverter(
447 render_process_id_, entry->render_view_id(), controller);
448 }
449 controller->Close(
450 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
451 audio_log_->OnClosed(stream_id);
452 }
453
DeleteEntry(scoped_ptr<AudioEntry> entry)454 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
456
457 // At this point, make the final "say" in audio playback state.
458 MediaObserver* const media_observer =
459 GetContentClient()->browser()->GetMediaObserver();
460 if (media_observer) {
461 media_observer->OnAudioStreamPlayingChanged(
462 render_process_id_, entry->render_view_id(), entry->stream_id(),
463 false, -std::numeric_limits<float>::infinity(), false);
464 }
465 }
466
ReportErrorAndClose(int stream_id)467 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
469
470 // Make sure this isn't a stray callback executing after the stream has been
471 // closed, so error notifications aren't sent after clients believe the stream
472 // is closed.
473 if (!LookupById(stream_id))
474 return;
475
476 SendErrorMessage(stream_id);
477
478 audio_log_->OnError(stream_id);
479 OnCloseStream(stream_id);
480 }
481
LookupById(int stream_id)482 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
484
485 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
486 return i != audio_entries_.end() ? i->second : NULL;
487 }
488
489 } // namespace content
490