xref: /aosp_15_r20/cts/tests/tests/media/audio/jni/appendix-b-1-1-buffer-queue.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright (C) 2015 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "OpenSL-ES-Test-B-1-1-Buffer-Queue"
19 
20 #include "sl-utils.h"
21 
22 /*
23  * See https://www.khronos.org/registry/sles/specs/OpenSL_ES_Specification_1.0.1.pdf
24  * Appendix B.1.1 sample code.
25  *
26  * Minor edits made to conform to Android coding style.
27  *
28  * Correction to code: SL_IID_VOLUME is now made optional for the mixer.
29  * It isn't supported on the standard Android mixer, but it is supported on the player.
30  */
31 
32 #define MAX_NUMBER_INTERFACES 3
33 
34 /* Local storage for Audio data in 16 bit words */
35 #define AUDIO_DATA_STORAGE_SIZE 4096
36 
37 #define AUDIO_DATA_SEGMENTS 8
38 
39 /* Audio data buffer size in 16 bit words. 8 data segments are used in
40    this simple example */
41 #define AUDIO_DATA_BUFFER_SIZE (AUDIO_DATA_STORAGE_SIZE / AUDIO_DATA_SEGMENTS)
42 
43 /* Structure for passing information to callback function */
44 typedef struct  {
45     SLPlayItf playItf;
46     SLint16  *pDataBase; // Base address of local audio data storage
47     SLint16  *pData;     // Current address of local audio data storage
48     SLuint32  size;
49 } CallbackCntxt;
50 
51 /* Local storage for Audio data */
52 static SLint16 pcmData[AUDIO_DATA_STORAGE_SIZE];
53 
54 /* Callback for Buffer Queue events */
BufferQueueCallback(SLBufferQueueItf queueItf,void * pContext)55 static void BufferQueueCallback(
56         SLBufferQueueItf queueItf,
57         void *pContext)
58 {
59     SLresult res;
60     CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
61     if (pCntxt->pData < (pCntxt->pDataBase + pCntxt->size)) {
62         res = (*queueItf)->Enqueue(queueItf, (void *)pCntxt->pData,
63                 sizeof(SLint16) * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
64         ALOGE_IF(res != SL_RESULT_SUCCESS, "error: %s", android::getSLErrStr(res));
65         /* Increase data pointer by buffer size */
66         pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
67     }
68 }
69 
70 /* Play some music from a buffer queue */
TestPlayMusicBufferQueue(SLObjectItf sl)71 static void TestPlayMusicBufferQueue(SLObjectItf sl)
72 {
73     SLEngineItf EngineItf;
74 
75     SLresult res;
76 
77     SLDataSource audioSource;
78     SLDataLocator_BufferQueue bufferQueue;
79     SLDataFormat_PCM pcm;
80 
81     SLDataSink audioSink;
82     SLDataLocator_OutputMix locator_outputmix;
83 
84     SLObjectItf player;
85     SLPlayItf playItf;
86     SLBufferQueueItf bufferQueueItf;
87     SLBufferQueueState state;
88 
89     SLObjectItf OutputMix;
90     SLVolumeItf volumeItf;
91 
92     int i;
93 
94     SLboolean required[MAX_NUMBER_INTERFACES];
95     SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
96 
97     /* Callback context for the buffer queue callback function */
98     CallbackCntxt cntxt;
99 
100     /* Get the SL Engine Interface which is implicit */
101     res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void *)&EngineItf);
102     CheckErr(res);
103 
104     /* Initialize arrays required[] and iidArray[] */
105     for (i = 0; i < MAX_NUMBER_INTERFACES; i++) {
106         required[i] = SL_BOOLEAN_FALSE;
107         iidArray[i] = SL_IID_NULL;
108     }
109 
110     // Set arrays required[] and iidArray[] for VOLUME interface
111     required[0] = SL_BOOLEAN_FALSE; // ANDROID: we don't require this interface
112     iidArray[0] = SL_IID_VOLUME;
113 
114 #if 0
115     const unsigned interfaces = 1;
116 #else
117 
118     /* FIXME: Android doesn't properly support optional interfaces (required == false).
119     [3.1.6] When an application requests explicit interfaces during object creation,
120     it can flag any interface as required. If an implementation is unable to satisfy
121     the request for an interface that is not flagged as required (i.e. it is not required),
122     this will not cause the object to fail creation. On the other hand, if the interface
123     is flagged as required and the implementation is unable to satisfy the request
124     for the interface, the object will not be created.
125     */
126     const unsigned interfaces = 0;
127 #endif
128     // Create Output Mix object to be used by player
129     res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, interfaces,
130             iidArray, required);
131     CheckErr(res);
132 
133     // Realizing the Output Mix object in synchronous mode.
134     res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
135     CheckErr(res);
136 
137     volumeItf = NULL; // ANDROID: Volume interface on mix object may not be supported
138     res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
139             (void *)&volumeItf);
140 
141     /* Setup the data source structure for the buffer queue */
142     bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
143     bufferQueue.numBuffers = 4; /* Four buffers in our buffer queue */
144 
145     /* Setup the format of the content in the buffer queue */
146     pcm.formatType = SL_DATAFORMAT_PCM;
147     pcm.numChannels = 2;
148     pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
149     pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
150     pcm.containerSize = 16;
151     pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
152     pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
153     audioSource.pFormat = (void *)&pcm;
154     audioSource.pLocator = (void *)&bufferQueue;
155 
156     /* Setup the data sink structure */
157     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
158     locator_outputmix.outputMix = OutputMix;
159     audioSink.pLocator = (void *)&locator_outputmix;
160     audioSink.pFormat = NULL;
161 
162     /* Initialize the context for Buffer queue callbacks */
163     cntxt.pDataBase = pcmData;
164     cntxt.pData = cntxt.pDataBase;
165     cntxt.size = sizeof(pcmData) / sizeof(pcmData[0]); // ANDROID: Bug
166 
167     /* Set arrays required[] and iidArray[] for SEEK interface
168        (PlayItf is implicit) */
169     required[0] = SL_BOOLEAN_TRUE;
170     iidArray[0] = SL_IID_BUFFERQUEUE;
171 
172     /* Create the music player */
173 
174     res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
175             &audioSource, &audioSink, 1, iidArray, required);
176     CheckErr(res);
177 
178     /* Realizing the player in synchronous mode. */
179     res = (*player)->Realize(player, SL_BOOLEAN_FALSE);
180     CheckErr(res);
181 
182     /* Get seek and play interfaces */
183     res = (*player)->GetInterface(player, SL_IID_PLAY, (void *)&playItf);
184     CheckErr(res);
185     res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
186             (void *)&bufferQueueItf);
187     CheckErr(res);
188 
189     /* Setup to receive buffer queue event callbacks */
190     res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
191             BufferQueueCallback, &cntxt /* BUG, was NULL */);
192     CheckErr(res);
193 
194     /* Before we start set volume to -3dB (-300mB) */
195     if (volumeItf != NULL) { // ANDROID: Volume interface may not be supported.
196         res = (*volumeItf)->SetVolumeLevel(volumeItf, -300);
197         CheckErr(res);
198     }
199 
200     /* Enqueue a few buffers to get the ball rolling */
201     res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
202             sizeof(SLint16) * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
203     CheckErr(res);
204     cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
205     res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
206             sizeof(SLint16) * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
207     CheckErr(res);
208     cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
209     res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
210             sizeof(SLint16) * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
211     CheckErr(res);
212     cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
213 
214     /* Play the PCM samples using a buffer queue */
215     res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
216     CheckErr(res);
217 
218     /* Wait until the PCM data is done playing, the buffer queue callback
219        will continue to queue buffers until the entire PCM data has been
220        played. This is indicated by waiting for the count member of the
221        SLBufferQueueState to go to zero.
222      */
223     res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
224     CheckErr(res);
225 
226     while (state.count) {
227         usleep(5 * 1000 /* usec */); // ANDROID: avoid busy waiting
228         (*bufferQueueItf)->GetState(bufferQueueItf, &state);
229     }
230 
231     /* Make sure player is stopped */
232     res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
233     CheckErr(res);
234 
235     /* Destroy the player */
236     (*player)->Destroy(player);
237 
238     /* Destroy Output Mix object */
239     (*OutputMix)->Destroy(OutputMix);
240 }
241 
Java_android_media_audio_cts_AudioNativeTest_nativeAppendixBBufferQueue(JNIEnv *,jclass)242 extern "C" void Java_android_media_audio_cts_AudioNativeTest_nativeAppendixBBufferQueue(
243         JNIEnv * /* env */, jclass /* clazz */)
244 {
245     SLObjectItf engineObject = android::OpenSLEngine();
246     LOG_ALWAYS_FATAL_IF(engineObject == NULL, "cannot open OpenSL ES engine");
247 
248     TestPlayMusicBufferQueue(engineObject);
249     android::CloseSLEngine(engineObject);
250 }
251