[blink-in-js] Migrate resources required for blink-in-js to grd - part 2
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_input_renderer_host.cc
blob41857bb3e4aa66fc040716699bb3f021112fe70a
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 {
24 void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
25 std::ostringstream oss;
26 oss << "[stream_id=" << stream_id << "] ";
27 if (add_prefix)
28 oss << "AIRH::";
29 oss << msg;
30 content::MediaStreamManager::SendMessageToNativeLog(oss.str());
31 DVLOG(1) << oss.str();
34 } // namespace
36 namespace content {
38 struct AudioInputRendererHost::AudioEntry {
39 AudioEntry();
40 ~AudioEntry();
42 // The AudioInputController that manages the audio input stream.
43 scoped_refptr<media::AudioInputController> controller;
45 // The audio input stream ID in the render view.
46 int stream_id;
48 // Shared memory for transmission of the audio data. It has
49 // |shared_memory_segment_count| equal lengthed segments.
50 base::SharedMemory shared_memory;
51 int shared_memory_segment_count;
53 // The synchronous writer to be used by the controller. We have the
54 // ownership of the writer.
55 scoped_ptr<media::AudioInputController::SyncWriter> writer;
57 // Set to true after we called Close() for the controller.
58 bool pending_close;
61 AudioInputRendererHost::AudioEntry::AudioEntry()
62 : stream_id(0),
63 shared_memory_segment_count(0),
64 pending_close(false) {
67 AudioInputRendererHost::AudioEntry::~AudioEntry() {}
69 AudioInputRendererHost::AudioInputRendererHost(
70 media::AudioManager* audio_manager,
71 MediaStreamManager* media_stream_manager,
72 AudioMirroringManager* audio_mirroring_manager,
73 media::UserInputMonitor* user_input_monitor)
74 : BrowserMessageFilter(AudioMsgStart),
75 audio_manager_(audio_manager),
76 media_stream_manager_(media_stream_manager),
77 audio_mirroring_manager_(audio_mirroring_manager),
78 user_input_monitor_(user_input_monitor),
79 audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
80 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
82 AudioInputRendererHost::~AudioInputRendererHost() {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
84 DCHECK(audio_entries_.empty());
87 void AudioInputRendererHost::OnChannelClosing() {
88 // Since the IPC sender is gone, close all requested audio streams.
89 DeleteEntries();
92 void AudioInputRendererHost::OnDestruct() const {
93 BrowserThread::DeleteOnIOThread::Destruct(this);
96 void AudioInputRendererHost::OnCreated(
97 media::AudioInputController* controller) {
98 BrowserThread::PostTask(
99 BrowserThread::IO,
100 FROM_HERE,
101 base::Bind(
102 &AudioInputRendererHost::DoCompleteCreation,
103 this,
104 make_scoped_refptr(controller)));
107 void AudioInputRendererHost::OnRecording(
108 media::AudioInputController* controller) {
109 BrowserThread::PostTask(
110 BrowserThread::IO,
111 FROM_HERE,
112 base::Bind(
113 &AudioInputRendererHost::DoSendRecordingMessage,
114 this,
115 make_scoped_refptr(controller)));
118 void AudioInputRendererHost::OnError(media::AudioInputController* controller,
119 media::AudioInputController::ErrorCode error_code) {
120 BrowserThread::PostTask(
121 BrowserThread::IO,
122 FROM_HERE,
123 base::Bind(
124 &AudioInputRendererHost::DoHandleError,
125 this,
126 make_scoped_refptr(controller),
127 error_code));
130 void AudioInputRendererHost::OnData(media::AudioInputController* controller,
131 const media::AudioBus* data) {
132 NOTREACHED() << "Only low-latency mode is supported.";
135 void AudioInputRendererHost::OnLog(media::AudioInputController* controller,
136 const std::string& message) {
137 BrowserThread::PostTask(BrowserThread::IO,
138 FROM_HERE,
139 base::Bind(&AudioInputRendererHost::DoLog,
140 this,
141 make_scoped_refptr(controller),
142 message));
145 void AudioInputRendererHost::DoCompleteCreation(
146 media::AudioInputController* controller) {
147 DCHECK_CURRENTLY_ON(BrowserThread::IO);
149 AudioEntry* entry = LookupByController(controller);
150 if (!entry) {
151 NOTREACHED() << "AudioInputController is invalid.";
152 return;
155 if (!PeerHandle()) {
156 NOTREACHED() << "Renderer process handle is invalid.";
157 DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
158 return;
161 if (!entry->controller->SharedMemoryAndSyncSocketMode()) {
162 NOTREACHED() << "Only shared-memory/sync-socket mode is supported.";
163 DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
164 return;
167 // Once the audio stream is created then complete the creation process by
168 // mapping shared memory and sharing with the renderer process.
169 base::SharedMemoryHandle foreign_memory_handle;
170 if (!entry->shared_memory.ShareToProcess(PeerHandle(),
171 &foreign_memory_handle)) {
172 // If we failed to map and share the shared memory then close the audio
173 // stream and send an error message.
174 DeleteEntryOnError(entry, MEMORY_SHARING_FAILED);
175 return;
178 AudioInputSyncWriter* writer =
179 static_cast<AudioInputSyncWriter*>(entry->writer.get());
181 base::SyncSocket::TransitDescriptor socket_transit_descriptor;
183 // If we failed to prepare the sync socket for the renderer then we fail
184 // the construction of audio input stream.
185 if (!writer->PrepareForeignSocket(PeerHandle(), &socket_transit_descriptor)) {
186 DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
187 return;
190 LogMessage(entry->stream_id,
191 "DoCompleteCreation: IPC channel and stream are now open",
192 true);
194 Send(new AudioInputMsg_NotifyStreamCreated(
195 entry->stream_id, foreign_memory_handle, socket_transit_descriptor,
196 entry->shared_memory.requested_size(),
197 entry->shared_memory_segment_count));
200 void AudioInputRendererHost::DoSendRecordingMessage(
201 media::AudioInputController* controller) {
202 DCHECK_CURRENTLY_ON(BrowserThread::IO);
203 // TODO(henrika): See crbug.com/115262 for details on why this method
204 // should be implemented.
205 AudioEntry* entry = LookupByController(controller);
206 if (!entry) {
207 NOTREACHED() << "AudioInputController is invalid.";
208 return;
210 LogMessage(
211 entry->stream_id, "DoSendRecordingMessage: stream is now started", true);
214 void AudioInputRendererHost::DoHandleError(
215 media::AudioInputController* controller,
216 media::AudioInputController::ErrorCode error_code) {
217 DCHECK_CURRENTLY_ON(BrowserThread::IO);
218 AudioEntry* entry = LookupByController(controller);
219 if (!entry) {
220 NOTREACHED() << "AudioInputController is invalid.";
221 return;
224 // This is a fix for crbug.com/357501. The error can be triggered when closing
225 // the lid on Macs, which causes more problems than it fixes.
226 // Also, in crbug.com/357569, the goal is to remove usage of the error since
227 // it was added to solve a crash on Windows that no longer can be reproduced.
228 if (error_code == media::AudioInputController::NO_DATA_ERROR) {
229 // TODO(henrika): it might be possible to do something other than just
230 // logging when we detect many NO_DATA_ERROR calls for a stream.
231 LogMessage(entry->stream_id, "AIC::DoCheckForNoData: NO_DATA_ERROR", false);
232 return;
235 std::ostringstream oss;
236 oss << "AIC reports error_code=" << error_code;
237 LogMessage(entry->stream_id, oss.str(), false);
239 audio_log_->OnError(entry->stream_id);
240 DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
243 void AudioInputRendererHost::DoLog(media::AudioInputController* controller,
244 const std::string& message) {
245 DCHECK_CURRENTLY_ON(BrowserThread::IO);
246 AudioEntry* entry = LookupByController(controller);
247 if (!entry) {
248 NOTREACHED() << "AudioInputController is invalid.";
249 return;
252 // Add stream ID and current audio level reported by AIC to native log.
253 LogMessage(entry->stream_id, message, false);
256 bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
257 bool handled = true;
258 IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHost, message)
259 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
260 IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
261 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
262 IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
263 IPC_MESSAGE_UNHANDLED(handled = false)
264 IPC_END_MESSAGE_MAP()
266 return handled;
269 void AudioInputRendererHost::OnCreateStream(
270 int stream_id,
271 int render_view_id,
272 int session_id,
273 const AudioInputHostMsg_CreateStream_Config& config) {
274 DCHECK_CURRENTLY_ON(BrowserThread::IO);
276 std::ostringstream oss;
277 oss << "[stream_id=" << stream_id << "] "
278 << "AIRH::OnCreateStream(render_view_id=" << render_view_id
279 << ", session_id=" << session_id << ")";
280 DCHECK_GT(render_view_id, 0);
282 // media::AudioParameters is validated in the deserializer.
283 if (LookupById(stream_id) != NULL) {
284 SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
285 return;
288 media::AudioParameters audio_params(config.params);
289 if (media_stream_manager_->audio_input_device_manager()->
290 ShouldUseFakeDevice()) {
291 audio_params.Reset(
292 media::AudioParameters::AUDIO_FAKE,
293 config.params.channel_layout(), config.params.channels(),
294 config.params.sample_rate(), config.params.bits_per_sample(),
295 config.params.frames_per_buffer());
298 // Check if we have the permission to open the device and which device to use.
299 std::string device_name;
300 std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
301 if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
302 const StreamDeviceInfo* info = media_stream_manager_->
303 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
304 if (!info) {
305 SendErrorMessage(stream_id, PERMISSION_DENIED);
306 DLOG(WARNING) << "No permission has been granted to input stream with "
307 << "session_id=" << session_id;
308 return;
311 device_id = info->device.id;
312 device_name = info->device.name;
313 oss << ": device_name=" << device_name;
316 // Create a new AudioEntry structure.
317 scoped_ptr<AudioEntry> entry(new AudioEntry());
319 const uint32 segment_size =
320 (sizeof(media::AudioInputBufferParameters) +
321 media::AudioBus::CalculateMemorySize(audio_params));
322 entry->shared_memory_segment_count = config.shared_memory_count;
324 // Create the shared memory and share it with the renderer process
325 // using a new SyncWriter object.
326 base::CheckedNumeric<uint32> size = segment_size;
327 size *= entry->shared_memory_segment_count;
328 if (!size.IsValid() ||
329 !entry->shared_memory.CreateAndMapAnonymous(size.ValueOrDie())) {
330 // If creation of shared memory failed then send an error message.
331 SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
332 return;
335 scoped_ptr<AudioInputSyncWriter> writer(new AudioInputSyncWriter(
336 &entry->shared_memory, entry->shared_memory_segment_count, audio_params));
338 if (!writer->Init()) {
339 SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
340 return;
343 // If we have successfully created the SyncWriter then assign it to the
344 // entry and construct an AudioInputController.
345 entry->writer.reset(writer.release());
346 if (WebContentsCaptureUtil::IsWebContentsDeviceId(device_id)) {
347 entry->controller = media::AudioInputController::CreateForStream(
348 audio_manager_->GetTaskRunner(),
349 this,
350 WebContentsAudioInputStream::Create(
351 device_id,
352 audio_params,
353 audio_manager_->GetWorkerTaskRunner(),
354 audio_mirroring_manager_),
355 entry->writer.get(),
356 user_input_monitor_);
357 } else {
358 // TODO(henrika): replace CreateLowLatency() with Create() as soon
359 // as satish has ensured that Speech Input also uses the default low-
360 // latency path. See crbug.com/112472 for details.
361 entry->controller =
362 media::AudioInputController::CreateLowLatency(audio_manager_,
363 this,
364 audio_params,
365 device_id,
366 entry->writer.get(),
367 user_input_monitor_);
370 if (!entry->controller.get()) {
371 SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
372 return;
375 // Set the initial AGC state for the audio input stream. Note that, the AGC
376 // is only supported in AUDIO_PCM_LOW_LATENCY mode.
377 if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY) {
378 entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
379 oss << ", AGC=" << config.automatic_gain_control;
382 MediaStreamManager::SendMessageToNativeLog(oss.str());
383 DVLOG(1) << oss.str();
385 // Since the controller was created successfully, create an entry and add it
386 // to the map.
387 entry->stream_id = stream_id;
388 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
389 audio_log_->OnCreated(stream_id, audio_params, device_id);
392 void AudioInputRendererHost::OnRecordStream(int stream_id) {
393 DCHECK_CURRENTLY_ON(BrowserThread::IO);
394 LogMessage(stream_id, "OnRecordStream", true);
396 AudioEntry* entry = LookupById(stream_id);
397 if (!entry) {
398 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
399 return;
402 entry->controller->Record();
403 audio_log_->OnStarted(stream_id);
406 void AudioInputRendererHost::OnCloseStream(int stream_id) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO);
408 LogMessage(stream_id, "OnCloseStream", true);
410 AudioEntry* entry = LookupById(stream_id);
412 if (entry)
413 CloseAndDeleteStream(entry);
416 void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
417 DCHECK_CURRENTLY_ON(BrowserThread::IO);
419 AudioEntry* entry = LookupById(stream_id);
420 if (!entry) {
421 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
422 return;
425 entry->controller->SetVolume(volume);
426 audio_log_->OnSetVolume(stream_id, volume);
429 void AudioInputRendererHost::SendErrorMessage(
430 int stream_id, ErrorCode error_code) {
431 std::string err_msg =
432 base::StringPrintf("SendErrorMessage(error_code=%d)", error_code);
433 LogMessage(stream_id, err_msg, true);
435 Send(new AudioInputMsg_NotifyStreamStateChanged(
436 stream_id, media::AudioInputIPCDelegate::kError));
439 void AudioInputRendererHost::DeleteEntries() {
440 DCHECK_CURRENTLY_ON(BrowserThread::IO);
442 for (AudioEntryMap::iterator i = audio_entries_.begin();
443 i != audio_entries_.end(); ++i) {
444 CloseAndDeleteStream(i->second);
448 void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
449 DCHECK_CURRENTLY_ON(BrowserThread::IO);
451 if (!entry->pending_close) {
452 LogMessage(entry->stream_id, "CloseAndDeleteStream", true);
453 entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
454 this, entry));
455 entry->pending_close = true;
456 audio_log_->OnClosed(entry->stream_id);
460 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
461 DCHECK_CURRENTLY_ON(BrowserThread::IO);
462 LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true);
464 // Delete the entry when this method goes out of scope.
465 scoped_ptr<AudioEntry> entry_deleter(entry);
467 // Erase the entry from the map.
468 audio_entries_.erase(entry->stream_id);
471 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
472 ErrorCode error_code) {
473 DCHECK_CURRENTLY_ON(BrowserThread::IO);
475 // Sends the error message first before we close the stream because
476 // |entry| is destroyed in DeleteEntry().
477 SendErrorMessage(entry->stream_id, error_code);
478 CloseAndDeleteStream(entry);
481 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
482 int stream_id) {
483 DCHECK_CURRENTLY_ON(BrowserThread::IO);
485 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
486 if (i != audio_entries_.end())
487 return i->second;
488 return NULL;
491 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
492 media::AudioInputController* controller) {
493 DCHECK_CURRENTLY_ON(BrowserThread::IO);
495 // Iterate the map of entries.
496 // TODO(hclam): Implement a faster look up method.
497 for (AudioEntryMap::iterator i = audio_entries_.begin();
498 i != audio_entries_.end(); ++i) {
499 if (controller == i->second->controller.get())
500 return i->second;
502 return NULL;
505 } // namespace content