1809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten/* 2809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * Copyright (C) 2010 The Android Open Source Project 3809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * 4809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * you may not use this file except in compliance with the License. 6809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * You may obtain a copy of the License at 7809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * 8809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * 10809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * Unless required by applicable law or agreed to in writing, software 11809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * See the License for the specific language governing permissions and 14809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * limitations under the License. 15809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * 16809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten */ 17809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 18809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten/* This is a JNI example where we use native methods to play sounds 19809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * using OpenSL ES. See the corresponding Java source file located at: 20809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * 21809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten * src/com/example/nativeaudio/NativeAudio/NativeAudio.java 22809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten */ 23809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 24809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <assert.h> 25809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <jni.h> 26809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <string.h> 27809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 28809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message"); 29809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// #include <android/log.h> 30809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 31809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// for native audio 32809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <SLES/OpenSLES.h> 33ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten#include <SLES/OpenSLES_Android.h> 34809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 35809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// for native asset manager 36809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <sys/types.h> 37809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <android/asset_manager.h> 38809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include <android/asset_manager_jni.h> 39809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 40809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// pre-recorded sound clips, both are 8 kHz mono 16-bit signed little endian 41809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 42809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic const char hello[] = 43809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include "hello_clip.h" 44809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten; 45809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 46809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic const char android[] = 47809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#include "android_clip.h" 48809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten; 49809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 50809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// engine interfaces 51809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLObjectItf engineObject = NULL; 52809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLEngineItf engineEngine; 53809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 54809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// output mix interfaces 55809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLObjectItf outputMixObject = NULL; 56809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL; 57809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 58809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// buffer queue player interfaces 59809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLObjectItf bqPlayerObject = NULL; 60809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLPlayItf bqPlayerPlay; 61809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; 62809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLEffectSendItf bqPlayerEffectSend; 63ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLMuteSoloItf bqPlayerMuteSolo; 64ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLVolumeItf bqPlayerVolume; 65809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 66809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// aux effect on the output mix, used by the buffer queue player 67809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic const SLEnvironmentalReverbSettings reverbSettings = 68809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 69809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 70809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// URI player interfaces 71809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLObjectItf uriPlayerObject = NULL; 72809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLPlayItf uriPlayerPlay; 73809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLSeekItf uriPlayerSeek; 74ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLMuteSoloItf uriPlayerMuteSolo; 75ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLVolumeItf uriPlayerVolume; 76809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 77809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// file descriptor player interfaces 78809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLObjectItf fdPlayerObject = NULL; 79809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLPlayItf fdPlayerPlay; 80809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLSeekItf fdPlayerSeek; 81ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLMuteSoloItf fdPlayerMuteSolo; 82ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLVolumeItf fdPlayerVolume; 83809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 84809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// recorder interfaces 85809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLObjectItf recorderObject = NULL; 86809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLRecordItf recorderRecord; 87809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLAndroidSimpleBufferQueueItf recorderBufferQueue; 88809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 89809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// synthesized sawtooth clip 90809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#define SAWTOOTH_FRAMES 8000 91809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic short sawtoothBuffer[SAWTOOTH_FRAMES]; 92809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 93809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// 5 seconds of recorded audio at 16 kHz mono, 16-bit signed little endian 94809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten#define RECORDER_FRAMES (16000 * 5) 95809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic short recorderBuffer[RECORDER_FRAMES]; 96809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic unsigned recorderSize = 0; 97809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic SLmilliHertz recorderSR; 98809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 99809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// pointer and size of the next player buffer to enqueue, and number of remaining buffers 100809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic short *nextBuffer; 101809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic unsigned nextSize; 102809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenstatic int nextCount; 103809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 104809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 105809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// synthesize a mono sawtooth wave and place it into a buffer (called automatically on load) 106809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten__attribute__((constructor)) static void onDlOpen(void) 107809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 108809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten unsigned i; 109809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten for (i = 0; i < SAWTOOTH_FRAMES; ++i) { 110809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten sawtoothBuffer[i] = 32768 - ((i % 100) * 660); 111809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 112809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 113809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 114809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 115809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// this callback handler is called every time a buffer finishes playing 116809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) 117809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 118809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(bq == bqPlayerBufferQueue); 119809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(NULL == context); 120809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // for streaming playback, replace this test by logic to find and fill the next buffer 121809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) { 122809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 123809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // enqueue another buffer 124809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize); 125809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, 126809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // which for this code example would indicate a programming error 127809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 128c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 129809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 130809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 131809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 132809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 133809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// this callback handler is called every time a buffer finishes recording 134809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) 135809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 1367986b0872e2f6be7c9cb9d85ef2684c767ba245aAndrew Hsieh assert(bq == recorderBufferQueue); 137809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(NULL == context); 138809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // for streaming recording, here we would call Enqueue to give recorder the next buffer to fill 139809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // but instead, this is a one-time buffer so we stop recording 140809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 141809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); 142809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS == result) { 143809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderSize = RECORDER_FRAMES * sizeof(short); 144809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderSR = SL_SAMPLINGRATE_16; 145809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 146809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 147809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 148809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 149809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// create the engine and output mix objects 150809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_createEngine(JNIEnv* env, jclass clazz) 151809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 152809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 153809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 154809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // create engine 155809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 156809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 157c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 158809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 159809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // realize the engine 160809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 161809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 162c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 163809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 164809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the engine interface, which is needed in order to create other objects 165809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 166809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 167c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 168809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 169809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // create output mix, with environmental reverb specified as a non-required interface 170809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; 171809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten const SLboolean req[1] = {SL_BOOLEAN_FALSE}; 172809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req); 173809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 174c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 175809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 176809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // realize the output mix 177809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 178809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 179c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 180809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 181809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the environmental reverb interface 182809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // this could fail if the environmental reverb effect is not available, 183809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // either because the feature is not present, excessive CPU load, or 184809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted 185809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, 186809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten &outputMixEnvironmentalReverb); 187809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS == result) { 188809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties( 189809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten outputMixEnvironmentalReverb, &reverbSettings); 190c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 191809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 192809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // ignore unsuccessful result codes for environmental reverb, as it is optional for this example 193809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 194809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 195809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 196809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 197809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// create buffer queue audio player 198809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_createBufferQueueAudioPlayer(JNIEnv* env, 199809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jclass clazz) 200809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 201809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 202809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 203809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio source 204809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; 205809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_8, 206809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, 207809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN}; 208809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSource audioSrc = {&loc_bufq, &format_pcm}; 209809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 210809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio sink 211809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 212809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSink audioSnk = {&loc_outmix, NULL}; 213809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 214809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // create audio player 215ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, 216ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME}; 217ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, 218ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE}; 219809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 220ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 3, ids, req); 221809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 222c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 223809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 224809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // realize the player 225809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); 226809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 227c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 228809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 229809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the play interface 230809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); 231809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 232c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 233809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 234809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the buffer queue interface 235809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, 236809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten &bqPlayerBufferQueue); 237809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 238c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 239809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 240809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // register callback on the buffer queue 241809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); 242809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 243c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 244809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 245809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the effect send interface 246809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, 247809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten &bqPlayerEffectSend); 248809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 249c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 250809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 251ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten#if 0 // mute/solo is not supported for sources that are known to be mono, as this is 252ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // get the mute/solo interface 253ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo); 254ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 255c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 256ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten#endif 257ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 258ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // get the volume interface 259ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); 260ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 261c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 262ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 263809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // set the player's state to playing 264809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); 265809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 266c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 267809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 268809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 269809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 270809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// create URI audio player 271809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenjboolean Java_com_example_nativeaudio_NativeAudio_createUriAudioPlayer(JNIEnv* env, jclass clazz, 272809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jstring uri) 273809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 274809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 275809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 276809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // convert Java string to UTF-8 2774ba2dd50808be479df49c15b0baf68fd57220c17Andrew Hsieh const char *utf8 = (*env)->GetStringUTFChars(env, uri, NULL); 278809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(NULL != utf8); 279809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 280809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio source 281809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // (requires the INTERNET permission depending on the uri parameter) 282809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_URI loc_uri = {SL_DATALOCATOR_URI, (SLchar *) utf8}; 283809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; 284809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSource audioSrc = {&loc_uri, &format_mime}; 285809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 286809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio sink 287809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 288809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSink audioSnk = {&loc_outmix, NULL}; 289809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 290809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // create audio player 291ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME}; 292ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 293809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &uriPlayerObject, &audioSrc, 294ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten &audioSnk, 3, ids, req); 295809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // note that an invalid URI is not detected here, but during prepare/prefetch on Android, 296809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // or possibly during Realize on other platforms 297809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 298c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 299809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 300809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // release the Java string and UTF-8 301809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*env)->ReleaseStringUTFChars(env, uri, utf8); 302809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 303809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // realize the player 304809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*uriPlayerObject)->Realize(uriPlayerObject, SL_BOOLEAN_FALSE); 305809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // this will always succeed on Android, but we check result for portability to other platforms 306809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS != result) { 307809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*uriPlayerObject)->Destroy(uriPlayerObject); 308809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten uriPlayerObject = NULL; 309809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 310809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 311809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 312809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the play interface 313809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, &uriPlayerPlay); 314809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 315c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 316809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 317809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the seek interface 318809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_SEEK, &uriPlayerSeek); 319809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 320c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 321809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 322ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // get the mute/solo interface 323ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_MUTESOLO, &uriPlayerMuteSolo); 324ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 325c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 326ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 327ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // get the volume interface 328ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_VOLUME, &uriPlayerVolume); 329809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 330c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 331809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 332809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_TRUE; 333809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 334809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 335809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 336809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// set the playing state for the URI audio player 337ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten// to PLAYING (true) or PAUSED (false) 338809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setPlayingUriAudioPlayer(JNIEnv* env, 339809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jclass clazz, jboolean isPlaying) 340809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 341809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 342809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 343809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // make sure the URI audio player was created 344809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (NULL != uriPlayerPlay) { 345809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 346809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // set the player's state 347809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*uriPlayerPlay)->SetPlayState(uriPlayerPlay, isPlaying ? 348809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED); 349809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 350c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 351809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 352809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 353809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 354809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 355809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 356ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten// set the whole file looping state for the URI audio player 357ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setLoopingUriAudioPlayer(JNIEnv* env, 358ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jclass clazz, jboolean isLooping) 359ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 360ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 361ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 362ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // make sure the URI audio player was created 363ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != uriPlayerSeek) { 364ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 365ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // set the looping state 366ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, (SLboolean) isLooping, 0, 367ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SL_TIME_UNKNOWN); 368ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 369c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 370ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 371ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 372ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 373ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 374ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 375ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten// expose the mute/solo APIs to Java for one of the 3 players 376ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 377ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLMuteSoloItf getMuteSolo() 378ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 379ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (uriPlayerMuteSolo != NULL) 380ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return uriPlayerMuteSolo; 381ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten else if (fdPlayerMuteSolo != NULL) 382ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return fdPlayerMuteSolo; 383ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten else 384ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return bqPlayerMuteSolo; 385ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 386ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 387ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setChannelMuteUriAudioPlayer(JNIEnv* env, 388ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jclass clazz, jint chan, jboolean mute) 389ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 390ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 391ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLMuteSoloItf muteSoloItf = getMuteSolo(); 392ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != muteSoloItf) { 393ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*muteSoloItf)->SetChannelMute(muteSoloItf, chan, mute); 394ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 395c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 396ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 397ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 398ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 399ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setChannelSoloUriAudioPlayer(JNIEnv* env, 400ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jclass clazz, jint chan, jboolean solo) 401ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 402ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 403ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLMuteSoloItf muteSoloItf = getMuteSolo(); 404ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != muteSoloItf) { 405ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*muteSoloItf)->SetChannelSolo(muteSoloItf, chan, solo); 406ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 407c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 408ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 409ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 410ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 411ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenint Java_com_example_nativeaudio_NativeAudio_getNumChannelsUriAudioPlayer(JNIEnv* env, jclass clazz) 412ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 413ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLuint8 numChannels; 414ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 415ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLMuteSoloItf muteSoloItf = getMuteSolo(); 416ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != muteSoloItf) { 417ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*muteSoloItf)->GetNumChannels(muteSoloItf, &numChannels); 418ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (SL_RESULT_PRECONDITIONS_VIOLATED == result) { 419ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // channel count is not yet known 420ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten numChannels = 0; 421ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } else { 422ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 423ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 424ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } else { 425ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten numChannels = 0; 426ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 427ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return numChannels; 428ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 429ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 430ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten// expose the volume APIs to Java for one of the 3 players 431ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 432ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenstatic SLVolumeItf getVolume() 433ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 434ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (uriPlayerVolume != NULL) 435ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return uriPlayerVolume; 436ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten else if (fdPlayerVolume != NULL) 437ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return fdPlayerVolume; 438ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten else 439ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten return bqPlayerVolume; 440ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 441ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 442ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setVolumeUriAudioPlayer(JNIEnv* env, jclass clazz, 443ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jint millibel) 444ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 445ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 446ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLVolumeItf volumeItf = getVolume(); 447ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != volumeItf) { 448ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*volumeItf)->SetVolumeLevel(volumeItf, millibel); 449ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 450c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 451ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 452ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 453ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 454ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setMuteUriAudioPlayer(JNIEnv* env, jclass clazz, 455ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jboolean mute) 456ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 457ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 458ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLVolumeItf volumeItf = getVolume(); 459ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != volumeItf) { 460ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*volumeItf)->SetMute(volumeItf, mute); 461ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 462c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 463ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 464ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 465ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 466ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_enableStereoPositionUriAudioPlayer(JNIEnv* env, 467ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jclass clazz, jboolean enable) 468ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 469ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 470ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLVolumeItf volumeItf = getVolume(); 471ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != volumeItf) { 472ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*volumeItf)->EnableStereoPosition(volumeItf, enable); 473ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 474c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 475ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 476ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 477ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 478ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setStereoPositionUriAudioPlayer(JNIEnv* env, 479ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten jclass clazz, jint permille) 480ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten{ 481ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLresult result; 482ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten SLVolumeItf volumeItf = getVolume(); 483ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten if (NULL != volumeItf) { 484ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*volumeItf)->SetStereoPosition(volumeItf, permille); 485ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 486c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 487ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten } 488ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten} 489ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 490809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// enable reverb on the buffer queue player 491809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenjboolean Java_com_example_nativeaudio_NativeAudio_enableReverb(JNIEnv* env, jclass clazz, 492809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jboolean enabled) 493809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 494809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 495809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 496809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // we might not have been able to add environmental reverb to the output mix 497809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (NULL == outputMixEnvironmentalReverb) { 498809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 499809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 500809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 501809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerEffectSend)->EnableEffectSend(bqPlayerEffectSend, 502809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten outputMixEnvironmentalReverb, (SLboolean) enabled, (SLmillibel) 0); 503809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // and even if environmental reverb was present, it might no longer be available 504809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS != result) { 505809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 506809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 507809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 508809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_TRUE; 509809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 510809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 511809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 512809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// select the desired clip and play count, and enqueue the first buffer if idle 513809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenjboolean Java_com_example_nativeaudio_NativeAudio_selectClip(JNIEnv* env, jclass clazz, jint which, 514809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jint count) 515809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 516809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten switch (which) { 517809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten case 0: // CLIP_NONE 518809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextBuffer = (short *) NULL; 519809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextSize = 0; 520809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten break; 521809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten case 1: // CLIP_HELLO 522809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextBuffer = (short *) hello; 523809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextSize = sizeof(hello); 524809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten break; 525809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten case 2: // CLIP_ANDROID 526809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextBuffer = (short *) android; 527809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextSize = sizeof(android); 528809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten break; 529809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten case 3: // CLIP_SAWTOOTH 530809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextBuffer = sawtoothBuffer; 531809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextSize = sizeof(sawtoothBuffer); 532809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten break; 533809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten case 4: // CLIP_PLAYBACK 534809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // we recorded at 16 kHz, but are playing buffers at 8 Khz, so do a primitive down-sample 535809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (recorderSR == SL_SAMPLINGRATE_16) { 536809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten unsigned i; 537809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten for (i = 0; i < recorderSize; i += 2 * sizeof(short)) { 538809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderBuffer[i >> 2] = recorderBuffer[i >> 1]; 539809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 540809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderSR = SL_SAMPLINGRATE_8; 541809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderSize >>= 1; 542809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 543809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextBuffer = recorderBuffer; 544809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextSize = recorderSize; 545809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten break; 546809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten default: 547809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextBuffer = NULL; 548809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextSize = 0; 549809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten break; 550809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 551809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten nextCount = count; 552809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (nextSize > 0) { 553809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // here we only enqueue one buffer because it is a long clip, 554809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // but for streaming playback we would typically enqueue at least 2 buffers to start 555809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 556809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize); 557809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS != result) { 558809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 559809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 560809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 561809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 562809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_TRUE; 563809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 564809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 565809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 566809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// create asset audio player 567809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenjboolean Java_com_example_nativeaudio_NativeAudio_createAssetAudioPlayer(JNIEnv* env, jclass clazz, 568809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jobject assetManager, jstring filename) 569809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 570809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 571809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 572809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // convert Java string to UTF-8 5734ba2dd50808be479df49c15b0baf68fd57220c17Andrew Hsieh const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL); 574809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(NULL != utf8); 575809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 576809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // use asset manager to open asset by filename 577809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten AAssetManager* mgr = AAssetManager_fromJava(env, assetManager); 578809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(NULL != mgr); 5794ba2dd50808be479df49c15b0baf68fd57220c17Andrew Hsieh AAsset* asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN); 580809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 581809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // release the Java string and UTF-8 582809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*env)->ReleaseStringUTFChars(env, filename, utf8); 583809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 584809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // the asset might not be found 585809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (NULL == asset) { 586809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 587809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 588809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 589809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // open asset as file descriptor 590809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten off_t start, length; 591809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten int fd = AAsset_openFileDescriptor(asset, &start, &length); 592809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(0 <= fd); 593809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten AAsset_close(asset); 594809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 595809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio source 596809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length}; 597809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED}; 598809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSource audioSrc = {&loc_fd, &format_mime}; 599809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 600809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio sink 601809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 602809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSink audioSnk = {&loc_outmix, NULL}; 603809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 604809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // create audio player 605ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME}; 606ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 607809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineEngine)->CreateAudioPlayer(engineEngine, &fdPlayerObject, &audioSrc, &audioSnk, 608ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 3, ids, req); 609809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 610c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 611809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 612809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // realize the player 613809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*fdPlayerObject)->Realize(fdPlayerObject, SL_BOOLEAN_FALSE); 614809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 615c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 616809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 617809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the play interface 618809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_PLAY, &fdPlayerPlay); 619809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 620c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 621809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 622809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the seek interface 623809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_SEEK, &fdPlayerSeek); 624809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 625c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 626809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 627ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // get the mute/solo interface 628ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_MUTESOLO, &fdPlayerMuteSolo); 629ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 630c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 631ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 632ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten // get the volume interface 633ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_VOLUME, &fdPlayerVolume); 634ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten assert(SL_RESULT_SUCCESS == result); 635c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 636ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten 637809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // enable whole file looping 638809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*fdPlayerSeek)->SetLoop(fdPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN); 639809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 640c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 641809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 642809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_TRUE; 643809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 644809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 645809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 646809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// set the playing state for the asset audio player 647809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_setPlayingAssetAudioPlayer(JNIEnv* env, 648809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten jclass clazz, jboolean isPlaying) 649809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 650809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 651809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 652809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // make sure the asset audio player was created 653809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (NULL != fdPlayerPlay) { 654809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 655809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // set the player's state 656809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, isPlaying ? 657809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED); 658809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 659c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 660809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 661809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 662809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 663809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 664809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 665809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// create audio recorder 666809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenjboolean Java_com_example_nativeaudio_NativeAudio_createAudioRecorder(JNIEnv* env, jclass clazz) 667809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 668809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 669809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 670809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio source 671809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, 672809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_DEFAULTDEVICEID_AUDIOINPUT, NULL}; 673809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSource audioSrc = {&loc_dev, NULL}; 674809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 675809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // configure audio sink 676809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; 677809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16, 678809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, 679809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN}; 680809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLDataSink audioSnk = {&loc_bq, &format_pcm}; 681809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 682809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // create audio recorder 683809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // (requires the RECORD_AUDIO permission) 684809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; 685809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten const SLboolean req[1] = {SL_BOOLEAN_TRUE}; 686809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, 687809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten &audioSnk, 1, id, req); 688809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS != result) { 689809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 690809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 691809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 692809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // realize the audio recorder 693809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE); 694809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (SL_RESULT_SUCCESS != result) { 695809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_FALSE; 696809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 697809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 698809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the record interface 699809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord); 700809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 701c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 702809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 703809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // get the buffer queue interface 704809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 705809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten &recorderBufferQueue); 706809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 707c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 708809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 709809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // register callback on the buffer queue 710809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, 711809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten NULL); 712809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 713c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 714809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 715809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten return JNI_TRUE; 716809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 717809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 718809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 719809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// set the recording state for the audio recorder 720809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_startRecording(JNIEnv* env, jclass clazz) 721809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 722809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten SLresult result; 723809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 724809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // in case already recording, stop recording and clear buffer queue 725809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); 726809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 727c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 728809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderBufferQueue)->Clear(recorderBufferQueue); 729809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 730c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 731809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 732809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // the buffer is not valid for playback yet 733809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderSize = 0; 734809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 735809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // enqueue an empty buffer to be filled by the recorder 736809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // (for streaming recording, we would enqueue at least 2 empty buffers to start things off) 737809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer, 738809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten RECORDER_FRAMES * sizeof(short)); 739809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, 740809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // which for this code example would indicate a programming error 741809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 742c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 743809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 744809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // start recording 745809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING); 746809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten assert(SL_RESULT_SUCCESS == result); 747c21a50504496ddc53598da246686ffd91941edfdAndrew Hsieh (void)result; 748809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 749809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 750809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 751809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten// shut down the native audio system 752809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kastenvoid Java_com_example_nativeaudio_NativeAudio_shutdown(JNIEnv* env, jclass clazz) 753809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten{ 754809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 755809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // destroy buffer queue audio player object, and invalidate all associated interfaces 756809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (bqPlayerObject != NULL) { 757809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*bqPlayerObject)->Destroy(bqPlayerObject); 758809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten bqPlayerObject = NULL; 759809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten bqPlayerPlay = NULL; 760809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten bqPlayerBufferQueue = NULL; 761809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten bqPlayerEffectSend = NULL; 762ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten bqPlayerMuteSolo = NULL; 763ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten bqPlayerVolume = NULL; 764809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 765809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 766809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // destroy file descriptor audio player object, and invalidate all associated interfaces 767809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (fdPlayerObject != NULL) { 768809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*fdPlayerObject)->Destroy(fdPlayerObject); 769809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten fdPlayerObject = NULL; 770809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten fdPlayerPlay = NULL; 771809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten fdPlayerSeek = NULL; 772ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten fdPlayerMuteSolo = NULL; 773ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten fdPlayerVolume = NULL; 774809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 775809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 776809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // destroy URI audio player object, and invalidate all associated interfaces 777809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (uriPlayerObject != NULL) { 778809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*uriPlayerObject)->Destroy(uriPlayerObject); 779809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten uriPlayerObject = NULL; 780809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten uriPlayerPlay = NULL; 781809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten uriPlayerSeek = NULL; 782ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten uriPlayerMuteSolo = NULL; 783ccdb9cb2b02d9296bac80dd3d6858534fffae7feGlenn Kasten uriPlayerVolume = NULL; 784809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 785809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 786809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // destroy audio recorder object, and invalidate all associated interfaces 787809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (recorderObject != NULL) { 788809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*recorderObject)->Destroy(recorderObject); 789809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderObject = NULL; 790809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderRecord = NULL; 791809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten recorderBufferQueue = NULL; 792809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 793809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 794809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // destroy output mix object, and invalidate all associated interfaces 795809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (outputMixObject != NULL) { 796809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*outputMixObject)->Destroy(outputMixObject); 797809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten outputMixObject = NULL; 798809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten outputMixEnvironmentalReverb = NULL; 799809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 800809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 801809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten // destroy engine object, and invalidate all associated interfaces 802809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten if (engineObject != NULL) { 803809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten (*engineObject)->Destroy(engineObject); 804809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten engineObject = NULL; 805809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten engineEngine = NULL; 806809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten } 807809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten 808809ec924d28657e8be8ca36871ce6ddbfedcdc40Glenn Kasten} 809