Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/android/opensles_input.h" | 5 #include "media/audio/android/opensles_input.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "media/audio/android/audio_manager_android.h" | 8 #include "media/audio/android/audio_manager_android.h" |
| 9 | 9 |
| 10 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \ | 10 #define LOG_ON_FAILURE_AND_RETURN(op, ...) \ |
| 11 do { \ | 11 do { \ |
| 12 SLresult err = (op); \ | 12 SLresult err = (op); \ |
| 13 if (err != SL_RESULT_SUCCESS) { \ | 13 if (err != SL_RESULT_SUCCESS) { \ |
| 14 DLOG(ERROR) << #op << " failed: " << err; \ | 14 DLOG(ERROR) << #op << " failed: " << err; \ |
| 15 return __VA_ARGS__; \ | 15 return __VA_ARGS__; \ |
| 16 } \ | 16 } \ |
| 17 } while (0) | 17 } while (0) |
| 18 | 18 |
| 19 namespace media { | 19 namespace media { |
| 20 | 20 |
| 21 OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager, | 21 OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager, |
| 22 const AudioParameters& params) | 22 const AudioParameters& params) |
| 23 : audio_manager_(audio_manager), | 23 : audio_manager_(audio_manager), |
| 24 callback_(NULL), | 24 callback_(NULL), |
| 25 recorder_(NULL), | 25 recorder_(NULL), |
| 26 simple_buffer_queue_(NULL), | 26 simple_buffer_queue_(NULL), |
| 27 active_queue_(0), | 27 active_queue_(0), |
| 28 buffer_size_bytes_(0), | 28 buffer_size_bytes_(0), |
| 29 started_(false) { | 29 started_(false) { |
| 30 DVLOG(2) << "OpenSLESInputStream::OpenSLESInputStream()"; | |
| 30 format_.formatType = SL_DATAFORMAT_PCM; | 31 format_.formatType = SL_DATAFORMAT_PCM; |
| 31 format_.numChannels = static_cast<SLuint32>(params.channels()); | 32 format_.numChannels = static_cast<SLuint32>(params.channels()); |
| 32 // Provides sampling rate in milliHertz to OpenSLES. | 33 // Provides sampling rate in milliHertz to OpenSLES. |
| 33 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); | 34 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); |
| 34 format_.bitsPerSample = params.bits_per_sample(); | 35 format_.bitsPerSample = params.bits_per_sample(); |
| 35 format_.containerSize = params.bits_per_sample(); | 36 format_.containerSize = params.bits_per_sample(); |
| 36 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; | 37 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; |
| 37 if (format_.numChannels == 1) | 38 if (format_.numChannels == 1) |
| 38 format_.channelMask = SL_SPEAKER_FRONT_CENTER; | 39 format_.channelMask = SL_SPEAKER_FRONT_CENTER; |
| 39 else if (format_.numChannels == 2) | 40 else if (format_.numChannels == 2) |
| 40 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; | 41 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; |
| 41 else | 42 else |
| 42 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; | 43 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; |
| 43 | 44 |
| 44 buffer_size_bytes_ = params.GetBytesPerBuffer(); | 45 buffer_size_bytes_ = params.GetBytesPerBuffer(); |
| 45 | 46 |
| 46 memset(&audio_data_, 0, sizeof(audio_data_)); | 47 memset(&audio_data_, 0, sizeof(audio_data_)); |
| 47 } | 48 } |
| 48 | 49 |
| 49 OpenSLESInputStream::~OpenSLESInputStream() { | 50 OpenSLESInputStream::~OpenSLESInputStream() { |
| 51 DVLOG(2) << "OpenSLESInputStream::~OpenSLESInputStream()"; | |
| 52 DCHECK(thread_checker_.CalledOnValidThread()); | |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
nice to have the thread checker in here.
henrika (OOO until Aug 14)
2013/08/29 11:59:07
Thanks. It was a really smart guy who suggested it
| |
| 50 DCHECK(!recorder_object_.Get()); | 53 DCHECK(!recorder_object_.Get()); |
| 51 DCHECK(!engine_object_.Get()); | 54 DCHECK(!engine_object_.Get()); |
| 52 DCHECK(!recorder_); | 55 DCHECK(!recorder_); |
| 53 DCHECK(!simple_buffer_queue_); | 56 DCHECK(!simple_buffer_queue_); |
| 54 DCHECK(!audio_data_[0]); | 57 DCHECK(!audio_data_[0]); |
| 55 } | 58 } |
| 56 | 59 |
| 57 bool OpenSLESInputStream::Open() { | 60 bool OpenSLESInputStream::Open() { |
| 61 DVLOG(2) << "OpenSLESInputStream::Open()"; | |
| 62 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 58 if (engine_object_.Get()) | 63 if (engine_object_.Get()) |
| 59 return false; | 64 return false; |
| 60 | 65 |
| 61 if (!CreateRecorder()) | 66 if (!CreateRecorder()) |
| 62 return false; | 67 return false; |
| 63 | 68 |
| 64 SetupAudioBuffer(); | 69 SetupAudioBuffer(); |
| 65 | 70 |
| 66 return true; | 71 return true; |
| 67 } | 72 } |
| 68 | 73 |
| 69 void OpenSLESInputStream::Start(AudioInputCallback* callback) { | 74 void OpenSLESInputStream::Start(AudioInputCallback* callback) { |
| 75 DVLOG(2) << "OpenSLESInputStream::Start()"; | |
| 76 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 70 DCHECK(callback); | 77 DCHECK(callback); |
| 71 DCHECK(recorder_); | 78 DCHECK(recorder_); |
| 72 DCHECK(simple_buffer_queue_); | 79 DCHECK(simple_buffer_queue_); |
| 73 if (started_) | 80 if (started_) |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
this needs to be checked under the lock
henrika (OOO until Aug 14)
2013/08/29 11:59:07
Done.
| |
| 74 return; | 81 return; |
| 75 | 82 { |
| 76 // Enable the flags before streaming. | 83 base::AutoLock lock(lock_); |
| 77 callback_ = callback; | 84 // Enable the flags before streaming. |
| 78 active_queue_ = 0; | 85 callback_ = callback; |
| 79 started_ = true; | 86 active_queue_ = 0; |
| 87 started_ = true; | |
| 88 } | |
| 80 | 89 |
| 81 SLresult err = SL_RESULT_UNKNOWN_ERROR; | 90 SLresult err = SL_RESULT_UNKNOWN_ERROR; |
| 82 // Enqueues |kNumOfQueuesInBuffer| zero buffers to get the ball rolling. | 91 // Enqueues |kNumOfQueuesInBuffer| zero buffers to get the ball rolling. |
| 83 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | 92 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
| 84 err = (*simple_buffer_queue_)->Enqueue( | 93 err = (*simple_buffer_queue_)->Enqueue( |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
As is, it looks to me that you need to hold the lo
henrika (OOO until Aug 14)
2013/08/29 11:59:07
I find it difficult to guarantee that the worker t
| |
| 85 simple_buffer_queue_, | 94 simple_buffer_queue_, |
| 86 audio_data_[i], | 95 audio_data_[i], |
| 87 buffer_size_bytes_); | 96 buffer_size_bytes_); |
| 88 if (SL_RESULT_SUCCESS != err) { | 97 if (SL_RESULT_SUCCESS != err) { |
| 89 HandleError(err); | 98 HandleError(err); |
| 90 return; | 99 return; |
| 91 } | 100 } |
| 92 } | 101 } |
| 93 | 102 |
| 94 // Start the recording by setting the state to |SL_RECORDSTATE_RECORDING|. | 103 // Start the recording by setting the state to |SL_RECORDSTATE_RECORDING|. |
| 95 err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING); | 104 err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING); |
| 96 if (SL_RESULT_SUCCESS != err) | 105 if (SL_RESULT_SUCCESS != err) |
| 97 HandleError(err); | 106 HandleError(err); |
| 98 } | 107 } |
| 99 | 108 |
| 100 void OpenSLESInputStream::Stop() { | 109 void OpenSLESInputStream::Stop() { |
| 110 DVLOG(2) << "OpenSLESInputStream::Stop()"; | |
| 111 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 101 if (!started_) | 112 if (!started_) |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
need to hold lock.
henrika (OOO until Aug 14)
2013/08/29 11:59:07
Done.
| |
| 102 return; | 113 return; |
| 103 | 114 |
| 104 // Stop recording by setting the record state to |SL_RECORDSTATE_STOPPED|. | 115 // Stop recording by setting the record state to |SL_RECORDSTATE_STOPPED|. |
| 105 LOG_ON_FAILURE_AND_RETURN( | 116 LOG_ON_FAILURE_AND_RETURN( |
| 106 (*recorder_)->SetRecordState(recorder_, | 117 (*recorder_)->SetRecordState(recorder_, |
| 107 SL_RECORDSTATE_STOPPED)); | 118 SL_RECORDSTATE_STOPPED)); |
| 119 { | |
| 120 base::AutoLock lock(lock_); | |
| 108 | 121 |
| 109 // Clear the buffer queue to get rid of old data when resuming recording. | 122 // Clear the buffer queue to get rid of old data when resuming recording. |
| 110 LOG_ON_FAILURE_AND_RETURN( | 123 LOG_ON_FAILURE_AND_RETURN( |
| 111 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); | 124 (*simple_buffer_queue_)->Clear(simple_buffer_queue_)); |
| 112 | 125 |
| 113 started_ = false; | 126 started_ = false; |
| 127 } | |
| 114 } | 128 } |
| 115 | 129 |
| 116 void OpenSLESInputStream::Close() { | 130 void OpenSLESInputStream::Close() { |
| 131 DVLOG(2) << "OpenSLESInputStream::Close()"; | |
| 132 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 117 // Stop the stream if it is still recording. | 133 // Stop the stream if it is still recording. |
| 118 Stop(); | 134 Stop(); |
| 135 { | |
| 136 base::AutoLock lock(lock_); | |
| 137 if (callback_) { | |
| 138 callback_->OnClose(this); | |
| 139 callback_ = NULL; | |
| 140 } | |
| 141 } | |
| 119 | 142 |
| 120 // Explicitly free the player objects and invalidate their associated | 143 // Explicitly free the player objects and invalidate their associated |
| 121 // interfaces. They have to be done in the correct order. | 144 // interfaces. They have to be done in the correct order. |
| 122 recorder_object_.Reset(); | 145 recorder_object_.Reset(); |
| 123 engine_object_.Reset(); | 146 engine_object_.Reset(); |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
If I understand things correctly, resetting the en
henrika (OOO until Aug 14)
2013/08/29 11:59:07
Good point, thanks. Analyzed how things are create
| |
| 124 simple_buffer_queue_ = NULL; | 147 { |
| 148 base::AutoLock lock(lock_); | |
| 149 simple_buffer_queue_ = NULL; | |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
here you actually do grab the lock before changing
henrika (OOO until Aug 14)
2013/08/29 11:59:07
Done.
| |
| 150 } | |
| 125 recorder_ = NULL; | 151 recorder_ = NULL; |
| 126 | 152 |
| 127 ReleaseAudioBuffer(); | 153 ReleaseAudioBuffer(); |
| 128 | 154 |
| 129 audio_manager_->ReleaseInputStream(this); | 155 audio_manager_->ReleaseInputStream(this); |
| 130 } | 156 } |
| 131 | 157 |
| 132 double OpenSLESInputStream::GetMaxVolume() { | 158 double OpenSLESInputStream::GetMaxVolume() { |
| 133 NOTIMPLEMENTED(); | 159 NOTIMPLEMENTED(); |
| 134 return 0.0; | 160 return 0.0; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 146 void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { | 172 void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { |
| 147 NOTIMPLEMENTED(); | 173 NOTIMPLEMENTED(); |
| 148 } | 174 } |
| 149 | 175 |
| 150 bool OpenSLESInputStream::GetAutomaticGainControl() { | 176 bool OpenSLESInputStream::GetAutomaticGainControl() { |
| 151 NOTIMPLEMENTED(); | 177 NOTIMPLEMENTED(); |
| 152 return false; | 178 return false; |
| 153 } | 179 } |
| 154 | 180 |
| 155 bool OpenSLESInputStream::CreateRecorder() { | 181 bool OpenSLESInputStream::CreateRecorder() { |
| 182 DCHECK(thread_checker_.CalledOnValidThread()); | |
|
tommi (sloooow) - chröme
2013/08/29 09:56:27
We should also dcheck that all interface and objec
henrika (OOO until Aug 14)
2013/08/29 11:59:07
Done.
| |
| 156 // Initializes the engine object with specific option. After working with the | 183 // Initializes the engine object with specific option. After working with the |
| 157 // object, we need to free the object and its resources. | 184 // object, we need to free the object and its resources. |
| 158 SLEngineOption option[] = { | 185 SLEngineOption option[] = { |
| 159 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } | 186 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } |
| 160 }; | 187 }; |
| 161 LOG_ON_FAILURE_AND_RETURN(slCreateEngine(engine_object_.Receive(), | 188 LOG_ON_FAILURE_AND_RETURN(slCreateEngine(engine_object_.Receive(), |
| 162 1, | 189 1, |
| 163 option, | 190 option, |
| 164 0, | 191 0, |
| 165 NULL, | 192 NULL, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 258 } | 285 } |
| 259 | 286 |
| 260 void OpenSLESInputStream::SimpleBufferQueueCallback( | 287 void OpenSLESInputStream::SimpleBufferQueueCallback( |
| 261 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { | 288 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { |
| 262 OpenSLESInputStream* stream = | 289 OpenSLESInputStream* stream = |
| 263 reinterpret_cast<OpenSLESInputStream*>(instance); | 290 reinterpret_cast<OpenSLESInputStream*>(instance); |
| 264 stream->ReadBufferQueue(); | 291 stream->ReadBufferQueue(); |
| 265 } | 292 } |
| 266 | 293 |
| 267 void OpenSLESInputStream::ReadBufferQueue() { | 294 void OpenSLESInputStream::ReadBufferQueue() { |
| 295 base::AutoLock lock(lock_); | |
| 268 if (!started_) | 296 if (!started_) |
| 269 return; | 297 return; |
| 270 | 298 |
| 271 // TODO(xians): Get an accurate delay estimation. | 299 // TODO(xians): Get an accurate delay estimation. |
| 272 callback_->OnData(this, | 300 callback_->OnData(this, |
| 273 audio_data_[active_queue_], | 301 audio_data_[active_queue_], |
| 274 buffer_size_bytes_, | 302 buffer_size_bytes_, |
| 275 buffer_size_bytes_, | 303 buffer_size_bytes_, |
| 276 0.0); | 304 0.0); |
| 277 | 305 |
| 278 // Done with this buffer. Send it to device for recording. | 306 // Done with this buffer. Send it to device for recording. |
| 279 SLresult err = (*simple_buffer_queue_)->Enqueue( | 307 SLresult err = (*simple_buffer_queue_)->Enqueue( |
| 280 simple_buffer_queue_, | 308 simple_buffer_queue_, |
| 281 audio_data_[active_queue_], | 309 audio_data_[active_queue_], |
| 282 buffer_size_bytes_); | 310 buffer_size_bytes_); |
| 283 if (SL_RESULT_SUCCESS != err) | 311 if (SL_RESULT_SUCCESS != err) |
| 284 HandleError(err); | 312 HandleError(err); |
| 285 | 313 |
| 286 active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer; | 314 active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer; |
| 287 } | 315 } |
| 288 | 316 |
| 289 void OpenSLESInputStream::SetupAudioBuffer() { | 317 void OpenSLESInputStream::SetupAudioBuffer() { |
| 318 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 290 DCHECK(!audio_data_[0]); | 319 DCHECK(!audio_data_[0]); |
| 291 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | 320 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
| 292 audio_data_[i] = new uint8[buffer_size_bytes_]; | 321 audio_data_[i] = new uint8[buffer_size_bytes_]; |
| 293 } | 322 } |
| 294 } | 323 } |
| 295 | 324 |
| 296 void OpenSLESInputStream::ReleaseAudioBuffer() { | 325 void OpenSLESInputStream::ReleaseAudioBuffer() { |
| 326 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 297 if (audio_data_[0]) { | 327 if (audio_data_[0]) { |
| 298 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | 328 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
| 299 delete [] audio_data_[i]; | 329 delete [] audio_data_[i]; |
| 300 audio_data_[i] = NULL; | 330 audio_data_[i] = NULL; |
| 301 } | 331 } |
| 302 } | 332 } |
| 303 } | 333 } |
| 304 | 334 |
| 305 void OpenSLESInputStream::HandleError(SLresult error) { | 335 void OpenSLESInputStream::HandleError(SLresult error) { |
| 306 DLOG(FATAL) << "OpenSLES Input error " << error; | 336 DLOG(FATAL) << "OpenSLES Input error " << error; |
| 307 if (callback_) | 337 if (callback_) |
| 308 callback_->OnError(this); | 338 callback_->OnError(this); |
| 309 } | 339 } |
| 310 | 340 |
| 311 } // namespace media | 341 } // namespace media |
| OLD | NEW |