opensles_input.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "media/audio/android/opensles_input.h" 6 7#include "base/debug/trace_event.h" 8#include "base/logging.h" 9#include "media/audio/android/audio_manager_android.h" 10 11#define LOG_ON_FAILURE_AND_RETURN(op, ...) \ 12 do { \ 13 SLresult err = (op); \ 14 if (err != SL_RESULT_SUCCESS) { \ 15 DLOG(ERROR) << #op << " failed: " << err; \ 16 return __VA_ARGS__; \ 17 } \ 18 } while (0) 19 20namespace media { 21 22OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager, 23 const AudioParameters& params) 24 : audio_manager_(audio_manager), 25 callback_(NULL), 26 recorder_(NULL), 27 simple_buffer_queue_(NULL), 28 active_buffer_index_(0), 29 buffer_size_bytes_(0), 30 started_(false) { 31 DVLOG(2) << __PRETTY_FUNCTION__; 32 format_.formatType = SL_DATAFORMAT_PCM; 33 format_.numChannels = static_cast<SLuint32>(params.channels()); 34 // Provides sampling rate in milliHertz to OpenSLES. 35 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); 36 format_.bitsPerSample = params.bits_per_sample(); 37 format_.containerSize = params.bits_per_sample(); 38 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; 39 if (format_.numChannels == 1) 40 format_.channelMask = SL_SPEAKER_FRONT_CENTER; 41 else if (format_.numChannels == 2) 42 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 43 else 44 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; 45 46 buffer_size_bytes_ = params.GetBytesPerBuffer(); 47 48 memset(&audio_data_, 0, sizeof(audio_data_)); 49} 50 51OpenSLESInputStream::~OpenSLESInputStream() { 52 DVLOG(2) << __PRETTY_FUNCTION__; 53 DCHECK(thread_checker_.CalledOnValidThread()); 54 DCHECK(!recorder_object_.Get()); 55 DCHECK(!engine_object_.Get()); 56 DCHECK(!recorder_); 57 DCHECK(!simple_buffer_queue_); 58 DCHECK(!audio_data_[0]); 59} 60 61bool OpenSLESInputStream::Open() { 62 DVLOG(2) << __PRETTY_FUNCTION__; 63 DCHECK(thread_checker_.CalledOnValidThread()); 64 if (engine_object_.Get()) 65 return false; 66 67 if (!CreateRecorder()) 68 return false; 69 70 SetupAudioBuffer(); 71 72 return true; 73} 74 75void OpenSLESInputStream::Start(AudioInputCallback* callback) { 76 DVLOG(2) << __PRETTY_FUNCTION__; 77 DCHECK(thread_checker_.CalledOnValidThread()); 78 DCHECK(callback); 79 DCHECK(recorder_); 80 DCHECK(simple_buffer_queue_); 81 if (started_) 82 return; 83 84 base::AutoLock lock(lock_); 85 DCHECK(callback_ == NULL || callback_ == callback); 86 callback_ = callback; 87 active_buffer_index_ = 0; 88 89 // Enqueues kMaxNumOfBuffersInQueue zero buffers to get the ball rolling. 90 // TODO(henrika): add support for Start/Stop/Start sequences when we are 91 // able to clear the buffer queue. There is currently a bug in the OpenSLES 92 // implementation which forces us to always call Stop() and Close() before 93 // calling Start() again. 94 SLresult err = SL_RESULT_UNKNOWN_ERROR; 95 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 96 err = (*simple_buffer_queue_)->Enqueue( 97 simple_buffer_queue_, audio_data_[i], buffer_size_bytes_); 98 if (SL_RESULT_SUCCESS != err) { 99 HandleError(err); 100 started_ = false; 101 return; 102 } 103 } 104 105 // Start the recording by setting the state to SL_RECORDSTATE_RECORDING. 106 // When the object is in the SL_RECORDSTATE_RECORDING state, adding buffers 107 // will implicitly start the filling process. 108 err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING); 109 if (SL_RESULT_SUCCESS != err) { 110 HandleError(err); 111 started_ = false; 112 return; 113 } 114 115 started_ = true; 116} 117 118void OpenSLESInputStream::Stop() { 119 DVLOG(2) << __PRETTY_FUNCTION__; 120 DCHECK(thread_checker_.CalledOnValidThread()); 121 if (!started_) 122 return; 123 124 base::AutoLock lock(lock_); 125 126 // Stop recording by setting the record state to SL_RECORDSTATE_STOPPED. 127 LOG_ON_FAILURE_AND_RETURN( 128 (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_STOPPED)); 129 130 // Clear the buffer queue to get rid of old data when resuming recording. 131 LOG_ON_FAILURE_AND_RETURN( 132 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); 133 134 started_ = false; 135 callback_ = NULL; 136} 137 138void OpenSLESInputStream::Close() { 139 DVLOG(2) << __PRETTY_FUNCTION__; 140 DCHECK(thread_checker_.CalledOnValidThread()); 141 142 // Stop the stream if it is still recording. 143 Stop(); 144 { 145 // TODO(henrika): Do we need to hold the lock here? 146 base::AutoLock lock(lock_); 147 148 // Destroy the buffer queue recorder object and invalidate all associated 149 // interfaces. 150 recorder_object_.Reset(); 151 simple_buffer_queue_ = NULL; 152 recorder_ = NULL; 153 154 // Destroy the engine object. We don't store any associated interface for 155 // this object. 156 engine_object_.Reset(); 157 ReleaseAudioBuffer(); 158 } 159 160 audio_manager_->ReleaseInputStream(this); 161} 162 163double OpenSLESInputStream::GetMaxVolume() { 164 NOTIMPLEMENTED(); 165 return 0.0; 166} 167 168void OpenSLESInputStream::SetVolume(double volume) { 169 NOTIMPLEMENTED(); 170} 171 172double OpenSLESInputStream::GetVolume() { 173 NOTIMPLEMENTED(); 174 return 0.0; 175} 176 177void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { 178 NOTIMPLEMENTED(); 179} 180 181bool OpenSLESInputStream::GetAutomaticGainControl() { 182 NOTIMPLEMENTED(); 183 return false; 184} 185 186bool OpenSLESInputStream::CreateRecorder() { 187 DCHECK(thread_checker_.CalledOnValidThread()); 188 DCHECK(!engine_object_.Get()); 189 DCHECK(!recorder_object_.Get()); 190 DCHECK(!recorder_); 191 DCHECK(!simple_buffer_queue_); 192 193 // Initializes the engine object with specific option. After working with the 194 // object, we need to free the object and its resources. 195 SLEngineOption option[] = { 196 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}}; 197 LOG_ON_FAILURE_AND_RETURN( 198 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), 199 false); 200 201 // Realize the SL engine object in synchronous mode. 202 LOG_ON_FAILURE_AND_RETURN( 203 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false); 204 205 // Get the SL engine interface which is implicit. 206 SLEngineItf engine; 207 LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface( 208 engine_object_.Get(), SL_IID_ENGINE, &engine), 209 false); 210 211 // Audio source configuration. 212 SLDataLocator_IODevice mic_locator = { 213 SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, 214 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; 215 SLDataSource audio_source = {&mic_locator, NULL}; 216 217 // Audio sink configuration. 218 SLDataLocator_AndroidSimpleBufferQueue buffer_queue = { 219 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 220 static_cast<SLuint32>(kMaxNumOfBuffersInQueue)}; 221 SLDataSink audio_sink = {&buffer_queue, &format_}; 222 223 // Create an audio recorder. 224 const SLInterfaceID interface_id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 225 SL_IID_ANDROIDCONFIGURATION}; 226 const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 227 228 // Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION. 229 LOG_ON_FAILURE_AND_RETURN( 230 (*engine)->CreateAudioRecorder(engine, 231 recorder_object_.Receive(), 232 &audio_source, 233 &audio_sink, 234 arraysize(interface_id), 235 interface_id, 236 interface_required), 237 false); 238 239 SLAndroidConfigurationItf recorder_config; 240 LOG_ON_FAILURE_AND_RETURN( 241 recorder_object_->GetInterface(recorder_object_.Get(), 242 SL_IID_ANDROIDCONFIGURATION, 243 &recorder_config), 244 false); 245 246 // Uses the main microphone tuned for audio communications. 247 SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; 248 LOG_ON_FAILURE_AND_RETURN( 249 (*recorder_config)->SetConfiguration(recorder_config, 250 SL_ANDROID_KEY_RECORDING_PRESET, 251 &stream_type, 252 sizeof(SLint32)), 253 false); 254 255 // Realize the recorder object in synchronous mode. 256 LOG_ON_FAILURE_AND_RETURN( 257 recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE), 258 false); 259 260 // Get an implicit recorder interface. 261 LOG_ON_FAILURE_AND_RETURN( 262 recorder_object_->GetInterface( 263 recorder_object_.Get(), SL_IID_RECORD, &recorder_), 264 false); 265 266 // Get the simple buffer queue interface. 267 LOG_ON_FAILURE_AND_RETURN( 268 recorder_object_->GetInterface(recorder_object_.Get(), 269 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 270 &simple_buffer_queue_), 271 false); 272 273 // Register the input callback for the simple buffer queue. 274 // This callback will be called when receiving new data from the device. 275 LOG_ON_FAILURE_AND_RETURN( 276 (*simple_buffer_queue_)->RegisterCallback( 277 simple_buffer_queue_, SimpleBufferQueueCallback, this), 278 false); 279 280 return true; 281} 282 283void OpenSLESInputStream::SimpleBufferQueueCallback( 284 SLAndroidSimpleBufferQueueItf buffer_queue, 285 void* instance) { 286 OpenSLESInputStream* stream = 287 reinterpret_cast<OpenSLESInputStream*>(instance); 288 stream->ReadBufferQueue(); 289} 290 291void OpenSLESInputStream::ReadBufferQueue() { 292 base::AutoLock lock(lock_); 293 if (!started_) 294 return; 295 296 TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue"); 297 298 // TODO(henrika): Investigate if it is possible to get an accurate 299 // delay estimation. 300 callback_->OnData(this, 301 audio_data_[active_buffer_index_], 302 buffer_size_bytes_, 303 buffer_size_bytes_, 304 0.0); 305 306 // Done with this buffer. Send it to device for recording. 307 SLresult err = 308 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_, 309 audio_data_[active_buffer_index_], 310 buffer_size_bytes_); 311 if (SL_RESULT_SUCCESS != err) 312 HandleError(err); 313 314 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue; 315} 316 317void OpenSLESInputStream::SetupAudioBuffer() { 318 DCHECK(thread_checker_.CalledOnValidThread()); 319 DCHECK(!audio_data_[0]); 320 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 321 audio_data_[i] = new uint8[buffer_size_bytes_]; 322 } 323} 324 325void OpenSLESInputStream::ReleaseAudioBuffer() { 326 DCHECK(thread_checker_.CalledOnValidThread()); 327 if (audio_data_[0]) { 328 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 329 delete[] audio_data_[i]; 330 audio_data_[i] = NULL; 331 } 332 } 333} 334 335void OpenSLESInputStream::HandleError(SLresult error) { 336 DLOG(ERROR) << "OpenSLES Input error " << error; 337 if (callback_) 338 callback_->OnError(this); 339} 340 341} // namespace media 342