1e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer/*
2e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Copyright 2015 The Android Open Source Project
3e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
4e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Licensed under the Apache License, Version 2.0 (the "License");
5e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * you may not use this file except in compliance with the License.
6e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * You may obtain a copy of the License at
7e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
8e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *      http://www.apache.org/licenses/LICENSE-2.0
9e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
10e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Unless required by applicable law or agreed to in writing, software
11e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * distributed under the License is distributed on an "AS IS" BASIS,
12e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * See the License for the specific language governing permissions and
14e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * limitations under the License.
15e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer */
16e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
17e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <android/log.h>
18e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <assert.h>
19e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <jni.h>
20e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <malloc.h>
21e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <math.h>
22e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <sys/types.h>
23e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
24e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// for native audio
25e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <SLES/OpenSLES.h>
26e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <SLES/OpenSLES_Android.h>
27e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include <SLES/OpenSLES_AndroidConfiguration.h>
28e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
29e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#include "sync_clock.h"
30e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
31e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// logging
32e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#define APPNAME "WALT"
33e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
34e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// engine interfaces
35e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLObjectItf engineObject = NULL;
36e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLEngineItf engineEngine = NULL;
37e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
38e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// output mix interfaces
39e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLObjectItf outputMixObject = NULL;
40e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
41e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// buffer queue player interfaces
42e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLObjectItf bqPlayerObject = NULL;
43e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLPlayItf bqPlayerPlay = NULL;
44e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
45e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
46e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// recorder interfaces
47e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLObjectItf recorderObject = NULL;
48e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLRecordItf recorderRecord;
49e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic SLAndroidSimpleBufferQueueItf recorderBufferQueue;
50e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic volatile int bqPlayerRecorderBusy = 0;
51e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
52e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic unsigned int recorder_frames;
53e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic short* recorderBuffer;
54e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic unsigned recorderSize = 0;
55e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
56e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic unsigned int framesPerBuffer;
57e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
58e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#define CHANNELS 1  // 1 for mono, 2 for stereo
59e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
60e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// Each short represents a 16-bit audio sample
61e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic short* beepBuffer = NULL;
62e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic short* silenceBuffer = NULL;
63e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic unsigned int bufferSizeInBytes = 0;
64e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
65e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#define MAXIMUM_AMPLITUDE_VALUE 32767
66e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
67e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// how many times to play the wave table (so we can actually hear it)
68e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer#define BUFFERS_TO_PLAY 10
69e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
70e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic unsigned buffersRemaining = 0;
71e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerstatic short warmedUp = 0;
72e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
73e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
74e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// Timestamps
75e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// te - enqueue time
76e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// tc - callback time
77e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerint64_t te_play = 0, te_rec = 0, tc_rec = 0;
78e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
79e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer/**
80e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Create wave tables for audio out.
81e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer */
82e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmervoid createWaveTables(){
83e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    bufferSizeInBytes = framesPerBuffer * sizeof(*beepBuffer);
84e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    silenceBuffer = malloc(bufferSizeInBytes);
85e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    beepBuffer = malloc(bufferSizeInBytes);
86e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
87e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
88e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    __android_log_print(ANDROID_LOG_VERBOSE,
89e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        APPNAME,
90e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        "Creating wave tables, 1 channel. Frames: %i Buffer size (bytes): %i",
91e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        framesPerBuffer,
92e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        bufferSizeInBytes);
93e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
94e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    unsigned int i;
95e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    for (i = 0; i < framesPerBuffer; i++) {
96e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        silenceBuffer[i] = 0;
97e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        beepBuffer[i] = (i & 2 - 1) * MAXIMUM_AMPLITUDE_VALUE;
98e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // This fills a buffer that looks like [min, min, max, max, min, min...]
99e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // which is a square wave at 1/4 frequency of the sampling rate
100e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // for 48kHz sampling this is 12kHz pitch, still well audible.
101e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
102e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
103e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
104e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// this callback handler is called every time a buffer finishes playing
105ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, __attribute__((unused)) void *context)
106e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
107e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (bq == NULL) {
108e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        __android_log_print(ANDROID_LOG_ERROR, APPNAME, "buffer queue is null");
109e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
110e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(bq == bqPlayerBufferQueue);
111e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(NULL == context);
112e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
113e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (buffersRemaining > 0) { // continue playing tone
114e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        if(buffersRemaining == BUFFERS_TO_PLAY && warmedUp) {
115e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            // Enqueue the first non-silent buffer, save the timestamp
116e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            // For cold test Enqueue happens in playTone rather than here.
117e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            te_play = uptimeMicros();
118e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
119e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        buffersRemaining--;
120e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
121e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, beepBuffer,
122e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                                          bufferSizeInBytes);
123e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (void)result;
124e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        assert(SL_RESULT_SUCCESS == result);
125e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    } else if (warmedUp) {      // stop tone but keep playing silence
126e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, silenceBuffer,
127e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                                 bufferSizeInBytes);
128e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        assert(SL_RESULT_SUCCESS == result);
129e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (void) result;
130e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    } else {                    // stop playing completely
131e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
132e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        assert(SL_RESULT_SUCCESS == result);
133e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (void)result;
134e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
135e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Done playing tone");
136e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
137e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
138e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
139ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmerjlong Java_org_chromium_latency_walt_AudioTest_playTone(__attribute__((unused)) JNIEnv* env,
140ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                        __attribute__((unused)) jclass clazz){
141e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
142e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    int64_t t_start = uptimeMicros();
143e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    te_play = 0;
144e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
145e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
146e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
147e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (!warmedUp) {
148e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        result = (*bqPlayerBufferQueue)->Clear(bqPlayerBufferQueue);
149e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        assert(SL_RESULT_SUCCESS == result);
150e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (void)result;
151e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
152e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // Enqueue first buffer
153e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        te_play = uptimeMicros();
154e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, beepBuffer,
155e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                                 bufferSizeInBytes);
156e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        assert(SL_RESULT_SUCCESS == result);
157e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (void) result;
158e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
159e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
160e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        assert(SL_RESULT_SUCCESS == result);
161e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (void) result;
162e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
163e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        int dt_state = uptimeMicros() - t_start;
164e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "playTone() changed state to playing dt=%d us", dt_state);
165e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // TODO: this block takes lots of time (~13ms on Nexus 7) research this and decide how to measure.
166e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
167e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
168e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Playing tone");
169e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    buffersRemaining = BUFFERS_TO_PLAY;
170e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
171e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    return (jlong) t_start;
172e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
173e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
174e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
175e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// create the engine and output mix objects
176ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid Java_org_chromium_latency_walt_AudioTest_createEngine(__attribute__((unused)) JNIEnv* env,
177ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                           __attribute__((unused)) jclass clazz)
178e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
179e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Creating audio engine");
180e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
181e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
182e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
183e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // create engine
184e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
185e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
186e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
187e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
188e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // realize the engine
189e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
190e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
191e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
192e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
193e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // get the engine interface, which is needed in order to create other objects
194e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
195e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
196e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
197e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
198e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // create output mix,
199e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
200e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
201e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
202e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
203e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // realize the output mix
204e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
205e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
206e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
207e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
208e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
209ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid Java_org_chromium_latency_walt_AudioTest_destroyEngine(__attribute__((unused)) JNIEnv *env,
210ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                            __attribute__((unused)) jclass clazz)
211e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
212e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (bqPlayerObject != NULL) {
213e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (*bqPlayerObject)->Destroy(bqPlayerObject);
214e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        bqPlayerObject = NULL;
215e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
216e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
217e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (outputMixObject != NULL) {
218e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (*outputMixObject)->Destroy(outputMixObject);
219e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        outputMixObject = NULL;
220e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
221e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
222e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (engineObject != NULL) {
223e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (*engineObject)->Destroy(engineObject);
224e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        engineObject = NULL;
225e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
226e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
227e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
228e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// create buffer queue audio player
229ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid Java_org_chromium_latency_walt_AudioTest_createBufferQueueAudioPlayer(
230ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        __attribute__((unused)) JNIEnv* env,
231ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        __attribute__((unused)) jclass clazz,
232ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        jint optimalFrameRate,
233ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        jint optimalFramesPerBuffer)
234e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
235e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Creating audio player with frame rate %d and frames per buffer %d",
236e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        optimalFrameRate, optimalFramesPerBuffer);
237e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
238e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    framesPerBuffer = optimalFramesPerBuffer;
239e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    createWaveTables();
240e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
241e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
242e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
243e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // configure the audio source (supply data through a buffer queue in PCM format)
244e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_source;
245e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataFormat_PCM format_pcm;
246e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataSource audio_source;
247e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
248e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // source location
249e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    locator_bufferqueue_source.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
250e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    locator_bufferqueue_source.numBuffers = 1;
251e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
252e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // source format
253e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.formatType = SL_DATAFORMAT_PCM;
254e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.numChannels = 1;
255e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
256e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // Note: this shouldn't be called samplesPerSec it should be called *framesPerSec*
257e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // because when channels = 2 then there are 2 samples per frame.
258e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.samplesPerSec = (SLuint32) optimalFrameRate * 1000;
259e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
260e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.containerSize = 16;
261e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
262e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
263e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
264e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    audio_source.pLocator = &locator_bufferqueue_source;
265e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    audio_source.pFormat = &format_pcm;
266e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
267e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // configure the output: An output mix sink
268e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataLocator_OutputMix locator_output_mix;
269e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataSink audio_sink;
270e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
271e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    locator_output_mix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
272e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    locator_output_mix.outputMix = outputMixObject;
273e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
274e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    audio_sink.pLocator = &locator_output_mix;
275e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    audio_sink.pFormat = NULL;
276e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
277e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // create audio player
278e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // Note: Adding other output interfaces here will result in your audio being routed using the
279e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // normal path NOT the fast path
280e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    const SLInterfaceID interface_ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };
281e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    const SLboolean interfaces_required[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
282e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
283e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*engineEngine)->CreateAudioPlayer(
284e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        engineEngine,
285e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        &bqPlayerObject,
286e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        &audio_source,
287e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        &audio_sink,
288e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        2, // Number of interfaces
289e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        interface_ids,
290e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        interfaces_required
291e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    );
292e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
293e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
294e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
295e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
296e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // realize the player
297e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
298e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
299e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
300e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
301e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // get the play interface
302e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
303e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
304e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
305e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
306e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // get the buffer queue interface
307e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
308e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            &bqPlayerBufferQueue);
309e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
310e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
311e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
312e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // register callback on the buffer queue
313e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
314e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
315e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
316e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
317e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
318ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid Java_org_chromium_latency_walt_AudioTest_startWarmTest(__attribute__((unused)) JNIEnv* env,
319ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                            __attribute__((unused)) jclass clazz) {
320e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
321e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
322e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerBufferQueue)->Clear(bqPlayerBufferQueue);
323e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
324e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
325e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
326e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // enqueue some silence
327e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, silenceBuffer, bufferSizeInBytes);
328e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
329e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
330e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
331e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // set the player's state to playing
332e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
333e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
334e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
335e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
336e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    warmedUp = 1;
337e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
338e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
339ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid Java_org_chromium_latency_walt_AudioTest_stopTests(__attribute__((unused)) JNIEnv *env,
340ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                        __attribute__((unused)) jclass clazz) {
341e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
342e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
343e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
344e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
345e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
346e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
347e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    warmedUp = 0;
348e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
349e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
350e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// this callback handler is called every time a buffer finishes recording
351ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid bqRecorderCallback(__attribute__((unused)) SLAndroidSimpleBufferQueueItf bq,
352ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                        __attribute__((unused)) void *context)
353e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
354e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    tc_rec = uptimeMicros();
355e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(bq == recorderBufferQueue);
356e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(NULL == context);
357e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
358e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // for streaming recording, here we would call Enqueue to give recorder the next buffer to fill
359e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // but instead, this is a one-time buffer so we stop recording
360e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
361e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
362e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (SL_RESULT_SUCCESS == result) {
363e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        recorderSize = recorder_frames * sizeof(short);
364e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
365e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    bqPlayerRecorderBusy = 0;
366e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
367e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    //// TODO: Use small buffers and re-enqueue each time
368e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer,
369e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    //         recorder_frames * sizeof(short));
370e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // assert(SL_RESULT_SUCCESS == result);
371e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
372e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
373e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// create audio recorder
374ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmerjboolean Java_org_chromium_latency_walt_AudioTest_createAudioRecorder(
375ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        __attribute__((unused)) JNIEnv* env,
376ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        __attribute__((unused)) jclass clazz,
377ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        jint optimalFrameRate,
378ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        jint framesToRecord)
379e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
380e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
381e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
382e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Creating audio recorder with frame rate %d and frames to record %d",
383e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        optimalFrameRate, framesToRecord);
384e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // Allocate buffer
385e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    recorder_frames = framesToRecord;
386e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    recorderBuffer = malloc(sizeof(*recorderBuffer) * recorder_frames);
387e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
388e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // configure audio source
389e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataLocator_IODevice loc_dev = {
390e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            SL_DATALOCATOR_IODEVICE,
391e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            SL_IODEVICE_AUDIOINPUT,
392e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            SL_DEFAULTDEVICEID_AUDIOINPUT,
393e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            NULL
394e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        };
395e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataSource audioSrc = {&loc_dev, NULL};
396e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
397e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // configure audio sink
398e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataLocator_AndroidSimpleBufferQueue loc_bq;
399e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
400e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    loc_bq.numBuffers = 2;
401e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
402e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
403e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // source format
404e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataFormat_PCM format_pcm;
405e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.formatType = SL_DATAFORMAT_PCM;
406e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.numChannels = CHANNELS;
407e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // Note: this shouldn't be called samplesPerSec it should be called *framesPerSec*
408e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // because when channels = 2 then there are 2 samples per frame.
409e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.samplesPerSec = (SLuint32) optimalFrameRate * 1000;
410e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
411e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.containerSize = 16;
412e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
413e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
414e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
415e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
416e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLDataSink audioSnk = {&loc_bq, &format_pcm};
417e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
418e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // create audio recorder
419e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // (requires the RECORD_AUDIO permission)
420e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    const SLInterfaceID id[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
421e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                 SL_IID_ANDROIDCONFIGURATION };
422e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
423e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*engineEngine)->CreateAudioRecorder(engineEngine,
424e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                              &recorderObject,
425e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                              &audioSrc,
426e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                              &audioSnk,
427e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                              sizeof(id)/sizeof(id[0]),
428e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                              id, req);
429e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
430e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // Configure the voice recognition preset which has no
431e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // signal processing for lower latency.
432e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLAndroidConfigurationItf inputConfig;
433e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderObject)->GetInterface(recorderObject,
434e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                            SL_IID_ANDROIDCONFIGURATION,
435e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                            &inputConfig);
436e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (SL_RESULT_SUCCESS == result) {
437e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
438e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        (*inputConfig)->SetConfiguration(inputConfig,
439e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                         SL_ANDROID_KEY_RECORDING_PRESET,
440e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                         &presetValue,
441e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                                         sizeof(SLuint32));
442e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
443e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
444e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // realize the audio recorder
445e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
446e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (SL_RESULT_SUCCESS != result) {
447e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return JNI_FALSE;
448e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
449e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
450e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // get the record interface
451e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
452e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
453e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
454e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
455e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // get the buffer queue interface
456e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
457e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            &recorderBufferQueue);
458e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
459e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
460e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
461e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // register callback on the buffer queue
462e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback,
463e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            NULL);
464e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
465e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
466e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
467e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Audio recorder created, buffer size: %d frames",
468e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                        recorder_frames);
469e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
470e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    return JNI_TRUE;
471e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
472e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
473e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
474e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer// set the recording state for the audio recorder
475ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmervoid Java_org_chromium_latency_walt_AudioTest_startRecording(__attribute__((unused)) JNIEnv* env,
476ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                             __attribute__((unused)) jclass clazz)
477e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
478e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    SLresult result;
479e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
480e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if( bqPlayerRecorderBusy) {
481e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return;
482e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
483e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // in case already recording, stop recording and clear buffer queue
484e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
485e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
486e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
487e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderBufferQueue)->Clear(recorderBufferQueue);
488e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
489e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
490e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
491e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // the buffer is not valid for playback yet
492e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    recorderSize = 0;
493e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
494e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // enqueue an empty buffer to be filled by the recorder
495e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // (for streaming recording, we would enqueue at least 2 empty buffers to start things off)
496e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    te_rec = uptimeMicros();  // TODO: investigate if it's better to time after SetRecordState
497e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    tc_rec = 0;
498e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, recorderBuffer,
499e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            recorder_frames * sizeof(short));
500e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
501e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // which for this code example would indicate a programming error
502e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
503e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
504e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
505e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    // start recording
506e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
507e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    assert(SL_RESULT_SUCCESS == result);
508e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (void)result;
509e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    bqPlayerRecorderBusy = 1;
510e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
511e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
512ed462e937cd99e9aaee98613c4e3e0469145d719Andrew LehmerjshortArray Java_org_chromium_latency_walt_AudioTest_getRecordedWave(
513ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        JNIEnv *env,
514ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer        __attribute__((unused)) jclass cls)
515e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer{
516e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    jshortArray result;
517e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    result = (*env)->NewShortArray(env, recorder_frames);
518e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    if (result == NULL) {
519e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return NULL; /* out of memory error thrown */
520e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
521e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    (*env)->SetShortArrayRegion(env, result, 0, recorder_frames, recorderBuffer);
522e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    return result;
523e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
524e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
525ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmerjlong Java_org_chromium_latency_walt_AudioTest_getTcRec(__attribute__((unused)) JNIEnv *env,
526ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                        __attribute__((unused)) jclass cls) {
527e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    return (jlong) tc_rec;
528e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
529e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
530ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmerjlong Java_org_chromium_latency_walt_AudioTest_getTeRec(__attribute__((unused)) JNIEnv *env,
531ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                        __attribute__((unused)) jclass cls) {
532e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    return (jlong) te_rec;
533e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
534e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
535ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmerjlong Java_org_chromium_latency_walt_AudioTest_getTePlay(__attribute__((unused)) JNIEnv *env,
536ed462e937cd99e9aaee98613c4e3e0469145d719Andrew Lehmer                                                         __attribute__((unused)) jclass cls) {
537e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    return (jlong) te_play;
538e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
539