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