opensles_output.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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_output.h" 6 7#include "base/logging.h" 8#include "media/audio/audio_util.h" 9#include "media/audio/android/audio_manager_android.h" 10 11namespace media { 12 13OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager, 14 const AudioParameters& params) 15 : audio_manager_(manager), 16 callback_(NULL), 17 player_(NULL), 18 simple_buffer_queue_(NULL), 19 active_queue_(0), 20 buffer_size_bytes_(0), 21 started_(false), 22 volume_(1.0) { 23 format_.formatType = SL_DATAFORMAT_PCM; 24 format_.numChannels = static_cast<SLuint32>(params.channels()); 25 // Provides sampling rate in milliHertz to OpenSLES. 26 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); 27 format_.bitsPerSample = params.bits_per_sample(); 28 format_.containerSize = params.bits_per_sample(); 29 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; 30 if (format_.numChannels == 1) 31 format_.channelMask = SL_SPEAKER_FRONT_CENTER; 32 else if (format_.numChannels == 2) 33 format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; 34 else 35 NOTREACHED() << "Unsupported number of channels: " << format_.numChannels; 36 37 buffer_size_bytes_ = params.GetBytesPerBuffer(); 38 audio_bus_ = AudioBus::Create(params); 39 40 memset(&audio_data_, 0, sizeof(audio_data_)); 41} 42 43OpenSLESOutputStream::~OpenSLESOutputStream() { 44 DCHECK(!engine_object_.Get()); 45 DCHECK(!player_object_.Get()); 46 DCHECK(!output_mixer_.Get()); 47 DCHECK(!player_); 48 DCHECK(!simple_buffer_queue_); 49 DCHECK(!audio_data_[0]); 50} 51 52bool OpenSLESOutputStream::Open() { 53 if (engine_object_.Get()) 54 return false; 55 56 if (!CreatePlayer()) 57 return false; 58 59 SetupAudioBuffer(); 60 61 return true; 62} 63 64void OpenSLESOutputStream::Start(AudioSourceCallback* callback) { 65 DCHECK(callback); 66 DCHECK(player_); 67 DCHECK(simple_buffer_queue_); 68 if (started_) 69 return; 70 71 // Enable the flags before streaming. 72 callback_ = callback; 73 active_queue_ = 0; 74 started_ = true; 75 76 // Avoid start-up glitches by filling up one buffer queue before starting 77 // the stream. 78 FillBufferQueue(); 79 80 // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|. 81 SLresult err = (*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING); 82 DCHECK_EQ(SL_RESULT_SUCCESS, err); 83 if (SL_RESULT_SUCCESS != err) { 84 DLOG(WARNING) << "SetPlayState() failed to start playing"; 85 } 86} 87 88void OpenSLESOutputStream::Stop() { 89 if (!started_) 90 return; 91 92 started_ = false; 93 // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|. 94 SLresult err = (*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED); 95 if (SL_RESULT_SUCCESS != err) { 96 DLOG(WARNING) << "SetPlayState() failed to set the state to stop"; 97 } 98 99 // Clear the buffer queue so that the old data won't be played when 100 // resuming playing. 101 err = (*simple_buffer_queue_)->Clear(simple_buffer_queue_); 102 if (SL_RESULT_SUCCESS != err) { 103 DLOG(WARNING) << "Clear() failed to clear the buffer queue"; 104 } 105} 106 107void OpenSLESOutputStream::Close() { 108 // Stop the stream if it is still playing. 109 Stop(); 110 111 // Explicitly free the player objects and invalidate their associated 112 // interfaces. They have to be done in the correct order. 113 output_mixer_.Reset(); 114 player_object_.Reset(); 115 engine_object_.Reset(); 116 simple_buffer_queue_ = NULL; 117 player_ = NULL; 118 119 ReleaseAudioBuffer(); 120 121 audio_manager_->ReleaseOutputStream(this); 122} 123 124void OpenSLESOutputStream::SetVolume(double volume) { 125 float volume_float = static_cast<float>(volume); 126 if (volume_float < 0.0f || volume_float > 1.0f) { 127 return; 128 } 129 volume_ = volume_float; 130} 131 132void OpenSLESOutputStream::GetVolume(double* volume) { 133 *volume = static_cast<double>(volume_); 134} 135 136bool OpenSLESOutputStream::CreatePlayer() { 137 // Initializes the engine object with specific option. After working with the 138 // object, we need to free the object and its resources. 139 SLEngineOption option[] = { 140 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } 141 }; 142 SLresult err = slCreateEngine(engine_object_.Receive(), 1, option, 0, 143 NULL, NULL); 144 DCHECK_EQ(SL_RESULT_SUCCESS, err); 145 if (SL_RESULT_SUCCESS != err) 146 return false; 147 148 // Realize the SL engine object in synchronous mode. 149 err = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE); 150 DCHECK_EQ(SL_RESULT_SUCCESS, err); 151 if (SL_RESULT_SUCCESS != err) 152 return false; 153 154 // Get the SL engine interface which is implicit. 155 SLEngineItf engine; 156 err = engine_object_->GetInterface(engine_object_.Get(), 157 SL_IID_ENGINE, 158 &engine); 159 DCHECK_EQ(SL_RESULT_SUCCESS, err); 160 if (SL_RESULT_SUCCESS != err) 161 return false; 162 163 // Create ouput mixer object to be used by the player. 164 // TODO(xians): Do we need the environmental reverb auxiliary effect? 165 err = (*engine)->CreateOutputMix(engine, 166 output_mixer_.Receive(), 167 0, 168 NULL, 169 NULL); 170 DCHECK_EQ(SL_RESULT_SUCCESS, err); 171 if (SL_RESULT_SUCCESS != err) 172 return false; 173 174 // Realizing the output mix object in synchronous mode. 175 err = output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE); 176 DCHECK_EQ(SL_RESULT_SUCCESS, err); 177 if (SL_RESULT_SUCCESS != err) 178 return false; 179 180 // Audio source configuration. 181 SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = { 182 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 183 static_cast<SLuint32>(kNumOfQueuesInBuffer) 184 }; 185 SLDataSource audio_source = { &simple_buffer_queue, &format_ }; 186 187 // Audio sink configuration. 188 SLDataLocator_OutputMix locator_output_mix = { 189 SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get() 190 }; 191 SLDataSink audio_sink = { &locator_output_mix, NULL }; 192 193 // Create an audio player. 194 const SLuint32 number_of_interfaces = 1; 195 const SLInterfaceID interface_id[number_of_interfaces] = { 196 SL_IID_BUFFERQUEUE 197 }; 198 const SLboolean interface_required[number_of_interfaces] = { 199 SL_BOOLEAN_TRUE 200 }; 201 err = (*engine)->CreateAudioPlayer(engine, 202 player_object_.Receive(), 203 &audio_source, 204 &audio_sink, 205 number_of_interfaces, 206 interface_id, 207 interface_required); 208 DCHECK_EQ(SL_RESULT_SUCCESS, err); 209 if (SL_RESULT_SUCCESS != err) { 210 DLOG(ERROR) << "CreateAudioPlayer() failed with error code " << err; 211 return false; 212 } 213 214 // Realize the player object in synchronous mode. 215 err = player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE); 216 DCHECK_EQ(SL_RESULT_SUCCESS, err); 217 if (SL_RESULT_SUCCESS != err) { 218 DLOG(ERROR) << "Player Realize() failed with error code " << err; 219 return false; 220 } 221 222 // Get an implicit player interface. 223 err = player_object_->GetInterface( 224 player_object_.Get(), SL_IID_PLAY, &player_); 225 DCHECK_EQ(SL_RESULT_SUCCESS, err); 226 if (SL_RESULT_SUCCESS != err) 227 return false; 228 229 // Get the simple buffer queue interface. 230 err = player_object_->GetInterface(player_object_.Get(), 231 SL_IID_BUFFERQUEUE, 232 &simple_buffer_queue_); 233 DCHECK_EQ(SL_RESULT_SUCCESS, err); 234 if (SL_RESULT_SUCCESS != err) 235 return false; 236 237 // Register the input callback for the simple buffer queue. 238 // This callback will be called when the soundcard needs data. 239 err = (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_, 240 SimpleBufferQueueCallback, 241 this); 242 DCHECK_EQ(SL_RESULT_SUCCESS, err); 243 244 return (SL_RESULT_SUCCESS == err); 245} 246 247void OpenSLESOutputStream::SimpleBufferQueueCallback( 248 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { 249 OpenSLESOutputStream* stream = 250 reinterpret_cast<OpenSLESOutputStream*>(instance); 251 stream->FillBufferQueue(); 252} 253 254void OpenSLESOutputStream::FillBufferQueue() { 255 if (!started_) 256 return; 257 258 // Read data from the registered client source. 259 // TODO(xians): Get an accurate delay estimation. 260 uint32 hardware_delay = buffer_size_bytes_; 261 int frames_filled = callback_->OnMoreData( 262 audio_bus_.get(), AudioBuffersState(0, hardware_delay)); 263 int num_filled_bytes = 264 frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8; 265 DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_); 266 // Note: If this ever changes to output raw float the data must be clipped and 267 // sanitized since it may come from an untrusted source such as NaCl. 268 audio_bus_->ToInterleaved( 269 frames_filled, format_.bitsPerSample / 8, audio_data_[active_queue_]); 270 271 // Perform in-place, software-volume adjustments. 272 media::AdjustVolume(audio_data_[active_queue_], 273 num_filled_bytes, 274 format_.numChannels, 275 format_.bitsPerSample / 8, 276 volume_); 277 278 // Enqueue the buffer for playback. 279 SLresult err = (*simple_buffer_queue_)->Enqueue( 280 simple_buffer_queue_, 281 audio_data_[active_queue_], 282 num_filled_bytes); 283 if (SL_RESULT_SUCCESS != err) 284 HandleError(err); 285 286 active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer; 287} 288 289void OpenSLESOutputStream::SetupAudioBuffer() { 290 DCHECK(!audio_data_[0]); 291 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { 292 audio_data_[i] = new uint8[buffer_size_bytes_]; 293 } 294} 295 296void OpenSLESOutputStream::ReleaseAudioBuffer() { 297 if (audio_data_[0]) { 298 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { 299 delete [] audio_data_[i]; 300 audio_data_[i] = NULL; 301 } 302 } 303} 304 305void OpenSLESOutputStream::HandleError(SLresult error) { 306 DLOG(FATAL) << "OpenSLES error " << error; 307 if (callback_) 308 callback_->OnError(this, error); 309} 310 311} // namespace media 312