Index: media/audio/android/opensles_input.cc |
diff --git a/media/audio/android/opensles_input.cc b/media/audio/android/opensles_input.cc |
index 15c3eac3726389bb7f8d0a7f37ee4b8d35a82f91..60a94debef9897bdcd5c0214ab2f88319594ccc6 100644 |
--- a/media/audio/android/opensles_input.cc |
+++ b/media/audio/android/opensles_input.cc |
@@ -4,16 +4,17 @@ |
#include "media/audio/android/opensles_input.h" |
+#include "base/debug/trace_event.h" |
#include "base/logging.h" |
#include "media/audio/android/audio_manager_android.h" |
-#define LOG_ON_FAILURE_AND_RETURN(op, ...) \ |
- do { \ |
- SLresult err = (op); \ |
- if (err != SL_RESULT_SUCCESS) { \ |
+#define LOG_ON_FAILURE_AND_RETURN(op, ...) \ |
+ do { \ |
+ SLresult err = (op); \ |
+ if (err != SL_RESULT_SUCCESS) { \ |
DLOG(ERROR) << #op << " failed: " << err; \ |
- return __VA_ARGS__; \ |
- } \ |
+ return __VA_ARGS__; \ |
+ } \ |
} while (0) |
namespace media { |
@@ -24,9 +25,10 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager, |
callback_(NULL), |
recorder_(NULL), |
simple_buffer_queue_(NULL), |
- active_queue_(0), |
+ active_buffer_index_(0), |
buffer_size_bytes_(0), |
started_(false) { |
+ DVLOG(2) << "OpenSLESInputStream::OpenSLESInputStream()"; |
format_.formatType = SL_DATAFORMAT_PCM; |
format_.numChannels = static_cast<SLuint32>(params.channels()); |
// Provides sampling rate in milliHertz to OpenSLES. |
@@ -47,6 +49,8 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager, |
} |
OpenSLESInputStream::~OpenSLESInputStream() { |
+ DVLOG(2) << "OpenSLESInputStream::~OpenSLESInputStream()"; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(!recorder_object_.Get()); |
DCHECK(!engine_object_.Get()); |
DCHECK(!recorder_); |
@@ -55,6 +59,8 @@ OpenSLESInputStream::~OpenSLESInputStream() { |
} |
bool OpenSLESInputStream::Open() { |
+ DVLOG(2) << "OpenSLESInputStream::Open()"; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
if (engine_object_.Get()) |
return false; |
@@ -67,44 +73,59 @@ bool OpenSLESInputStream::Open() { |
} |
void OpenSLESInputStream::Start(AudioInputCallback* callback) { |
+ DVLOG(2) << "OpenSLESInputStream::Start()"; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(callback); |
DCHECK(recorder_); |
DCHECK(simple_buffer_queue_); |
if (started_) |
return; |
- // Enable the flags before streaming. |
+ base::AutoLock lock(lock_); |
+ DCHECK(callback_ == NULL || callback_ == callback); |
callback_ = callback; |
- active_queue_ = 0; |
- started_ = true; |
+ active_buffer_index_ = 0; |
+ // Enqueues kMaxNumOfBuffersInQueue zero buffers to get the ball rolling. |
+ // TODO(henrika): add support for Start/Stop/Start sequences when we are |
+ // able to clear the buffer queue. There is currently a bug in the OpenSLES |
+ // implementation which forces us to always call Stop() and Close() before |
+ // calling Start() again. |
SLresult err = SL_RESULT_UNKNOWN_ERROR; |
- // Enqueues |kNumOfQueuesInBuffer| zero buffers to get the ball rolling. |
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { |
err = (*simple_buffer_queue_)->Enqueue( |
- simple_buffer_queue_, |
- audio_data_[i], |
- buffer_size_bytes_); |
+ simple_buffer_queue_, audio_data_[i], buffer_size_bytes_); |
if (SL_RESULT_SUCCESS != err) { |
HandleError(err); |
+ started_ = false; |
return; |
} |
} |
- // Start the recording by setting the state to |SL_RECORDSTATE_RECORDING|. |
+ // Start the recording by setting the state to SL_RECORDSTATE_RECORDING. |
+ // When the object is in the SL_RECORDSTATE_RECORDING state, adding buffers |
+ // will implicitly start the filling process. |
err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING); |
- if (SL_RESULT_SUCCESS != err) |
+ if (SL_RESULT_SUCCESS != err) { |
HandleError(err); |
+ started_ = false; |
+ return; |
+ } |
+ |
+ started_ = true; |
} |
void OpenSLESInputStream::Stop() { |
+ DVLOG(2) << "OpenSLESInputStream::Stop()"; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
if (!started_) |
return; |
- // Stop recording by setting the record state to |SL_RECORDSTATE_STOPPED|. |
+ base::AutoLock lock(lock_); |
+ |
+ // Stop recording by setting the record state to SL_RECORDSTATE_STOPPED. |
LOG_ON_FAILURE_AND_RETURN( |
- (*recorder_)->SetRecordState(recorder_, |
- SL_RECORDSTATE_STOPPED)); |
+ (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_STOPPED)); |
// Clear the buffer queue to get rid of old data when resuming recording. |
LOG_ON_FAILURE_AND_RETURN( |
@@ -114,17 +135,30 @@ void OpenSLESInputStream::Stop() { |
} |
void OpenSLESInputStream::Close() { |
+ DVLOG(2) << "OpenSLESInputStream::Close()"; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
// Stop the stream if it is still recording. |
Stop(); |
+ { |
+ base::AutoLock lock(lock_); |
+ |
+ if (callback_) { |
+ callback_->OnClose(this); |
wjia(left Chromium)
2013/09/10 16:33:35
Since none of us knows why callback is passed in a
henrika (OOO until Aug 14)
2013/09/11 13:25:01
Done.
|
+ callback_ = NULL; |
+ } |
- // Explicitly free the player objects and invalidate their associated |
- // interfaces. They have to be done in the correct order. |
- recorder_object_.Reset(); |
- engine_object_.Reset(); |
- simple_buffer_queue_ = NULL; |
- recorder_ = NULL; |
+ // Destroy the buffer queue recorder object and invalidate all associated |
+ // interfaces. |
+ recorder_object_.Reset(); |
+ simple_buffer_queue_ = NULL; |
+ recorder_ = NULL; |
- ReleaseAudioBuffer(); |
+ // Destroy the engine object. We don't store any associated interface for |
+ // this object. |
+ engine_object_.Reset(); |
+ ReleaseAudioBuffer(); |
+ } |
audio_manager_->ReleaseInputStream(this); |
} |
@@ -134,9 +168,7 @@ double OpenSLESInputStream::GetMaxVolume() { |
return 0.0; |
} |
-void OpenSLESInputStream::SetVolume(double volume) { |
- NOTIMPLEMENTED(); |
-} |
+void OpenSLESInputStream::SetVolume(double volume) { NOTIMPLEMENTED(); } |
double OpenSLESInputStream::GetVolume() { |
NOTIMPLEMENTED(); |
@@ -153,54 +185,47 @@ bool OpenSLESInputStream::GetAutomaticGainControl() { |
} |
bool OpenSLESInputStream::CreateRecorder() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(!engine_object_.Get()); |
+ DCHECK(!recorder_object_.Get()); |
+ DCHECK(!recorder_); |
+ DCHECK(!simple_buffer_queue_); |
+ |
// Initializes the engine object with specific option. After working with the |
// object, we need to free the object and its resources. |
SLEngineOption option[] = { |
- { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } |
- }; |
- LOG_ON_FAILURE_AND_RETURN(slCreateEngine(engine_object_.Receive(), |
- 1, |
- option, |
- 0, |
- NULL, |
- NULL), |
- false); |
+ {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}}; |
+ LOG_ON_FAILURE_AND_RETURN( |
+ slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL), |
+ false); |
// Realize the SL engine object in synchronous mode. |
- LOG_ON_FAILURE_AND_RETURN(engine_object_->Realize(engine_object_.Get(), |
- SL_BOOLEAN_FALSE), |
- false); |
+ LOG_ON_FAILURE_AND_RETURN( |
+ engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false); |
// Get the SL engine interface which is implicit. |
SLEngineItf engine; |
- LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(engine_object_.Get(), |
- SL_IID_ENGINE, |
- &engine), |
+ LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface( |
+ engine_object_.Get(), SL_IID_ENGINE, &engine), |
false); |
// Audio source configuration. |
SLDataLocator_IODevice mic_locator = { |
- SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, |
- SL_DEFAULTDEVICEID_AUDIOINPUT, NULL |
- }; |
- SLDataSource audio_source = { &mic_locator, NULL }; |
+ SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, |
+ SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; |
+ SLDataSource audio_source = {&mic_locator, NULL}; |
// Audio sink configuration. |
SLDataLocator_AndroidSimpleBufferQueue buffer_queue = { |
- SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // Locator type. |
- static_cast<SLuint32>(kNumOfQueuesInBuffer) // Number of buffers. |
- }; |
- SLDataSink audio_sink = { &buffer_queue, &format_ }; |
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, |
+ static_cast<SLuint32>(kMaxNumOfBuffersInQueue)}; |
+ SLDataSink audio_sink = {&buffer_queue, &format_}; |
// Create an audio recorder. |
- const SLInterfaceID interface_id[] = { |
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE, |
- SL_IID_ANDROIDCONFIGURATION |
- }; |
- const SLboolean interface_required[] = { |
- SL_BOOLEAN_TRUE, |
- SL_BOOLEAN_TRUE |
- }; |
+ const SLInterfaceID interface_id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, |
+ SL_IID_ANDROIDCONFIGURATION}; |
+ const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; |
+ |
// Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION. |
LOG_ON_FAILURE_AND_RETURN( |
(*engine)->CreateAudioRecorder(engine, |
@@ -219,24 +244,24 @@ bool OpenSLESInputStream::CreateRecorder() { |
&recorder_config), |
false); |
+ // Uses the main microphone tuned for audio communications. |
SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; |
LOG_ON_FAILURE_AND_RETURN( |
(*recorder_config)->SetConfiguration(recorder_config, |
SL_ANDROID_KEY_RECORDING_PRESET, |
- &stream_type, sizeof(SLint32)), |
+ &stream_type, |
+ sizeof(SLint32)), |
false); |
// Realize the recorder object in synchronous mode. |
LOG_ON_FAILURE_AND_RETURN( |
- recorder_object_->Realize(recorder_object_.Get(), |
- SL_BOOLEAN_FALSE), |
+ recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE), |
false); |
// Get an implicit recorder interface. |
LOG_ON_FAILURE_AND_RETURN( |
- recorder_object_->GetInterface(recorder_object_.Get(), |
- SL_IID_RECORD, |
- &recorder_), |
+ recorder_object_->GetInterface( |
+ recorder_object_.Get(), SL_IID_RECORD, &recorder_), |
false); |
// Get the simple buffer queue interface. |
@@ -249,61 +274,66 @@ bool OpenSLESInputStream::CreateRecorder() { |
// Register the input callback for the simple buffer queue. |
// This callback will be called when receiving new data from the device. |
LOG_ON_FAILURE_AND_RETURN( |
- (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_, |
- SimpleBufferQueueCallback, |
- this), |
+ (*simple_buffer_queue_)->RegisterCallback( |
+ simple_buffer_queue_, SimpleBufferQueueCallback, this), |
false); |
return true; |
} |
void OpenSLESInputStream::SimpleBufferQueueCallback( |
- SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { |
+ SLAndroidSimpleBufferQueueItf buffer_queue, |
+ void* instance) { |
OpenSLESInputStream* stream = |
reinterpret_cast<OpenSLESInputStream*>(instance); |
stream->ReadBufferQueue(); |
} |
void OpenSLESInputStream::ReadBufferQueue() { |
+ base::AutoLock lock(lock_); |
if (!started_) |
return; |
- // TODO(xians): Get an accurate delay estimation. |
+ TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue"); |
+ |
+ // TODO(henrika): Investigate if it is possible to get an accurate |
+ // delay estimation. |
callback_->OnData(this, |
- audio_data_[active_queue_], |
+ audio_data_[active_buffer_index_], |
buffer_size_bytes_, |
buffer_size_bytes_, |
0.0); |
// Done with this buffer. Send it to device for recording. |
- SLresult err = (*simple_buffer_queue_)->Enqueue( |
- simple_buffer_queue_, |
- audio_data_[active_queue_], |
- buffer_size_bytes_); |
+ err = (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_, |
+ audio_data_[active_buffer_index_], |
+ buffer_size_bytes_); |
if (SL_RESULT_SUCCESS != err) |
HandleError(err); |
- active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer; |
+ active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue; |
} |
void OpenSLESInputStream::SetupAudioBuffer() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(!audio_data_[0]); |
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { |
audio_data_[i] = new uint8[buffer_size_bytes_]; |
} |
} |
void OpenSLESInputStream::ReleaseAudioBuffer() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
if (audio_data_[0]) { |
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { |
- delete [] audio_data_[i]; |
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) { |
+ delete[] audio_data_[i]; |
audio_data_[i] = NULL; |
} |
} |
} |
void OpenSLESInputStream::HandleError(SLresult error) { |
- DLOG(FATAL) << "OpenSLES Input error " << error; |
+ DLOG(ERROR) << "OpenSLES Input error " << error; |
if (callback_) |
callback_->OnError(this); |
} |