audio_input_device.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/audio/audio_input_device.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/time/time.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_manager_base.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_bus.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media { 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The number of shared memory buffer segments indicated to browser process 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// in order to avoid data overwriting. This number can be any positive number, 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// dependent how fast the renderer process can pick up captured data from 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// shared memory. 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kRequestedSharedMemoryCount = 10; 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Takes care of invoking the capture callback on the audio thread. 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// An instance of this class is created for each capture stream in 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OnLowLatencyCreated(). 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AudioInputDevice::AudioThreadCallback 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : public AudioDeviceThread::Callback { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioThreadCallback(const AudioParameters& audio_parameters, 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::SharedMemoryHandle memory, 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int memory_length, 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int total_segments, 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CaptureCallback* capture_callback); 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~AudioThreadCallback(); 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void MapSharedMemory() OVERRIDE; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Called whenever we receive notifications about pending data. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void Process(int pending_data) OVERRIDE; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int current_segment_id_; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CaptureCallback* capture_callback_; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<AudioBus> audio_bus_; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioInputDevice::AudioInputDevice( 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<AudioInputIPC> ipc, 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<base::MessageLoopProxy>& io_loop) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : ScopedLoopObserver(io_loop), 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_(NULL), 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ipc_(ipc.Pass()), 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_(IDLE), 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_id_(0), 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) agc_is_enabled_(false), 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stopping_hack_(false) { 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK(ipc_); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The correctness of the code depends on the relative values assigned in the 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // State enum. 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0); 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1); 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) COMPILE_ASSERT(CREATING_STREAM < RECORDING, invalid_enum_value_assignment_2); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::Initialize(const AudioParameters& params, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CaptureCallback* callback, 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int session_id) { 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(params.IsValid()); 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!callback_); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(0, session_id_); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_parameters_ = params; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_ = callback; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_id_ = session_id; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::Start() { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(callback_) << "Initialize hasn't been called"; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "Start()"; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop()->PostTask(FROM_HERE, 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&AudioInputDevice::StartUpOnIOThread, this)); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::Stop() { 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "Stop()"; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoLock auto_lock(audio_thread_lock_); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_thread_.Stop(base::MessageLoop::current()); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) stopping_hack_ = true; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop()->PostTask(FROM_HERE, 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::SetVolume(double volume) { 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (volume < 0 || volume > 1.0) { 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(ERROR) << "Invalid volume value specified"; 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop()->PostTask(FROM_HERE, 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume)); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::SetAutomaticGainControl(bool enabled) { 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) message_loop()->PostTask(FROM_HERE, 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread, 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, enabled)); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::OnStreamCreated( 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::SharedMemoryHandle handle, 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::SyncSocket::Handle socket_handle, 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int length, 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int total_segments) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(message_loop()->BelongsToCurrentThread()); 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(handle); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(socket_handle); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(handle.fd, 0); 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(socket_handle, 0); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 128c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch DCHECK_GT(length, 0); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state_ != CREATING_STREAM) 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoLock auto_lock(audio_thread_lock_); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice. 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Interface changes need to be made; likely, after AudioInputDevice is merged 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // into AudioOutputDevice (http://crbug.com/179597). 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (stopping_hack_) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(audio_thread_.IsStopped()); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_callback_.reset( 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new AudioInputDevice::AudioThreadCallback( 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_parameters_, handle, length, total_segments, callback_)); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = RECORDING; 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ipc_->RecordStream(); 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::OnVolume(double volume) { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTIMPLEMENTED(); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::OnStateChanged( 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioInputIPCDelegate::State state) { 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(message_loop()->BelongsToCurrentThread()); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Do nothing if the stream has been closed. 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state_ < CREATING_STREAM) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(miu): Clean-up inconsistent and incomplete handling here. 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // http://crbug.com/180640 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (state) { 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case AudioInputIPCDelegate::kStopped: 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShutDownOnIOThread(); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case AudioInputIPCDelegate::kRecording: 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTIMPLEMENTED(); 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case AudioInputIPCDelegate::kError: 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't dereference the callback object if the audio thread 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // is stopped or stopping. That could mean that the callback 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // object has been deleted. 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(tommi): Add an explicit contract for clearing the callback 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // object. Possibly require calling Initialize again or provide 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // a callback object via Start() and clear it in Stop(). 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!audio_thread_.IsStopped()) 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_->OnCaptureError(); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::OnIPCClosed() { 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(message_loop()->BelongsToCurrentThread()); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = IPC_CLOSED; 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ipc_.reset(); 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioInputDevice::~AudioInputDevice() { 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(henrika): The current design requires that the user calls 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Stop before deleting this class. 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(audio_thread_.IsStopped()); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::StartUpOnIOThread() { 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(message_loop()->BelongsToCurrentThread()); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make sure we don't call Start() more than once. 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state_ != IDLE) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (session_id_ <= 0) { 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(WARNING) << "Invalid session id for the input stream " << session_id_; 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = CREATING_STREAM; 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ipc_->CreateStream(this, session_id_, audio_parameters_, 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) agc_is_enabled_, kRequestedSharedMemoryCount); 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AudioInputDevice::ShutDownOnIOThread() { 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(message_loop()->BelongsToCurrentThread()); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Close the stream, if we haven't already. 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state_ >= CREATING_STREAM) { 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ipc_->CloseStream(); 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state_ = IDLE; 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) agc_is_enabled_ = false; 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We can run into an issue where ShutDownOnIOThread is called right after 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // OnStreamCreated is called in cases where Start/Stop are called before we 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // get the OnStreamCreated callback. To handle that corner case, we call 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Stop(). In most cases, the thread will already be stopped. 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Another situation is when the IO thread goes away before Stop() is called 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in which case, we cannot use the message loop to close the thread handle 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and can't not rely on the main thread existing either. 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoLock auto_lock_(audio_thread_lock_); 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ThreadRestrictions::ScopedAllowIO allow_io; 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_thread_.Stop(NULL); 238 audio_callback_.reset(); 239 stopping_hack_ = false; 240} 241 242void AudioInputDevice::SetVolumeOnIOThread(double volume) { 243 DCHECK(message_loop()->BelongsToCurrentThread()); 244 if (state_ >= CREATING_STREAM) 245 ipc_->SetVolume(volume); 246} 247 248void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { 249 DCHECK(message_loop()->BelongsToCurrentThread()); 250 251 if (state_ >= CREATING_STREAM) { 252 DLOG(WARNING) << "The AGC state can not be modified after starting."; 253 return; 254 } 255 256 // We simply store the new AGC setting here. This value will be used when 257 // a new stream is initialized and by GetAutomaticGainControl(). 258 agc_is_enabled_ = enabled; 259} 260 261void AudioInputDevice::WillDestroyCurrentMessageLoop() { 262 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 263 ShutDownOnIOThread(); 264} 265 266// AudioInputDevice::AudioThreadCallback 267AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 268 const AudioParameters& audio_parameters, 269 base::SharedMemoryHandle memory, 270 int memory_length, 271 int total_segments, 272 CaptureCallback* capture_callback) 273 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 274 total_segments), 275 current_segment_id_(0), 276 capture_callback_(capture_callback) { 277 audio_bus_ = AudioBus::Create(audio_parameters_); 278} 279 280AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 281} 282 283void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 284 shared_memory_.Map(memory_length_); 285} 286 287void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { 288 // The shared memory represents parameters, size of the data buffer and the 289 // actual data buffer containing audio data. Map the memory into this 290 // structure and parse out parameters and the data area. 291 uint8* ptr = static_cast<uint8*>(shared_memory_.memory()); 292 ptr += current_segment_id_ * segment_length_; 293 AudioInputBuffer* buffer = reinterpret_cast<AudioInputBuffer*>(ptr); 294 DCHECK_EQ(buffer->params.size, 295 segment_length_ - sizeof(AudioInputBufferParameters)); 296 double volume = buffer->params.volume; 297 298 int audio_delay_milliseconds = pending_data / bytes_per_ms_; 299 int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]); 300 const int bytes_per_sample = sizeof(memory[0]); 301 302 if (++current_segment_id_ >= total_segments_) 303 current_segment_id_ = 0; 304 305 // Deinterleave each channel and convert to 32-bit floating-point 306 // with nominal range -1.0 -> +1.0. 307 audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample); 308 309 // Deliver captured data to the client in floating point format 310 // and update the audio-delay measurement. 311 capture_callback_->Capture(audio_bus_.get(), 312 audio_delay_milliseconds, volume); 313} 314 315} // namespace media 316