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