15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/audio_input_renderer_host.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/memory/shared_memory.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
10a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/process.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/browser/media/media_internals.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/audio_input_device_manager.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/media_stream_manager.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/web_contents_audio_input_stream.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/web_contents_capture_util.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_manager_base.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct AudioInputRendererHost::AudioEntry {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry();
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~AudioEntry();
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The AudioInputController that manages the audio input stream.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<media::AudioInputController> controller;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The audio input stream ID in the render view.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int stream_id;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Shared memory for transmission of the audio data. It has
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |shared_memory_segment_count| equal lengthed segments.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SharedMemory shared_memory;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int shared_memory_segment_count;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The synchronous writer to be used by the controller. We have the
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ownership of the writer.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<media::AudioInputController::SyncWriter> writer;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set to true after we called Close() for the controller.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pending_close;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry::AudioEntry()
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : stream_id(0),
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shared_memory_segment_count(0),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_close(false) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry::~AudioEntry() {}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioInputRendererHost(
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioManager* audio_manager,
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    MediaStreamManager* media_stream_manager,
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    AudioMirroringManager* audio_mirroring_manager,
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    media::UserInputMonitor* user_input_monitor)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : audio_manager_(audio_manager),
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      media_stream_manager_(media_stream_manager),
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      audio_mirroring_manager_(audio_mirroring_manager),
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      user_input_monitor_(user_input_monitor),
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::~AudioInputRendererHost() {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_entries_.empty());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnChannelClosing() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since the IPC channel is gone, close all requested audio streams.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteEntries();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnDestruct() const {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::DeleteOnIOThread::Destruct(this);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnCreated(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &AudioInputRendererHost::DoCompleteCreation,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          make_scoped_refptr(controller)));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnRecording(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &AudioInputRendererHost::DoSendRecordingMessage,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          make_scoped_refptr(controller)));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputRendererHost::OnError(media::AudioInputController* controller) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &AudioInputRendererHost::DoHandleError,
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          make_scoped_refptr(controller)));
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnData(media::AudioInputController* controller,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const uint8* data,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    uint32 size) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Only low-latency mode is supported.";
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DoCompleteCreation(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupByController(controller);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!PeerHandle()) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Renderer process handle is invalid.";
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteEntryOnError(entry);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry->controller->LowLatencyMode()) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Only low-latency mode is supported.";
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteEntryOnError(entry);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Once the audio stream is created then complete the creation process by
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mapping shared memory and sharing with the renderer process.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SharedMemoryHandle foreign_memory_handle;
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!entry->shared_memory.ShareToProcess(PeerHandle(),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &foreign_memory_handle)) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we failed to map and share the shared memory then close the audio
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // stream and send an error message.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteEntryOnError(entry);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioInputSyncWriter* writer =
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<AudioInputSyncWriter*>(entry->writer.get());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SyncSocket::Handle foreign_socket_handle;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FileDescriptor foreign_socket_handle;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we failed to prepare the sync socket for the renderer then we fail
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the construction of audio input stream.
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!writer->PrepareForeignSocketHandle(PeerHandle(),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          &foreign_socket_handle)) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteEntryOnError(entry);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      foreign_memory_handle, foreign_socket_handle,
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      entry->shared_memory.requested_size(),
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entry->shared_memory_segment_count));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DoSendRecordingMessage(
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(henrika): See crbug.com/115262 for details on why this method
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should be implemented.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DoHandleError(
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    media::AudioInputController* controller) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupByController(controller);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnError(entry->stream_id);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteEntryOnError(entry);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               bool* message_was_ok) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP_EX(AudioInputRendererHost, message, *message_was_ok)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP_EX()
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnCreateStream(
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int stream_id,
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int render_view_id,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int session_id,
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const AudioInputHostMsg_CreateStream_Config& config) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DVLOG(1) << "AudioInputRendererHost@" << this
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           << "::OnCreateStream(stream_id=" << stream_id
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           << ", render_view_id=" << render_view_id
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           << ", session_id=" << session_id << ")";
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GT(render_view_id, 0);
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // media::AudioParameters is validated in the deserializer.
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (LookupById(stream_id) != NULL) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SendErrorMessage(stream_id);
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  media::AudioParameters audio_params(config.params);
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (media_stream_manager_->audio_input_device_manager()->
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ShouldUseFakeDevice()) {
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    audio_params.Reset(
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        media::AudioParameters::AUDIO_FAKE,
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        config.params.channel_layout(), config.params.channels(), 0,
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        config.params.sample_rate(), config.params.bits_per_sample(),
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        config.params.frames_per_buffer());
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if we have the permission to open the device and which device to use.
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StreamDeviceInfo* info = media_stream_manager_->
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!info) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SendErrorMessage(stream_id);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DLOG(WARNING) << "No permission has been granted to input stream with "
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    << "session_id=" << session_id;
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    device_id = info->device.id;
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a new AudioEntry structure.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<AudioEntry> entry(new AudioEntry());
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const uint32 segment_size = (sizeof(media::AudioInputBufferParameters) +
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               audio_params.GetBytesPerBuffer());
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  entry->shared_memory_segment_count = config.shared_memory_count;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the shared memory and share it with the renderer process
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // using a new SyncWriter object.
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!entry->shared_memory.CreateAndMapAnonymous(
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      segment_size * entry->shared_memory_segment_count)) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If creation of shared memory failed then send an error message.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendErrorMessage(stream_id);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<AudioInputSyncWriter> writer(
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new AudioInputSyncWriter(&entry->shared_memory,
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               entry->shared_memory_segment_count));
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!writer->Init()) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendErrorMessage(stream_id);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have successfully created the SyncWriter then assign it to the
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entry and construct an AudioInputController.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->writer.reset(writer.release());
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (WebContentsCaptureUtil::IsWebContentsDeviceId(device_id)) {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry->controller = media::AudioInputController::CreateForStream(
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        audio_manager_->GetMessageLoop(),
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this,
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        WebContentsAudioInputStream::Create(device_id,
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            audio_params,
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            audio_manager_->GetWorkerLoop(),
2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            audio_mirroring_manager_),
2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        entry->writer.get(),
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        user_input_monitor_);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(henrika): replace CreateLowLatency() with Create() as soon
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // as satish has ensured that Speech Input also uses the default low-
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // latency path. See crbug.com/112472 for details.
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    entry->controller =
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        media::AudioInputController::CreateLowLatency(audio_manager_,
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      this,
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      audio_params,
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      device_id,
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      entry->writer.get(),
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      user_input_monitor_);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->controller.get()) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendErrorMessage(stream_id);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the initial AGC state for the audio input stream. Note that, the AGC
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is only supported in AUDIO_PCM_LOW_LATENCY mode.
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY)
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Since the controller was created successfully, create an entry and add it
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the map.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->stream_id = stream_id;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_entries_.insert(std::make_pair(stream_id, entry.release()));
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnCreated(stream_id, audio_params, device_id, std::string());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnRecordStream(int stream_id) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupById(stream_id);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendErrorMessage(stream_id);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->controller->Record();
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnStarted(stream_id);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnCloseStream(int stream_id) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupById(stream_id);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseAndDeleteStream(entry);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupById(stream_id);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendErrorMessage(stream_id);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->controller->SetVolume(volume);
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnSetVolume(stream_id, volume);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::SendErrorMessage(int stream_id) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Send(new AudioInputMsg_NotifyStreamStateChanged(
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_id, media::AudioInputIPCDelegate::kError));
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DeleteEntries() {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (AudioEntryMap::iterator i = audio_entries_.begin();
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != audio_entries_.end(); ++i) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseAndDeleteStream(i->second);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry->pending_close) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        this, entry));
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->pending_close = true;
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    audio_log_->OnClosed(entry->stream_id);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the entry when this method goes out of scope.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<AudioEntry> entry_deleter(entry);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Erase the entry from the map.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_entries_.erase(entry->stream_id);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sends the error message first before we close the stream because
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |entry| is destroyed in DeleteEntry().
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendErrorMessage(entry->stream_id);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAndDeleteStream(entry);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int stream_id) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntryMap::iterator i = audio_entries_.find(stream_id);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i != audio_entries_.end())
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return i->second;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate the map of entries.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(hclam): Implement a faster look up method.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (AudioEntryMap::iterator i = audio_entries_.begin();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != audio_entries_.end(); ++i) {
412868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (controller == i->second->controller.get())
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i->second;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
419