Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(217)

Side by Side Diff: media/audio/android/opensles_output.cc

Issue 9655023: Adding input and output audio backend to Android. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased && addressed qinmin's comments Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698