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