opensles_input.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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) << "OpenSLESInputStream::OpenSLESInputStream()"; 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) << "OpenSLESInputStream::~OpenSLESInputStream()"; 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) << "OpenSLESInputStream::Open()"; 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) << "OpenSLESInputStream::Start()"; 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) << "OpenSLESInputStream::Stop()"; 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} 136 137void OpenSLESInputStream::Close() { 138 DVLOG(2) << "OpenSLESInputStream::Close()"; 139 DCHECK(thread_checker_.CalledOnValidThread()); 140 141 // Stop the stream if it is still recording. 142 Stop(); 143 { 144 base::AutoLock lock(lock_); 145 146 // TODO(henrika): we use |callback_| in Close() but |callback_| is set 147 // in Start(). Hence, it should be cleared in Stop() and not used here. 148 if (callback_) { 149 callback_->OnClose(this); 150 callback_ = NULL; 151 } 152 153 // Destroy the buffer queue recorder object and invalidate all associated 154 // interfaces. 155 recorder_object_.Reset(); 156 simple_buffer_queue_ = NULL; 157 recorder_ = NULL; 158 159 // Destroy the engine object. We don't store any associated interface for 160 // this object. 161 engine_object_.Reset(); 162 ReleaseAudioBuffer(); 163 } 164 165 audio_manager_->ReleaseInputStream(this); 166} 167 168double OpenSLESInputStream::GetMaxVolume() { 169 NOTIMPLEMENTED(); 170 return 0.0; 171} 172 173void OpenSLESInputStream::SetVolume(double volume) { NOTIMPLEMENTED(); } 174 175double OpenSLESInputStream::GetVolume() { 176 NOTIMPLEMENTED(); 177 return 0.0; 178} 179 180void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { 181 NOTIMPLEMENTED(); 182} 183 184bool OpenSLESInputStream::GetAutomaticGainControl() { 185 NOTIMPLEMENTED(); 186 return false; 187} 188 189bool OpenSLESInputStream::CreateRecorder() { 190 DCHECK(thread_checker_.CalledOnValidThread()); 191 DCHECK(!engine_object_.Get()); 192 DCHECK(!recorder_object_.Get()); 193 DCHECK(!recorder_); 194 DCHECK(!simple_buffer_queue_); 195 196 // Initializes the engine object with specific option. After working with the 197 // object, we need to free the object and its resources. 198 SLEngineOption option[] = { 199 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}}; 200 LOG_ON_FAILURE_AND_RETURN( 201 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), 202 false); 203 204 // Realize the SL engine object in synchronous mode. 205 LOG_ON_FAILURE_AND_RETURN( 206 engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false); 207 208 // Get the SL engine interface which is implicit. 209 SLEngineItf engine; 210 LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface( 211 engine_object_.Get(), SL_IID_ENGINE, &engine), 212 false); 213 214 // Audio source configuration. 215 SLDataLocator_IODevice mic_locator = { 216 SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, 217 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; 218 SLDataSource audio_source = {&mic_locator, NULL}; 219 220 // Audio sink configuration. 221 SLDataLocator_AndroidSimpleBufferQueue buffer_queue = { 222 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 223 static_cast<SLuint32>(kMaxNumOfBuffersInQueue)}; 224 SLDataSink audio_sink = {&buffer_queue, &format_}; 225 226 // Create an audio recorder. 227 const SLInterfaceID interface_id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 228 SL_IID_ANDROIDCONFIGURATION}; 229 const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 230 231 // Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION. 232 LOG_ON_FAILURE_AND_RETURN( 233 (*engine)->CreateAudioRecorder(engine, 234 recorder_object_.Receive(), 235 &audio_source, 236 &audio_sink, 237 arraysize(interface_id), 238 interface_id, 239 interface_required), 240 false); 241 242 SLAndroidConfigurationItf recorder_config; 243 LOG_ON_FAILURE_AND_RETURN( 244 recorder_object_->GetInterface(recorder_object_.Get(), 245 SL_IID_ANDROIDCONFIGURATION, 246 &recorder_config), 247 false); 248 249 // Uses the main microphone tuned for audio communications. 250 SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; 251 LOG_ON_FAILURE_AND_RETURN( 252 (*recorder_config)->SetConfiguration(recorder_config, 253 SL_ANDROID_KEY_RECORDING_PRESET, 254 &stream_type, 255 sizeof(SLint32)), 256 false); 257 258 // Realize the recorder object in synchronous mode. 259 LOG_ON_FAILURE_AND_RETURN( 260 recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE), 261 false); 262 263 // Get an implicit recorder interface. 264 LOG_ON_FAILURE_AND_RETURN( 265 recorder_object_->GetInterface( 266 recorder_object_.Get(), SL_IID_RECORD, &recorder_), 267 false); 268 269 // Get the simple buffer queue interface. 270 LOG_ON_FAILURE_AND_RETURN( 271 recorder_object_->GetInterface(recorder_object_.Get(), 272 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 273 &simple_buffer_queue_), 274 false); 275 276 // Register the input callback for the simple buffer queue. 277 // This callback will be called when receiving new data from the device. 278 LOG_ON_FAILURE_AND_RETURN( 279 (*simple_buffer_queue_)->RegisterCallback( 280 simple_buffer_queue_, SimpleBufferQueueCallback, this), 281 false); 282 283 return true; 284} 285 286void OpenSLESInputStream::SimpleBufferQueueCallback( 287 SLAndroidSimpleBufferQueueItf buffer_queue, 288 void* instance) { 289 OpenSLESInputStream* stream = 290 reinterpret_cast<OpenSLESInputStream*>(instance); 291 stream->ReadBufferQueue(); 292} 293 294void OpenSLESInputStream::ReadBufferQueue() { 295 base::AutoLock lock(lock_); 296 if (!started_) 297 return; 298 299 TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue"); 300 301 // TODO(henrika): Investigate if it is possible to get an accurate 302 // delay estimation. 303 callback_->OnData(this, 304 audio_data_[active_buffer_index_], 305 buffer_size_bytes_, 306 buffer_size_bytes_, 307 0.0); 308 309 // Done with this buffer. Send it to device for recording. 310 SLresult err = 311 (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_, 312 audio_data_[active_buffer_index_], 313 buffer_size_bytes_); 314 if (SL_RESULT_SUCCESS != err) 315 HandleError(err); 316 317 active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue; 318} 319 320void OpenSLESInputStream::SetupAudioBuffer() { 321 DCHECK(thread_checker_.CalledOnValidThread()); 322 DCHECK(!audio_data_[0]); 323 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 324 audio_data_[i] = new uint8[buffer_size_bytes_]; 325 } 326} 327 328void OpenSLESInputStream::ReleaseAudioBuffer() { 329 DCHECK(thread_checker_.CalledOnValidThread()); 330 if (audio_data_[0]) { 331 for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { 332 delete[] audio_data_[i]; 333 audio_data_[i] = NULL; 334 } 335 } 336} 337 338void OpenSLESInputStream::HandleError(SLresult error) { 339 DLOG(ERROR) << "OpenSLES Input error " << error; 340 if (callback_) 341 callback_->OnError(this); 342} 343 344} // namespace media 345