Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_input_renderer_host.cc
blobb536cf31ebfe5acd655e116cf0b4849eba312eba
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"
21 namespace content {
23 struct AudioInputRendererHost::AudioEntry {
24 AudioEntry();
25 ~AudioEntry();
27 // The AudioInputController that manages the audio input stream.
28 scoped_refptr<media::AudioInputController> controller;
30 // The audio input stream ID in the render view.
31 int stream_id;
33 // Shared memory for transmission of the audio data. It has
34 // |shared_memory_segment_count| equal lengthed segments.
35 base::SharedMemory shared_memory;
36 int shared_memory_segment_count;
38 // The synchronous writer to be used by the controller. We have the
39 // ownership of the writer.
40 scoped_ptr<media::AudioInputController::SyncWriter> writer;
42 // Set to true after we called Close() for the controller.
43 bool pending_close;
46 AudioInputRendererHost::AudioEntry::AudioEntry()
47 : stream_id(0),
48 shared_memory_segment_count(0),
49 pending_close(false) {
52 AudioInputRendererHost::AudioEntry::~AudioEntry() {}
54 AudioInputRendererHost::AudioInputRendererHost(
55 media::AudioManager* audio_manager,
56 MediaStreamManager* media_stream_manager,
57 AudioMirroringManager* audio_mirroring_manager,
58 media::UserInputMonitor* user_input_monitor)
59 : BrowserMessageFilter(AudioMsgStart),
60 audio_manager_(audio_manager),
61 media_stream_manager_(media_stream_manager),
62 audio_mirroring_manager_(audio_mirroring_manager),
63 user_input_monitor_(user_input_monitor),
64 audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
65 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
67 AudioInputRendererHost::~AudioInputRendererHost() {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
69 DCHECK(audio_entries_.empty());
72 void AudioInputRendererHost::OnChannelClosing() {
73 // Since the IPC channel is gone, close all requested audio streams.
74 DeleteEntries();
77 void AudioInputRendererHost::OnDestruct() const {
78 BrowserThread::DeleteOnIOThread::Destruct(this);
81 void AudioInputRendererHost::OnCreated(
82 media::AudioInputController* controller) {
83 BrowserThread::PostTask(
84 BrowserThread::IO,
85 FROM_HERE,
86 base::Bind(
87 &AudioInputRendererHost::DoCompleteCreation,
88 this,
89 make_scoped_refptr(controller)));
92 void AudioInputRendererHost::OnRecording(
93 media::AudioInputController* controller) {
94 BrowserThread::PostTask(
95 BrowserThread::IO,
96 FROM_HERE,
97 base::Bind(
98 &AudioInputRendererHost::DoSendRecordingMessage,
99 this,
100 make_scoped_refptr(controller)));
103 void AudioInputRendererHost::OnError(media::AudioInputController* controller,
104 media::AudioInputController::ErrorCode error_code) {
105 BrowserThread::PostTask(
106 BrowserThread::IO,
107 FROM_HERE,
108 base::Bind(
109 &AudioInputRendererHost::DoHandleError,
110 this,
111 make_scoped_refptr(controller),
112 error_code));
115 void AudioInputRendererHost::OnData(media::AudioInputController* controller,
116 const uint8* data,
117 uint32 size) {
118 NOTREACHED() << "Only low-latency mode is supported.";
121 void AudioInputRendererHost::DoCompleteCreation(
122 media::AudioInputController* controller) {
123 DCHECK_CURRENTLY_ON(BrowserThread::IO);
125 AudioEntry* entry = LookupByController(controller);
126 if (!entry)
127 return;
129 if (!PeerHandle()) {
130 NOTREACHED() << "Renderer process handle is invalid.";
131 DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
132 return;
135 if (!entry->controller->SharedMemoryAndSyncSocketMode()) {
136 NOTREACHED() << "Only shared-memory/sync-socket mode is supported.";
137 DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
138 return;
141 // Once the audio stream is created then complete the creation process by
142 // mapping shared memory and sharing with the renderer process.
143 base::SharedMemoryHandle foreign_memory_handle;
144 if (!entry->shared_memory.ShareToProcess(PeerHandle(),
145 &foreign_memory_handle)) {
146 // If we failed to map and share the shared memory then close the audio
147 // stream and send an error message.
148 DeleteEntryOnError(entry, MEMORY_SHARING_FAILED);
149 return;
152 AudioInputSyncWriter* writer =
153 static_cast<AudioInputSyncWriter*>(entry->writer.get());
155 #if defined(OS_WIN)
156 base::SyncSocket::Handle foreign_socket_handle;
157 #else
158 base::FileDescriptor foreign_socket_handle;
159 #endif
161 // If we failed to prepare the sync socket for the renderer then we fail
162 // the construction of audio input stream.
163 if (!writer->PrepareForeignSocketHandle(PeerHandle(),
164 &foreign_socket_handle)) {
165 DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
166 return;
169 Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
170 foreign_memory_handle, foreign_socket_handle,
171 entry->shared_memory.requested_size(),
172 entry->shared_memory_segment_count));
175 void AudioInputRendererHost::DoSendRecordingMessage(
176 media::AudioInputController* controller) {
177 DCHECK_CURRENTLY_ON(BrowserThread::IO);
178 // TODO(henrika): See crbug.com/115262 for details on why this method
179 // should be implemented.
182 void AudioInputRendererHost::DoHandleError(
183 media::AudioInputController* controller,
184 media::AudioInputController::ErrorCode error_code) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO);
186 // Log all errors even it is ignored later.
187 MediaStreamManager::SendMessageToNativeLog(
188 base::StringPrintf("AudioInputController error: %d", error_code));
190 // This is a fix for crbug.com/357501. The error can be triggered when closing
191 // the lid on Macs, which causes more problems than it fixes.
192 // Also, in crbug.com/357569, the goal is to remove usage of the error since
193 // it was added to solve a crash on Windows that no longer can be reproduced.
194 if (error_code == media::AudioInputController::NO_DATA_ERROR) {
195 DVLOG(1) << "AudioInputRendererHost@" << this << "::DoHandleError: "
196 << "NO_DATA_ERROR ignored.";
197 return;
200 AudioEntry* entry = LookupByController(controller);
201 if (!entry)
202 return;
204 audio_log_->OnError(entry->stream_id);
205 DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
208 bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
209 bool* message_was_ok) {
210 bool handled = true;
211 IPC_BEGIN_MESSAGE_MAP_EX(AudioInputRendererHost, message, *message_was_ok)
212 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
213 IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
214 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
215 IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
216 IPC_MESSAGE_UNHANDLED(handled = false)
217 IPC_END_MESSAGE_MAP_EX()
219 return handled;
222 void AudioInputRendererHost::OnCreateStream(
223 int stream_id,
224 int render_view_id,
225 int session_id,
226 const AudioInputHostMsg_CreateStream_Config& config) {
227 DCHECK_CURRENTLY_ON(BrowserThread::IO);
229 DVLOG(1) << "AudioInputRendererHost@" << this
230 << "::OnCreateStream(stream_id=" << stream_id
231 << ", render_view_id=" << render_view_id
232 << ", session_id=" << session_id << ")";
233 DCHECK_GT(render_view_id, 0);
235 // media::AudioParameters is validated in the deserializer.
236 if (LookupById(stream_id) != NULL) {
237 SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
238 return;
241 media::AudioParameters audio_params(config.params);
242 if (media_stream_manager_->audio_input_device_manager()->
243 ShouldUseFakeDevice()) {
244 audio_params.Reset(
245 media::AudioParameters::AUDIO_FAKE,
246 config.params.channel_layout(), config.params.channels(), 0,
247 config.params.sample_rate(), config.params.bits_per_sample(),
248 config.params.frames_per_buffer());
251 // Check if we have the permission to open the device and which device to use.
252 std::string device_name;
253 std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
254 if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
255 const StreamDeviceInfo* info = media_stream_manager_->
256 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
257 if (!info) {
258 SendErrorMessage(stream_id, PERMISSION_DENIED);
259 DLOG(WARNING) << "No permission has been granted to input stream with "
260 << "session_id=" << session_id;
261 return;
264 device_id = info->device.id;
265 device_name = info->device.name;
268 // Create a new AudioEntry structure.
269 scoped_ptr<AudioEntry> entry(new AudioEntry());
271 const uint32 segment_size = (sizeof(media::AudioInputBufferParameters) +
272 audio_params.GetBytesPerBuffer());
273 entry->shared_memory_segment_count = config.shared_memory_count;
275 // Create the shared memory and share it with the renderer process
276 // using a new SyncWriter object.
277 base::CheckedNumeric<uint32> size = segment_size;
278 size *= entry->shared_memory_segment_count;
279 if (!size.IsValid() ||
280 !entry->shared_memory.CreateAndMapAnonymous(size.ValueOrDie())) {
281 // If creation of shared memory failed then send an error message.
282 SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
283 return;
286 scoped_ptr<AudioInputSyncWriter> writer(
287 new AudioInputSyncWriter(&entry->shared_memory,
288 entry->shared_memory_segment_count));
290 if (!writer->Init()) {
291 SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
292 return;
295 // If we have successfully created the SyncWriter then assign it to the
296 // entry and construct an AudioInputController.
297 entry->writer.reset(writer.release());
298 if (WebContentsCaptureUtil::IsWebContentsDeviceId(device_id)) {
299 entry->controller = media::AudioInputController::CreateForStream(
300 audio_manager_->GetTaskRunner(),
301 this,
302 WebContentsAudioInputStream::Create(
303 device_id,
304 audio_params,
305 audio_manager_->GetWorkerTaskRunner(),
306 audio_mirroring_manager_),
307 entry->writer.get(),
308 user_input_monitor_);
309 } else {
310 // TODO(henrika): replace CreateLowLatency() with Create() as soon
311 // as satish has ensured that Speech Input also uses the default low-
312 // latency path. See crbug.com/112472 for details.
313 entry->controller =
314 media::AudioInputController::CreateLowLatency(audio_manager_,
315 this,
316 audio_params,
317 device_id,
318 entry->writer.get(),
319 user_input_monitor_);
322 if (!entry->controller.get()) {
323 SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
324 return;
327 // Set the initial AGC state for the audio input stream. Note that, the AGC
328 // is only supported in AUDIO_PCM_LOW_LATENCY mode.
329 if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY)
330 entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
332 // Since the controller was created successfully, create an entry and add it
333 // to the map.
334 entry->stream_id = stream_id;
335 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
337 MediaStreamManager::SendMessageToNativeLog(
338 "Audio input stream created successfully. Device name: " + device_name);
339 audio_log_->OnCreated(stream_id, audio_params, device_id);
342 void AudioInputRendererHost::OnRecordStream(int stream_id) {
343 DCHECK_CURRENTLY_ON(BrowserThread::IO);
345 AudioEntry* entry = LookupById(stream_id);
346 if (!entry) {
347 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
348 return;
351 entry->controller->Record();
352 audio_log_->OnStarted(stream_id);
355 void AudioInputRendererHost::OnCloseStream(int stream_id) {
356 DCHECK_CURRENTLY_ON(BrowserThread::IO);
358 AudioEntry* entry = LookupById(stream_id);
360 if (entry)
361 CloseAndDeleteStream(entry);
364 void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
365 DCHECK_CURRENTLY_ON(BrowserThread::IO);
367 AudioEntry* entry = LookupById(stream_id);
368 if (!entry) {
369 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
370 return;
373 entry->controller->SetVolume(volume);
374 audio_log_->OnSetVolume(stream_id, volume);
377 void AudioInputRendererHost::SendErrorMessage(
378 int stream_id, ErrorCode error_code) {
379 MediaStreamManager::SendMessageToNativeLog(
380 base::StringPrintf("AudioInputRendererHost error: %d", error_code));
381 Send(new AudioInputMsg_NotifyStreamStateChanged(
382 stream_id, media::AudioInputIPCDelegate::kError));
385 void AudioInputRendererHost::DeleteEntries() {
386 DCHECK_CURRENTLY_ON(BrowserThread::IO);
388 for (AudioEntryMap::iterator i = audio_entries_.begin();
389 i != audio_entries_.end(); ++i) {
390 CloseAndDeleteStream(i->second);
394 void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
395 DCHECK_CURRENTLY_ON(BrowserThread::IO);
397 if (!entry->pending_close) {
398 entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
399 this, entry));
400 entry->pending_close = true;
401 audio_log_->OnClosed(entry->stream_id);
405 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
406 DCHECK_CURRENTLY_ON(BrowserThread::IO);
408 // Delete the entry when this method goes out of scope.
409 scoped_ptr<AudioEntry> entry_deleter(entry);
411 // Erase the entry from the map.
412 audio_entries_.erase(entry->stream_id);
415 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
416 ErrorCode error_code) {
417 DCHECK_CURRENTLY_ON(BrowserThread::IO);
419 // Sends the error message first before we close the stream because
420 // |entry| is destroyed in DeleteEntry().
421 SendErrorMessage(entry->stream_id, error_code);
422 CloseAndDeleteStream(entry);
425 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
426 int stream_id) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO);
429 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
430 if (i != audio_entries_.end())
431 return i->second;
432 return NULL;
435 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
436 media::AudioInputController* controller) {
437 DCHECK_CURRENTLY_ON(BrowserThread::IO);
439 // Iterate the map of entries.
440 // TODO(hclam): Implement a faster look up method.
441 for (AudioEntryMap::iterator i = audio_entries_.begin();
442 i != audio_entries_.end(); ++i) {
443 if (controller == i->second->controller.get())
444 return i->second;
446 return NULL;
449 } // namespace content