Revert of Remove the last piece of deprecated synchronous IO code. (patchset #5 of...
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_input_renderer_host.cc
blob2dcc56d0918090e456ba0227cae5774e33bd947d
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_input_renderer_host.h"
7 #include "base/bind.h"
8 #include "base/memory/shared_memory.h"
9 #include "base/metrics/histogram.h"
10 #include "base/numerics/safe_math.h"
11 #include "base/process/process.h"
12 #include "base/strings/stringprintf.h"
13 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
14 #include "content/browser/media/capture/web_contents_capture_util.h"
15 #include "content/browser/media/media_internals.h"
16 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
17 #include "content/browser/renderer_host/media/audio_input_sync_writer.h"
18 #include "content/browser/renderer_host/media/media_stream_manager.h"
19 #include "media/audio/audio_manager_base.h"
20 #include "media/base/audio_bus.h"
22 namespace content {
24 struct AudioInputRendererHost::AudioEntry {
25 AudioEntry();
26 ~AudioEntry();
28 // The AudioInputController that manages the audio input stream.
29 scoped_refptr<media::AudioInputController> controller;
31 // The audio input stream ID in the render view.
32 int stream_id;
34 // Shared memory for transmission of the audio data. It has
35 // |shared_memory_segment_count| equal lengthed segments.
36 base::SharedMemory shared_memory;
37 int shared_memory_segment_count;
39 // The synchronous writer to be used by the controller. We have the
40 // ownership of the writer.
41 scoped_ptr<media::AudioInputController::SyncWriter> writer;
43 // Set to true after we called Close() for the controller.
44 bool pending_close;
47 AudioInputRendererHost::AudioEntry::AudioEntry()
48 : stream_id(0),
49 shared_memory_segment_count(0),
50 pending_close(false) {
53 AudioInputRendererHost::AudioEntry::~AudioEntry() {}
55 AudioInputRendererHost::AudioInputRendererHost(
56 media::AudioManager* audio_manager,
57 MediaStreamManager* media_stream_manager,
58 AudioMirroringManager* audio_mirroring_manager,
59 media::UserInputMonitor* user_input_monitor)
60 : BrowserMessageFilter(AudioMsgStart),
61 audio_manager_(audio_manager),
62 media_stream_manager_(media_stream_manager),
63 audio_mirroring_manager_(audio_mirroring_manager),
64 user_input_monitor_(user_input_monitor),
65 audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
66 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
68 AudioInputRendererHost::~AudioInputRendererHost() {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
70 DCHECK(audio_entries_.empty());
73 void AudioInputRendererHost::OnChannelClosing() {
74 // Since the IPC sender is gone, close all requested audio streams.
75 DeleteEntries();
78 void AudioInputRendererHost::OnDestruct() const {
79 BrowserThread::DeleteOnIOThread::Destruct(this);
82 void AudioInputRendererHost::OnCreated(
83 media::AudioInputController* controller) {
84 BrowserThread::PostTask(
85 BrowserThread::IO,
86 FROM_HERE,
87 base::Bind(
88 &AudioInputRendererHost::DoCompleteCreation,
89 this,
90 make_scoped_refptr(controller)));
93 void AudioInputRendererHost::OnRecording(
94 media::AudioInputController* controller) {
95 BrowserThread::PostTask(
96 BrowserThread::IO,
97 FROM_HERE,
98 base::Bind(
99 &AudioInputRendererHost::DoSendRecordingMessage,
100 this,
101 make_scoped_refptr(controller)));
104 void AudioInputRendererHost::OnError(media::AudioInputController* controller,
105 media::AudioInputController::ErrorCode error_code) {
106 BrowserThread::PostTask(
107 BrowserThread::IO,
108 FROM_HERE,
109 base::Bind(
110 &AudioInputRendererHost::DoHandleError,
111 this,
112 make_scoped_refptr(controller),
113 error_code));
116 void AudioInputRendererHost::OnData(media::AudioInputController* controller,
117 const media::AudioBus* data) {
118 NOTREACHED() << "Only low-latency mode is supported.";
121 void AudioInputRendererHost::OnLog(media::AudioInputController* controller,
122 const std::string& message) {
123 BrowserThread::PostTask(BrowserThread::IO,
124 FROM_HERE,
125 base::Bind(&AudioInputRendererHost::DoLog,
126 this,
127 make_scoped_refptr(controller),
128 message));
131 void AudioInputRendererHost::DoCompleteCreation(
132 media::AudioInputController* controller) {
133 DCHECK_CURRENTLY_ON(BrowserThread::IO);
135 AudioEntry* entry = LookupByController(controller);
136 if (!entry)
137 return;
139 if (!PeerHandle()) {
140 NOTREACHED() << "Renderer process handle is invalid.";
141 DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
142 return;
145 if (!entry->controller->SharedMemoryAndSyncSocketMode()) {
146 NOTREACHED() << "Only shared-memory/sync-socket mode is supported.";
147 DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
148 return;
151 // Once the audio stream is created then complete the creation process by
152 // mapping shared memory and sharing with the renderer process.
153 base::SharedMemoryHandle foreign_memory_handle;
154 if (!entry->shared_memory.ShareToProcess(PeerHandle(),
155 &foreign_memory_handle)) {
156 // If we failed to map and share the shared memory then close the audio
157 // stream and send an error message.
158 DeleteEntryOnError(entry, MEMORY_SHARING_FAILED);
159 return;
162 AudioInputSyncWriter* writer =
163 static_cast<AudioInputSyncWriter*>(entry->writer.get());
165 #if defined(OS_WIN)
166 base::SyncSocket::Handle foreign_socket_handle;
167 #else
168 base::FileDescriptor foreign_socket_handle;
169 #endif
171 // If we failed to prepare the sync socket for the renderer then we fail
172 // the construction of audio input stream.
173 if (!writer->PrepareForeignSocketHandle(PeerHandle(),
174 &foreign_socket_handle)) {
175 DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
176 return;
179 Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
180 foreign_memory_handle, foreign_socket_handle,
181 entry->shared_memory.requested_size(),
182 entry->shared_memory_segment_count));
185 void AudioInputRendererHost::DoSendRecordingMessage(
186 media::AudioInputController* controller) {
187 DCHECK_CURRENTLY_ON(BrowserThread::IO);
188 // TODO(henrika): See crbug.com/115262 for details on why this method
189 // should be implemented.
192 void AudioInputRendererHost::DoHandleError(
193 media::AudioInputController* controller,
194 media::AudioInputController::ErrorCode error_code) {
195 DCHECK_CURRENTLY_ON(BrowserThread::IO);
196 // Log all errors even it is ignored later.
197 MediaStreamManager::SendMessageToNativeLog(
198 base::StringPrintf("AudioInputController error: %d", error_code));
200 // This is a fix for crbug.com/357501. The error can be triggered when closing
201 // the lid on Macs, which causes more problems than it fixes.
202 // Also, in crbug.com/357569, the goal is to remove usage of the error since
203 // it was added to solve a crash on Windows that no longer can be reproduced.
204 if (error_code == media::AudioInputController::NO_DATA_ERROR) {
205 DVLOG(1) << "AudioInputRendererHost@" << this << "::DoHandleError: "
206 << "NO_DATA_ERROR ignored.";
207 return;
210 AudioEntry* entry = LookupByController(controller);
211 if (!entry)
212 return;
214 audio_log_->OnError(entry->stream_id);
215 DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
218 void AudioInputRendererHost::DoLog(media::AudioInputController* controller,
219 const std::string& message) {
220 DCHECK_CURRENTLY_ON(BrowserThread::IO);
221 AudioEntry* entry = LookupByController(controller);
222 if (!entry)
223 return;
225 // Add stream ID and current audio level reported by AIC to native log.
226 std::string log_string =
227 base::StringPrintf("[stream_id=%d] ", entry->stream_id);
228 log_string += message;
229 MediaStreamManager::SendMessageToNativeLog(log_string);
230 DVLOG(1) << log_string;
233 bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
234 bool handled = true;
235 IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHost, message)
236 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
237 IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
238 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
239 IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
240 IPC_MESSAGE_UNHANDLED(handled = false)
241 IPC_END_MESSAGE_MAP()
243 return handled;
246 void AudioInputRendererHost::OnCreateStream(
247 int stream_id,
248 int render_view_id,
249 int session_id,
250 const AudioInputHostMsg_CreateStream_Config& config) {
251 DCHECK_CURRENTLY_ON(BrowserThread::IO);
253 DVLOG(1) << "AudioInputRendererHost@" << this
254 << "::OnCreateStream(stream_id=" << stream_id
255 << ", render_view_id=" << render_view_id
256 << ", session_id=" << session_id << ")";
257 DCHECK_GT(render_view_id, 0);
259 // media::AudioParameters is validated in the deserializer.
260 if (LookupById(stream_id) != NULL) {
261 SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
262 return;
265 media::AudioParameters audio_params(config.params);
266 if (media_stream_manager_->audio_input_device_manager()->
267 ShouldUseFakeDevice()) {
268 audio_params.Reset(
269 media::AudioParameters::AUDIO_FAKE,
270 config.params.channel_layout(), config.params.channels(), 0,
271 config.params.sample_rate(), config.params.bits_per_sample(),
272 config.params.frames_per_buffer());
275 // Check if we have the permission to open the device and which device to use.
276 std::string device_name;
277 std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
278 if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
279 const StreamDeviceInfo* info = media_stream_manager_->
280 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
281 if (!info) {
282 SendErrorMessage(stream_id, PERMISSION_DENIED);
283 DLOG(WARNING) << "No permission has been granted to input stream with "
284 << "session_id=" << session_id;
285 return;
288 device_id = info->device.id;
289 device_name = info->device.name;
292 // Create a new AudioEntry structure.
293 scoped_ptr<AudioEntry> entry(new AudioEntry());
295 const uint32 segment_size =
296 (sizeof(media::AudioInputBufferParameters) +
297 media::AudioBus::CalculateMemorySize(audio_params));
298 entry->shared_memory_segment_count = config.shared_memory_count;
300 // Create the shared memory and share it with the renderer process
301 // using a new SyncWriter object.
302 base::CheckedNumeric<uint32> size = segment_size;
303 size *= entry->shared_memory_segment_count;
304 if (!size.IsValid() ||
305 !entry->shared_memory.CreateAndMapAnonymous(size.ValueOrDie())) {
306 // If creation of shared memory failed then send an error message.
307 SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
308 return;
311 scoped_ptr<AudioInputSyncWriter> writer(new AudioInputSyncWriter(
312 &entry->shared_memory, entry->shared_memory_segment_count, audio_params));
314 if (!writer->Init()) {
315 SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
316 return;
319 // If we have successfully created the SyncWriter then assign it to the
320 // entry and construct an AudioInputController.
321 entry->writer.reset(writer.release());
322 if (WebContentsCaptureUtil::IsWebContentsDeviceId(device_id)) {
323 entry->controller = media::AudioInputController::CreateForStream(
324 audio_manager_->GetTaskRunner(),
325 this,
326 WebContentsAudioInputStream::Create(
327 device_id,
328 audio_params,
329 audio_manager_->GetWorkerTaskRunner(),
330 audio_mirroring_manager_),
331 entry->writer.get(),
332 user_input_monitor_);
333 } else {
334 // TODO(henrika): replace CreateLowLatency() with Create() as soon
335 // as satish has ensured that Speech Input also uses the default low-
336 // latency path. See crbug.com/112472 for details.
337 entry->controller =
338 media::AudioInputController::CreateLowLatency(audio_manager_,
339 this,
340 audio_params,
341 device_id,
342 entry->writer.get(),
343 user_input_monitor_);
346 if (!entry->controller.get()) {
347 SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
348 return;
351 // Set the initial AGC state for the audio input stream. Note that, the AGC
352 // is only supported in AUDIO_PCM_LOW_LATENCY mode.
353 if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY)
354 entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
356 // Since the controller was created successfully, create an entry and add it
357 // to the map.
358 entry->stream_id = stream_id;
359 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
361 MediaStreamManager::SendMessageToNativeLog(
362 "Audio input stream created successfully. Device name: " + device_name);
363 audio_log_->OnCreated(stream_id, audio_params, device_id);
366 void AudioInputRendererHost::OnRecordStream(int stream_id) {
367 DCHECK_CURRENTLY_ON(BrowserThread::IO);
369 AudioEntry* entry = LookupById(stream_id);
370 if (!entry) {
371 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
372 return;
375 entry->controller->Record();
376 audio_log_->OnStarted(stream_id);
379 void AudioInputRendererHost::OnCloseStream(int stream_id) {
380 DCHECK_CURRENTLY_ON(BrowserThread::IO);
382 AudioEntry* entry = LookupById(stream_id);
384 if (entry)
385 CloseAndDeleteStream(entry);
388 void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
389 DCHECK_CURRENTLY_ON(BrowserThread::IO);
391 AudioEntry* entry = LookupById(stream_id);
392 if (!entry) {
393 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
394 return;
397 entry->controller->SetVolume(volume);
398 audio_log_->OnSetVolume(stream_id, volume);
401 void AudioInputRendererHost::SendErrorMessage(
402 int stream_id, ErrorCode error_code) {
403 MediaStreamManager::SendMessageToNativeLog(
404 base::StringPrintf("AudioInputRendererHost error: %d", error_code));
405 Send(new AudioInputMsg_NotifyStreamStateChanged(
406 stream_id, media::AudioInputIPCDelegate::kError));
409 void AudioInputRendererHost::DeleteEntries() {
410 DCHECK_CURRENTLY_ON(BrowserThread::IO);
412 for (AudioEntryMap::iterator i = audio_entries_.begin();
413 i != audio_entries_.end(); ++i) {
414 CloseAndDeleteStream(i->second);
418 void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
419 DCHECK_CURRENTLY_ON(BrowserThread::IO);
421 if (!entry->pending_close) {
422 entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
423 this, entry));
424 entry->pending_close = true;
425 audio_log_->OnClosed(entry->stream_id);
429 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
430 DCHECK_CURRENTLY_ON(BrowserThread::IO);
432 // Delete the entry when this method goes out of scope.
433 scoped_ptr<AudioEntry> entry_deleter(entry);
435 // Erase the entry from the map.
436 audio_entries_.erase(entry->stream_id);
439 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
440 ErrorCode error_code) {
441 DCHECK_CURRENTLY_ON(BrowserThread::IO);
443 // Sends the error message first before we close the stream because
444 // |entry| is destroyed in DeleteEntry().
445 SendErrorMessage(entry->stream_id, error_code);
446 CloseAndDeleteStream(entry);
449 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
450 int stream_id) {
451 DCHECK_CURRENTLY_ON(BrowserThread::IO);
453 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
454 if (i != audio_entries_.end())
455 return i->second;
456 return NULL;
459 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
460 media::AudioInputController* controller) {
461 DCHECK_CURRENTLY_ON(BrowserThread::IO);
463 // Iterate the map of entries.
464 // TODO(hclam): Implement a faster look up method.
465 for (AudioEntryMap::iterator i = audio_entries_.begin();
466 i != audio_entries_.end(); ++i) {
467 if (controller == i->second->controller.get())
468 return i->second;
470 return NULL;
473 } // namespace content