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