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"
10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/numerics/safe_math.h"
11a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/process.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/stringprintf.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/web_contents_audio_input_stream.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/web_contents_capture_util.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/browser/media/media_internals.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/audio_input_device_manager.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/audio_input_sync_writer.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/renderer_host/media/media_stream_manager.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_manager_base.h"
206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "media/base/audio_bus.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::ostringstream oss;
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  oss << "[stream_id=" << stream_id << "] ";
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (add_prefix)
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    oss << "AIRH::";
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  oss << msg;
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::MediaStreamManager::SendMessageToNativeLog(oss.str());
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DVLOG(1) << oss.str();
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct AudioInputRendererHost::AudioEntry {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry();
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~AudioEntry();
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The AudioInputController that manages the audio input stream.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<media::AudioInputController> controller;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The audio input stream ID in the render view.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int stream_id;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Shared memory for transmission of the audio data. It has
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |shared_memory_segment_count| equal lengthed segments.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SharedMemory shared_memory;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int shared_memory_segment_count;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The synchronous writer to be used by the controller. We have the
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ownership of the writer.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<media::AudioInputController::SyncWriter> writer;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set to true after we called Close() for the controller.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pending_close;
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If this entry's layout has a keyboard mic channel.
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool has_keyboard_mic_;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry::AudioEntry()
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : stream_id(0),
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shared_memory_segment_count(0),
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pending_close(false),
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      has_keyboard_mic_(false) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry::~AudioEntry() {}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioInputRendererHost(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioManager* audio_manager,
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    MediaStreamManager* media_stream_manager,
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    AudioMirroringManager* audio_mirroring_manager,
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    media::UserInputMonitor* user_input_monitor)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : BrowserMessageFilter(AudioMsgStart),
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      audio_manager_(audio_manager),
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      media_stream_manager_(media_stream_manager),
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      audio_mirroring_manager_(audio_mirroring_manager),
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      user_input_monitor_(user_input_monitor),
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::~AudioInputRendererHost() {
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(audio_entries_.empty());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnChannelClosing() {
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Since the IPC sender is gone, close all requested audio streams.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteEntries();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnDestruct() const {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::DeleteOnIOThread::Destruct(this);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnCreated(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &AudioInputRendererHost::DoCompleteCreation,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          make_scoped_refptr(controller)));
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnRecording(
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &AudioInputRendererHost::DoSendRecordingMessage,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          make_scoped_refptr(controller)));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AudioInputRendererHost::OnError(media::AudioInputController* controller,
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    media::AudioInputController::ErrorCode error_code) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::IO,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &AudioInputRendererHost::DoHandleError,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          this,
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          make_scoped_refptr(controller),
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          error_code));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnData(media::AudioInputController* controller,
1356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                    const media::AudioBus* data) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Only low-latency mode is supported.";
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AudioInputRendererHost::OnLog(media::AudioInputController* controller,
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                   const std::string& message) {
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::IO,
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          FROM_HERE,
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          base::Bind(&AudioInputRendererHost::DoLog,
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     this,
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     make_scoped_refptr(controller),
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     message));
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DoCompleteCreation(
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupByController(controller);
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!entry) {
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NOTREACHED() << "AudioInputController is invalid.";
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!PeerHandle()) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Renderer process handle is invalid.";
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!entry->controller->SharedMemoryAndSyncSocketMode()) {
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    NOTREACHED() << "Only shared-memory/sync-socket mode is supported.";
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Once the audio stream is created then complete the creation process by
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mapping shared memory and sharing with the renderer process.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SharedMemoryHandle foreign_memory_handle;
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!entry->shared_memory.ShareToProcess(PeerHandle(),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &foreign_memory_handle)) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we failed to map and share the shared memory then close the audio
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // stream and send an error message.
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeleteEntryOnError(entry, MEMORY_SHARING_FAILED);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioInputSyncWriter* writer =
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<AudioInputSyncWriter*>(entry->writer.get());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::SyncSocket::TransitDescriptor socket_transit_descriptor;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we failed to prepare the sync socket for the renderer then we fail
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the construction of audio input stream.
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!writer->PrepareForeignSocket(PeerHandle(), &socket_transit_descriptor)) {
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(entry->stream_id,
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             "DoCompleteCreation: IPC channel and stream are now open",
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             true);
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Send(new AudioInputMsg_NotifyStreamCreated(
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      entry->stream_id, foreign_memory_handle, socket_transit_descriptor,
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      entry->shared_memory.requested_size(),
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      entry->shared_memory_segment_count));
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DoSendRecordingMessage(
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(henrika): See crbug.com/115262 for details on why this method
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should be implemented.
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AudioEntry* entry = LookupByController(controller);
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!entry) {
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NOTREACHED() << "AudioInputController is invalid.";
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      entry->stream_id, "DoSendRecordingMessage: stream is now started", true);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DoHandleError(
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    media::AudioInputController* controller,
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    media::AudioInputController::ErrorCode error_code) {
221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AudioEntry* entry = LookupByController(controller);
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!entry) {
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NOTREACHED() << "AudioInputController is invalid.";
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
228a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // This is a fix for crbug.com/357501. The error can be triggered when closing
229a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // the lid on Macs, which causes more problems than it fixes.
230a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Also, in crbug.com/357569, the goal is to remove usage of the error since
231a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // it was added to solve a crash on Windows that no longer can be reproduced.
232a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (error_code == media::AudioInputController::NO_DATA_ERROR) {
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(henrika): it might be possible to do something other than just
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // logging when we detect many NO_DATA_ERROR calls for a stream.
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LogMessage(entry->stream_id, "AIC::DoCheckForNoData: NO_DATA_ERROR", false);
236a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return;
237a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
238a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::ostringstream oss;
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  oss << "AIC reports error_code=" << error_code;
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(entry->stream_id, oss.str(), false);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnError(entry->stream_id);
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AudioInputRendererHost::DoLog(media::AudioInputController* controller,
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                   const std::string& message) {
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::IO);
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AudioEntry* entry = LookupByController(controller);
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!entry) {
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NOTREACHED() << "AudioInputController is invalid.";
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Add stream ID and current audio level reported by AIC to native log.
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(entry->stream_id, message, false);
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHost, message)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnCreateStream(
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int stream_id,
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int render_view_id,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int session_id,
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const AudioInputHostMsg_CreateStream_Config& config) {
278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(OS_CHROMEOS)
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config.params.channel_layout() ==
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    media_stream_manager_->audio_input_device_manager()
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ->RegisterKeyboardMicStream(
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            base::Bind(&AudioInputRendererHost::DoCreateStream,
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       this,
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       stream_id,
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       render_view_id,
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       session_id,
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       config));
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DoCreateStream(stream_id, render_view_id, session_id, config);
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#else
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DoCreateStream(stream_id, render_view_id, session_id, config);
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AudioInputRendererHost::DoCreateStream(
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int stream_id,
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int render_view_id,
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int session_id,
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const AudioInputHostMsg_CreateStream_Config& config) {
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::ostringstream oss;
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  oss << "[stream_id=" << stream_id << "] "
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      << "AIRH::OnCreateStream(render_view_id=" << render_view_id
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      << ", session_id=" << session_id << ")";
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_GT(render_view_id, 0);
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // media::AudioParameters is validated in the deserializer.
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (LookupById(stream_id) != NULL) {
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MaybeUnregisterKeyboardMicStream(config);
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  media::AudioParameters audio_params(config.params);
320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (media_stream_manager_->audio_input_device_manager()->
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ShouldUseFakeDevice()) {
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    audio_params.Reset(
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        media::AudioParameters::AUDIO_FAKE,
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        config.params.channel_layout(), config.params.channels(),
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        config.params.sample_rate(), config.params.bits_per_sample(),
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        config.params.frames_per_buffer());
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if we have the permission to open the device and which device to use.
330a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  std::string device_name;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StreamDeviceInfo* info = media_stream_manager_->
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!info) {
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      SendErrorMessage(stream_id, PERMISSION_DENIED);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DLOG(WARNING) << "No permission has been granted to input stream with "
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    << "session_id=" << session_id;
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      MaybeUnregisterKeyboardMicStream(config);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
343bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    device_id = info->device.id;
344a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    device_name = info->device.name;
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    oss << ": device_name=" << device_name;
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a new AudioEntry structure.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<AudioEntry> entry(new AudioEntry());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const uint32 segment_size =
3526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      (sizeof(media::AudioInputBufferParameters) +
3536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)       media::AudioBus::CalculateMemorySize(audio_params));
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  entry->shared_memory_segment_count = config.shared_memory_count;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the shared memory and share it with the renderer process
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // using a new SyncWriter object.
358c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  base::CheckedNumeric<uint32> size = segment_size;
359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  size *= entry->shared_memory_segment_count;
360c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!size.IsValid() ||
361c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !entry->shared_memory.CreateAndMapAnonymous(size.ValueOrDie())) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If creation of shared memory failed then send an error message.
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MaybeUnregisterKeyboardMicStream(config);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  scoped_ptr<AudioInputSyncWriter> writer(new AudioInputSyncWriter(
3696d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      &entry->shared_memory, entry->shared_memory_segment_count, audio_params));
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!writer->Init()) {
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MaybeUnregisterKeyboardMicStream(config);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have successfully created the SyncWriter then assign it to the
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // entry and construct an AudioInputController.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->writer.reset(writer.release());
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (WebContentsCaptureUtil::IsWebContentsDeviceId(device_id)) {
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry->controller = media::AudioInputController::CreateForStream(
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        audio_manager_->GetTaskRunner(),
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this,
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        WebContentsAudioInputStream::Create(
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            device_id,
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            audio_params,
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            audio_manager_->GetWorkerTaskRunner(),
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            audio_mirroring_manager_),
3893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        entry->writer.get(),
3903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        user_input_monitor_);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(henrika): replace CreateLowLatency() with Create() as soon
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // as satish has ensured that Speech Input also uses the default low-
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // latency path. See crbug.com/112472 for details.
3953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    entry->controller =
3963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        media::AudioInputController::CreateLowLatency(audio_manager_,
3973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      this,
3983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      audio_params,
3993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      device_id,
4003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      entry->writer.get(),
4013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                      user_input_monitor_);
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->controller.get()) {
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
4061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MaybeUnregisterKeyboardMicStream(config);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the initial AGC state for the audio input stream. Note that, the AGC
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is only supported in AUDIO_PCM_LOW_LATENCY mode.
4121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY) {
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    oss << ", AGC=" << config.automatic_gain_control;
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
41734680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)#if defined(OS_CHROMEOS)
41834680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  if (config.params.channel_layout() ==
41934680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)          media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
42034680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)    entry->has_keyboard_mic_ = true;
42134680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)  }
42234680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)#endif
42334680572440d7894ef8dafce81d8039ed80726a2Torne (Richard Coles)
4241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MediaStreamManager::SendMessageToNativeLog(oss.str());
4251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DVLOG(1) << oss.str();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Since the controller was created successfully, create an entry and add it
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the map.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->stream_id = stream_id;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_entries_.insert(std::make_pair(stream_id, entry.release()));
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_log_->OnCreated(stream_id, audio_params, device_id);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnRecordStream(int stream_id) {
435effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(stream_id, "OnRecordStream", true);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupById(stream_id);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry) {
440a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->controller->Record();
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnStarted(stream_id);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnCloseStream(int stream_id) {
449effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(stream_id, "OnCloseStream", true);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupById(stream_id);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseAndDeleteStream(entry);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
459effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntry* entry = LookupById(stream_id);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry) {
463a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  entry->controller->SetVolume(volume);
468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  audio_log_->OnSetVolume(stream_id, volume);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
471a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AudioInputRendererHost::SendErrorMessage(
472a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int stream_id, ErrorCode error_code) {
4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string err_msg =
4741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::StringPrintf("SendErrorMessage(error_code=%d)", error_code);
4751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(stream_id, err_msg, true);
4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Send(new AudioInputMsg_NotifyStreamStateChanged(
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stream_id, media::AudioInputIPCDelegate::kError));
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DeleteEntries() {
482effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (AudioEntryMap::iterator i = audio_entries_.begin();
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != audio_entries_.end(); ++i) {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseAndDeleteStream(i->second);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
491effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!entry->pending_close) {
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LogMessage(entry->stream_id, "CloseAndDeleteStream", true);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        this, entry));
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->pending_close = true;
498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    audio_log_->OnClosed(entry->stream_id);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
503effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true);
5051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(OS_CHROMEOS)
5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (entry->has_keyboard_mic_) {
5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    media_stream_manager_->audio_input_device_manager()
5091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ->UnregisterKeyboardMicStream();
5101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
5111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the entry when this method goes out of scope.
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<AudioEntry> entry_deleter(entry);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Erase the entry from the map.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  audio_entries_.erase(entry->stream_id);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
521a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ErrorCode error_code) {
522effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sends the error message first before we close the stream because
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |entry| is destroyed in DeleteEntry().
526a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SendErrorMessage(entry->stream_id, error_code);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseAndDeleteStream(entry);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int stream_id) {
532effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AudioEntryMap::iterator i = audio_entries_.find(stream_id);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i != audio_entries_.end())
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return i->second;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioInputController* controller) {
542effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate the map of entries.
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(hclam): Implement a faster look up method.
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (AudioEntryMap::iterator i = audio_entries_.begin();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != audio_entries_.end(); ++i) {
548868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (controller == i->second->controller.get())
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i->second;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AudioInputRendererHost::MaybeUnregisterKeyboardMicStream(
5551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const AudioInputHostMsg_CreateStream_Config& config) {
5561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(OS_CHROMEOS)
5571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config.params.channel_layout() ==
5581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
5591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    media_stream_manager_->audio_input_device_manager()
5601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ->UnregisterKeyboardMicStream();
5611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
5621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif
5631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
5641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
566