xref: /aosp_15_r20/external/oboe/src/opensles/EngineOpenSLES.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <dlfcn.h>
18 #include "common/OboeDebug.h"
19 #include "EngineOpenSLES.h"
20 #include "OpenSLESUtilities.h"
21 
22 using namespace oboe;
23 
24 // OpenSL ES is deprecated in SDK 30.
25 // So we use custom dynamic linking to access the library.
26 #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;
37 
38 // Load the OpenSL ES library and the one primary entry point.
39 // @return true if linked OK
linkOpenSLES()40 static bool linkOpenSLES() {
41     if (gLibOpenSlesLibraryHandle == nullptr && gFunction_slCreateEngine == nullptr) {
42         // Use RTLD_NOW to avoid the unpredictable behavior that RTLD_LAZY can cause.
43         // 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);
47         } else {
48             gFunction_slCreateEngine = (prototype_slCreateEngine) dlsym(
49                     gLibOpenSlesLibraryHandle,
50                     "slCreateEngine");
51             LOGD("linkOpenSLES(): dlsym(%s) returned %p", "slCreateEngine",
52                  gFunction_slCreateEngine);
53         }
54     }
55     return gFunction_slCreateEngine != nullptr;
56 }
57 
getInstance()58 EngineOpenSLES &EngineOpenSLES::getInstance() {
59     static EngineOpenSLES sInstance;
60     return sInstance;
61 }
62 
open()63 SLresult EngineOpenSLES::open() {
64     std::lock_guard<std::mutex> lock(mLock);
65 
66     SLresult result = SL_RESULT_SUCCESS;
67     if (mOpenCount++ == 0) {
68         // load the library and link to it
69         if (!linkOpenSLES()) {
70             result = SL_RESULT_FEATURE_UNSUPPORTED;
71             goto error;
72         };
73 
74         // create engine
75         result = (*gFunction_slCreateEngine)(&mEngineObject, 0, NULL, 0, NULL, NULL);
76         if (SL_RESULT_SUCCESS != result) {
77             LOGE("EngineOpenSLES - slCreateEngine() result:%s", getSLErrStr(result));
78             goto error;
79         }
80 
81         // realize the engine
82         result = (*mEngineObject)->Realize(mEngineObject, SL_BOOLEAN_FALSE);
83         if (SL_RESULT_SUCCESS != result) {
84             LOGE("EngineOpenSLES - Realize() engine result:%s", getSLErrStr(result));
85             goto error;
86         }
87 
88         // get the engine interface, which is needed in order to create other objects
89         result = (*mEngineObject)->GetInterface(mEngineObject, SL_IID_ENGINE, &mEngineInterface);
90         if (SL_RESULT_SUCCESS != result) {
91             LOGE("EngineOpenSLES - GetInterface() engine result:%s", getSLErrStr(result));
92             goto error;
93         }
94     }
95 
96     return result;
97 
98 error:
99     close();
100     return result;
101 }
102 
close()103 void EngineOpenSLES::close() {
104     std::lock_guard<std::mutex> lock(mLock);
105     if (--mOpenCount == 0) {
106         if (mEngineObject != nullptr) {
107             (*mEngineObject)->Destroy(mEngineObject);
108             mEngineObject = nullptr;
109             mEngineInterface = nullptr;
110         }
111     }
112 }
113 
createOutputMix(SLObjectItf * objectItf)114 SLresult EngineOpenSLES::createOutputMix(SLObjectItf *objectItf) {
115     return (*mEngineInterface)->CreateOutputMix(mEngineInterface, objectItf, 0, 0, 0);
116 }
117 
createAudioPlayer(SLObjectItf * objectItf,SLDataSource * audioSource,SLDataSink * audioSink)118 SLresult EngineOpenSLES::createAudioPlayer(SLObjectItf *objectItf,
119                                            SLDataSource *audioSource,
120                                            SLDataSink *audioSink) {
121 
122     const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION};
123     const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
124 
125     return (*mEngineInterface)->CreateAudioPlayer(mEngineInterface, objectItf, audioSource,
126                                                   audioSink,
127                                                   sizeof(ids) / sizeof(ids[0]), ids, reqs);
128 }
129 
createAudioRecorder(SLObjectItf * objectItf,SLDataSource * audioSource,SLDataSink * audioSink)130 SLresult EngineOpenSLES::createAudioRecorder(SLObjectItf *objectItf,
131                                              SLDataSource *audioSource,
132                                              SLDataSink *audioSink) {
133 
134     const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
135     const SLboolean reqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
136 
137     return (*mEngineInterface)->CreateAudioRecorder(mEngineInterface, objectItf, audioSource,
138                                                     audioSink,
139                                                     sizeof(ids) / sizeof(ids[0]), ids, reqs);
140 }
141 
142