summaryrefslogtreecommitdiff
path: root/LoopbackApp/app/src/main/jni
diff options
context:
space:
mode:
Diffstat (limited to 'LoopbackApp/app/src/main/jni')
-rw-r--r--LoopbackApp/app/src/main/jni/Android.mk27
-rw-r--r--LoopbackApp/app/src/main/jni/audio_utils/atomic.c40
-rw-r--r--LoopbackApp/app/src/main/jni/audio_utils/atomic.h38
-rw-r--r--LoopbackApp/app/src/main/jni/audio_utils/fifo.c154
-rw-r--r--LoopbackApp/app/src/main/jni/audio_utils/fifo.h88
-rw-r--r--LoopbackApp/app/src/main/jni/audio_utils/roundup.c32
-rw-r--r--LoopbackApp/app/src/main/jni/audio_utils/roundup.h31
-rw-r--r--LoopbackApp/app/src/main/jni/jni_sles.c178
-rw-r--r--LoopbackApp/app/src/main/jni/jni_sles.h69
-rw-r--r--LoopbackApp/app/src/main/jni/sles.cpp1051
-rw-r--r--LoopbackApp/app/src/main/jni/sles.h174
11 files changed, 0 insertions, 1882 deletions
diff --git a/LoopbackApp/app/src/main/jni/Android.mk b/LoopbackApp/app/src/main/jni/Android.mk
deleted file mode 100644
index ef0c829..0000000
--- a/LoopbackApp/app/src/main/jni/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libloopback
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := \
- sles.cpp \
- jni_sles.c \
- audio_utils/atomic.c \
- audio_utils/fifo.c \
- audio_utils/roundup.c
-LOCAL_C_INCLUDES := \
- frameworks/wilhelm/include
-
-LOCAL_SHARED_LIBRARIES := \
- libOpenSLES \
- liblog \
- libandroid
-
-LOCAL_LDLIBS += -lOpenSLES -llog -landroid
-#LOCAL_PRELINK_MODULE := false
-
-#LOCAL_LDFLAGS += -Wl,--hash-style=sysv
-#LOCAL_CFLAGS := -DSTDC_HEADERS
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/LoopbackApp/app/src/main/jni/audio_utils/atomic.c b/LoopbackApp/app/src/main/jni/audio_utils/atomic.c
deleted file mode 100644
index b76b1f4..0000000
--- a/LoopbackApp/app/src/main/jni/audio_utils/atomic.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "atomic.h"
-
-#include <stdatomic.h>
-#include <stdbool.h>
-
-int32_t android_atomic_acquire_load(volatile const int32_t* addr) {
- volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*) addr;
- return atomic_load_explicit(a, memory_order_acquire);
-}
-
-void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
- volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*) addr;
- atomic_store_explicit(a, value, memory_order_release);
-}
-
-int32_t android_atomic_exchange(int32_t value, volatile const int32_t* addr) {
- volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*) addr;
- return atomic_exchange(a, value);
-}
-
-bool android_atomic_compare_exchange(int32_t* expect, int32_t desire, volatile const int32_t* addr) {
- volatile atomic_int_least32_t* a = (volatile atomic_int_least32_t*) addr;
- return atomic_compare_exchange_weak(a, expect, desire);
-}
diff --git a/LoopbackApp/app/src/main/jni/audio_utils/atomic.h b/LoopbackApp/app/src/main/jni/audio_utils/atomic.h
deleted file mode 100644
index 164ad17..0000000
--- a/LoopbackApp/app/src/main/jni/audio_utils/atomic.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_AUDIO_ATOMIC_H
-#define ANDROID_AUDIO_ATOMIC_H
-
-#include <stdlib.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int32_t android_atomic_acquire_load(volatile const int32_t* addr);
-void android_atomic_release_store(int32_t value, volatile int32_t* addr);
-
-// FIXME: use standard atomic library instead of these functions
-int32_t android_atomic_exchange(int32_t value, volatile const int32_t* addr);
-bool android_atomic_compare_exchange(int32_t* expect, int32_t desire, volatile const int32_t* addr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ANDROID_AUDIO_ATOMIC_H
diff --git a/LoopbackApp/app/src/main/jni/audio_utils/fifo.c b/LoopbackApp/app/src/main/jni/audio_utils/fifo.c
deleted file mode 100644
index e00fc28..0000000
--- a/LoopbackApp/app/src/main/jni/audio_utils/fifo.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "audio_utils_fifo"
-
-#include <stdlib.h>
-#include <string.h>
-#include "fifo.h"
-#include "roundup.h"
-#include "atomic.h"
-//#include <cutils/log.h>
-#define ALOG_ASSERT(exp)
-
-
-void audio_utils_fifo_init(struct audio_utils_fifo *fifo, size_t frameCount, size_t frameSize,
- void *buffer) {
- // We would need a 64-bit roundup to support larger frameCount.
- ALOG_ASSERT(fifo != NULL && frameCount > 0 && frameSize > 0 && buffer != NULL);
- fifo->mFrameCount = frameCount;
- fifo->mFrameCountP2 = roundup(frameCount);
- fifo->mFudgeFactor = fifo->mFrameCountP2 - fifo->mFrameCount;
- fifo->mFrameSize = frameSize;
- fifo->mBuffer = buffer;
- fifo->mFront = 0;
- fifo->mRear = 0;
-}
-
-
-void audio_utils_fifo_deinit(struct audio_utils_fifo *fifo __unused)
-{
-}
-
-
-// Return a new index as the sum of an old index (either mFront or mRear) and a specified increment.
-static inline int32_t audio_utils_fifo_sum(struct audio_utils_fifo *fifo, int32_t index,
- uint32_t increment) {
- if (fifo->mFudgeFactor) {
- uint32_t mask = fifo->mFrameCountP2 - 1;
- ALOG_ASSERT((index & mask) < fifo->mFrameCount);
- ALOG_ASSERT(/*0 <= increment &&*/ increment <= fifo->mFrameCountP2);
- if ((index & mask) + increment >= fifo->mFrameCount) {
- increment += fifo->mFudgeFactor;
- }
-
- index += increment;
- ALOG_ASSERT((index & mask) < fifo->mFrameCount);
- return index;
- } else {
- return index + increment;
- }
-}
-
-
-// Return the difference between two indices: rear - front, where 0 <= difference <= mFrameCount.
-static inline size_t audio_utils_fifo_diff(struct audio_utils_fifo *fifo, int32_t rear,
- int32_t front) {
- int32_t diff = rear - front;
-
- if (fifo->mFudgeFactor) {
- uint32_t mask = ~(fifo->mFrameCountP2 - 1);
- int32_t genDiff = (rear & mask) - (front & mask);
-
- if (genDiff != 0) {
- ALOG_ASSERT(genDiff == (int32_t) fifo->mFrameCountP2);
- diff -= fifo->mFudgeFactor;
- }
- }
-
- // FIFO should not be overfull
- ALOG_ASSERT(0 <= diff && diff <= (int32_t) fifo->mFrameCount);
- return (size_t) diff;
-}
-
-
-ssize_t audio_utils_fifo_write(struct audio_utils_fifo *fifo, const void *buffer, size_t count) {
- int32_t front = android_atomic_acquire_load(&fifo->mFront);
- int32_t rear = fifo->mRear;
- size_t availToWrite = fifo->mFrameCount - audio_utils_fifo_diff(fifo, rear, front);
-
- if (availToWrite > count) {
- availToWrite = count;
- }
-
- rear &= fifo->mFrameCountP2 - 1;
- size_t part1 = fifo->mFrameCount - rear;
- if (part1 > availToWrite) {
- part1 = availToWrite;
- }
-
- if (part1 > 0) {
- memcpy((char *) fifo->mBuffer + (rear * fifo->mFrameSize), buffer,
- part1 * fifo->mFrameSize);
- size_t part2 = availToWrite - part1;
-
- if (part2 > 0) {
- memcpy(fifo->mBuffer, (char *) buffer + (part1 * fifo->mFrameSize),
- part2 * fifo->mFrameSize);
- }
-
- android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mRear, availToWrite),
- &fifo->mRear);
- }
- return availToWrite;
-}
-
-
-ssize_t audio_utils_fifo_read(struct audio_utils_fifo *fifo, void *buffer, size_t count) {
- int32_t rear = android_atomic_acquire_load(&fifo->mRear);
- int32_t front = fifo->mFront;
- size_t availToRead = audio_utils_fifo_diff(fifo, rear, front);
- if (availToRead > count) {
- availToRead = count;
- }
-
- front &= fifo->mFrameCountP2 - 1;
- size_t part1 = fifo->mFrameCount - front;
- if (part1 > availToRead) {
- part1 = availToRead;
- }
-
- if (part1 > 0) {
- memcpy(buffer, (char *) fifo->mBuffer + (front * fifo->mFrameSize),
- part1 * fifo->mFrameSize);
- size_t part2 = availToRead - part1;
- if (part2 > 0) {
- memcpy((char *) buffer + (part1 * fifo->mFrameSize), fifo->mBuffer,
- part2 * fifo->mFrameSize);
- }
- android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mFront, availToRead),
- &fifo->mFront);
- }
- return availToRead;
-}
-
-size_t audio_utils_fifo_availToRead(struct audio_utils_fifo *fifo) {
- int32_t rear = android_atomic_acquire_load(&fifo->mRear);
- int32_t front = fifo->mFront;
- size_t availToRead = audio_utils_fifo_diff(fifo, rear, front);
- return availToRead;
-}
diff --git a/LoopbackApp/app/src/main/jni/audio_utils/fifo.h b/LoopbackApp/app/src/main/jni/audio_utils/fifo.h
deleted file mode 100644
index 37a9df8..0000000
--- a/LoopbackApp/app/src/main/jni/audio_utils/fifo.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_AUDIO_FIFO_H
-#define ANDROID_AUDIO_FIFO_H
-
-#include <stdlib.h>
-
-// FIXME use atomic_int_least32_t and new atomic operations instead of legacy Android ones
-// #include <stdatomic.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Single writer, single reader non-blocking FIFO.
-// Writer and reader must be in same process.
-
-// No user-serviceable parts within.
-struct audio_utils_fifo {
- // These fields are const after initialization
- size_t mFrameCount; // max number of significant frames to be stored in the FIFO > 0
- size_t mFrameCountP2; // roundup(mFrameCount)
- size_t mFudgeFactor; // mFrameCountP2 - mFrameCount, the number of "wasted" frames after
- // the end of mBuffer. Only the indices are wasted, not any memory.
- size_t mFrameSize; // size of each frame in bytes
- void *mBuffer; // pointer to caller-allocated buffer of size mFrameCount frames
-
- volatile int32_t mFront; // frame index of first frame slot available to read, or read index
- volatile int32_t mRear; // frame index of next frame slot available to write, or write index
-};
-
-// Initialize a FIFO object.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-// frameCount Max number of significant frames to be stored in the FIFO > 0.
-// If writes and reads always use the same count, and that count is a divisor of
-// frameCount, then the writes and reads will never do a partial transfer.
-// frameSize Size of each frame in bytes.
-// buffer Pointer to a caller-allocated buffer of frameCount frames.
-void audio_utils_fifo_init(struct audio_utils_fifo *fifo, size_t frameCount, size_t frameSize,
- void *buffer);
-
-// De-initialize a FIFO object.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-void audio_utils_fifo_deinit(struct audio_utils_fifo *fifo);
-
-// Write to FIFO.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-// buffer Pointer to source buffer containing 'count' frames of data.
-// Returns actual number of frames written <= count.
-// The actual transfer count may be zero if the FIFO is full,
-// or partial if the FIFO was almost full.
-// A negative return value indicates an error. Currently there are no errors defined.
-ssize_t audio_utils_fifo_write(struct audio_utils_fifo *fifo, const void *buffer, size_t count);
-
-// Read from FIFO.
-// Input parameters:
-// fifo Pointer to the FIFO object.
-// buffer Pointer to destination buffer to be filled with up to 'count' frames of data.
-// Returns actual number of frames read <= count.
-// The actual transfer count may be zero if the FIFO is empty,
-// or partial if the FIFO was almost empty.
-// A negative return value indicates an error. Currently there are no errors defined.
-ssize_t audio_utils_fifo_read(struct audio_utils_fifo *fifo, void *buffer, size_t count);
-
-size_t audio_utils_fifo_availToRead(struct audio_utils_fifo *fifo);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // !ANDROID_AUDIO_FIFO_H
diff --git a/LoopbackApp/app/src/main/jni/audio_utils/roundup.c b/LoopbackApp/app/src/main/jni/audio_utils/roundup.c
deleted file mode 100644
index 6c8e504..0000000
--- a/LoopbackApp/app/src/main/jni/audio_utils/roundup.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "roundup.h"
-
-unsigned roundup(unsigned v) {
- // __builtin_clz is undefined for zero input
- if (v == 0) {
- v = 1;
- }
-
- int lz = __builtin_clz((int) v);
- unsigned rounded = ((unsigned) 0x80000000) >> lz;
- // 0x800000001 and higher are actually rounded _down_ to prevent overflow
- if (v > rounded && lz > 0) {
- rounded <<= 1;
- }
- return rounded;
-}
diff --git a/LoopbackApp/app/src/main/jni/audio_utils/roundup.h b/LoopbackApp/app/src/main/jni/audio_utils/roundup.h
deleted file mode 100644
index ad34289..0000000
--- a/LoopbackApp/app/src/main/jni/audio_utils/roundup.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_AUDIO_ROUNDUP_H
-#define ANDROID_AUDIO_ROUNDUP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Round up to the next highest power of 2
-unsigned roundup(unsigned v);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ANDROID_AUDIO_ROUNDUP_H
diff --git a/LoopbackApp/app/src/main/jni/jni_sles.c b/LoopbackApp/app/src/main/jni/jni_sles.c
deleted file mode 100644
index 0417252..0000000
--- a/LoopbackApp/app/src/main/jni/jni_sles.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/log.h>
-#include "sles.h"
-#include "jni_sles.h"
-#include <stdio.h>
-
-
-JNIEXPORT jlong JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesInit
- (JNIEnv *env, jobject obj __unused, jint samplingRate, jint frameCount, jint micSource,
- jint performanceMode,
- jint testType, jdouble frequency1, jobject byteBuffer, jshortArray loopbackTone,
- jint maxRecordedLateCallbacks, jint ignoreFirstFrames) {
-
- sles_data * pSles = NULL;
-
- char* byteBufferPtr = (*env)->GetDirectBufferAddress(env, byteBuffer);
- int byteBufferLength = (*env)->GetDirectBufferCapacity(env, byteBuffer);
-
- short* loopbackToneArray = (*env)->GetShortArrayElements(env, loopbackTone, 0);
-
- if (slesInit(&pSles, samplingRate, frameCount, micSource,
- performanceMode,
- testType, frequency1, byteBufferPtr, byteBufferLength,
- loopbackToneArray, maxRecordedLateCallbacks, ignoreFirstFrames) != SLES_FAIL) {
- return (long) pSles;
- }
-
- // FIXME This should be stored as a (long) field in the object,
- // so that incorrect Java code could not synthesize a bad sles pointer.
- return 0;
-}
-
-
-JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesProcessNext
-(JNIEnv *env __unused, jobject obj __unused, jlong sles, jdoubleArray samplesArray, jlong offset) {
- sles_data * pSles = (sles_data*) (size_t) sles;
-
- long maxSamples = (*env)->GetArrayLength(env, samplesArray);
- double *pSamples = (*env)->GetDoubleArrayElements(env, samplesArray, 0);
-
- long availableSamples = maxSamples-offset;
- double *pCurrentSample = pSamples+offset;
-
- SLES_PRINTF("jni slesProcessNext pSles:%p, currentSample %p, availableSamples %ld ",
- pSles, pCurrentSample, availableSamples);
-
- int samplesRead = slesProcessNext(pSles, pCurrentSample, availableSamples);
- return samplesRead;
-}
-
-
-JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesDestroy
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- int status = slesDestroy(&pSles);
- return status;
-}
-
-
-JNIEXPORT jintArray JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderBufferPeriod
- (JNIEnv *env, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- int* recorderBufferPeriod = slesGetRecorderBufferPeriod(pSles);
-
- // get the length = RANGE
- jintArray result = (*env)->NewIntArray(env, RANGE);
- (*env)->SetIntArrayRegion(env, result, 0, RANGE, recorderBufferPeriod);
-
- return result;
-}
-
-
-JNIEXPORT jint JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderMaxBufferPeriod
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- int recorderMaxBufferPeriod = slesGetRecorderMaxBufferPeriod(pSles);
-
- return recorderMaxBufferPeriod;
-}
-
-
-JNIEXPORT jdouble JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderVarianceBufferPeriod
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data *pSles = (sles_data *) (size_t) sles;
- int64_t result = slesGetRecorderVarianceBufferPeriod(pSles);
- // variance has units ns^2 so we have to square the conversion factor
- double scaled = (double) result / ((double) NANOS_PER_MILLI * (double) NANOS_PER_MILLI);
- return scaled;
-}
-
-
-JNIEXPORT jintArray
-JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerBufferPeriod
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- int* playerBufferPeriod = slesGetPlayerBufferPeriod(pSles);
-
- jintArray result = (*env)->NewIntArray(env, RANGE);
- (*env)->SetIntArrayRegion(env, result, 0, RANGE, playerBufferPeriod);
-
- return result;
-}
-
-
-JNIEXPORT jint JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerMaxBufferPeriod
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- int playerMaxBufferPeriod = slesGetPlayerMaxBufferPeriod(pSles);
-
- return playerMaxBufferPeriod;
-}
-
-
-JNIEXPORT jdouble JNICALL
-Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerVarianceBufferPeriod
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data *pSles = (sles_data *) (size_t) sles;
- int64_t result = slesGetPlayerVarianceBufferPeriod(pSles);
- // variance has units ns^2 so we have to square the conversion factor
- double scaled = (double) result / ((double) NANOS_PER_MILLI * (double) NANOS_PER_MILLI);
- return scaled;
-}
-
-
-jobject getCallbackTimes(JNIEnv *env, callbackTimeStamps *callbacks, short expectedBufferPeriod){
- jintArray timeStamps = (*env)->NewIntArray(env, callbacks->index);
- (*env)->SetIntArrayRegion(env, timeStamps, 0, callbacks->index, callbacks->timeStampsMs);
-
- jshortArray callbackLengths = (*env)->NewShortArray(env, callbacks->index);
- (*env)->SetShortArrayRegion(env, callbackLengths, 0, callbacks->index,
- callbacks->callbackDurations);
-
- jclass cls = (*env)->FindClass(env, "org/drrickorang/loopback/BufferCallbackTimes");
- jmethodID methodID = (*env)->GetMethodID(env, cls, "<init>", "([I[SZS)V");
- jobject callbackTimes=(*env)->NewObject(env,cls, methodID, timeStamps, callbackLengths,
- callbacks->exceededCapacity, expectedBufferPeriod);
- return callbackTimes;
-}
-
-JNIEXPORT jobject
-JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerCallbackTimeStamps
- (JNIEnv *env, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- return getCallbackTimes(env, &(pSles->playerTimeStamps), pSles->expectedBufferPeriod);
-}
-
-JNIEXPORT jobject
-JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderCallbackTimeStamps
- (JNIEnv *env, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- return getCallbackTimes(env, &(pSles->recorderTimeStamps), pSles->expectedBufferPeriod);
-}
-
-JNIEXPORT jint
-JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesGetCaptureRank
- (JNIEnv *env __unused, jobject obj __unused, jlong sles) {
- sles_data * pSles = (sles_data*) (size_t) sles;
- return slesGetCaptureRank(pSles);
-}
diff --git a/LoopbackApp/app/src/main/jni/jni_sles.h b/LoopbackApp/app/src/main/jni/jni_sles.h
deleted file mode 100644
index f25bd52..0000000
--- a/LoopbackApp/app/src/main/jni/jni_sles.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-
-#ifndef _Included_org_drrickorang_loopback_jni
-#define _Included_org_drrickorang_loopback_jni
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-////////////////////////
-////SLE
-JNIEXPORT jlong JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesInit
- (JNIEnv *, jobject, jint, jint, jint, jint, jint, jdouble, jobject byteBuffer,
- jshortArray loopbackTone, jint maxRecordedLateCallbacks, jint ignoreFirstFrames);
-
-JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesProcessNext
- (JNIEnv *, jobject, jlong, jdoubleArray, jlong);
-
-JNIEXPORT jint JNICALL Java_org_drrickorang_loopback_NativeAudioThread_slesDestroy
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jintArray JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderBufferPeriod
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jint JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderMaxBufferPeriod
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jdouble JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetRecorderVarianceBufferPeriod
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jintArray JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerBufferPeriod
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jint JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerMaxBufferPeriod
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jdouble JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetPlayerVarianceBufferPeriod
- (JNIEnv *, jobject, jlong);
-
-JNIEXPORT jint JNICALL
- Java_org_drrickorang_loopback_NativeAudioThread_slesGetCaptureRank
- (JNIEnv *, jobject, jlong);
-
-#ifdef __cplusplus
-}
-#endif
-#endif //_Included_org_drrickorang_loopback_jni
diff --git a/LoopbackApp/app/src/main/jni/sles.cpp b/LoopbackApp/app/src/main/jni/sles.cpp
deleted file mode 100644
index 159269b..0000000
--- a/LoopbackApp/app/src/main/jni/sles.cpp
+++ /dev/null
@@ -1,1051 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-// FIXME taken from OpenSLES_AndroidConfiguration.h
-#define SL_ANDROID_KEY_PERFORMANCE_MODE ((const SLchar*) "androidPerformanceMode")
-
-////////////////////////////////////////////
-/// Actual sles functions.
-
-
-// Test program to record from default audio input and playback to default audio output.
-// It will generate feedback (Larsen effect) if played through on-device speakers,
-// or acts as a delay if played through headset.
-
-#define _USE_MATH_DEFINES
-#include <cmath>
-#include "sles.h"
-#include "audio_utils/atomic.h"
-#include <stdio.h>
-#include <assert.h>
-#include <unistd.h>
-#include <string.h>
-
-int slesInit(sles_data ** ppSles, int samplingRate, int frameCount, int micSource,
- int performanceMode,
- int testType, double frequency1, char* byteBufferPtr, int byteBufferLength,
- short* loopbackTone, int maxRecordedLateCallbacks, int ignoreFirstFrames) {
- int status = SLES_FAIL;
- if (ppSles != NULL) {
- sles_data * pSles = (sles_data*) malloc(sizeof(sles_data));
-
- memset(pSles, 0, sizeof(sles_data));
-
- SLES_PRINTF("pSles malloc %zu bytes at %p", sizeof(sles_data), pSles);
- //__android_log_print(ANDROID_LOG_INFO, "sles_jni",
- //"malloc %d bytes at %p", sizeof(sles_data), pSles);//Or ANDROID_LOG_INFO, ...
- *ppSles = pSles;
- if (pSles != NULL)
- {
- SLES_PRINTF("creating server. Sampling rate =%d, frame count = %d",
- samplingRate, frameCount);
- status = slesCreateServer(pSles, samplingRate, frameCount, micSource,
- performanceMode, testType,
- frequency1, byteBufferPtr, byteBufferLength, loopbackTone,
- maxRecordedLateCallbacks, ignoreFirstFrames);
- SLES_PRINTF("slesCreateServer =%d", status);
- }
- }
-
- return status;
-}
-int slesDestroy(sles_data ** ppSles) {
- int status = SLES_FAIL;
- if (ppSles != NULL) {
- slesDestroyServer(*ppSles);
-
- if (*ppSles != NULL)
- {
- SLES_PRINTF("free memory at %p",*ppSles);
- free(*ppSles);
- *ppSles = 0;
- }
- status = SLES_SUCCESS;
- }
- return status;
-}
-
-#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
- (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
-
-// Called after audio recorder fills a buffer with data, then we can read from this filled buffer
-static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void *context) {
- sles_data *pSles = (sles_data*) context;
- if (pSles != NULL) {
- collectBufferPeriod(&pSles->recorderBufferStats, NULL /*fdpStats*/, &pSles->recorderTimeStamps,
- pSles->expectedBufferPeriod);
-
- //__android_log_print(ANDROID_LOG_INFO, "sles_jni", "in recorderCallback");
- SLresult result;
-
- //ee SLES_PRINTF("<R");
-
- // We should only be called when a recording buffer is done
- assert(pSles->rxFront <= pSles->rxBufCount);
- assert(pSles->rxRear <= pSles->rxBufCount);
- assert(pSles->rxFront != pSles->rxRear);
- char *buffer = pSles->rxBuffers[pSles->rxFront]; //pSles->rxBuffers stores the data recorded
-
-
- // Remove buffer from record queue
- if (++pSles->rxFront > pSles->rxBufCount) {
- pSles->rxFront = 0;
- }
-
- if (pSles->testType == TEST_TYPE_LATENCY) {
- // Throw out first frames
- if (pSles->ignoreFirstFrames) {
- int framesToErase = pSles->ignoreFirstFrames;
- if (framesToErase > (int) pSles->bufSizeInFrames) {
- framesToErase = pSles->bufSizeInFrames;
- }
- pSles->ignoreFirstFrames -= framesToErase;
- memset(buffer, 0, framesToErase * pSles->channels * sizeof(short));
- }
-
- ssize_t actual = audio_utils_fifo_write(&(pSles->fifo), buffer,
- (size_t) pSles->bufSizeInFrames);
-
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "?", 1);
- }
-
- // This is called by a realtime (SCHED_FIFO) thread,
- // and it is unsafe to do I/O as it could block for unbounded time.
- // Flash filesystem is especially notorious for blocking.
- if (pSles->fifo2Buffer != NULL) {
- actual = audio_utils_fifo_write(&(pSles->fifo2), buffer,
- (size_t) pSles->bufSizeInFrames);
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "?", 1);
- }
- }
- } else if (pSles->testType == TEST_TYPE_BUFFER_PERIOD) {
- if (pSles->fifo2Buffer != NULL) {
- ssize_t actual = byteBuffer_write(pSles, buffer, (size_t) pSles->bufSizeInFrames);
-
- //FIXME should log errors using other methods instead of printing to terminal
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "?", 1);
- }
- }
- }
-
-
- // Enqueue this same buffer for the recorder to fill again.
- result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue, buffer,
- pSles->bufSizeInBytes);
- //__android_log_print(ANDROID_LOG_INFO, "recorderCallback", "recorder buffer size: %i",
- // pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
-
- // Update our model of the record queue
- SLuint32 rxRearNext = pSles->rxRear + 1;
- if (rxRearNext > pSles->rxBufCount) {
- rxRearNext = 0;
- }
- assert(rxRearNext != pSles->rxFront);
- pSles->rxBuffers[pSles->rxRear] = buffer;
- pSles->rxRear = rxRearNext;
-
-
-
- //ee SLES_PRINTF("r>");
-
- } //pSles not null
-}
-
-
-// Write "count" amount of short from buffer to pSles->byteBufferPtr. This byteBuffer will read by
-// java code.
-ssize_t byteBuffer_write(sles_data *pSles, char *buffer, size_t count) {
- // bytebufferSize is in byte
- int32_t rear; // rear should not exceed 2^31 - 1, or else overflow will happen
- memcpy(&rear, (char *) (pSles->byteBufferPtr + pSles->byteBufferLength - 4), sizeof(rear));
-
- size_t frameSize = pSles->channels * sizeof(short); // only one channel
- int32_t maxLengthInShort = (pSles->byteBufferLength - 4) / frameSize;
- // mask the upper bits to get the correct position in the pipe
- int32_t tempRear = rear & (maxLengthInShort - 1);
- size_t part1 = maxLengthInShort - tempRear;
-
- if (part1 > count) {
- part1 = count;
- }
-
- if (part1 > 0) {
- memcpy(pSles->byteBufferPtr + (tempRear * frameSize), buffer,
- part1 * frameSize);
-
- size_t part2 = count - part1;
- if (part2 > 0) {
- memcpy(pSles->byteBufferPtr, (buffer + (part1 * frameSize)),
- part2 * frameSize);
- }
-
- //TODO do we need something similar to the below function call?
- //android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mRear, availToWrite),
- // &fifo->mRear);
- }
-
- // increase value of rear
- int32_t* rear2 = (int32_t *) (pSles->byteBufferPtr + pSles->byteBufferLength - 4);
- *rear2 += count;
- return count;
-}
-
-// Calculate nanosecond difference between two timespec structs from clock_gettime(CLOCK_MONOTONIC)
-// tv_sec [0, max time_t] , tv_nsec [0, 999999999]
-int64_t diffInNano(struct timespec previousTime, struct timespec currentTime) {
- return (int64_t) (currentTime.tv_sec - previousTime.tv_sec) * (int64_t) NANOS_PER_SECOND +
- currentTime.tv_nsec - previousTime.tv_nsec;
-}
-
-// Called after audio player empties a buffer of data
-static void playerCallback(SLBufferQueueItf caller __unused, void *context) {
- sles_data *pSles = (sles_data*) context;
- if (pSles != NULL) {
- collectBufferPeriod(&pSles->playerBufferStats, &pSles->recorderBufferStats /*fdpStats*/,
- &pSles->playerTimeStamps, pSles->expectedBufferPeriod);
- SLresult result;
-
- //ee SLES_PRINTF("<P");
-
- // Get the buffer that just finished playing
- assert(pSles->txFront <= pSles->txBufCount);
- assert(pSles->txRear <= pSles->txBufCount);
- assert(pSles->txFront != pSles->txRear);
- char *buffer = pSles->txBuffers[pSles->txFront];
- if (++pSles->txFront > pSles->txBufCount) {
- pSles->txFront = 0;
- }
-
- if (pSles->testType == TEST_TYPE_LATENCY) {
- // Jitter buffer should have strictly less than 2 buffers worth of data in it.
- // This is to prevent the test itself from adding too much latency.
- size_t discardedInputFrames = 0;
- for (;;) {
- size_t availToRead = audio_utils_fifo_availToRead(&pSles->fifo);
- if (availToRead < pSles->bufSizeInFrames * 2) {
- break;
- }
- ssize_t actual = audio_utils_fifo_read(&pSles->fifo, buffer, pSles->bufSizeInFrames);
- if (actual > 0) {
- discardedInputFrames += actual;
- }
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- break;
- }
- }
- if (discardedInputFrames > 0) {
- if (pSles->totalDiscardedInputFrames > 0) {
- __android_log_print(ANDROID_LOG_WARN, "sles_jni",
- "Discarded an additional %zu input frames after a total of %zu input frames"
- " had previously been discarded",
- discardedInputFrames, pSles->totalDiscardedInputFrames);
- }
- pSles->totalDiscardedInputFrames += discardedInputFrames;
- }
-
- ssize_t actual = audio_utils_fifo_read(&(pSles->fifo), buffer, pSles->bufSizeInFrames);
- if (actual != (ssize_t) pSles->bufSizeInFrames) {
- write(1, "/", 1);
- // on underrun from pipe, substitute silence
- memset(buffer, 0, pSles->bufSizeInFrames * pSles->channels * sizeof(short));
- }
-
- if (pSles->injectImpulse == -1) { // here we inject pulse
-
- /*// Experimentally, a single frame impulse was insufficient to trigger feedback.
- // Also a Nyquist frequency signal was also insufficient, probably because
- // the response of output and/or input path was not adequate at high frequencies.
- // This short burst of a few cycles of square wave at Nyquist/4 found to work well.
- for (unsigned i = 0; i < pSles->bufSizeInFrames / 8; i += 8) {
- for (int j = 0; j < 8; j++) {
- for (unsigned k = 0; k < pSles->channels; k++) {
- ((short *) buffer)[(i + j) * pSles->channels + k] =
- j < 4 ? 0x7FFF : 0x8000;
- }
- }
- }*/
-
- //inject java generated tone
- for (unsigned i = 0; i < pSles->bufSizeInFrames; ++i) {
- for (unsigned k = 0; k < pSles->channels; ++k) {
- ((short *) buffer)[i * pSles->channels + k] = pSles->loopbackTone[i];
- }
- }
-
- pSles->injectImpulse = 0;
- pSles->totalDiscardedInputFrames = 0;
- }
- } else if (pSles->testType == TEST_TYPE_BUFFER_PERIOD) {
- double twoPi = M_PI * 2;
- int maxShort = 32767;
- float amplitude = 0.8;
- short value;
- double phaseIncrement = pSles->frequency1 / pSles->sampleRate;
- bool isGlitchEnabled = false;
- for (unsigned i = 0; i < pSles->bufSizeInFrames; i++) {
- value = (short) (sin(pSles->bufferTestPhase1) * maxShort * amplitude);
- for (unsigned k = 0; k < pSles->channels; ++k) {
- ((short *) buffer)[i* pSles->channels + k] = value;
- }
-
- pSles->bufferTestPhase1 += twoPi * phaseIncrement;
- // insert glitches if isGlitchEnabled == true, and insert it for every second
- if (isGlitchEnabled && (pSles->count % pSles->sampleRate == 0)) {
- pSles->bufferTestPhase1 += twoPi * phaseIncrement;
- }
-
- pSles->count++;
-
- while (pSles->bufferTestPhase1 > twoPi) {
- pSles->bufferTestPhase1 -= twoPi;
- }
- }
- }
-
- // Enqueue the filled buffer for playing
- result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue, buffer,
- pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Update our model of the player queue
- assert(pSles->txFront <= pSles->txBufCount);
- assert(pSles->txRear <= pSles->txBufCount);
- SLuint32 txRearNext = pSles->txRear + 1;
- if (txRearNext > pSles->txBufCount) {
- txRearNext = 0;
- }
- assert(txRearNext != pSles->txFront);
- pSles->txBuffers[pSles->txRear] = buffer;
- pSles->txRear = txRearNext;
-
- } //pSles not null
-}
-
-// Used to set initial values for the bufferStats struct before values can be recorded.
-void initBufferStats(bufferStats *stats) {
- stats->buffer_period = new int[RANGE](); // initialized to zeros
- stats->previous_time = {0,0};
- stats->current_time = {0,0};
-
- stats->buffer_count = 0;
- stats->max_buffer_period = 0;
-
- stats->measurement_count = 0;
- stats->SDM = 0;
- stats->var = 0;
-}
-
-// Called in the beginning of playerCallback() to collect the interval between each callback.
-// fdpStats is either NULL or a pointer to the buffer statistics for the full-duplex partner.
-void collectBufferPeriod(bufferStats *stats, bufferStats *fdpStats, callbackTimeStamps *timeStamps,
- short expectedBufferPeriod) {
- clock_gettime(CLOCK_MONOTONIC, &(stats->current_time));
-
- if (timeStamps->startTime.tv_sec == 0 && timeStamps->startTime.tv_nsec == 0) {
- timeStamps->startTime = stats->current_time;
- }
-
- (stats->buffer_count)++;
-
- if (stats->previous_time.tv_sec != 0 && stats->buffer_count > BUFFER_PERIOD_DISCARD &&
- (fdpStats == NULL || fdpStats->buffer_count > BUFFER_PERIOD_DISCARD_FULL_DUPLEX_PARTNER)) {
-
- int64_t callbackDuration = diffInNano(stats->previous_time, stats->current_time);
-
- bool outlier = updateBufferStats(stats, callbackDuration, expectedBufferPeriod);
-
- //recording timestamps of buffer periods not at expected buffer period
- if (outlier) {
- int64_t timeStamp = diffInNano(timeStamps->startTime, stats->current_time);
- recordTimeStamp(timeStamps, callbackDuration, timeStamp);
- }
- }
-
- stats->previous_time = stats->current_time;
-}
-
-// Records an outlier given the duration in nanoseconds and the number of nanoseconds
-// between it and the start of the test.
-void recordTimeStamp(callbackTimeStamps *timeStamps,
- int64_t callbackDuration, int64_t timeStamp) {
- if (timeStamps->exceededCapacity) {
- return;
- }
-
- //only marked as exceeded if attempting to record a late callback after arrays full
- if (timeStamps->index == timeStamps->capacity){
- timeStamps->exceededCapacity = true;
- } else {
- timeStamps->callbackDurations[timeStamps->index] =
- (short) ((callbackDuration + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI);
- timeStamps->timeStampsMs[timeStamps->index] =
- (int) ((timeStamp + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI);
- timeStamps->index++;
- }
-}
-
-void atomicSetIfGreater(volatile int32_t *addr, int32_t val) {
- // TODO: rewrite this to avoid the need for unbounded spinning
- int32_t old;
- do {
- old = *addr;
- if (val < old) return;
- } while(!android_atomic_compare_exchange(&old, val, addr));
-}
-
-// Updates the stats being collected about buffer periods. Returns true if this is an outlier.
-bool updateBufferStats(bufferStats *stats, int64_t diff_in_nano, int expectedBufferPeriod) {
- stats->measurement_count++;
-
- // round up to nearest millisecond
- int diff_in_milli = (int) ((diff_in_nano + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI);
-
- if (diff_in_milli > stats->max_buffer_period) {
- stats->max_buffer_period = diff_in_milli;
- }
-
- // from 0 ms to 1000 ms, plus a sum of all instances > 1000ms
- if (diff_in_milli >= (RANGE - 1)) {
- (stats->buffer_period)[RANGE-1]++;
- } else if (diff_in_milli >= 0) {
- (stats->buffer_period)[diff_in_milli]++;
- } else { // for diff_in_milli < 0
- __android_log_print(ANDROID_LOG_INFO, "sles_player", "Having negative BufferPeriod.");
- }
-
- int64_t delta = diff_in_nano - (int64_t) expectedBufferPeriod * NANOS_PER_MILLI;
- stats->SDM += delta * delta;
- if (stats->measurement_count > 1) {
- stats->var = stats->SDM / stats->measurement_count;
- }
-
- // check if the lateness is so bad that a systrace should be captured
- // TODO: replace static threshold of lateness with a dynamic determination
- if (diff_in_milli > expectedBufferPeriod + LATE_CALLBACK_CAPTURE_THRESHOLD) {
- // TODO: log in a non-blocking way
- //__android_log_print(ANDROID_LOG_INFO, "buffer_stats", "Callback late by %d ms",
- // diff_in_milli - expectedBufferPeriod);
- atomicSetIfGreater(&(stats->captureRank), diff_in_milli - expectedBufferPeriod);
- }
- return diff_in_milli > expectedBufferPeriod + LATE_CALLBACK_OUTLIER_THRESHOLD;
-}
-
-int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount, int micSource,
- int performanceMode,
- int testType, double frequency1, char *byteBufferPtr, int byteBufferLength,
- short *loopbackTone, int maxRecordedLateCallbacks, int ignoreFirstFrames) {
- int status = SLES_FAIL;
-
- if (pSles != NULL) {
-
- // adb shell slesTest_feedback -r1 -t1 -s48000 -f240 -i300 -e3 -o/sdcard/log.wav
- // r1 and t1 are the receive and transmit buffer counts, typically 1
- // s is the sample rate, typically 48000 or 44100
- // f is the frame count per buffer, typically 240 or 256
- // i is the number of milliseconds before impulse. You may need to adjust this.
- // e is number of seconds to record
- // o is output .wav file name
-
-
- // // default values
- // SLuint32 rxBufCount = 1; // -r#
- // SLuint32 txBufCount = 1; // -t#
- // SLuint32 bufSizeInFrames = 240; // -f#
- // SLuint32 channels = 1; // -c#
- // SLuint32 sampleRate = 48000; // -s#
- // SLuint32 exitAfterSeconds = 3; // -e#
- // SLuint32 freeBufCount = 0; // calculated
- // SLuint32 bufSizeInBytes = 0; // calculated
- // int injectImpulse = 300; // -i#i
- //
- // // Storage area for the buffer queues
- // char **rxBuffers;
- // char **txBuffers;
- // char **freeBuffers;
- //
- // // Buffer indices
- // SLuint32 rxFront; // oldest recording
- // SLuint32 rxRear; // next to be recorded
- // SLuint32 txFront; // oldest playing
- // SLuint32 txRear; // next to be played
- // SLuint32 freeFront; // oldest free
- // SLuint32 freeRear; // next to be freed
- //
- // audio_utils_fifo fifo; //(*)
- // SLAndroidSimpleBufferQueueItf recorderBufferQueue;
- // SLBufferQueueItf playerBufferQueue;
-
- // default values
- pSles->rxBufCount = 1; // -r#
- pSles->txBufCount = 1; // -t#
- pSles->bufSizeInFrames = frameCount;//240; // -f#
- pSles->channels = 1; // -c#
- pSles->sampleRate = samplingRate;//48000; // -s#
- pSles->exitAfterSeconds = 3; // -e#
- pSles->freeBufCount = 0; // calculated
- pSles->bufSizeInBytes = 0; // calculated
- pSles->injectImpulse = 300; // -i#i
- pSles->totalDiscardedInputFrames = 0;
- pSles->ignoreFirstFrames = ignoreFirstFrames;
-
- // Storage area for the buffer queues
- // char **rxBuffers;
- // char **txBuffers;
- // char **freeBuffers;
-
- // Buffer indices
- pSles->rxFront; // oldest recording
- pSles->rxRear; // next to be recorded
- pSles->txFront; // oldest playing
- pSles->txRear; // next to be played
- pSles->freeFront; // oldest free
- pSles->freeRear; // next to be freed
-
- pSles->fifo; //(*)
- pSles->fifo2Buffer = NULL; //this fifo is for sending data to java code (to plot it)
- pSles->recorderBufferQueue;
- pSles->playerBufferQueue;
-
-
-
- // compute total free buffers as -r plus -t
- pSles->freeBufCount = pSles->rxBufCount + pSles->txBufCount;
- // compute buffer size
- pSles->bufSizeInBytes = pSles->channels * pSles->bufSizeInFrames * sizeof(short);
-
- // Initialize free buffers
- pSles->freeBuffers = (char **) calloc(pSles->freeBufCount + 1, sizeof(char *));
- SLES_PRINTF(" calloc freeBuffers %zu bytes at %p",pSles->freeBufCount + 1,
- pSles->freeBuffers);
- unsigned j;
- for (j = 0; j < pSles->freeBufCount; ++j) {
- pSles->freeBuffers[j] = (char *) malloc(pSles->bufSizeInBytes);
- SLES_PRINTF(" buff%d malloc %zu bytes at %p",j, pSles->bufSizeInBytes,
- pSles->freeBuffers[j]);
- }
- pSles->freeFront = 0;
- pSles->freeRear = pSles->freeBufCount;
- pSles->freeBuffers[j] = NULL;
-
- // Initialize record queue
- pSles->rxBuffers = (char **) calloc(pSles->rxBufCount + 1, sizeof(char *));
- SLES_PRINTF(" calloc rxBuffers %zu bytes at %p",pSles->rxBufCount + 1, pSles->rxBuffers);
- pSles->rxFront = 0;
- pSles->rxRear = 0;
-
- // Initialize play queue
- pSles->txBuffers = (char **) calloc(pSles->txBufCount + 1, sizeof(char *));
- SLES_PRINTF(" calloc txBuffers %zu bytes at %p",pSles->txBufCount + 1, pSles->txBuffers);
- pSles->txFront = 0;
- pSles->txRear = 0;
-
- size_t frameSize = pSles->channels * sizeof(short);
-#define FIFO_FRAMES 1024
- pSles->fifoBuffer = new short[FIFO_FRAMES * pSles->channels];
- audio_utils_fifo_init(&(pSles->fifo), FIFO_FRAMES, frameSize, pSles->fifoBuffer);
-
- // SNDFILE *sndfile;
- // if (outFileName != NULL) {
- // create .wav writer
- // SF_INFO info;
- // info.frames = 0;
- // info.samplerate = sampleRate;
- // info.channels = channels;
- // info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
- // sndfile = sf_open(outFileName, SFM_WRITE, &info);
- // if (sndfile != NULL) {
-#define FIFO2_FRAMES 65536
- pSles->fifo2Buffer = new short[FIFO2_FRAMES * pSles->channels];
- audio_utils_fifo_init(&(pSles->fifo2), FIFO2_FRAMES, frameSize, pSles->fifo2Buffer);
- // } else {
- // fprintf(stderr, "sf_open failed\n");
- // }
- // } else {
- // sndfile = NULL;
- // }
-
- initBufferStats(&pSles->recorderBufferStats);
- initBufferStats(&pSles->playerBufferStats);
-
- // init other variables needed for buffer test
- pSles->testType = testType;
- pSles->frequency1 = frequency1;
- pSles->bufferTestPhase1 = 0;
- pSles->count = 0;
- pSles->byteBufferPtr = byteBufferPtr;
- pSles->byteBufferLength = byteBufferLength;
-
- //init loopback tone
- pSles->loopbackTone = loopbackTone;
-
- pSles->recorderTimeStamps = {
- new int[maxRecordedLateCallbacks], //int* timeStampsMs
- new short[maxRecordedLateCallbacks], //short* callbackDurations
- 0, //short index
- {0,0}, //struct timespec startTime;
- maxRecordedLateCallbacks, //int capacity
- false //bool exceededCapacity
- };
-
- pSles->playerTimeStamps = {
- new int[maxRecordedLateCallbacks], //int* timeStampsMs
- new short[maxRecordedLateCallbacks], //short* callbackDurations;
- 0, //short index
- {0,0}, //struct timespec startTime;
- maxRecordedLateCallbacks, //int capacity
- false //bool exceededCapacity
- };
-
- pSles->expectedBufferPeriod = (short) (
- round(pSles->bufSizeInFrames * MILLIS_PER_SECOND / (float) pSles->sampleRate));
-
- SLresult result;
-
- // create engine
- pSles->engineObject;
- result = slCreateEngine(&(pSles->engineObject), 0, NULL, 0, NULL, NULL);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->engineObject))->Realize(pSles->engineObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLEngineItf engineEngine;
- result = (*(pSles->engineObject))->GetInterface(pSles->engineObject, SL_IID_ENGINE,
- &engineEngine);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // create output mix
- pSles->outputmixObject;
- result = (*engineEngine)->CreateOutputMix(engineEngine, &(pSles->outputmixObject), 0, NULL,
- NULL);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->outputmixObject))->Realize(pSles->outputmixObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // create an audio player with buffer queue source and output mix sink
- SLDataSource audiosrc;
- SLDataSink audiosnk;
- SLDataFormat_PCM pcm;
- SLDataLocator_OutputMix locator_outputmix;
- SLDataLocator_BufferQueue locator_bufferqueue_tx;
- locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
- locator_bufferqueue_tx.numBuffers = pSles->txBufCount;
- locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
- locator_outputmix.outputMix = pSles->outputmixObject;
- pcm.formatType = SL_DATAFORMAT_PCM;
- pcm.numChannels = pSles->channels;
- pcm.samplesPerSec = pSles->sampleRate * 1000;
- pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
- pcm.containerSize = 16;
- pcm.channelMask = pSles->channels == 1 ? SL_SPEAKER_FRONT_CENTER :
- (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
- pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
- audiosrc.pLocator = &locator_bufferqueue_tx;
- audiosrc.pFormat = &pcm;
- audiosnk.pLocator = &locator_outputmix;
- audiosnk.pFormat = NULL;
- pSles->playerObject = NULL;
- pSles->recorderObject = NULL;
- SLInterfaceID ids_tx[2] = {SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION};
- SLboolean flags_tx[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
- result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(pSles->playerObject),
- &audiosrc, &audiosnk, 2, ids_tx, flags_tx);
- if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
- fprintf(stderr, "Could not create audio player (result %x), check sample rate\n",
- result);
- SLES_PRINTF("ERROR: Could not create audio player (result %x), check sample rate\n",
- result);
- goto cleanup;
- }
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- {
- /* Get the Android configuration interface which is explicit */
- SLAndroidConfigurationItf configItf;
- result = (*(pSles->playerObject))->GetInterface(pSles->playerObject,
- SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- /* Use the configuration interface to configure the player before it's realized */
- if (performanceMode != -1) {
- SLuint32 performanceMode32 = performanceMode;
- result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
- &performanceMode32, sizeof(SLuint32));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- }
-
- result = (*(pSles->playerObject))->Realize(pSles->playerObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLPlayItf playerPlay;
- result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_PLAY,
- &playerPlay);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_BUFFERQUEUE,
- &(pSles->playerBufferQueue));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- result = (*(pSles->playerBufferQueue))->RegisterCallback(pSles->playerBufferQueue,
- playerCallback, pSles); //playerCallback is the name of callback function
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Enqueue some zero buffers for the player
- for (j = 0; j < pSles->txBufCount; ++j) {
-
- // allocate a free buffer
- assert(pSles->freeFront != pSles->freeRear);
- char *buffer = pSles->freeBuffers[pSles->freeFront];
- if (++pSles->freeFront > pSles->freeBufCount) {
- pSles->freeFront = 0;
- }
-
- // put on play queue
- SLuint32 txRearNext = pSles->txRear + 1;
- if (txRearNext > pSles->txBufCount) {
- txRearNext = 0;
- }
- assert(txRearNext != pSles->txFront);
- pSles->txBuffers[pSles->txRear] = buffer;
- pSles->txRear = txRearNext;
- result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue,
- buffer, pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Create an audio recorder with microphone device source and buffer queue sink.
- // The buffer queue as sink is an Android-specific extension.
- SLDataLocator_IODevice locator_iodevice;
- SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
-
- locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
- locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
- locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
- locator_iodevice.device = NULL;
-
- audiosrc.pLocator = &locator_iodevice;
- audiosrc.pFormat = NULL;
-
- locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
- locator_bufferqueue_rx.numBuffers = pSles->rxBufCount;
-
- audiosnk.pLocator = &locator_bufferqueue_rx;
- audiosnk.pFormat = &pcm;
-
- { //why brackets here?
- SLInterfaceID ids_rx[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- SL_IID_ANDROIDCONFIGURATION};
- SLboolean flags_rx[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
- result = (*engineEngine)->CreateAudioRecorder(engineEngine, &(pSles->recorderObject),
- &audiosrc, &audiosnk, 2, ids_rx, flags_rx);
- if (SL_RESULT_SUCCESS != result) {
- fprintf(stderr, "Could not create audio recorder (result %x), "
- "check sample rate and channel count\n", result);
- status = SLES_FAIL;
-
- SLES_PRINTF("ERROR: Could not create audio recorder (result %x), "
- "check sample rate and channel count\n", result);
- goto cleanup;
- }
- }
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- {
- /* Get the Android configuration interface which is explicit */
- SLAndroidConfigurationItf configItf;
- result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
- SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- SLuint32 presetValue = micSource;
- //SL_ANDROID_RECORDING_PRESET_CAMCORDER;//SL_ANDROID_RECORDING_PRESET_NONE;
-
- /* Use the configuration interface to configure the recorder before it's realized */
- if (presetValue != SL_ANDROID_RECORDING_PRESET_NONE) {
- result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
- &presetValue, sizeof(SLuint32));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
- if (performanceMode != -1) {
- SLuint32 performanceMode32 = performanceMode;
- result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
- &performanceMode32, sizeof(SLuint32));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- }
-
- result = (*(pSles->recorderObject))->Realize(pSles->recorderObject, SL_BOOLEAN_FALSE);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- SLRecordItf recorderRecord;
- result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject, SL_IID_RECORD,
- &recorderRecord);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(pSles->recorderBufferQueue));
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- result = (*(pSles->recorderBufferQueue))->RegisterCallback(pSles->recorderBufferQueue,
- recorderCallback, pSles);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- // Enqueue some empty buffers for the recorder
- for (j = 0; j < pSles->rxBufCount; ++j) {
-
- // allocate a free buffer
- assert(pSles->freeFront != pSles->freeRear);
- char *buffer = pSles->freeBuffers[pSles->freeFront];
- if (++pSles->freeFront > pSles->freeBufCount) {
- pSles->freeFront = 0;
- }
-
- // put on record queue
- SLuint32 rxRearNext = pSles->rxRear + 1;
- if (rxRearNext > pSles->rxBufCount) {
- rxRearNext = 0;
- }
- assert(rxRearNext != pSles->rxFront);
- pSles->rxBuffers[pSles->rxRear] = buffer;
- pSles->rxRear = rxRearNext;
- result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue,
- buffer, pSles->bufSizeInBytes);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- // Kick off the recorder
- result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
-
-
- // Tear down the objects and exit
- status = SLES_SUCCESS;
- cleanup:
-
- SLES_PRINTF("Finished initialization with status: %d", status);
-
- int xx = 1;
-
- }
- return status;
-}
-
-// Read data from fifo2Buffer and store into pSamples.
-int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples) {
- //int status = SLES_FAIL;
-
- SLES_PRINTF("slesProcessNext: pSles = %p, currentSample: %p, maxSamples = %ld",
- pSles, pSamples, maxSamples);
-
- int samplesRead = 0;
-
- int currentSample = 0;
- double *pCurrentSample = pSamples;
- int maxValue = 32768;
-
- if (pSles != NULL) {
-
- SLresult result;
- for (int i = 0; i < 10; i++) {
- usleep(100000); // sleep for 0.1s
- if (pSles->fifo2Buffer != NULL) {
- for (;;) {
- short buffer[pSles->bufSizeInFrames * pSles->channels];
- ssize_t actual = audio_utils_fifo_read(&(pSles->fifo2), buffer,
- pSles->bufSizeInFrames);
- if (actual <= 0)
- break;
- {
- for (int jj = 0; jj < actual && currentSample < maxSamples; jj++) {
- *(pCurrentSample++) = ((double) buffer[jj]) / maxValue;
- currentSample++;
- }
- }
- samplesRead += actual;
- }
- }
- if (pSles->injectImpulse > 0) {
- if (pSles->injectImpulse <= 100) {
- pSles->injectImpulse = -1;
- write(1, "I", 1);
- } else {
- if ((pSles->injectImpulse % 1000) < 100) {
- write(1, "i", 1);
- }
- pSles->injectImpulse -= 100;
- }
- } else if (i == 9) {
- write(1, ".", 1);
- }
- }
- SLBufferQueueState playerBQState;
- result = (*(pSles->playerBufferQueue))->GetState(pSles->playerBufferQueue,
- &playerBQState);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- SLAndroidSimpleBufferQueueState recorderBQState;
- result = (*(pSles->recorderBufferQueue))->GetState(pSles->recorderBufferQueue,
- &recorderBQState);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- SLES_PRINTF("End of slesProcessNext: pSles = %p, samplesRead = %d, maxSamples = %ld",
- pSles, samplesRead, maxSamples);
- }
- return samplesRead;
-}
-
-
-int slesDestroyServer(sles_data *pSles) {
- int status = SLES_FAIL;
-
- SLES_PRINTF("Start slesDestroyServer: pSles = %p", pSles);
-
- if (pSles != NULL) {
- if (NULL != pSles->playerObject) {
- SLES_PRINTF("stopping player...");
- SLPlayItf playerPlay;
- SLresult result = (*(pSles->playerObject))->GetInterface(pSles->playerObject,
- SL_IID_PLAY, &playerPlay);
-
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- //stop player and recorder if they exist
- result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- if (NULL != pSles->recorderObject) {
- SLES_PRINTF("stopping recorder...");
- SLRecordItf recorderRecord;
- SLresult result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
- SL_IID_RECORD, &recorderRecord);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
-
- result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
- ASSERT_EQ(SL_RESULT_SUCCESS, result);
- }
-
- usleep(1000);
-
- audio_utils_fifo_deinit(&(pSles->fifo));
- delete[] pSles->fifoBuffer;
-
- SLES_PRINTF("slesDestroyServer 2");
-
- // if (sndfile != NULL) {
- audio_utils_fifo_deinit(&(pSles->fifo2));
- delete[] pSles->fifo2Buffer;
-
- SLES_PRINTF("slesDestroyServer 3");
-
- // sf_close(sndfile);
- // }
- if (NULL != pSles->playerObject) {
- (*(pSles->playerObject))->Destroy(pSles->playerObject);
- }
-
- SLES_PRINTF("slesDestroyServer 4");
-
- if (NULL != pSles->recorderObject) {
- (*(pSles->recorderObject))->Destroy(pSles->recorderObject);
- }
-
- SLES_PRINTF("slesDestroyServer 5");
-
- (*(pSles->outputmixObject))->Destroy(pSles->outputmixObject);
- SLES_PRINTF("slesDestroyServer 6");
- (*(pSles->engineObject))->Destroy(pSles->engineObject);
- SLES_PRINTF("slesDestroyServer 7");
-
- //free buffers
- if (NULL != pSles->freeBuffers) {
- for (unsigned j = 0; j < pSles->freeBufCount; ++j) {
- if (NULL != pSles->freeBuffers[j]) {
- SLES_PRINTF(" free buff%d at %p",j, pSles->freeBuffers[j]);
- free (pSles->freeBuffers[j]);
- }
- }
- SLES_PRINTF(" free freeBuffers at %p", pSles->freeBuffers);
- free(pSles->freeBuffers);
- } else {
- SLES_PRINTF(" freeBuffers NULL, no need to free");
- }
-
-
- if (NULL != pSles->rxBuffers) {
- SLES_PRINTF(" free rxBuffers at %p", pSles->rxBuffers);
- free(pSles->rxBuffers);
- } else {
- SLES_PRINTF(" rxBuffers NULL, no need to free");
- }
-
- if (NULL != pSles->txBuffers) {
- SLES_PRINTF(" free txBuffers at %p", pSles->txBuffers);
- free(pSles->txBuffers);
- } else {
- SLES_PRINTF(" txBuffers NULL, no need to free");
- }
-
-
- status = SLES_SUCCESS;
- }
- SLES_PRINTF("End slesDestroyServer: status = %d", status);
- return status;
-}
-
-
-int* slesGetRecorderBufferPeriod(sles_data *pSles) {
- return pSles->recorderBufferStats.buffer_period;
-}
-
-int slesGetRecorderMaxBufferPeriod(sles_data *pSles) {
- return pSles->recorderBufferStats.max_buffer_period;
-}
-
-int64_t slesGetRecorderVarianceBufferPeriod(sles_data *pSles) {
- return pSles->recorderBufferStats.var;
-}
-
-int* slesGetPlayerBufferPeriod(sles_data *pSles) {
- return pSles->playerBufferStats.buffer_period;
-}
-
-int slesGetPlayerMaxBufferPeriod(sles_data *pSles) {
- return pSles->playerBufferStats.max_buffer_period;
-}
-
-int64_t slesGetPlayerVarianceBufferPeriod(sles_data *pSles) {
- return pSles->playerBufferStats.var;
-}
-
-int slesGetCaptureRank(sles_data *pSles) {
- // clear the capture flags since they're being handled now
- int recorderRank = android_atomic_exchange(0, &pSles->recorderBufferStats.captureRank);
- int playerRank = android_atomic_exchange(0, &pSles->playerBufferStats.captureRank);
-
- if (recorderRank > playerRank) {
- return recorderRank;
- } else {
- return playerRank;
- }
-}
diff --git a/LoopbackApp/app/src/main/jni/sles.h b/LoopbackApp/app/src/main/jni/sles.h
deleted file mode 100644
index c176656..0000000
--- a/LoopbackApp/app/src/main/jni/sles.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <SLES/OpenSLES.h>
-#include <SLES/OpenSLES_Android.h>
-#include <pthread.h>
-#include <android/log.h>
-#include <jni.h>
-#include <stdbool.h>
-
-#ifndef _Included_org_drrickorang_loopback_sles
-#define _Included_org_drrickorang_loopback_sles
-
-//struct audio_utils_fifo;
-#define SLES_PRINTF(...) __android_log_print(ANDROID_LOG_INFO, "sles_jni", __VA_ARGS__);
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <audio_utils/fifo.h>
-
-typedef struct {
- int* timeStampsMs; // Array of milliseconds since first callback
- short* callbackDurations; // Array of milliseconds between callback and previous callback
- short index; // Current write position
- struct timespec startTime; // Time of first callback {seconds,nanoseconds}
- int capacity; // Total number of callback times/lengths that can be recorded
- bool exceededCapacity; // Set only if late callbacks come after array is full
-} callbackTimeStamps;
-
-typedef struct {
- int* buffer_period;
- struct timespec previous_time;
- struct timespec current_time;
- int buffer_count;
- int max_buffer_period;
-
- volatile int32_t captureRank; // Set > 0 when the callback requests a systrace/bug report
-
- int measurement_count; // number of measurements which were actually recorded
- int64_t SDM; // sum of squares of deviations from the expected mean
- int64_t var; // variance in nanoseconds^2
-} bufferStats;
-
-//TODO fix this
-typedef struct {
- SLuint32 rxBufCount; // -r#
- SLuint32 txBufCount; // -t#
- SLuint32 bufSizeInFrames; // -f#
- SLuint32 channels; // -c#
- SLuint32 sampleRate; // -s#
- SLuint32 exitAfterSeconds; // -e#
- SLuint32 freeBufCount; // calculated
- SLuint32 bufSizeInBytes; // calculated
- int injectImpulse; // -i#i
- size_t totalDiscardedInputFrames; // total number of input frames discarded
- int ignoreFirstFrames;
-
- // Storage area for the buffer queues
- char **rxBuffers;
- char **txBuffers;
- char **freeBuffers;
-
- // Buffer indices
- SLuint32 rxFront; // oldest recording
- SLuint32 rxRear; // next to be recorded
- SLuint32 txFront; // oldest playing
- SLuint32 txRear; // next to be played
- SLuint32 freeFront; // oldest free
- SLuint32 freeRear; // next to be freed
-
- struct audio_utils_fifo fifo; // jitter buffer between recorder and player callbacks,
- // to mitigate unpredictable phase difference between these,
- // or even concurrent callbacks on two CPU cores
- struct audio_utils_fifo fifo2; // For sending data to java code (to plot it)
- short *fifo2Buffer;
- short *fifoBuffer;
- SLAndroidSimpleBufferQueueItf recorderBufferQueue;
- SLBufferQueueItf playerBufferQueue;
-
- //other things that belong here
- SLObjectItf playerObject;
- SLObjectItf recorderObject;
- SLObjectItf outputmixObject;
- SLObjectItf engineObject;
-
- bufferStats recorderBufferStats;
- bufferStats playerBufferStats;
-
- int testType;
- double frequency1;
- double bufferTestPhase1;
- int count;
- char* byteBufferPtr;
- int byteBufferLength;
-
- short* loopbackTone;
-
- callbackTimeStamps recorderTimeStamps;
- callbackTimeStamps playerTimeStamps;
- short expectedBufferPeriod;
-} sles_data;
-
-#define NANOS_PER_SECOND 1000000000
-#define NANOS_PER_MILLI 1000000
-#define MILLIS_PER_SECOND 1000
-
-// how late in ms a callback must be to trigger a systrace/bugreport
-#define LATE_CALLBACK_CAPTURE_THRESHOLD 4
-#define LATE_CALLBACK_OUTLIER_THRESHOLD 1
-#define BUFFER_PERIOD_DISCARD 10
-#define BUFFER_PERIOD_DISCARD_FULL_DUPLEX_PARTNER 2
-
-enum {
- SLES_SUCCESS = 0,
- SLES_FAIL = 1,
- RANGE = 1002,
- TEST_TYPE_LATENCY = 222,
- TEST_TYPE_BUFFER_PERIOD = 223
-} SLES_STATUS_ENUM;
-
-int slesInit(sles_data ** ppSles, int samplingRate, int frameCount, int micSource,
- int performanceMode,
- int testType, double frequency1, char* byteBufferPtr, int byteBufferLength,
- short* loopbackTone, int maxRecordedLateCallbacks, int ignoreFirstFrames);
-
-//note the double pointer to properly free the memory of the structure
-int slesDestroy(sles_data ** ppSles);
-
-
-///full
-int slesFull(sles_data *pSles);
-
-int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount, int micSource,
- int performanceMode,
- int testType, double frequency1, char* byteBufferPtr, int byteBufferLength,
- short* loopbackTone, int maxRecordedLateCallbacks, int ignoreFirstFrames);
-int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples);
-int slesDestroyServer(sles_data *pSles);
-int* slesGetRecorderBufferPeriod(sles_data *pSles);
-int slesGetRecorderMaxBufferPeriod(sles_data *pSles);
-int64_t slesGetRecorderVarianceBufferPeriod(sles_data *pSles);
-int* slesGetPlayerBufferPeriod(sles_data *pSles);
-int slesGetPlayerMaxBufferPeriod(sles_data *pSles);
-int64_t slesGetPlayerVarianceBufferPeriod(sles_data *pSles);
-int slesGetCaptureRank(sles_data *pSles);
-
-void initBufferStats(bufferStats *stats);
-void collectBufferPeriod(bufferStats *stats, bufferStats *fdpStats, callbackTimeStamps *timeStamps,
- short expectedBufferPeriod);
-bool updateBufferStats(bufferStats *stats, int64_t diff_in_nano, int expectedBufferPeriod);
-void recordTimeStamp(callbackTimeStamps *timeStamps,
- int64_t callbackDuration, int64_t timeStamp);
-
-ssize_t byteBuffer_write(sles_data *pSles, char *buffer, size_t count);
-
-#ifdef __cplusplus
-}
-#endif
-#endif //_Included_org_drrickorang_loopback_sles