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
42static const char hello[] =
43#include "hello_clip.h"
44;
45
46static const char android[] =
47#include "android_clip.h"
48;
49
50// engine interfaces
51static SLObjectItf engineObject = NULL;
52static SLEngineItf engineEngine;
53
54// output mix interfaces
55static SLObjectItf outputMixObject = NULL;
56static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
57
58// buffer queue player interfaces
59static SLObjectItf bqPlayerObject = NULL;
60static SLPlayItf bqPlayerPlay;
61static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
62static SLEffectSendItf bqPlayerEffectSend;
63static SLMuteSoloItf bqPlayerMuteSolo;
64static SLVolumeItf bqPlayerVolume;
65
66// aux effect on the output mix, used by the buffer queue player
67static const SLEnvironmentalReverbSettings reverbSettings =
68    SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
69
70// URI player interfaces
71static SLObjectItf uriPlayerObject = NULL;
72static SLPlayItf uriPlayerPlay;
73static SLSeekItf uriPlayerSeek;
74static SLMuteSoloItf uriPlayerMuteSolo;
75static SLVolumeItf uriPlayerVolume;
76
77// file descriptor player interfaces
78static SLObjectItf fdPlayerObject = NULL;
79static SLPlayItf fdPlayerPlay;
80static SLSeekItf fdPlayerSeek;
81static SLMuteSoloItf fdPlayerMuteSolo;
82static SLVolumeItf fdPlayerVolume;
83
84// recorder interfaces
85static SLObjectItf recorderObject = NULL;
86static SLRecordItf recorderRecord;
87static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
88
89// synthesized sawtooth clip
90#define SAWTOOTH_FRAMES 8000
91static 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)
95static short recorderBuffer[RECORDER_FRAMES];
96static unsigned recorderSize = 0;
97static SLmilliHertz recorderSR;
98
99// pointer and size of the next player buffer to enqueue, and number of remaining buffers
100static short *nextBuffer;
101static unsigned nextSize;
102static int nextCount;
103
104
105// synthesize a mono sawtooth wave and place it into a buffer (called automatically on load)
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
116void 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
133void 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
149void 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
191void 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
256jboolean 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)
318void 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
337void 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
357static 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
367void 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
378void 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
389int 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
410static 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
420void 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
431void 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
442void 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
453void 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
465jboolean 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
487jboolean 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
542jboolean 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
615void 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
634jboolean 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
685void 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
714void 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