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