This source file includes following definitions.
- volume_
- Start
- Stop
- Close
- SetVolume
- GetVolume
- SetMute
- CreatePlayer
- SimpleBufferQueueCallback
- FillBufferQueue
- FillBufferQueueNoLock
- SetupAudioBuffer
- ReleaseAudioBuffer
- HandleError
#include "media/audio/android/opensles_output.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) { \
DLOG(ERROR) << #op << " failed: " << err; \
return __VA_ARGS__; \
} \
} while (0)
namespace media {
OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
const AudioParameters& params,
SLint32 stream_type)
: audio_manager_(manager),
stream_type_(stream_type),
callback_(NULL),
player_(NULL),
simple_buffer_queue_(NULL),
active_buffer_index_(0),
buffer_size_bytes_(0),
started_(false),
muted_(false),
volume_(1.0) {
DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream("
<< "stream_type=" << stream_type << ")";
format_.formatType = SL_DATAFORMAT_PCM;
format_.numChannels = static_cast<SLuint32>(params.channels());
format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000);
format_.bitsPerSample = params.bits_per_sample();
format_.containerSize = params.bits_per_sample();
format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
if (format_.numChannels == 1)
format_.channelMask = SL_SPEAKER_FRONT_CENTER;
else if (format_.numChannels == 2)
format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
else
NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
buffer_size_bytes_ = params.GetBytesPerBuffer();
audio_bus_ = AudioBus::Create(params);
memset(&audio_data_, 0, sizeof(audio_data_));
}
OpenSLESOutputStream::~OpenSLESOutputStream() {
DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()";
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!engine_object_.Get());
DCHECK(!player_object_.Get());
DCHECK(!output_mixer_.Get());
DCHECK(!player_);
DCHECK(!simple_buffer_queue_);
DCHECK(!audio_data_[0]);
}
bool OpenSLESOutputStream::Open() {
DVLOG(2) << "OpenSLESOutputStream::Open()";
DCHECK(thread_checker_.CalledOnValidThread());
if (engine_object_.Get())
return false;
if (!CreatePlayer())
return false;
SetupAudioBuffer();
active_buffer_index_ = 0;
return true;
}
void OpenSLESOutputStream::Start(AudioSourceCallback* callback) {
DVLOG(2) << "OpenSLESOutputStream::Start()";
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(callback);
DCHECK(player_);
DCHECK(simple_buffer_queue_);
if (started_)
return;
base::AutoLock lock(lock_);
DCHECK(callback_ == NULL || callback_ == callback);
callback_ = callback;
FillBufferQueueNoLock();
LOG_ON_FAILURE_AND_RETURN(
(*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING));
started_ = true;
}
void OpenSLESOutputStream::Stop() {
DVLOG(2) << "OpenSLESOutputStream::Stop()";
DCHECK(thread_checker_.CalledOnValidThread());
if (!started_)
return;
base::AutoLock lock(lock_);
LOG_ON_FAILURE_AND_RETURN(
(*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED));
LOG_ON_FAILURE_AND_RETURN(
(*simple_buffer_queue_)->Clear(simple_buffer_queue_));
#ifndef NDEBUG
SLAndroidSimpleBufferQueueState buffer_queue_state;
LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState(
simple_buffer_queue_, &buffer_queue_state));
DCHECK_EQ(0u, buffer_queue_state.count);
DCHECK_EQ(0u, buffer_queue_state.index);
#endif
callback_ = NULL;
started_ = false;
}
void OpenSLESOutputStream::Close() {
DVLOG(2) << "OpenSLESOutputStream::Close()";
DCHECK(thread_checker_.CalledOnValidThread());
Stop();
{
player_object_.Reset();
simple_buffer_queue_ = NULL;
player_ = NULL;
output_mixer_.Reset();
engine_object_.Reset();
ReleaseAudioBuffer();
}
audio_manager_->ReleaseOutputStream(this);
}
void OpenSLESOutputStream::SetVolume(double volume) {
DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")";
DCHECK(thread_checker_.CalledOnValidThread());
float volume_float = static_cast<float>(volume);
if (volume_float < 0.0f || volume_float > 1.0f) {
return;
}
volume_ = volume_float;
}
void OpenSLESOutputStream::GetVolume(double* volume) {
DCHECK(thread_checker_.CalledOnValidThread());
*volume = static_cast<double>(volume_);
}
void OpenSLESOutputStream::SetMute(bool muted) {
DVLOG(2) << "OpenSLESOutputStream::SetMute(" << muted << ")";
DCHECK(thread_checker_.CalledOnValidThread());
muted_ = muted;
}
bool OpenSLESOutputStream::CreatePlayer() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!engine_object_.Get());
DCHECK(!player_object_.Get());
DCHECK(!output_mixer_.Get());
DCHECK(!player_);
DCHECK(!simple_buffer_queue_);
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);
LOG_ON_FAILURE_AND_RETURN(
engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
SLEngineItf engine;
LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
engine_object_.Get(), SL_IID_ENGINE, &engine),
false);
LOG_ON_FAILURE_AND_RETURN((*engine)->CreateOutputMix(
engine, output_mixer_.Receive(), 0, NULL, NULL),
false);
LOG_ON_FAILURE_AND_RETURN(
output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), false);
SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
SLDataSource audio_source = {&simple_buffer_queue, &format_};
SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX,
output_mixer_.Get()};
SLDataSink audio_sink = {&locator_output_mix, NULL};
const SLInterfaceID interface_id[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME,
SL_IID_ANDROIDCONFIGURATION};
const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
SL_BOOLEAN_TRUE};
LOG_ON_FAILURE_AND_RETURN(
(*engine)->CreateAudioPlayer(engine,
player_object_.Receive(),
&audio_source,
&audio_sink,
arraysize(interface_id),
interface_id,
interface_required),
false);
SLAndroidConfigurationItf player_config;
LOG_ON_FAILURE_AND_RETURN(
player_object_->GetInterface(
player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config),
false);
LOG_ON_FAILURE_AND_RETURN(
(*player_config)->SetConfiguration(player_config,
SL_ANDROID_KEY_STREAM_TYPE,
&stream_type_,
sizeof(SLint32)),
false);
LOG_ON_FAILURE_AND_RETURN(
player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false);
LOG_ON_FAILURE_AND_RETURN(
player_object_->GetInterface(player_object_.Get(), SL_IID_PLAY, &player_),
false);
LOG_ON_FAILURE_AND_RETURN(
player_object_->GetInterface(
player_object_.Get(), SL_IID_BUFFERQUEUE, &simple_buffer_queue_),
false);
LOG_ON_FAILURE_AND_RETURN(
(*simple_buffer_queue_)->RegisterCallback(
simple_buffer_queue_, SimpleBufferQueueCallback, this),
false);
return true;
}
void OpenSLESOutputStream::SimpleBufferQueueCallback(
SLAndroidSimpleBufferQueueItf buffer_queue,
void* instance) {
OpenSLESOutputStream* stream =
reinterpret_cast<OpenSLESOutputStream*>(instance);
stream->FillBufferQueue();
}
void OpenSLESOutputStream::FillBufferQueue() {
base::AutoLock lock(lock_);
if (!started_)
return;
TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue");
SLuint32 state;
SLresult err = (*player_)->GetPlayState(player_, &state);
if (SL_RESULT_SUCCESS != err) {
HandleError(err);
return;
}
if (state != SL_PLAYSTATE_PLAYING) {
DLOG(WARNING) << "Received callback in non-playing state";
return;
}
FillBufferQueueNoLock();
}
void OpenSLESOutputStream::FillBufferQueueNoLock() {
lock_.AssertAcquired();
const uint32 hardware_delay = buffer_size_bytes_;
int frames_filled = callback_->OnMoreData(
audio_bus_.get(), AudioBuffersState(0, hardware_delay));
if (frames_filled <= 0) {
return;
}
audio_bus_->Scale(muted_ ? 0.0f : volume_);
audio_bus_->ToInterleaved(frames_filled,
format_.bitsPerSample / 8,
audio_data_[active_buffer_index_]);
const int num_filled_bytes =
frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
SLresult err =
(*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
audio_data_[active_buffer_index_],
num_filled_bytes);
if (SL_RESULT_SUCCESS != err)
HandleError(err);
active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
}
void OpenSLESOutputStream::SetupAudioBuffer() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!audio_data_[0]);
for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
audio_data_[i] = new uint8[buffer_size_bytes_];
}
}
void OpenSLESOutputStream::ReleaseAudioBuffer() {
DCHECK(thread_checker_.CalledOnValidThread());
if (audio_data_[0]) {
for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
delete[] audio_data_[i];
audio_data_[i] = NULL;
}
}
}
void OpenSLESOutputStream::HandleError(SLresult error) {
DLOG(ERROR) << "OpenSLES Output error " << error;
if (callback_)
callback_->OnError(this);
}
}