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