1515 */
1616
1717#include < dlfcn.h>
18+
1819#include " common/OboeDebug.h"
1920#include " EngineOpenSLES.h"
2021#include " OpenSLESUtilities.h"
@@ -24,40 +25,92 @@ using namespace oboe;
2425// OpenSL ES is deprecated in SDK 30.
2526// So we use custom dynamic linking to access the library.
2627#define LIB_OPENSLES_NAME " libOpenSLES.so"
27- typedef SLresult (*prototype_slCreateEngine)(
28- SLObjectItf *pEngine,
29- SLuint32 numOptions,
30- const SLEngineOption *pEngineOptions,
31- SLuint32 numInterfaces,
32- const SLInterfaceID *pInterfaceIds,
33- const SLboolean *pInterfaceRequired
34- );
35- static prototype_slCreateEngine gFunction_slCreateEngine = nullptr ;
36- static void *gLibOpenSlesLibraryHandle = nullptr ;
28+
29+ EngineOpenSLES &EngineOpenSLES::getInstance () {
30+ static EngineOpenSLES sInstance ;
31+ return sInstance ;
32+ }
33+
34+ // Satisfy extern in OpenSLES.h
35+ // These are required because of b/337360630, which was causing
36+ // Oboe to have link failures if libOpenSLES.so was not available.
37+ SL_API const SLInterfaceID SL_IID_ENGINE = nullptr ;
38+ SL_API const SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE = nullptr ;
39+ SL_API const SLInterfaceID SL_IID_ANDROIDCONFIGURATION = nullptr ;
40+ SL_API const SLInterfaceID SL_IID_RECORD = nullptr ;
41+ SL_API const SLInterfaceID SL_IID_BUFFERQUEUE = nullptr ;
42+ SL_API const SLInterfaceID SL_IID_VOLUME = nullptr ;
43+ SL_API const SLInterfaceID SL_IID_PLAY = nullptr ;
44+
45+ static const char *getSafeDlerror () {
46+ static const char *defaultMessage = " not found?" ;
47+ char *errorMessage = dlerror ();
48+ return (errorMessage == nullptr ) ? defaultMessage : errorMessage;
49+ }
3750
3851// Load the OpenSL ES library and the one primary entry point.
3952// @return true if linked OK
40- static bool linkOpenSLES () {
41- if (gLibOpenSlesLibraryHandle == nullptr && gFunction_slCreateEngine == nullptr ) {
53+ bool EngineOpenSLES::linkOpenSLES () {
54+ if (mDynamicLinkState == kLinkStateBad ) {
55+ LOGE (" %s(), OpenSL ES not available, based on previous link failure." , __func__);
56+ } else if (mDynamicLinkState == kLinkStateUninitialized ) {
57+ // Set to BAD now in case we return because of an error.
58+ // This is safe form race conditions because this function is always called
59+ // under mLock amd the state is only accessed from this function.
60+ mDynamicLinkState = kLinkStateBad ;
4261 // Use RTLD_NOW to avoid the unpredictable behavior that RTLD_LAZY can cause.
4362 // Also resolving all the links now will prevent a run-time penalty later.
44- gLibOpenSlesLibraryHandle = dlopen (LIB_OPENSLES_NAME, RTLD_NOW);
45- if (gLibOpenSlesLibraryHandle == nullptr ) {
46- LOGE (" linkOpenSLES() could not find " LIB_OPENSLES_NAME);
63+ mLibOpenSlesLibraryHandle = dlopen (LIB_OPENSLES_NAME, RTLD_NOW);
64+ if (mLibOpenSlesLibraryHandle == nullptr ) {
65+ LOGE (" %s() could not dlopen(%s), %s" , __func__, LIB_OPENSLES_NAME, getSafeDlerror ());
66+ return false ;
4767 } else {
48- gFunction_slCreateEngine = (prototype_slCreateEngine) dlsym (
49- gLibOpenSlesLibraryHandle ,
68+ mFunction_slCreateEngine = (prototype_slCreateEngine) dlsym (
69+ mLibOpenSlesLibraryHandle ,
5070 " slCreateEngine" );
51- LOGD (" linkOpenSLES(): dlsym(%s) returned %p" , " slCreateEngine" ,
52- gFunction_slCreateEngine );
71+ LOGD (" %s(): dlsym(%s) returned %p" , __func__,
72+ " slCreateEngine" , mFunction_slCreateEngine );
73+ if (mFunction_slCreateEngine == nullptr ) {
74+ LOGE (" %s(): dlsym(slCreateEngine) returned null, %s" , __func__, getSafeDlerror ());
75+ return false ;
76+ }
77+
78+ // Load IID interfaces.
79+ LOCAL_SL_IID_ENGINE = getIidPointer (" SL_IID_ENGINE" );
80+ if (LOCAL_SL_IID_ENGINE == nullptr ) return false ;
81+ LOCAL_SL_IID_ANDROIDSIMPLEBUFFERQUEUE = getIidPointer (
82+ " SL_IID_ANDROIDSIMPLEBUFFERQUEUE" );
83+ if (LOCAL_SL_IID_ANDROIDSIMPLEBUFFERQUEUE == nullptr ) return false ;
84+ LOCAL_SL_IID_ANDROIDCONFIGURATION = getIidPointer (
85+ " SL_IID_ANDROIDCONFIGURATION" );
86+ if (LOCAL_SL_IID_ANDROIDCONFIGURATION == nullptr ) return false ;
87+ LOCAL_SL_IID_RECORD = getIidPointer (" SL_IID_RECORD" );
88+ if (LOCAL_SL_IID_RECORD == nullptr ) return false ;
89+ LOCAL_SL_IID_BUFFERQUEUE = getIidPointer (" SL_IID_BUFFERQUEUE" );
90+ if (LOCAL_SL_IID_BUFFERQUEUE == nullptr ) return false ;
91+ LOCAL_SL_IID_VOLUME = getIidPointer (" SL_IID_VOLUME" );
92+ if (LOCAL_SL_IID_VOLUME == nullptr ) return false ;
93+ LOCAL_SL_IID_PLAY = getIidPointer (" SL_IID_PLAY" );
94+ if (LOCAL_SL_IID_PLAY == nullptr ) return false ;
95+
96+ mDynamicLinkState = kLinkStateGood ;
5397 }
5498 }
55- return gFunction_slCreateEngine != nullptr ;
99+ return ( mDynamicLinkState == kLinkStateGood ) ;
56100}
57101
58- EngineOpenSLES &EngineOpenSLES::getInstance () {
59- static EngineOpenSLES sInstance ;
60- return sInstance ;
102+ // A symbol like SL_IID_PLAY is a pointer to a structure.
103+ // The dlsym() function returns the address of the pointer, not the structure.
104+ // To get the address of the structure we have to dereference the pointer.
105+ SLInterfaceID EngineOpenSLES::getIidPointer (const char *symbolName) {
106+ SLInterfaceID *iid_address = (SLInterfaceID *) dlsym (
107+ mLibOpenSlesLibraryHandle ,
108+ symbolName);
109+ if (iid_address == nullptr ) {
110+ LOGE (" %s(): dlsym(%s) returned null, %s" , __func__, symbolName, getSafeDlerror ());
111+ return (SLInterfaceID) nullptr ;
112+ }
113+ return *iid_address; // Get address of the structure.
61114}
62115
63116SLresult EngineOpenSLES::open () {
@@ -72,7 +125,7 @@ SLresult EngineOpenSLES::open() {
72125 };
73126
74127 // create engine
75- result = (*gFunction_slCreateEngine )(&mEngineObject , 0 , NULL , 0 , NULL , NULL );
128+ result = (*mFunction_slCreateEngine )(&mEngineObject , 0 , NULL , 0 , NULL , NULL );
76129 if (SL_RESULT_SUCCESS != result) {
77130 LOGE (" EngineOpenSLES - slCreateEngine() result:%s" , getSLErrStr (result));
78131 goto error;
@@ -86,7 +139,9 @@ SLresult EngineOpenSLES::open() {
86139 }
87140
88141 // get the engine interface, which is needed in order to create other objects
89- result = (*mEngineObject )->GetInterface (mEngineObject , SL_IID_ENGINE, &mEngineInterface );
142+ result = (*mEngineObject )->GetInterface (mEngineObject ,
143+ EngineOpenSLES::getInstance ().getIidEngine (),
144+ &mEngineInterface );
90145 if (SL_RESULT_SUCCESS != result) {
91146 LOGE (" EngineOpenSLES - GetInterface() engine result:%s" , getSLErrStr (result));
92147 goto error;
@@ -96,12 +151,17 @@ SLresult EngineOpenSLES::open() {
96151 return result;
97152
98153error:
99- close ();
154+ close_l ();
100155 return result;
101156}
102157
103158void EngineOpenSLES::close () {
104159 std::lock_guard<std::mutex> lock (mLock );
160+ close_l ();
161+ }
162+
163+ // This must be called under mLock
164+ void EngineOpenSLES::close_l () {
105165 if (--mOpenCount == 0 ) {
106166 if (mEngineObject != nullptr ) {
107167 (*mEngineObject )->Destroy (mEngineObject );
@@ -119,8 +179,8 @@ SLresult EngineOpenSLES::createAudioPlayer(SLObjectItf *objectItf,
119179 SLDataSource *audioSource,
120180 SLDataSink *audioSink) {
121181
122- const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
123- const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
182+ SLInterfaceID ids[] = {LOCAL_SL_IID_BUFFERQUEUE, LOCAL_SL_IID_ANDROIDCONFIGURATION };
183+ SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
124184
125185 return (*mEngineInterface )->CreateAudioPlayer (mEngineInterface , objectItf, audioSource,
126186 audioSink,
@@ -131,8 +191,9 @@ SLresult EngineOpenSLES::createAudioRecorder(SLObjectItf *objectItf,
131191 SLDataSource *audioSource,
132192 SLDataSink *audioSink) {
133193
134- const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
135- const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
194+ SLInterfaceID ids[] = {LOCAL_SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
195+ LOCAL_SL_IID_ANDROIDCONFIGURATION };
196+ SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
136197
137198 return (*mEngineInterface )->CreateAudioRecorder (mEngineInterface , objectItf, audioSource,
138199 audioSink,
0 commit comments