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