• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 The Android Open Source Project
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <sys/types.h>
16 #include <cassert>
17 #include <android/log.h>
18 
19 
20 #include <SLES/OpenSLES.h>
21 #include <SLES/OpenSLES_Android.h>
22 #include <oboe/AudioStream.h>
23 #include <common/AudioClock.h>
24 
25 #include "common/OboeDebug.h"
26 #include "oboe/AudioStreamBuilder.h"
27 #include "AudioStreamOpenSLES.h"
28 #include "OpenSLESUtilities.h"
29 
30 using namespace oboe;
31 
AudioStreamOpenSLES(const AudioStreamBuilder & builder)32 AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder)
33     : AudioStreamBuffered(builder) {
34     // OpenSL ES does not support device IDs. So overwrite value from builder.
35     mDeviceId = kUnspecified;
36     // OpenSL ES does not support session IDs. So overwrite value from builder.
37     mSessionId = SessionId::None;
38 }
39 
40 static constexpr int32_t   kHighLatencyBufferSizeMillis = 20; // typical Android period
41 static constexpr SLuint32  kAudioChannelCountMax = 30; // TODO Why 30?
42 static constexpr SLuint32  SL_ANDROID_UNKNOWN_CHANNELMASK  = 0; // Matches name used internally.
43 
channelCountToChannelMaskDefault(int channelCount) const44 SLuint32 AudioStreamOpenSLES::channelCountToChannelMaskDefault(int channelCount) const {
45     if (channelCount > kAudioChannelCountMax) {
46         return SL_ANDROID_UNKNOWN_CHANNELMASK;
47     }
48 
49     SLuint32 bitfield = (1 << channelCount) - 1;
50 
51     // Check for OS at run-time.
52     if(getSdkVersion() >= __ANDROID_API_N__) {
53         return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield);
54     }
55 
56     // Indexed channels masks were added in N.
57     // For before N, the best we can do is use a positional channel mask.
58     return bitfield;
59 }
60 
s_isLittleEndian()61 static bool s_isLittleEndian() {
62     static uint32_t value = 1;
63     return (*reinterpret_cast<uint8_t *>(&value) == 1);  // Does address point to LSB?
64 }
65 
getDefaultByteOrder()66 SLuint32 AudioStreamOpenSLES::getDefaultByteOrder() {
67     return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
68 }
69 
open()70 Result AudioStreamOpenSLES::open() {
71 
72     LOGI("AudioStreamOpenSLES::open() chans=%d, rate=%d", mChannelCount, mSampleRate);
73 
74     SLresult result = EngineOpenSLES::getInstance().open();
75     if (SL_RESULT_SUCCESS != result) {
76         return Result::ErrorInternal;
77     }
78 
79     Result oboeResult = AudioStreamBuffered::open();
80     if (oboeResult != Result::OK) {
81         return oboeResult;
82     }
83     // Convert to defaults if UNSPECIFIED
84     if (mSampleRate == kUnspecified) {
85         mSampleRate = DefaultStreamValues::SampleRate;
86     }
87     if (mChannelCount == kUnspecified) {
88         mChannelCount = DefaultStreamValues::ChannelCount;
89     }
90 
91     mSharingMode = SharingMode::Shared;
92 
93     return Result::OK;
94 }
95 
configureBufferSizes(int32_t sampleRate)96 Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) {
97     LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d",
98             __func__, sampleRate, mFramesPerBurst, mFramesPerCallback);
99     // Decide frames per burst based on hints from caller.
100     if (mFramesPerCallback != kUnspecified) {
101         // Requested framesPerCallback must be honored.
102         mFramesPerBurst = mFramesPerCallback;
103     } else {
104         mFramesPerBurst = DefaultStreamValues::FramesPerBurst;
105 
106         // Calculate the size of a fixed duration high latency buffer based on sample rate.
107         int32_t framesPerHighLatencyBuffer =
108                 (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
109 
110         // For high latency streams, use a larger buffer size.
111         // Performance Mode support was added in N_MR1 (7.1)
112         if (getSdkVersion() >= __ANDROID_API_N_MR1__
113             && mPerformanceMode != PerformanceMode::LowLatency
114             && mFramesPerBurst < framesPerHighLatencyBuffer) {
115             // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
116             int32_t numBursts = (framesPerHighLatencyBuffer + mFramesPerBurst - 1) / mFramesPerBurst;
117             mFramesPerBurst *= numBursts;
118             LOGD("AudioStreamOpenSLES:%s() NOT low latency, set mFramesPerBurst = %d",
119                  __func__, mFramesPerBurst);
120         }
121         mFramesPerCallback = mFramesPerBurst;
122     }
123     LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d",
124          __func__, sampleRate, mFramesPerBurst, mFramesPerCallback);
125 
126     mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
127     if (mBytesPerCallback <= 0) {
128         LOGE("AudioStreamOpenSLES::open() bytesPerCallback < 0 = %d, bad format?",
129              mBytesPerCallback);
130         return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0
131     }
132 
133     mCallbackBuffer = std::make_unique<uint8_t[]>(mBytesPerCallback);
134 
135     if (!usingFIFO()) {
136         mBufferCapacityInFrames = mFramesPerBurst * kBufferQueueLength;
137         mBufferSizeInFrames = mBufferCapacityInFrames;
138     }
139 
140     return Result::OK;
141 }
142 
convertPerformanceMode(PerformanceMode oboeMode) const143 SLuint32 AudioStreamOpenSLES::convertPerformanceMode(PerformanceMode oboeMode) const {
144     SLuint32 openslMode = SL_ANDROID_PERFORMANCE_NONE;
145     switch(oboeMode) {
146         case PerformanceMode::None:
147             openslMode =  SL_ANDROID_PERFORMANCE_NONE;
148             break;
149         case PerformanceMode::LowLatency:
150             openslMode =  (getSessionId() == SessionId::None) ?  SL_ANDROID_PERFORMANCE_LATENCY : SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
151             break;
152         case PerformanceMode::PowerSaving:
153             openslMode =  SL_ANDROID_PERFORMANCE_POWER_SAVING;
154             break;
155         default:
156             break;
157     }
158     return openslMode;
159 }
160 
convertPerformanceMode(SLuint32 openslMode) const161 PerformanceMode AudioStreamOpenSLES::convertPerformanceMode(SLuint32 openslMode) const {
162     PerformanceMode oboeMode = PerformanceMode::None;
163     switch(openslMode) {
164         case SL_ANDROID_PERFORMANCE_NONE:
165             oboeMode =  PerformanceMode::None;
166             break;
167         case SL_ANDROID_PERFORMANCE_LATENCY:
168         case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
169             oboeMode =  PerformanceMode::LowLatency;
170             break;
171         case SL_ANDROID_PERFORMANCE_POWER_SAVING:
172             oboeMode =  PerformanceMode::PowerSaving;
173             break;
174         default:
175             break;
176     }
177     return oboeMode;
178 }
179 
logUnsupportedAttributes()180 void AudioStreamOpenSLES::logUnsupportedAttributes() {
181     // Log unsupported attributes
182     // only report if changed from the default
183 
184     // Device ID
185     if (mDeviceId != kUnspecified) {
186         LOGW("Device ID [AudioStreamBuilder::setDeviceId()] "
187              "is not supported on OpenSLES streams.");
188     }
189     // Sharing Mode
190     if (mSharingMode != SharingMode::Shared) {
191         LOGW("SharingMode [AudioStreamBuilder::setSharingMode()] "
192              "is not supported on OpenSLES streams.");
193     }
194     // Performance Mode
195     int sdkVersion = getSdkVersion();
196     if (mPerformanceMode != PerformanceMode::None && sdkVersion < __ANDROID_API_N_MR1__) {
197         LOGW("PerformanceMode [AudioStreamBuilder::setPerformanceMode()] "
198              "is not supported on OpenSLES streams running on pre-Android N-MR1 versions.");
199     }
200     // Content Type
201     if (mContentType != ContentType::Music) {
202         LOGW("ContentType [AudioStreamBuilder::setContentType()] "
203              "is not supported on OpenSLES streams.");
204     }
205 
206     // Session Id
207     if (mSessionId != SessionId::None) {
208         LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
209              "is not supported on OpenSLES streams.");
210     }
211 
212     // Input Preset
213     if (mInputPreset != InputPreset::VoiceRecognition) {
214         LOGW("InputPreset [AudioStreamBuilder::setInputPreset()] "
215              "is not supported on OpenSLES streams.");
216     }
217 }
218 
configurePerformanceMode(SLAndroidConfigurationItf configItf)219 SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) {
220 
221     if (configItf == nullptr) {
222         LOGW("%s() called with NULL configuration", __func__);
223         mPerformanceMode = PerformanceMode::None;
224         return SL_RESULT_INTERNAL_ERROR;
225     }
226     if (getSdkVersion() < __ANDROID_API_N_MR1__) {
227         LOGW("%s() not supported until N_MR1", __func__);
228         mPerformanceMode = PerformanceMode::None;
229         return SL_RESULT_SUCCESS;
230     }
231 
232     SLresult result = SL_RESULT_SUCCESS;
233     SLuint32 performanceMode = convertPerformanceMode(getPerformanceMode());
234     result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
235                                                      &performanceMode, sizeof(performanceMode));
236     if (SL_RESULT_SUCCESS != result) {
237         LOGW("SetConfiguration(PERFORMANCE_MODE, SL %u) returned %s",
238              performanceMode, getSLErrStr(result));
239         mPerformanceMode = PerformanceMode::None;
240     }
241 
242     return result;
243 }
244 
updateStreamParameters(SLAndroidConfigurationItf configItf)245 SLresult AudioStreamOpenSLES::updateStreamParameters(SLAndroidConfigurationItf configItf) {
246     SLresult result = SL_RESULT_SUCCESS;
247     if(getSdkVersion() >= __ANDROID_API_N_MR1__ && configItf != nullptr) {
248         SLuint32 performanceMode = 0;
249         SLuint32 performanceModeSize = sizeof(performanceMode);
250         result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
251                                                 &performanceModeSize, &performanceMode);
252         // A bug in GetConfiguration() before P caused a wrong result code to be returned.
253         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
254             result = SL_RESULT_SUCCESS; // Ignore actual result before P.
255         }
256 
257         if (SL_RESULT_SUCCESS != result) {
258             LOGW("GetConfiguration(SL_ANDROID_KEY_PERFORMANCE_MODE) returned %d", result);
259             mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
260         } else {
261             mPerformanceMode = convertPerformanceMode(performanceMode); // convert SL to Oboe mode
262         }
263     } else {
264         mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
265     }
266     return result;
267 }
268 
close()269 Result AudioStreamOpenSLES::close() {
270     if (mState == StreamState::Closed) {
271         return Result::ErrorClosed;
272     }
273 
274     AudioStreamBuffered::close();
275 
276     onBeforeDestroy();
277 
278     if (mObjectInterface != nullptr) {
279         (*mObjectInterface)->Destroy(mObjectInterface);
280         mObjectInterface = nullptr;
281     }
282 
283     onAfterDestroy();
284 
285     mSimpleBufferQueueInterface = nullptr;
286     EngineOpenSLES::getInstance().close();
287 
288     setState(StreamState::Closed);
289     return Result::OK;
290 }
291 
enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq)292 SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) {
293     return (*bq)->Enqueue(bq, mCallbackBuffer.get(), mBytesPerCallback);
294 }
295 
getBufferDepth(SLAndroidSimpleBufferQueueItf bq)296 int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) {
297     SLAndroidSimpleBufferQueueState queueState;
298     SLresult result = (*bq)->GetState(bq, &queueState);
299     return (result == SL_RESULT_SUCCESS) ? queueState.count : -1;
300 }
301 
processBufferCallback(SLAndroidSimpleBufferQueueItf bq)302 void AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
303     bool stopStream = false;
304     // Ask the app callback to process the buffer.
305     DataCallbackResult result = fireDataCallback(mCallbackBuffer.get(), mFramesPerCallback);
306     if (result == DataCallbackResult::Continue) {
307         // Pass the buffer to OpenSLES.
308         SLresult enqueueResult = enqueueCallbackBuffer(bq);
309         if (enqueueResult != SL_RESULT_SUCCESS) {
310             LOGE("%s() returned %d", __func__, enqueueResult);
311             stopStream = true;
312         }
313         // Update Oboe client position with frames handled by the callback.
314         if (getDirection() == Direction::Input) {
315             mFramesRead += mFramesPerCallback;
316         } else {
317             mFramesWritten += mFramesPerCallback;
318         }
319     } else if (result == DataCallbackResult::Stop) {
320         LOGD("Oboe callback returned Stop");
321         stopStream = true;
322     } else {
323         LOGW("Oboe callback returned unexpected value = %d", result);
324         stopStream = true;
325     }
326     if (stopStream) {
327         requestStop();
328     }
329 }
330 
331 // This callback handler is called every time a buffer has been processed by OpenSL ES.
bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq,void * context)332 static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) {
333     (reinterpret_cast<AudioStreamOpenSLES *>(context))->processBufferCallback(bq);
334 }
335 
registerBufferQueueCallback()336 SLresult AudioStreamOpenSLES::registerBufferQueueCallback() {
337     // The BufferQueue
338     SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
339                                                 &mSimpleBufferQueueInterface);
340     if (SL_RESULT_SUCCESS != result) {
341         LOGE("get buffer queue interface:%p result:%s",
342              mSimpleBufferQueueInterface,
343              getSLErrStr(result));
344     } else {
345         // Register the BufferQueue callback
346         result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface,
347                                                                   bqCallbackGlue, this);
348         if (SL_RESULT_SUCCESS != result) {
349             LOGE("RegisterCallback result:%s", getSLErrStr(result));
350         }
351     }
352     return result;
353 }
354 
getFramesPerBurst()355 int32_t AudioStreamOpenSLES::getFramesPerBurst() {
356     return mFramesPerBurst;
357 }
358 
getFramesProcessedByServer()359 int64_t AudioStreamOpenSLES::getFramesProcessedByServer() {
360     updateServiceFrameCounter();
361     int64_t millis64 = mPositionMillis.get();
362     int64_t framesProcessed = millis64 * getSampleRate() / kMillisPerSecond;
363     return framesProcessed;
364 }
365 
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)366 Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState,
367                                                      StreamState *nextState,
368                                                      int64_t timeoutNanoseconds) {
369     Result oboeResult = Result::ErrorTimeout;
370     int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
371     int64_t timeLeftNanos = timeoutNanoseconds;
372 
373     while (true) {
374         const StreamState state = getState(); // this does not require a lock
375         if (nextState != nullptr) {
376             *nextState = state;
377         }
378         if (currentState != state) { // state changed?
379             oboeResult = Result::OK;
380             break;
381         }
382 
383         // Did we timeout or did user ask for non-blocking?
384         if (timeoutNanoseconds <= 0) {
385             break;
386         }
387 
388         if (sleepTimeNanos > timeLeftNanos){
389             sleepTimeNanos = timeLeftNanos;
390         }
391         AudioClock::sleepForNanos(sleepTimeNanos);
392         timeLeftNanos -= sleepTimeNanos;
393     }
394 
395     return oboeResult;
396 }
397