Home | History | Annotate | Download | only in jni
      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)
    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
    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
    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
    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
    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
    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)
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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
    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
    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
    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
    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
    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
    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