xref: /aosp_15_r20/external/oboe/src/opensles/AudioInputStreamOpenSLES.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu /*
2*05767d91SRobert Wu  * Copyright 2017 The Android Open Source Project
3*05767d91SRobert Wu  *
4*05767d91SRobert Wu  * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu  * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu  * You may obtain a copy of the License at
7*05767d91SRobert Wu  *
8*05767d91SRobert Wu  *      http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu  *
10*05767d91SRobert Wu  * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu  * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu  * See the License for the specific language governing permissions and
14*05767d91SRobert Wu  * limitations under the License.
15*05767d91SRobert Wu  */
16*05767d91SRobert Wu 
17*05767d91SRobert Wu #include <cassert>
18*05767d91SRobert Wu 
19*05767d91SRobert Wu #include <SLES/OpenSLES.h>
20*05767d91SRobert Wu #include <SLES/OpenSLES_Android.h>
21*05767d91SRobert Wu 
22*05767d91SRobert Wu #include "common/OboeDebug.h"
23*05767d91SRobert Wu #include "oboe/AudioStreamBuilder.h"
24*05767d91SRobert Wu #include "AudioInputStreamOpenSLES.h"
25*05767d91SRobert Wu #include "AudioStreamOpenSLES.h"
26*05767d91SRobert Wu #include "OpenSLESUtilities.h"
27*05767d91SRobert Wu 
28*05767d91SRobert Wu using namespace oboe;
29*05767d91SRobert Wu 
OpenSLES_convertInputPreset(InputPreset oboePreset)30*05767d91SRobert Wu static SLuint32 OpenSLES_convertInputPreset(InputPreset oboePreset) {
31*05767d91SRobert Wu     SLuint32 openslPreset = SL_ANDROID_RECORDING_PRESET_NONE;
32*05767d91SRobert Wu     switch(oboePreset) {
33*05767d91SRobert Wu         case InputPreset::Generic:
34*05767d91SRobert Wu             openslPreset =  SL_ANDROID_RECORDING_PRESET_GENERIC;
35*05767d91SRobert Wu             break;
36*05767d91SRobert Wu         case InputPreset::Camcorder:
37*05767d91SRobert Wu             openslPreset =  SL_ANDROID_RECORDING_PRESET_CAMCORDER;
38*05767d91SRobert Wu             break;
39*05767d91SRobert Wu         case InputPreset::VoiceRecognition:
40*05767d91SRobert Wu         case InputPreset::VoicePerformance:
41*05767d91SRobert Wu             openslPreset =  SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
42*05767d91SRobert Wu             break;
43*05767d91SRobert Wu         case InputPreset::VoiceCommunication:
44*05767d91SRobert Wu             openslPreset =  SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
45*05767d91SRobert Wu             break;
46*05767d91SRobert Wu         case InputPreset::Unprocessed:
47*05767d91SRobert Wu             openslPreset =  SL_ANDROID_RECORDING_PRESET_UNPROCESSED;
48*05767d91SRobert Wu             break;
49*05767d91SRobert Wu         default:
50*05767d91SRobert Wu             break;
51*05767d91SRobert Wu     }
52*05767d91SRobert Wu     return openslPreset;
53*05767d91SRobert Wu }
54*05767d91SRobert Wu 
AudioInputStreamOpenSLES(const AudioStreamBuilder & builder)55*05767d91SRobert Wu AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &builder)
56*05767d91SRobert Wu         : AudioStreamOpenSLES(builder) {
57*05767d91SRobert Wu }
58*05767d91SRobert Wu 
~AudioInputStreamOpenSLES()59*05767d91SRobert Wu AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() {
60*05767d91SRobert Wu }
61*05767d91SRobert Wu 
62*05767d91SRobert Wu // Calculate masks specific to INPUT streams.
channelCountToChannelMask(int channelCount) const63*05767d91SRobert Wu SLuint32 AudioInputStreamOpenSLES::channelCountToChannelMask(int channelCount) const {
64*05767d91SRobert Wu     // Derived from internal sles_channel_in_mask_from_count(chanCount);
65*05767d91SRobert Wu     // in "frameworks/wilhelm/src/android/channels.cpp".
66*05767d91SRobert Wu     // Yes, it seems strange to use SPEAKER constants to describe inputs.
67*05767d91SRobert Wu     // But that is how OpenSL ES does it internally.
68*05767d91SRobert Wu     switch (channelCount) {
69*05767d91SRobert Wu         case 1:
70*05767d91SRobert Wu             return SL_SPEAKER_FRONT_LEFT;
71*05767d91SRobert Wu         case 2:
72*05767d91SRobert Wu             return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
73*05767d91SRobert Wu         default:
74*05767d91SRobert Wu             return channelCountToChannelMaskDefault(channelCount);
75*05767d91SRobert Wu     }
76*05767d91SRobert Wu }
77*05767d91SRobert Wu 
open()78*05767d91SRobert Wu Result AudioInputStreamOpenSLES::open() {
79*05767d91SRobert Wu     logUnsupportedAttributes();
80*05767d91SRobert Wu 
81*05767d91SRobert Wu     SLAndroidConfigurationItf configItf = nullptr;
82*05767d91SRobert Wu 
83*05767d91SRobert Wu     if (getSdkVersion() < __ANDROID_API_M__ && mFormat == AudioFormat::Float){
84*05767d91SRobert Wu         // TODO: Allow floating point format on API <23 using float->int16 converter
85*05767d91SRobert Wu         return Result::ErrorInvalidFormat;
86*05767d91SRobert Wu     }
87*05767d91SRobert Wu 
88*05767d91SRobert Wu     // If audio format is unspecified then choose a suitable default.
89*05767d91SRobert Wu     // API 23+: FLOAT
90*05767d91SRobert Wu     // API <23: INT16
91*05767d91SRobert Wu     if (mFormat == AudioFormat::Unspecified){
92*05767d91SRobert Wu         mFormat = (getSdkVersion() < __ANDROID_API_M__) ?
93*05767d91SRobert Wu                   AudioFormat::I16 : AudioFormat::Float;
94*05767d91SRobert Wu     }
95*05767d91SRobert Wu 
96*05767d91SRobert Wu     Result oboeResult = AudioStreamOpenSLES::open();
97*05767d91SRobert Wu     if (Result::OK != oboeResult) return oboeResult;
98*05767d91SRobert Wu 
99*05767d91SRobert Wu     SLuint32 bitsPerSample = static_cast<SLuint32>(getBytesPerSample() * kBitsPerByte);
100*05767d91SRobert Wu 
101*05767d91SRobert Wu     // configure audio sink
102*05767d91SRobert Wu     mBufferQueueLength = calculateOptimalBufferQueueLength();
103*05767d91SRobert Wu     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
104*05767d91SRobert Wu             SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,    // locatorType
105*05767d91SRobert Wu             static_cast<SLuint32>(mBufferQueueLength)};   // numBuffers
106*05767d91SRobert Wu 
107*05767d91SRobert Wu     // Define the audio data format.
108*05767d91SRobert Wu     SLDataFormat_PCM format_pcm = {
109*05767d91SRobert Wu             SL_DATAFORMAT_PCM,       // formatType
110*05767d91SRobert Wu             static_cast<SLuint32>(mChannelCount),           // numChannels
111*05767d91SRobert Wu             static_cast<SLuint32>(mSampleRate * kMillisPerSecond), // milliSamplesPerSec
112*05767d91SRobert Wu             bitsPerSample,                      // bitsPerSample
113*05767d91SRobert Wu             bitsPerSample,                      // containerSize;
114*05767d91SRobert Wu             channelCountToChannelMask(mChannelCount), // channelMask
115*05767d91SRobert Wu             getDefaultByteOrder(),
116*05767d91SRobert Wu     };
117*05767d91SRobert Wu 
118*05767d91SRobert Wu     SLDataSink audioSink = {&loc_bufq, &format_pcm};
119*05767d91SRobert Wu 
120*05767d91SRobert Wu     /**
121*05767d91SRobert Wu      * API 23 (Marshmallow) introduced support for floating-point data representation and an
122*05767d91SRobert Wu      * extended data format type: SLAndroidDataFormat_PCM_EX for recording streams (playback streams
123*05767d91SRobert Wu      * got this in API 21). If running on API 23+ use this newer format type, creating it from our
124*05767d91SRobert Wu      * original format.
125*05767d91SRobert Wu      */
126*05767d91SRobert Wu     SLAndroidDataFormat_PCM_EX format_pcm_ex;
127*05767d91SRobert Wu     if (getSdkVersion() >= __ANDROID_API_M__) {
128*05767d91SRobert Wu         SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat());
129*05767d91SRobert Wu         // Fill in the format structure.
130*05767d91SRobert Wu         format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation);
131*05767d91SRobert Wu         // Use in place of the previous format.
132*05767d91SRobert Wu         audioSink.pFormat = &format_pcm_ex;
133*05767d91SRobert Wu     }
134*05767d91SRobert Wu 
135*05767d91SRobert Wu 
136*05767d91SRobert Wu     // configure audio source
137*05767d91SRobert Wu     SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
138*05767d91SRobert Wu                                       SL_IODEVICE_AUDIOINPUT,
139*05767d91SRobert Wu                                       SL_DEFAULTDEVICEID_AUDIOINPUT,
140*05767d91SRobert Wu                                       NULL};
141*05767d91SRobert Wu     SLDataSource audioSrc = {&loc_dev, NULL};
142*05767d91SRobert Wu 
143*05767d91SRobert Wu     SLresult result = EngineOpenSLES::getInstance().createAudioRecorder(&mObjectInterface,
144*05767d91SRobert Wu                                                                         &audioSrc,
145*05767d91SRobert Wu                                                                         &audioSink);
146*05767d91SRobert Wu 
147*05767d91SRobert Wu     if (SL_RESULT_SUCCESS != result) {
148*05767d91SRobert Wu         LOGE("createAudioRecorder() result:%s", getSLErrStr(result));
149*05767d91SRobert Wu         goto error;
150*05767d91SRobert Wu     }
151*05767d91SRobert Wu 
152*05767d91SRobert Wu     // Configure the stream.
153*05767d91SRobert Wu     result = (*mObjectInterface)->GetInterface(mObjectInterface,
154*05767d91SRobert Wu                                             SL_IID_ANDROIDCONFIGURATION,
155*05767d91SRobert Wu                                             &configItf);
156*05767d91SRobert Wu 
157*05767d91SRobert Wu     if (SL_RESULT_SUCCESS != result) {
158*05767d91SRobert Wu         LOGW("%s() GetInterface(SL_IID_ANDROIDCONFIGURATION) failed with %s",
159*05767d91SRobert Wu              __func__, getSLErrStr(result));
160*05767d91SRobert Wu     } else {
161*05767d91SRobert Wu         if (getInputPreset() == InputPreset::VoicePerformance) {
162*05767d91SRobert Wu             LOGD("OpenSL ES does not support InputPreset::VoicePerformance. Use VoiceRecognition.");
163*05767d91SRobert Wu             mInputPreset = InputPreset::VoiceRecognition;
164*05767d91SRobert Wu         }
165*05767d91SRobert Wu         SLuint32 presetValue = OpenSLES_convertInputPreset(getInputPreset());
166*05767d91SRobert Wu         result = (*configItf)->SetConfiguration(configItf,
167*05767d91SRobert Wu                                          SL_ANDROID_KEY_RECORDING_PRESET,
168*05767d91SRobert Wu                                          &presetValue,
169*05767d91SRobert Wu                                          sizeof(SLuint32));
170*05767d91SRobert Wu         if (SL_RESULT_SUCCESS != result
171*05767d91SRobert Wu                 && presetValue != SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION) {
172*05767d91SRobert Wu             presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
173*05767d91SRobert Wu             LOGD("Setting InputPreset %d failed. Using VoiceRecognition instead.", getInputPreset());
174*05767d91SRobert Wu             mInputPreset = InputPreset::VoiceRecognition;
175*05767d91SRobert Wu             (*configItf)->SetConfiguration(configItf,
176*05767d91SRobert Wu                                              SL_ANDROID_KEY_RECORDING_PRESET,
177*05767d91SRobert Wu                                              &presetValue,
178*05767d91SRobert Wu                                              sizeof(SLuint32));
179*05767d91SRobert Wu         }
180*05767d91SRobert Wu 
181*05767d91SRobert Wu         result = configurePerformanceMode(configItf);
182*05767d91SRobert Wu         if (SL_RESULT_SUCCESS != result) {
183*05767d91SRobert Wu             goto error;
184*05767d91SRobert Wu         }
185*05767d91SRobert Wu     }
186*05767d91SRobert Wu 
187*05767d91SRobert Wu     result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE);
188*05767d91SRobert Wu     if (SL_RESULT_SUCCESS != result) {
189*05767d91SRobert Wu         LOGE("Realize recorder object result:%s", getSLErrStr(result));
190*05767d91SRobert Wu         goto error;
191*05767d91SRobert Wu     }
192*05767d91SRobert Wu 
193*05767d91SRobert Wu     result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_RECORD, &mRecordInterface);
194*05767d91SRobert Wu     if (SL_RESULT_SUCCESS != result) {
195*05767d91SRobert Wu         LOGE("GetInterface RECORD result:%s", getSLErrStr(result));
196*05767d91SRobert Wu         goto error;
197*05767d91SRobert Wu     }
198*05767d91SRobert Wu 
199*05767d91SRobert Wu     result = finishCommonOpen(configItf);
200*05767d91SRobert Wu     if (SL_RESULT_SUCCESS != result) {
201*05767d91SRobert Wu         goto error;
202*05767d91SRobert Wu     }
203*05767d91SRobert Wu 
204*05767d91SRobert Wu     setState(StreamState::Open);
205*05767d91SRobert Wu     return Result::OK;
206*05767d91SRobert Wu 
207*05767d91SRobert Wu error:
208*05767d91SRobert Wu     close(); // Clean up various OpenSL objects and prevent resource leaks.
209*05767d91SRobert Wu     return Result::ErrorInternal; // TODO convert error from SLES to OBOE
210*05767d91SRobert Wu }
211*05767d91SRobert Wu 
close()212*05767d91SRobert Wu Result AudioInputStreamOpenSLES::close() {
213*05767d91SRobert Wu     LOGD("AudioInputStreamOpenSLES::%s()", __func__);
214*05767d91SRobert Wu     std::lock_guard<std::mutex> lock(mLock);
215*05767d91SRobert Wu     Result result = Result::OK;
216*05767d91SRobert Wu     if (getState() == StreamState::Closed){
217*05767d91SRobert Wu         result = Result::ErrorClosed;
218*05767d91SRobert Wu     } else {
219*05767d91SRobert Wu         (void) requestStop_l();
220*05767d91SRobert Wu         if (OboeGlobals::areWorkaroundsEnabled()) {
221*05767d91SRobert Wu             sleepBeforeClose();
222*05767d91SRobert Wu         }
223*05767d91SRobert Wu         // invalidate any interfaces
224*05767d91SRobert Wu         mRecordInterface = nullptr;
225*05767d91SRobert Wu         result = AudioStreamOpenSLES::close_l();
226*05767d91SRobert Wu     }
227*05767d91SRobert Wu     return result;
228*05767d91SRobert Wu }
229*05767d91SRobert Wu 
setRecordState_l(SLuint32 newState)230*05767d91SRobert Wu Result AudioInputStreamOpenSLES::setRecordState_l(SLuint32 newState) {
231*05767d91SRobert Wu     LOGD("AudioInputStreamOpenSLES::%s(%u)", __func__, newState);
232*05767d91SRobert Wu     Result result = Result::OK;
233*05767d91SRobert Wu 
234*05767d91SRobert Wu     if (mRecordInterface == nullptr) {
235*05767d91SRobert Wu         LOGW("AudioInputStreamOpenSLES::%s() mRecordInterface is null", __func__);
236*05767d91SRobert Wu         return Result::ErrorInvalidState;
237*05767d91SRobert Wu     }
238*05767d91SRobert Wu     SLresult slResult = (*mRecordInterface)->SetRecordState(mRecordInterface, newState);
239*05767d91SRobert Wu     //LOGD("AudioInputStreamOpenSLES::%s(%u) returned %u", __func__, newState, slResult);
240*05767d91SRobert Wu     if (SL_RESULT_SUCCESS != slResult) {
241*05767d91SRobert Wu         LOGE("AudioInputStreamOpenSLES::%s(%u) returned error %s",
242*05767d91SRobert Wu                 __func__, newState, getSLErrStr(slResult));
243*05767d91SRobert Wu         result = Result::ErrorInternal; // TODO review
244*05767d91SRobert Wu     }
245*05767d91SRobert Wu     return result;
246*05767d91SRobert Wu }
247*05767d91SRobert Wu 
requestStart()248*05767d91SRobert Wu Result AudioInputStreamOpenSLES::requestStart() {
249*05767d91SRobert Wu     LOGD("AudioInputStreamOpenSLES(): %s() called", __func__);
250*05767d91SRobert Wu     std::lock_guard<std::mutex> lock(mLock);
251*05767d91SRobert Wu     StreamState initialState = getState();
252*05767d91SRobert Wu     switch (initialState) {
253*05767d91SRobert Wu         case StreamState::Starting:
254*05767d91SRobert Wu         case StreamState::Started:
255*05767d91SRobert Wu             return Result::OK;
256*05767d91SRobert Wu         case StreamState::Closed:
257*05767d91SRobert Wu             return Result::ErrorClosed;
258*05767d91SRobert Wu         default:
259*05767d91SRobert Wu             break;
260*05767d91SRobert Wu     }
261*05767d91SRobert Wu 
262*05767d91SRobert Wu     // We use a callback if the user requests one
263*05767d91SRobert Wu     // OR if we have an internal callback to fill the blocking IO buffer.
264*05767d91SRobert Wu     setDataCallbackEnabled(true);
265*05767d91SRobert Wu 
266*05767d91SRobert Wu     setState(StreamState::Starting);
267*05767d91SRobert Wu 
268*05767d91SRobert Wu     closePerformanceHint();
269*05767d91SRobert Wu 
270*05767d91SRobert Wu     if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
271*05767d91SRobert Wu         // Enqueue the first buffer to start the streaming.
272*05767d91SRobert Wu         // This does not call the callback function.
273*05767d91SRobert Wu         enqueueCallbackBuffer(mSimpleBufferQueueInterface);
274*05767d91SRobert Wu     }
275*05767d91SRobert Wu 
276*05767d91SRobert Wu     Result result = setRecordState_l(SL_RECORDSTATE_RECORDING);
277*05767d91SRobert Wu     if (result == Result::OK) {
278*05767d91SRobert Wu         setState(StreamState::Started);
279*05767d91SRobert Wu     } else {
280*05767d91SRobert Wu         setState(initialState);
281*05767d91SRobert Wu     }
282*05767d91SRobert Wu     return result;
283*05767d91SRobert Wu }
284*05767d91SRobert Wu 
285*05767d91SRobert Wu 
requestPause()286*05767d91SRobert Wu Result AudioInputStreamOpenSLES::requestPause() {
287*05767d91SRobert Wu     LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input "
288*05767d91SRobert Wu          "streams", __func__);
289*05767d91SRobert Wu     return Result::ErrorUnimplemented; // Matches AAudio behavior.
290*05767d91SRobert Wu }
291*05767d91SRobert Wu 
requestFlush()292*05767d91SRobert Wu Result AudioInputStreamOpenSLES::requestFlush() {
293*05767d91SRobert Wu     LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input "
294*05767d91SRobert Wu          "streams", __func__);
295*05767d91SRobert Wu     return Result::ErrorUnimplemented; // Matches AAudio behavior.
296*05767d91SRobert Wu }
297*05767d91SRobert Wu 
requestStop()298*05767d91SRobert Wu Result AudioInputStreamOpenSLES::requestStop() {
299*05767d91SRobert Wu     LOGD("AudioInputStreamOpenSLES(): %s() called", __func__);
300*05767d91SRobert Wu     std::lock_guard<std::mutex> lock(mLock);
301*05767d91SRobert Wu     return requestStop_l();
302*05767d91SRobert Wu }
303*05767d91SRobert Wu 
304*05767d91SRobert Wu // Call under mLock
requestStop_l()305*05767d91SRobert Wu Result AudioInputStreamOpenSLES::requestStop_l() {
306*05767d91SRobert Wu     StreamState initialState = getState();
307*05767d91SRobert Wu     switch (initialState) {
308*05767d91SRobert Wu         case StreamState::Stopping:
309*05767d91SRobert Wu         case StreamState::Stopped:
310*05767d91SRobert Wu             return Result::OK;
311*05767d91SRobert Wu         case StreamState::Uninitialized:
312*05767d91SRobert Wu         case StreamState::Closed:
313*05767d91SRobert Wu             return Result::ErrorClosed;
314*05767d91SRobert Wu         default:
315*05767d91SRobert Wu             break;
316*05767d91SRobert Wu     }
317*05767d91SRobert Wu 
318*05767d91SRobert Wu     setState(StreamState::Stopping);
319*05767d91SRobert Wu 
320*05767d91SRobert Wu     Result result = setRecordState_l(SL_RECORDSTATE_STOPPED);
321*05767d91SRobert Wu     if (result == Result::OK) {
322*05767d91SRobert Wu         mPositionMillis.reset32(); // OpenSL ES resets its millisecond position when stopped.
323*05767d91SRobert Wu         setState(StreamState::Stopped);
324*05767d91SRobert Wu     } else {
325*05767d91SRobert Wu         setState(initialState);
326*05767d91SRobert Wu     }
327*05767d91SRobert Wu     return result;
328*05767d91SRobert Wu }
329*05767d91SRobert Wu 
updateFramesWritten()330*05767d91SRobert Wu void AudioInputStreamOpenSLES::updateFramesWritten() {
331*05767d91SRobert Wu     if (usingFIFO()) {
332*05767d91SRobert Wu         AudioStreamBuffered::updateFramesWritten();
333*05767d91SRobert Wu     } else {
334*05767d91SRobert Wu         mFramesWritten = getFramesProcessedByServer();
335*05767d91SRobert Wu     }
336*05767d91SRobert Wu }
337*05767d91SRobert Wu 
updateServiceFrameCounter()338*05767d91SRobert Wu Result AudioInputStreamOpenSLES::updateServiceFrameCounter() {
339*05767d91SRobert Wu     Result result = Result::OK;
340*05767d91SRobert Wu     // Avoid deadlock if another thread is trying to stop or close this stream
341*05767d91SRobert Wu     // and this is being called from a callback.
342*05767d91SRobert Wu     if (mLock.try_lock()) {
343*05767d91SRobert Wu 
344*05767d91SRobert Wu         if (mRecordInterface == nullptr) {
345*05767d91SRobert Wu             mLock.unlock();
346*05767d91SRobert Wu             return Result::ErrorNull;
347*05767d91SRobert Wu         }
348*05767d91SRobert Wu         SLmillisecond msec = 0;
349*05767d91SRobert Wu         SLresult slResult = (*mRecordInterface)->GetPosition(mRecordInterface, &msec);
350*05767d91SRobert Wu         if (SL_RESULT_SUCCESS != slResult) {
351*05767d91SRobert Wu             LOGW("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult));
352*05767d91SRobert Wu             // set result based on SLresult
353*05767d91SRobert Wu             result = Result::ErrorInternal;
354*05767d91SRobert Wu         } else {
355*05767d91SRobert Wu             mPositionMillis.update32(msec);
356*05767d91SRobert Wu         }
357*05767d91SRobert Wu         mLock.unlock();
358*05767d91SRobert Wu     }
359*05767d91SRobert Wu     return result;
360*05767d91SRobert Wu }
361