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_input.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "media/audio/android/audio_manager_android.h" | |
9 | |
10 OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager, | |
11 const AudioParameters& params) | |
12 : audio_manager_(audio_manager), | |
13 callback_(NULL), | |
14 recorder_(NULL), | |
15 simple_buffer_queue_(NULL), | |
16 active_queue_(0), | |
17 buffer_size_bytes_(0), | |
18 started_(false) { | |
19 format_.formatType = SL_DATAFORMAT_PCM; | |
20 format_.numChannels = static_cast<SLuint32>(params.channels()); | |
21 // Provides sampling rate in milliHertz to OpenSLES. | |
22 format_.samplesPerSec = static_cast<SLuint32>(params.sample_rate() * 1000); | |
23 format_.bitsPerSample = params.bits_per_sample(); | |
24 format_.containerSize = params.bits_per_sample(); | |
25 format_.channelMask = SL_SPEAKER_FRONT_CENTER; | |
26 format_.endianness = SL_BYTEORDER_LITTLEENDIAN; | |
27 | |
28 buffer_size_bytes_ = params.GetBytesPerBuffer(); | |
29 | |
30 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) { | |
qinmin
2012/04/02 13:28:54
I still prefer you put this into the Open() functi
no longer working on chromium
2012/04/02 15:17:38
Done.
| |
31 audio_data_[i] = new uint8[buffer_size_bytes_]; | |
32 } | |
33 } | |
34 | |
35 OpenSLESInputStream::~OpenSLESInputStream() { | |
36 DCHECK(!recorder_object_.Get()); | |
37 DCHECK(!engine_object_.Get()); | |
38 DCHECK(!recorder_); | |
39 DCHECK(!simple_buffer_queue_); | |
40 for (int i = 0; i < kNumOfQueuesInBuffer; ++i) | |
41 delete [] audio_data_[i]; | |
42 } | |
43 | |
44 bool OpenSLESInputStream::Open() { | |
45 if (engine_object_.Get()) | |
46 return false; | |
47 | |
48 return CreateRecorder(); | |
49 } | |
50 | |
51 void OpenSLESInputStream::Start(AudioInputCallback* callback) { | |
52 DCHECK(callback); | |
53 DCHECK(recorder_); | |
54 DCHECK(simple_buffer_queue_); | |
55 if (started_) | |
56 return; | |
57 | |
58 // Enable the flags before streaming. | |
59 callback_ = callback; | |
60 active_queue_ = 0; | |
61 started_ = true; | |
62 | |
63 SLresult err = SL_RESULT_UNKNOWN_ERROR; | |
64 // Enqueues |kNumOfQueuesInBuffer| zero buffers to get the ball rolling. | |
65 for (int i = 0; i < kNumOfQueuesInBuffer - 1; ++i) { | |
66 err = (*simple_buffer_queue_)->Enqueue( | |
67 simple_buffer_queue_, | |
68 audio_data_[i], | |
69 buffer_size_bytes_); | |
70 if (SL_RESULT_SUCCESS != err) { | |
71 HandleError(err); | |
72 return; | |
73 } | |
74 } | |
75 | |
76 // Start the recording by setting the state to |SL_RECORDSTATE_RECORDING|. | |
77 err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING); | |
78 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
79 if (SL_RESULT_SUCCESS != err) | |
80 HandleError(err); | |
81 } | |
82 | |
83 void OpenSLESInputStream::Stop() { | |
84 if (!started_) | |
85 return; | |
86 | |
87 // Stop recording by setting the record state to |SL_RECORDSTATE_STOPPED|. | |
88 SLresult err = (*recorder_)->SetRecordState(recorder_, | |
89 SL_RECORDSTATE_STOPPED); | |
90 DLOG_IF(WARNING, SL_RESULT_SUCCESS != err) << "SetRecordState() failed to " | |
91 << "set the state to stop"; | |
92 | |
93 // Clear the buffer queue to get rid of old data when resuming recording. | |
94 err = (*simple_buffer_queue_)->Clear(simple_buffer_queue_); | |
95 DLOG_IF(WARNING, SL_RESULT_SUCCESS != err) << "Clear() failed to clear " | |
96 << "the buffer queue"; | |
97 | |
98 started_ = false; | |
99 } | |
100 | |
101 void OpenSLESInputStream::Close() { | |
102 // Stop the stream if it is still recording. | |
103 Stop(); | |
104 | |
105 // Explicitly free the player objects and invalidate their associated | |
106 // interfaces. They have to be done in the correct order. | |
107 recorder_object_.Reset(); | |
108 engine_object_.Reset(); | |
109 simple_buffer_queue_ = NULL; | |
110 recorder_ = NULL; | |
111 | |
112 audio_manager_->ReleaseInputStream(this); | |
113 } | |
114 | |
115 double OpenSLESInputStream::GetMaxVolume() { | |
116 NOTIMPLEMENTED(); | |
117 return 0.0; | |
118 } | |
119 | |
120 void OpenSLESInputStream::SetVolume(double volume) { | |
121 NOTIMPLEMENTED(); | |
122 } | |
123 | |
124 double OpenSLESInputStream::GetVolume() { | |
125 NOTIMPLEMENTED(); | |
126 return 0.0; | |
127 } | |
128 | |
129 void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { | |
130 NOTIMPLEMENTED(); | |
131 } | |
132 | |
133 bool OpenSLESInputStream::GetAutomaticGainControl() { | |
134 NOTIMPLEMENTED(); | |
135 return false; | |
136 } | |
137 | |
138 bool OpenSLESInputStream::CreateRecorder() { | |
139 // Initializes the engine object with specific option. After working with the | |
140 // object, we need to free the object and its resources. | |
141 SLEngineOption option[] = { | |
142 { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) } | |
143 }; | |
144 SLresult err = slCreateEngine(engine_object_.Receive(), | |
145 1, | |
146 option, | |
147 0, | |
148 NULL, | |
149 NULL); | |
150 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
151 if (SL_RESULT_SUCCESS != err) | |
152 return false; | |
153 | |
154 // Realize the SL engine object in synchronous mode. | |
155 err = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE); | |
156 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
157 if (SL_RESULT_SUCCESS != err) | |
158 return false; | |
159 | |
160 // Get the SL engine interface which is implicit. | |
161 SLEngineItf engine; | |
162 err = engine_object_->GetInterface( | |
163 engine_object_.Get(), SL_IID_ENGINE, &engine); | |
164 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
165 if (SL_RESULT_SUCCESS != err) | |
166 return false; | |
167 | |
168 // Audio source configuration. | |
169 SLDataLocator_IODevice mic_locator = { | |
170 SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, | |
171 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL | |
172 }; | |
173 SLDataSource audio_source = { &mic_locator, NULL }; | |
174 | |
175 // Audio sink configuration. | |
176 SLDataLocator_AndroidSimpleBufferQueue buffer_queue = { | |
177 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // Locator type. | |
178 static_cast<SLuint32>(kNumOfQueuesInBuffer) // Number of buffers. | |
179 }; | |
180 SLDataSink audio_sink = { &buffer_queue, &format_ }; | |
181 | |
182 // Create an audio recorder. | |
183 const SLuint32 number_of_interfaces = 1; | |
184 const SLInterfaceID interface_id[number_of_interfaces] = { | |
185 SL_IID_ANDROIDSIMPLEBUFFERQUEUE | |
186 }; | |
187 const SLboolean interface_required[number_of_interfaces] = { | |
188 SL_BOOLEAN_TRUE | |
189 }; | |
190 err = (*engine)->CreateAudioRecorder(engine, | |
191 recorder_object_.Receive(), | |
192 &audio_source, | |
193 &audio_sink, | |
194 number_of_interfaces, | |
195 interface_id, | |
196 interface_required); | |
197 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
198 if (SL_RESULT_SUCCESS != err) { | |
199 DLOG(ERROR) << "CreateAudioRecorder failed with error code " << err; | |
200 return false; | |
201 } | |
202 | |
203 // Realize the recorder object in synchronous mode. | |
204 err = recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE); | |
205 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
206 if (SL_RESULT_SUCCESS != err) { | |
207 DLOG(ERROR) << "Recprder Realize() failed with error code " << err; | |
208 return false; | |
209 } | |
210 | |
211 // Get an implicit recorder interface. | |
212 err = recorder_object_->GetInterface(recorder_object_.Get(), | |
213 SL_IID_RECORD, | |
214 &recorder_); | |
215 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
216 if (SL_RESULT_SUCCESS != err) | |
217 return false; | |
218 | |
219 // Get the simple buffer queue interface. | |
220 err = recorder_object_->GetInterface(recorder_object_.Get(), | |
221 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, | |
222 &simple_buffer_queue_); | |
223 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
224 if (SL_RESULT_SUCCESS != err) | |
225 return false; | |
226 | |
227 // Register the input callback for the simple buffer queue. | |
228 // This callback will be called when receiving new data from the device. | |
229 err = (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_, | |
230 SimpleBufferQueueCallback, | |
231 this); | |
232 DCHECK_EQ(SL_RESULT_SUCCESS, err); | |
233 | |
234 return (SL_RESULT_SUCCESS == err); | |
235 } | |
236 | |
237 void OpenSLESInputStream::SimpleBufferQueueCallback( | |
238 SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) { | |
239 OpenSLESInputStream* stream = | |
240 reinterpret_cast<OpenSLESInputStream*>(instance); | |
241 stream->ReadBufferQueue(); | |
242 } | |
243 | |
244 void OpenSLESInputStream::ReadBufferQueue() { | |
245 if (!started_) | |
246 return; | |
247 | |
248 // Get the enqueued buffer from the soundcard. | |
249 SLresult err = (*simple_buffer_queue_)->Enqueue( | |
250 simple_buffer_queue_, | |
251 audio_data_[active_queue_], | |
252 buffer_size_bytes_); | |
253 if (SL_RESULT_SUCCESS != err) | |
254 HandleError(err); | |
255 | |
256 // TODO(xians): Get an accurate delay estimation. | |
257 callback_->OnData(this, | |
258 audio_data_[active_queue_], | |
259 buffer_size_bytes_, | |
260 buffer_size_bytes_, | |
261 0.0); | |
262 | |
263 active_queue_ = ++active_queue_ % kNumOfQueuesInBuffer; | |
264 } | |
265 | |
266 void OpenSLESInputStream::HandleError(SLresult error) { | |
267 DLOG(FATAL) << "OpenSLES error " << error; | |
268 if (callback_) | |
269 callback_->OnError(this, error); | |
270 } | |
OLD | NEW |