Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,47 @@ oboe::Result ActivityRecording::startPlayback() {
return result;
}

ActivityRecording::RecordingStats ActivityRecording::computeRecordingStats() {
constexpr int chunkFrames = 512;

mRecording->rewind();

const int ch = mRecording->getChannelCount();
auto buffer = std::make_unique<float[]>(chunkFrames * ch);

const int32_t totalFrames = mRecording->getSizeInFrames();
int32_t frameIndex = 0;

RecordingStats recordingStats;

while (frameIndex < totalFrames) {
const int framesToRead = std::min<int>(chunkFrames, totalFrames - frameIndex);
const int framesRead = mRecording->read(buffer.get(), framesToRead);
if (framesRead <= 0) break;

const int samplesRead = framesRead * ch;

for (int i = 0; i < samplesRead; ++i) {
const double x = buffer[i];
recordingStats.peakAbs = std::max(recordingStats.peakAbs, std::abs(x));
recordingStats.sumSq += x * x;
}
recordingStats.n += samplesRead;

frameIndex += framesRead;

bool lastRemainingFramesRead = framesRead < framesToRead;
if (lastRemainingFramesRead) break;
}

return recordingStats;
}

ActivityRecording::RecordingStats ActivityRecording::getRecordingStats() {
return computeRecordingStats();
}


// ======================================================================= ActivityTapToTone
void ActivityTapToTone::configureAfterOpen() {
monoToMulti = std::make_unique<MonoToMultiConverter>(mChannelCount);
Expand Down
9 changes: 9 additions & 0 deletions apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,15 @@ class ActivityRecording : public ActivityTestInput {
PlayRecordingCallback mPlayRecordingCallback;
oboe::AudioStream *playbackStream = nullptr;

struct RecordingStats {
double peakAbs = 0.0;
double sumSq = 0.0;
int64_t n = 0; // total samples
};

RecordingStats computeRecordingStats();

ActivityRecording::RecordingStats getRecordingStats();
};

/**
Expand Down
35 changes: 35 additions & 0 deletions apps/OboeTester/app/src/main/cpp/jni-bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ static jfieldID g_stretchModeField = nullptr;
static jfieldID g_pitchField = nullptr;
static jfieldID g_speedField = nullptr;

static jclass g_recordingStatsClass = nullptr;
static jmethodID g_recordingStatsConstructor = nullptr;

JNIEXPORT jint JNICALL
Java_com_mobileer_oboetester_OboeAudioStream_openNative(JNIEnv *env, jobject,
jint nativeApi,
Expand Down Expand Up @@ -1117,6 +1120,16 @@ Java_com_mobileer_oboetester_ManualGlitchActivity_getRecentSamples(JNIEnv *env,
return numSamples;
}

JNIEXPORT jobject JNICALL
Java_com_mobileer_oboetester_RecorderActivity_getRecordingStatsJni(JNIEnv *env, jobject) {

ActivityRecording::RecordingStats params = engine.mActivityRecording.getRecordingStats();

return env->NewObject(g_recordingStatsClass, g_recordingStatsConstructor,
(jfloat)params.peakAbs,
(params.n > 0) ? (float)std::sqrt(params.sumSq / (float)params.n) : 0.0F);
}

JNIEXPORT void JNICALL
Java_com_mobileer_oboetester_TestAudioActivity_setDefaultAudioValues(JNIEnv *env, jclass clazz,
jint audio_manager_sample_rate,
Expand Down Expand Up @@ -1401,6 +1414,28 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_ERR;
}

const char* recordingStatsClassName = "com/mobileer/oboetester/RecordingStats";
jclass localRecordingStatsClass = env->FindClass(recordingStatsClassName);
if (localRecordingStatsClass == nullptr) {
LOGE("JNI_OnLoad: Could not find class %s", recordingStatsClassName);
if (env->ExceptionCheck()) env->ExceptionDescribe();
return JNI_ERR;
}
g_recordingStatsClass = (jclass)env->NewGlobalRef(localRecordingStatsClass);
env->DeleteLocalRef(localRecordingStatsClass);
if (g_recordingStatsClass == nullptr) {
LOGE("JNI_OnLoad: Could not create global ref for %s", recordingStatsClassName);
return JNI_ERR;
}

g_recordingStatsConstructor = env->GetMethodID(
g_recordingStatsClass, "<init>", "(FF)V");
if (g_recordingStatsConstructor == nullptr) {
LOGE("JNI_OnLoad: Could not find constructor for %s", recordingStatsClassName);
if (env->ExceptionCheck()) env->ExceptionDescribe();
return JNI_ERR;
}

g_fallbackModeField = env->GetFieldID(g_playbackParametersClass, "mFallbackMode", "I");
g_stretchModeField = env->GetFieldID(g_playbackParametersClass, "mStretchMode", "I");
g_pitchField = env->GetFieldID(g_playbackParametersClass, "mPitch", "F");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;

Expand All @@ -34,6 +35,7 @@ public class RecorderActivity extends TestInputActivity {
private Button mStopButton;
private Button mPlayButton;
private Button mShareButton;
private TextView mStatusView;
private boolean mGotRecording;

@Override
Expand All @@ -49,6 +51,7 @@ protected void onCreate(Bundle savedInstanceState) {
mStopButton = (Button) findViewById(R.id.button_stop_record_play);
mPlayButton = (Button) findViewById(R.id.button_start_playback);
mShareButton = (Button) findViewById(R.id.button_share);
mStatusView = (TextView) findViewById(R.id.status_view);
mRecorderState = AUDIO_STATE_STOPPED;
mGotRecording = false;
updateButtons();
Expand All @@ -75,6 +78,19 @@ public void onStopRecordPlay(View view) {
closeAudio();
mRecorderState = AUDIO_STATE_STOPPED;
updateButtons();

StringBuilder text = new StringBuilder();
for (StreamContext streamContext: mStreamContexts) {
RecordingStats recordingStats = getRecordingStatsJni();
text
.append("Peak amplitude: ")
.append(recordingStats.peak)
.append("\n")
.append("Rms: ")
.append(recordingStats.rms)
.append("\n");
}
mStatusView.setText(text);
}

public void onStartPlayback(View view) {
Expand Down Expand Up @@ -106,4 +122,5 @@ String getWaveTag() {
return "recording";
}

private native RecordingStats getRecordingStatsJni();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mobileer.oboetester;

public final class RecordingStats {
public final float peak;
public final float rms;

public RecordingStats(float peak, float rms) {
this.peak = peak;
this.rms = rms;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
</LinearLayout>

<TextView
android:id="@+id/statusView"
android:id="@+id/status_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lines="3"
Expand Down