Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_renderer_host.cc
blob0c8c310350bcfb86116470fc0889e092fdbd6d3e
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/command_line.h"
10 #include "base/metrics/histogram.h"
11 #include "base/process.h"
12 #include "base/shared_memory.h"
13 #include "content/browser/browser_main_loop.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_mirroring_manager.h"
17 #include "content/browser/renderer_host/media/audio_sync_reader.h"
18 #include "content/browser/renderer_host/media/media_stream_manager.h"
19 #include "content/common/media/audio_messages.h"
20 #include "content/public/browser/content_browser_client.h"
21 #include "content/public/browser/media_observer.h"
22 #include "content/public/common/content_switches.h"
23 #include "media/audio/audio_manager_base.h"
24 #include "media/audio/shared_memory_util.h"
25 #include "media/base/audio_bus.h"
26 #include "media/base/limits.h"
28 using media::AudioBus;
30 namespace content {
32 class AudioRendererHost::AudioEntry
33 : public media::AudioOutputController::EventHandler {
34 public:
35 AudioEntry(AudioRendererHost* host,
36 int stream_id,
37 int render_view_id,
38 const media::AudioParameters& params,
39 const std::string& input_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 media::AudioOutputController* controller() const { return controller_.get(); }
54 base::SharedMemory* shared_memory() {
55 return shared_memory_.get();
58 media::AudioOutputController::SyncReader* reader() const {
59 return reader_.get();
62 private:
63 // media::AudioOutputController::EventHandler implementation.
64 virtual void OnCreated() OVERRIDE;
65 virtual void OnPlaying() OVERRIDE;
66 virtual void OnAudible(bool is_audible) 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;
72 AudioRendererHost* const host_;
73 const int stream_id_;
75 // The routing ID of the source render view.
76 const int render_view_id_;
78 // The AudioOutputController that manages the audio stream.
79 const scoped_refptr<media::AudioOutputController> controller_;
81 // Shared memory for transmission of the audio data.
82 const scoped_ptr<base::SharedMemory> shared_memory_;
84 // The synchronous reader to be used by the controller.
85 const 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& input_device_id,
92 scoped_ptr<base::SharedMemory> shared_memory,
93 scoped_ptr<media::AudioOutputController::SyncReader> reader)
94 : host_(host),
95 stream_id_(stream_id),
96 render_view_id_(render_view_id),
97 controller_(media::AudioOutputController::Create(
98 host->audio_manager_, this, params, input_device_id, reader.get())),
99 shared_memory_(shared_memory.Pass()),
100 reader_(reader.Pass()) {
101 DCHECK(controller_.get());
104 AudioRendererHost::AudioEntry::~AudioEntry() {}
106 ///////////////////////////////////////////////////////////////////////////////
107 // AudioRendererHost implementations.
108 AudioRendererHost::AudioRendererHost(
109 int render_process_id,
110 media::AudioManager* audio_manager,
111 AudioMirroringManager* mirroring_manager,
112 MediaInternals* media_internals,
113 MediaStreamManager* media_stream_manager)
114 : render_process_id_(render_process_id),
115 audio_manager_(audio_manager),
116 mirroring_manager_(mirroring_manager),
117 media_internals_(media_internals),
118 media_stream_manager_(media_stream_manager) {
119 DCHECK(audio_manager_);
120 DCHECK(media_stream_manager_);
123 AudioRendererHost::~AudioRendererHost() {
124 DCHECK(audio_entries_.empty());
127 void AudioRendererHost::OnChannelClosing() {
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130 BrowserMessageFilter::OnChannelClosing();
132 // Since the IPC channel is gone, close all requested audio streams.
133 while (!audio_entries_.empty()) {
134 // Note: OnCloseStream() removes the entries from audio_entries_.
135 OnCloseStream(audio_entries_.begin()->first);
139 void AudioRendererHost::OnDestruct() const {
140 BrowserThread::DeleteOnIOThread::Destruct(this);
143 void AudioRendererHost::AudioEntry::OnCreated() {
144 BrowserThread::PostTask(
145 BrowserThread::IO,
146 FROM_HERE,
147 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, this));
150 void AudioRendererHost::AudioEntry::OnPlaying() {
151 BrowserThread::PostTask(
152 BrowserThread::IO,
153 FROM_HERE,
154 base::Bind(
155 base::IgnoreResult(&AudioRendererHost::Send), host_,
156 new AudioMsg_NotifyStreamStateChanged(
157 stream_id_, media::AudioOutputIPCDelegate::kPlaying)));
160 void AudioRendererHost::AudioEntry::OnAudible(bool is_audible) {
161 BrowserThread::PostTask(
162 BrowserThread::IO,
163 FROM_HERE,
164 base::Bind(&AudioRendererHost::DoNotifyAudibleState, host_,
165 this, is_audible));
168 void AudioRendererHost::AudioEntry::OnPaused() {
169 BrowserThread::PostTask(
170 BrowserThread::IO,
171 FROM_HERE,
172 base::Bind(
173 base::IgnoreResult(&AudioRendererHost::Send), host_,
174 new AudioMsg_NotifyStreamStateChanged(
175 stream_id_, media::AudioOutputIPCDelegate::kPaused)));
178 void AudioRendererHost::AudioEntry::OnError() {
179 BrowserThread::PostTask(
180 BrowserThread::IO,
181 FROM_HERE,
182 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
185 void AudioRendererHost::AudioEntry::OnDeviceChange(int new_buffer_size,
186 int new_sample_rate) {
187 BrowserThread::PostTask(
188 BrowserThread::IO,
189 FROM_HERE,
190 base::Bind(base::IgnoreResult(&AudioRendererHost::Send), host_,
191 new AudioMsg_NotifyDeviceChanged(
192 stream_id_, new_buffer_size, new_sample_rate)));
195 void AudioRendererHost::DoCompleteCreation(AudioEntry* entry) {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
198 if (!peer_handle()) {
199 NOTREACHED() << "Renderer process handle is invalid.";
200 ReportErrorAndClose(entry->stream_id());
201 return;
204 // Once the audio stream is created then complete the creation process by
205 // mapping shared memory and sharing with the renderer process.
206 base::SharedMemoryHandle foreign_memory_handle;
207 if (!entry->shared_memory()->ShareToProcess(peer_handle(),
208 &foreign_memory_handle)) {
209 // If we failed to map and share the shared memory then close the audio
210 // stream and send an error message.
211 ReportErrorAndClose(entry->stream_id());
212 return;
215 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
217 #if defined(OS_WIN)
218 base::SyncSocket::Handle foreign_socket_handle;
219 #else
220 base::FileDescriptor foreign_socket_handle;
221 #endif
223 // If we failed to prepare the sync socket for the renderer then we fail
224 // the construction of audio stream.
225 if (!reader->PrepareForeignSocketHandle(peer_handle(),
226 &foreign_socket_handle)) {
227 ReportErrorAndClose(entry->stream_id());
228 return;
231 Send(new AudioMsg_NotifyStreamCreated(
232 entry->stream_id(),
233 foreign_memory_handle,
234 foreign_socket_handle,
235 media::PacketSizeInBytes(entry->shared_memory()->requested_size())));
238 void AudioRendererHost::DoNotifyAudibleState(AudioEntry* entry,
239 bool is_audible) {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
242 MediaObserver* const media_observer =
243 GetContentClient()->browser()->GetMediaObserver();
244 if (media_observer) {
245 DVLOG(1) << "AudioRendererHost@" << this
246 << "::DoNotifyAudibleState(is_audible=" << is_audible
247 << ") for stream_id=" << entry->stream_id();
249 if (CommandLine::ForCurrentProcess()->HasSwitch(
250 switches::kEnableAudibleNotifications)) {
251 media_observer->OnAudioStreamPlayingChanged(
252 render_process_id_, entry->render_view_id(), entry->stream_id(),
253 is_audible);
258 ///////////////////////////////////////////////////////////////////////////////
259 // IPC Messages handler
260 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message,
261 bool* message_was_ok) {
262 bool handled = true;
263 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok)
264 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
265 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
266 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
267 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
268 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
269 IPC_MESSAGE_UNHANDLED(handled = false)
270 IPC_END_MESSAGE_MAP_EX()
272 return handled;
275 void AudioRendererHost::OnCreateStream(
276 int stream_id, int render_view_id, int session_id,
277 const media::AudioParameters& params) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
280 DVLOG(1) << "AudioRendererHost@" << this
281 << "::OnCreateStream(stream_id=" << stream_id
282 << ", render_view_id=" << render_view_id
283 << ", session_id=" << session_id << ")";
284 DCHECK_GT(render_view_id, 0);
286 // media::AudioParameters is validated in the deserializer.
287 int input_channels = params.input_channels();
288 if (input_channels < 0 ||
289 input_channels > media::limits::kMaxChannels ||
290 LookupById(stream_id) != NULL) {
291 SendErrorMessage(stream_id);
292 return;
295 // When the |input_channels| is valid, clients are trying to create a unified
296 // IO stream which opens an input device mapping to the |session_id|.
297 std::string input_device_id;
298 if (input_channels > 0) {
299 const StreamDeviceInfo* info = media_stream_manager_->
300 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
301 if (!info) {
302 SendErrorMessage(stream_id);
303 DLOG(WARNING) << "No permission has been granted to input stream with "
304 << "session_id=" << session_id;
305 return;
308 input_device_id = info->device.id;
311 // Calculate output and input memory size.
312 int output_memory_size = AudioBus::CalculateMemorySize(params);
313 int frames = params.frames_per_buffer();
314 int input_memory_size =
315 AudioBus::CalculateMemorySize(input_channels, frames);
317 // Create the shared memory and share with the renderer process.
318 // For synchronized I/O (if input_channels > 0) then we allocate
319 // extra memory after the output data for the input data.
320 uint32 io_buffer_size = output_memory_size + input_memory_size;
321 uint32 shared_memory_size =
322 media::TotalSharedMemorySizeInBytes(io_buffer_size);
323 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
324 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
325 SendErrorMessage(stream_id);
326 return;
329 scoped_ptr<AudioSyncReader> reader(
330 new AudioSyncReader(shared_memory.get(), params, input_channels));
331 if (!reader->Init()) {
332 SendErrorMessage(stream_id);
333 return;
336 scoped_ptr<AudioEntry> entry(new AudioEntry(
337 this, stream_id, render_view_id, params, input_device_id,
338 shared_memory.Pass(),
339 reader.PassAs<media::AudioOutputController::SyncReader>()));
340 if (mirroring_manager_) {
341 mirroring_manager_->AddDiverter(
342 render_process_id_, entry->render_view_id(), entry->controller());
344 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
345 if (media_internals_)
346 media_internals_->OnSetAudioStreamStatus(this, stream_id, "created");
349 void AudioRendererHost::OnPlayStream(int stream_id) {
350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
352 AudioEntry* entry = LookupById(stream_id);
353 if (!entry) {
354 SendErrorMessage(stream_id);
355 return;
358 entry->controller()->Play();
359 if (media_internals_)
360 media_internals_->OnSetAudioStreamPlaying(this, stream_id, true);
363 void AudioRendererHost::OnPauseStream(int stream_id) {
364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
366 AudioEntry* entry = LookupById(stream_id);
367 if (!entry) {
368 SendErrorMessage(stream_id);
369 return;
372 entry->controller()->Pause();
373 if (media_internals_)
374 media_internals_->OnSetAudioStreamPlaying(this, stream_id, false);
377 void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
380 AudioEntry* entry = LookupById(stream_id);
381 if (!entry) {
382 SendErrorMessage(stream_id);
383 return;
386 // Make sure the volume is valid.
387 if (volume < 0 || volume > 1.0)
388 return;
389 entry->controller()->SetVolume(volume);
390 if (media_internals_)
391 media_internals_->OnSetAudioStreamVolume(this, stream_id, volume);
394 void AudioRendererHost::SendErrorMessage(int stream_id) {
395 Send(new AudioMsg_NotifyStreamStateChanged(
396 stream_id, media::AudioOutputIPCDelegate::kError));
399 void AudioRendererHost::OnCloseStream(int stream_id) {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
402 // Prevent oustanding callbacks from attempting to close/delete the same
403 // AudioEntry twice.
404 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
405 if (i == audio_entries_.end())
406 return;
407 scoped_ptr<AudioEntry> entry(i->second);
408 audio_entries_.erase(i);
410 media::AudioOutputController* const controller = entry->controller();
411 if (mirroring_manager_) {
412 mirroring_manager_->RemoveDiverter(
413 render_process_id_, entry->render_view_id(), controller);
415 controller->Close(
416 base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
418 if (media_internals_)
419 media_internals_->OnSetAudioStreamStatus(this, stream_id, "closed");
422 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
425 // At this point, make the final "say" in audio playback state.
426 MediaObserver* const media_observer =
427 GetContentClient()->browser()->GetMediaObserver();
428 if (media_observer) {
429 media_observer->OnAudioStreamPlayingChanged(
430 render_process_id_, entry->render_view_id(), entry->stream_id(), false);
433 // Notify the media observer.
434 if (media_internals_)
435 media_internals_->OnDeleteAudioStream(this, entry->stream_id());
437 // Note: |entry| will be deleted upon leaving this scope.
440 void AudioRendererHost::ReportErrorAndClose(int stream_id) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
443 // Make sure this isn't a stray callback executing after the stream has been
444 // closed, so error notifications aren't sent after clients believe the stream
445 // is closed.
446 if (!LookupById(stream_id))
447 return;
449 SendErrorMessage(stream_id);
451 if (media_internals_)
452 media_internals_->OnSetAudioStreamStatus(this, stream_id, "error");
454 OnCloseStream(stream_id);
457 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
460 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
461 return i != audio_entries_.end() ? i->second : NULL;
464 } // namespace content