• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 
18 /* This is a JNI example where we use native methods to play sounds
19  * using OpenSL ES. See the corresponding Java source file located at:
20  *
21  *   src/com/example/nativeaudio/NativeAudio/NativeAudio.java
22  */
23 
24 #include <assert.h>
25 #include <jni.h>
26 #include <string.h>
27 
28 // for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
29 // #include <android/log.h>
30 
31 // for native audio
32 #include <SLES/OpenSLES.h>
33 #include <SLES/OpenSLES_Android.h>
34 
35 // for native asset manager
36 #include <sys/types.h>
37 #include <android/asset_manager.h>
38 #include <android/asset_manager_jni.h>
39 
40 // pre-recorded sound clips, both are 8 kHz mono 16-bit signed little endian
41 
42 static const char hello[] =
43 #include "hello_clip.h"
44 ;
45 
46 static const char android[] =
47 #include "android_clip.h"
48 ;
49 
50 // engine interfaces
51 static SLObjectItf engineObject = NULL;
52 static SLEngineItf engineEngine;
53 
54 // output mix interfaces
55 static SLObjectItf outputMixObject = NULL;
56 static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
57 
58 // buffer queue player interfaces
59 static SLObjectItf bqPlayerObject = NULL;
60 static SLPlayItf bqPlayerPlay;
61 static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
62 static SLEffectSendItf bqPlayerEffectSend;
63 static SLMuteSoloItf bqPlayerMuteSolo;
64 static SLVolumeItf bqPlayerVolume;
65 
66 // aux effect on the output mix, used by the buffer queue player
67 static const SLEnvironmentalReverbSettings reverbSettings =
68     SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
69 
70 // URI player interfaces
71 static SLObjectItf uriPlayerObject = NULL;
72 static SLPlayItf uriPlayerPlay;
73 static SLSeekItf uriPlayerSeek;
74 static SLMuteSoloItf uriPlayerMuteSolo;
75 static SLVolumeItf uriPlayerVolume;
76 
77 // file descriptor player interfaces
78 static SLObjectItf fdPlayerObject = NULL;
79 static SLPlayItf fdPlayerPlay;
80 static SLSeekItf fdPlayerSeek;
81 static SLMuteSoloItf fdPlayerMuteSolo;
82 static SLVolumeItf fdPlayerVolume;
83 
84 // recorder interfaces
85 static SLObjectItf recorderObject = NULL;
86 static SLRecordItf recorderRecord;
87 static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
88 
89 // synthesized sawtooth clip
90 #define SAWTOOTH_FRAMES 8000
91 static short sawtoothBuffer[SAWTOOTH_FRAMES];
92 
93 // 5 seconds of recorded audio at 16 kHz mono, 16-bit signed little endian
94 #define RECORDER_FRAMES (16000 * 5)
95 static short recorderBuffer[RECORDER_FRAMES];
96 static unsigned recorderSize = 0;
97 static SLmilliHertz recorderSR;
98 
99 // pointer and size of the next player buffer to enqueue, and number of remaining buffers
100 static short *nextBuffer;
101 static unsigned nextSize;
102 static int nextCount;
103 
104 
105 // synthesize a mono sawtooth wave and place it into a buffer (called automatically on load)
onDlOpen(void)106 __attribute__((constructor)) static void onDlOpen(void)
107 {
108     unsigned i;
109     for (i = 0; i < SAWTOOTH_FRAMES; ++i) {
110         sawtoothBuffer[i] = 32768 - ((i % 100) * 660);
111     }
112 }
113 
114 
115 // this callback handler is called every time a buffer finishes playing
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq,void * context)116 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
117 {
118     assert(bq == bqPlayerBufferQueue);
119     assert(NULL == context);
120     // for streaming playback, replace this test by logic to find and fill the next buffer
121     if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {
122         SLresult result;
123         // enqueue another buffer
124         result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
125         // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
126         // which for this code example would indicate a programming error
127         assert(SL_RESULT_SUCCESS == result);
128     }
129 }
130 
131 
132 // this callback handler is called every time a buffer finishes recording
bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq,void * context)133 void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
134 {
135     assert(bq == bqRecorderBufferQueue);
136     assert(NULL == context);
137     // for streaming recording, here we would call Enqueue to give recorder the next buffer to fill
138     // but instead, this is a one-time buffer so we stop recording
139     SLresult result;
140     result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
141     if (SL_RESULT_SUCCESS == result) {
142         recorderSize = RECORDER_FRAMES * sizeof(short);
143         recorderSR = SL_SAMPLINGRATE_16;
144     }
145 }
146 
147 
148 // create the engine and output mix objects
Java_com_example_nativeaudio_NativeAudio_createEngine(JNIEnv * env,jclass clazz)149 void Java_com_example_nativeaudio_NativeAudio_createEngine(JNIEnv* env, jclass clazz)
150 {
151     SLresult result;
152 
153     // create engine
154     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
155     assert(SL_RESULT_SUCCESS == result);
156 
157     // realize the engine
158     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
159     assert(SL_RESULT_SUCCESS == result);
160 
161     // get the engine interface, which is needed in order to create other objects
162     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
163     assert(SL_RESULT_SUCCESS == result);
164 
165     // create output mix, with environmental reverb specified as a non-required interface
166     const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
167     const SLboolean req[1] = {SL_BOOLEAN_FALSE};
168     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
169     assert(SL_RESULT_SUCCESS == result);
170 
171     // realize the output mix
172     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
173     assert(SL_RESULT_SUCCESS == result);
174 
175     // get the environmental reverb interface
176     // this could fail if the environmental reverb effect is not available,
177     // either because the feature is not present, excessive CPU load, or
178     // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted
179     result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
180             &outputMixEnvironmentalReverb);
181     if (SL_RESULT_SUCCESS == result) {
182         result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
183                 outputMixEnvironmentalReverb, &reverbSettings);
184     }
185     // ignore unsuccessful result codes for environmental reverb, as it is optional for this example
186 
187 }
188 
189 
190 // create buffer queue audio player
Java_com_example_nativeaudio_NativeAudio_createBufferQueueAudioPlayer(JNIEnv * env,jclass clazz)191 void Java_com_example_nativeaudio_NativeAudio_createBufferQueueAudioPlayer(JNIEnv* env,
192         jclass clazz)
193 {
194     SLresult result;
195 
196     // configure audio source
197     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
198     SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_8,
199         SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
200         SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};
201     SLDataSource audioSrc = {&loc_bufq, &format_pcm};
202 
203     // configure audio sink
204     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
205     SLDataSink audioSnk = {&loc_outmix, NULL};
206 
207     // create audio player
208     const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND,
209             /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME};
210     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
211             /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE};
212     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
213             3, ids, req);
214     assert(SL_RESULT_SUCCESS == result);
215 
216     // realize the player
217     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
218     assert(SL_RESULT_SUCCESS == result);
219 
220     // get the play interface
221     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
222     assert(SL_RESULT_SUCCESS == result);
223 
224     // get the buffer queue interface
225     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
226             &bqPlayerBufferQueue);
227     assert(SL_RESULT_SUCCESS == result);
228 
229     // register callback on the buffer queue
230     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
231     assert(SL_RESULT_SUCCESS == result);
232 
233     // get the effect send interface
234     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
235             &bqPlayerEffectSend);
236     assert(SL_RESULT_SUCCESS == result);
237 
238 #if 0   // mute/solo is not supported for sources that are known to be mono, as this is
239     // get the mute/solo interface
240     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
241     assert(SL_RESULT_SUCCESS == result);
242 #endif
243 
244     // get the volume interface
245     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
246     assert(SL_RESULT_SUCCESS == result);
247 
248     // set the player's state to playing
249     result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
250     assert(SL_RESULT_SUCCESS == result);
251 
252 }
253 
254 
255 // create URI audio player
Java_com_example_nativeaudio_NativeAudio_createUriAudioPlayer(JNIEnv * env,jclass clazz,jstring uri)256 jboolean Java_com_example_nativeaudio_NativeAudio_createUriAudioPlayer(JNIEnv* env, jclass clazz,
257         jstring uri)
258 {
259     SLresult result;
260 
261     // convert Java string to UTF-8
262     const jbyte *utf8 = (*env)->GetStringUTFChars(env, uri, NULL);
263     assert(NULL != utf8);
264 
265     // configure audio source
266     // (requires the INTERNET permission depending on the uri parameter)
267     SLDataLocator_URI loc_uri = {SL_DATALOCATOR_URI, (SLchar *) utf8};
268     SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
269     SLDataSource audioSrc = {&loc_uri, &format_mime};
270 
271     // configure audio sink
272     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
273     SLDataSink audioSnk = {&loc_outmix, NULL};
274 
275     // create audio player
276     const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME};
277     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
278     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &uriPlayerObject, &audioSrc,
279             &audioSnk, 3, ids, req);
280     // note that an invalid URI is not detected here, but during prepare/prefetch on Android,
281     // or possibly during Realize on other platforms
282     assert(SL_RESULT_SUCCESS == result);
283 
284     // release the Java string and UTF-8
285     (*env)->ReleaseStringUTFChars(env, uri, utf8);
286 
287     // realize the player
288     result = (*uriPlayerObject)->Realize(uriPlayerObject, SL_BOOLEAN_FALSE);
289     // this will always succeed on Android, but we check result for portability to other platforms
290     if (SL_RESULT_SUCCESS != result) {
291         (*uriPlayerObject)->Destroy(uriPlayerObject);
292         uriPlayerObject = NULL;
293         return JNI_FALSE;
294     }
295 
296     // get the play interface
297     result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay);
298     assert(SL_RESULT_SUCCESS == result);
299 
300     // get the seek interface
301     result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_SEEK, &uriPlayerSeek);
302     assert(SL_RESULT_SUCCESS == result);
303 
304     // get the mute/solo interface
305     result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_MUTESOLO, &uriPlayerMuteSolo);
306     assert(SL_RESULT_SUCCESS == result);
307 
308     // get the volume interface
309     result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_VOLUME, &uriPlayerVolume);
310     assert(SL_RESULT_SUCCESS == result);
311 
312     return JNI_TRUE;
313 }
314 
315 
316 // set the playing state for the URI audio player
317 // to PLAYING (true) or PAUSED (false)
Java_com_example_nativeaudio_NativeAudio_setPlayingUriAudioPlayer(JNIEnv * env,jclass clazz,jboolean isPlaying)318 void Java_com_example_nativeaudio_NativeAudio_setPlayingUriAudioPlayer(JNIEnv* env,
319         jclass clazz, jboolean isPlaying)
320 {
321     SLresult result;
322 
323     // make sure the URI audio player was created
324     if (NULL != uriPlayerPlay) {
325 
326         // set the player's state
327         result = (*uriPlayerPlay)->SetPlayState(uriPlayerPlay, isPlaying ?
328             SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED);
329         assert(SL_RESULT_SUCCESS == result);
330 
331     }
332 
333 }
334 
335 
336 // set the whole file looping state for the URI audio player
Java_com_example_nativeaudio_NativeAudio_setLoopingUriAudioPlayer(JNIEnv * env,jclass clazz,jboolean isLooping)337 void Java_com_example_nativeaudio_NativeAudio_setLoopingUriAudioPlayer(JNIEnv* env,
338         jclass clazz, jboolean isLooping)
339 {
340     SLresult result;
341 
342     // make sure the URI audio player was created
343     if (NULL != uriPlayerSeek) {
344 
345         // set the looping state
346         result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, (SLboolean) isLooping, 0,
347                 SL_TIME_UNKNOWN);
348         assert(SL_RESULT_SUCCESS == result);
349 
350     }
351 
352 }
353 
354 
355 // expose the mute/solo APIs to Java for one of the 3 players
356 
getMuteSolo()357 static SLMuteSoloItf getMuteSolo()
358 {
359     if (uriPlayerMuteSolo != NULL)
360         return uriPlayerMuteSolo;
361     else if (fdPlayerMuteSolo != NULL)
362         return fdPlayerMuteSolo;
363     else
364         return bqPlayerMuteSolo;
365 }
366 
Java_com_example_nativeaudio_NativeAudio_setChannelMuteUriAudioPlayer(JNIEnv * env,jclass clazz,jint chan,jboolean mute)367 void Java_com_example_nativeaudio_NativeAudio_setChannelMuteUriAudioPlayer(JNIEnv* env,
368         jclass clazz, jint chan, jboolean mute)
369 {
370     SLresult result;
371     SLMuteSoloItf muteSoloItf = getMuteSolo();
372     if (NULL != muteSoloItf) {
373         result = (*muteSoloItf)->SetChannelMute(muteSoloItf, chan, mute);
374         assert(SL_RESULT_SUCCESS == result);
375     }
376 }
377 
Java_com_example_nativeaudio_NativeAudio_setChannelSoloUriAudioPlayer(JNIEnv * env,jclass clazz,jint chan,jboolean solo)378 void Java_com_example_nativeaudio_NativeAudio_setChannelSoloUriAudioPlayer(JNIEnv* env,
379         jclass clazz, jint chan, jboolean solo)
380 {
381     SLresult result;
382     SLMuteSoloItf muteSoloItf = getMuteSolo();
383     if (NULL != muteSoloItf) {
384         result = (*muteSoloItf)->SetChannelSolo(muteSoloItf, chan, solo);
385         assert(SL_RESULT_SUCCESS == result);
386     }
387 }
388 
Java_com_example_nativeaudio_NativeAudio_getNumChannelsUriAudioPlayer(JNIEnv * env,jclass clazz)389 int Java_com_example_nativeaudio_NativeAudio_getNumChannelsUriAudioPlayer(JNIEnv* env, jclass clazz)
390 {
391     SLuint8 numChannels;
392     SLresult result;
393     SLMuteSoloItf muteSoloItf = getMuteSolo();
394     if (NULL != muteSoloItf) {
395         result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels);
396         if (SL_RESULT_PRECONDITIONS_VIOLATED == result) {
397             // channel count is not yet known
398             numChannels = 0;
399         } else {
400             assert(SL_RESULT_SUCCESS == result);
401         }
402     } else {
403         numChannels = 0;
404     }
405     return numChannels;
406 }
407 
408 // expose the volume APIs to Java for one of the 3 players
409 
getVolume()410 static SLVolumeItf getVolume()
411 {
412     if (uriPlayerVolume != NULL)
413         return uriPlayerVolume;
414     else if (fdPlayerVolume != NULL)
415         return fdPlayerVolume;
416     else
417         return bqPlayerVolume;
418 }
419 
Java_com_example_nativeaudio_NativeAudio_setVolumeUriAudioPlayer(JNIEnv * env,jclass clazz,jint millibel)420 void Java_com_example_nativeaudio_NativeAudio_setVolumeUriAudioPlayer(JNIEnv* env, jclass clazz,
421         jint millibel)
422 {
423     SLresult result;
424     SLVolumeItf volumeItf = getVolume();
425     if (NULL != volumeItf) {
426         result = (*volumeItf)->SetVolumeLevel(volumeItf, millibel);
427         assert(SL_RESULT_SUCCESS == result);
428     }
429 }
430 
Java_com_example_nativeaudio_NativeAudio_setMuteUriAudioPlayer(JNIEnv * env,jclass clazz,jboolean mute)431 void Java_com_example_nativeaudio_NativeAudio_setMuteUriAudioPlayer(JNIEnv* env, jclass clazz,
432         jboolean mute)
433 {
434     SLresult result;
435     SLVolumeItf volumeItf = getVolume();
436     if (NULL != volumeItf) {
437         result = (*volumeItf)->SetMute(volumeItf, mute);
438         assert(SL_RESULT_SUCCESS == result);
439     }
440 }
441 
Java_com_example_nativeaudio_NativeAudio_enableStereoPositionUriAudioPlayer(JNIEnv * env,jclass clazz,jboolean enable)442 void Java_com_example_nativeaudio_NativeAudio_enableStereoPositionUriAudioPlayer(JNIEnv* env,
443         jclass clazz, jboolean enable)
444 {
445     SLresult result;
446     SLVolumeItf volumeItf = getVolume();
447     if (NULL != volumeItf) {
448         result = (*volumeItf)->EnableStereoPosition(volumeItf, enable);
449         assert(SL_RESULT_SUCCESS == result);
450     }
451 }
452 
Java_com_example_nativeaudio_NativeAudio_setStereoPositionUriAudioPlayer(JNIEnv * env,jclass clazz,jint permille)453 void Java_com_example_nativeaudio_NativeAudio_setStereoPositionUriAudioPlayer(JNIEnv* env,
454         jclass clazz, jint permille)
455 {
456     SLresult result;
457     SLVolumeItf volumeItf = getVolume();
458     if (NULL != volumeItf) {
459         result = (*volumeItf)->SetStereoPosition(volumeItf, permille);
460         assert(SL_RESULT_SUCCESS == result);
461     }
462 }
463 
464 // enable reverb on the buffer queue player
Java_com_example_nativeaudio_NativeAudio_enableReverb(JNIEnv * env,jclass clazz,jboolean enabled)465 jboolean Java_com_example_nativeaudio_NativeAudio_enableReverb(JNIEnv* env, jclass clazz,
466         jboolean enabled)
467 {
468     SLresult result;
469 
470     // we might not have been able to add environmental reverb to the output mix
471     if (NULL == outputMixEnvironmentalReverb) {
472         return JNI_FALSE;
473     }
474 
475     result = (*bqPlayerEffectSend)->EnableEffectSend(bqPlayerEffectSend,
476             outputMixEnvironmentalReverb, (SLboolean) enabled, (SLmillibel) 0);
477     // and even if environmental reverb was present, it might no longer be available
478     if (SL_RESULT_SUCCESS != result) {
479         return JNI_FALSE;
480     }
481 
482     return JNI_TRUE;
483 }
484 
485 
486 // select the desired clip and play count, and enqueue the first buffer if idle
Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv * env,jclass clazz,jint which,jint count)487 jboolean Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv* env, jclass clazz, jint which,
488         jint count)
489 {
490     short *oldBuffer = nextBuffer;
491     switch (which) {
492     case 0:     // CLIP_NONE
493         nextBuffer = (short *) NULL;
494         nextSize = 0;
495         break;
496     case 1:     // CLIP_HELLO
497         nextBuffer = (short *) hello;
498         nextSize = sizeof(hello);
499         break;
500     case 2:     // CLIP_ANDROID
501         nextBuffer = (short *) android;
502         nextSize = sizeof(android);
503         break;
504     case 3:     // CLIP_SAWTOOTH
505         nextBuffer = sawtoothBuffer;
506         nextSize = sizeof(sawtoothBuffer);
507         break;
508     case 4:     // CLIP_PLAYBACK
509         // we recorded at 16 kHz, but are playing buffers at 8 Khz, so do a primitive down-sample
510         if (recorderSR == SL_SAMPLINGRATE_16) {
511             unsigned i;
512             for (i = 0; i < recorderSize; i += 2 * sizeof(short)) {
513                 recorderBuffer[i >> 2] = recorderBuffer[i >> 1];
514             }
515             recorderSR = SL_SAMPLINGRATE_8;
516             recorderSize >>= 1;
517         }
518         nextBuffer = recorderBuffer;
519         nextSize = recorderSize;
520         break;
521     default:
522         nextBuffer = NULL;
523         nextSize = 0;
524         break;
525     }
526     nextCount = count;
527     if (nextSize > 0) {
528         // here we only enqueue one buffer because it is a long clip,
529         // but for streaming playback we would typically enqueue at least 2 buffers to start
530         SLresult result;
531         result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
532         if (SL_RESULT_SUCCESS != result) {
533             return JNI_FALSE;
534         }
535     }
536 
537     return JNI_TRUE;
538 }
539 
540 
541 // create asset audio player
Java_com_example_nativeaudio_NativeAudio_createAssetAudioPlayer(JNIEnv * env,jclass clazz,jobject assetManager,jstring filename)542 jboolean Java_com_example_nativeaudio_NativeAudio_createAssetAudioPlayer(JNIEnv* env, jclass clazz,
543         jobject assetManager, jstring filename)
544 {
545     SLresult result;
546 
547     // convert Java string to UTF-8
548     const jbyte *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
549     assert(NULL != utf8);
550 
551     // use asset manager to open asset by filename
552     AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
553     assert(NULL != mgr);
554     AAsset* asset = AAssetManager_open(mgr, (const char *) utf8, AASSET_MODE_UNKNOWN);
555 
556     // release the Java string and UTF-8
557     (*env)->ReleaseStringUTFChars(env, filename, utf8);
558 
559     // the asset might not be found
560     if (NULL == asset) {
561         return JNI_FALSE;
562     }
563 
564     // open asset as file descriptor
565     off_t start, length;
566     int fd = AAsset_openFileDescriptor(asset, &start, &length);
567     assert(0 <= fd);
568     AAsset_close(asset);
569 
570     // configure audio source
571     SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
572     SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
573     SLDataSource audioSrc = {&loc_fd, &format_mime};
574 
575     // configure audio sink
576     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
577     SLDataSink audioSnk = {&loc_outmix, NULL};
578 
579     // create audio player
580     const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME};
581     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
582     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &fdPlayerObject, &audioSrc, &audioSnk,
583             3, ids, req);
584     assert(SL_RESULT_SUCCESS == result);
585 
586     // realize the player
587     result = (*fdPlayerObject)->Realize(fdPlayerObject, SL_BOOLEAN_FALSE);
588     assert(SL_RESULT_SUCCESS == result);
589 
590     // get the play interface
591     result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_PLAY, &fdPlayerPlay);
592     assert(SL_RESULT_SUCCESS == result);
593 
594     // get the seek interface
595     result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_SEEK, &fdPlayerSeek);
596     assert(SL_RESULT_SUCCESS == result);
597 
598     // get the mute/solo interface
599     result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_MUTESOLO, &fdPlayerMuteSolo);
600     assert(SL_RESULT_SUCCESS == result);
601 
602     // get the volume interface
603     result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_VOLUME, &fdPlayerVolume);
604     assert(SL_RESULT_SUCCESS == result);
605 
606     // enable whole file looping
607     result = (*fdPlayerSeek)->SetLoop(fdPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN);
608     assert(SL_RESULT_SUCCESS == result);
609 
610     return JNI_TRUE;
611 }
612 
613 
614 // set the playing state for the asset audio player
Java_com_example_nativeaudio_NativeAudio_setPlayingAssetAudioPlayer(JNIEnv * env,jclass clazz,jboolean isPlaying)615 void Java_com_example_nativeaudio_NativeAudio_setPlayingAssetAudioPlayer(JNIEnv* env,
616         jclass clazz, jboolean isPlaying)
617 {
618     SLresult result;
619 
620     // make sure the asset audio player was created
621     if (NULL != fdPlayerPlay) {
622 
623         // set the player's state
624         result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, isPlaying ?
625             SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED);
626         assert(SL_RESULT_SUCCESS == result);
627 
628     }
629 
630 }
631 
632 
633 // create audio recorder
Java_com_example_nativeaudio_NativeAudio_createAudioRecorder(JNIEnv * env,jclass clazz)634 jboolean Java_com_example_nativeaudio_NativeAudio_createAudioRecorder(JNIEnv* env, jclass clazz)
635 {
636     SLresult result;
637 
638     // configure audio source
639     SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
640             SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
641     SLDataSource audioSrc = {&loc_dev, NULL};
642 
643     // configure audio sink
644     SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
645     SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16,
646         SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
647         SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};
648     SLDataSink audioSnk = {&loc_bq, &format_pcm};
649 
650     // create audio recorder
651     // (requires the RECORD_AUDIO permission)
652     const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
653     const SLboolean req[1] = {SL_BOOLEAN_TRUE};
654     result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc,
655             &audioSnk, 1, id, req);
656     if (SL_RESULT_SUCCESS != result) {
657         return JNI_FALSE;
658     }
659 
660     // realize the audio recorder
661     result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
662     if (SL_RESULT_SUCCESS != result) {
663         return JNI_FALSE;
664     }
665 
666     // get the record interface
667     result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
668     assert(SL_RESULT_SUCCESS == result);
669 
670     // get the buffer queue interface
671     result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
672             &recorderBufferQueue);
673     assert(SL_RESULT_SUCCESS == result);
674 
675     // register callback on the buffer queue
676     result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback,
677             NULL);
678     assert(SL_RESULT_SUCCESS == result);
679 
680     return JNI_TRUE;
681 }
682 
683 
684 // set the recording state for the audio recorder
Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv * env,jclass clazz)685 void Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv* env, jclass clazz)
686 {
687     SLresult result;
688 
689     // in case already recording, stop recording and clear buffer queue
690     result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
691     assert(SL_RESULT_SUCCESS == result);
692     result = (*recorderBufferQueue)->Clear(recorderBufferQueue);
693     assert(SL_RESULT_SUCCESS == result);
694 
695     // the buffer is not valid for playback yet
696     recorderSize = 0;
697 
698     // enqueue an empty buffer to be filled by the recorder
699     // (for streaming recording, we would enqueue at least 2 empty buffers to start things off)
700     result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer,
701             RECORDER_FRAMES * sizeof(short));
702     // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
703     // which for this code example would indicate a programming error
704     assert(SL_RESULT_SUCCESS == result);
705 
706     // start recording
707     result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
708     assert(SL_RESULT_SUCCESS == result);
709 
710 }
711 
712 
713 // shut down the native audio system
Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv * env,jclass clazz)714 void Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv* env, jclass clazz)
715 {
716 
717     // destroy buffer queue audio player object, and invalidate all associated interfaces
718     if (bqPlayerObject != NULL) {
719         (*bqPlayerObject)->Destroy(bqPlayerObject);
720         bqPlayerObject = NULL;
721         bqPlayerPlay = NULL;
722         bqPlayerBufferQueue = NULL;
723         bqPlayerEffectSend = NULL;
724         bqPlayerMuteSolo = NULL;
725         bqPlayerVolume = NULL;
726     }
727 
728     // destroy file descriptor audio player object, and invalidate all associated interfaces
729     if (fdPlayerObject != NULL) {
730         (*fdPlayerObject)->Destroy(fdPlayerObject);
731         fdPlayerObject = NULL;
732         fdPlayerPlay = NULL;
733         fdPlayerSeek = NULL;
734         fdPlayerMuteSolo = NULL;
735         fdPlayerVolume = NULL;
736     }
737 
738     // destroy URI audio player object, and invalidate all associated interfaces
739     if (uriPlayerObject != NULL) {
740         (*uriPlayerObject)->Destroy(uriPlayerObject);
741         uriPlayerObject = NULL;
742         uriPlayerPlay = NULL;
743         uriPlayerSeek = NULL;
744         uriPlayerMuteSolo = NULL;
745         uriPlayerVolume = NULL;
746     }
747 
748     // destroy audio recorder object, and invalidate all associated interfaces
749     if (recorderObject != NULL) {
750         (*recorderObject)->Destroy(recorderObject);
751         recorderObject = NULL;
752         recorderRecord = NULL;
753         recorderBufferQueue = NULL;
754     }
755 
756     // destroy output mix object, and invalidate all associated interfaces
757     if (outputMixObject != NULL) {
758         (*outputMixObject)->Destroy(outputMixObject);
759         outputMixObject = NULL;
760         outputMixEnvironmentalReverb = NULL;
761     }
762 
763     // destroy engine object, and invalidate all associated interfaces
764     if (engineObject != NULL) {
765         (*engineObject)->Destroy(engineObject);
766         engineObject = NULL;
767         engineEngine = NULL;
768     }
769 
770 }
771