Skip to content

Commit bb3d818

Browse files
authored
OboeTester needs volume report in Recorder (#2120) (#2337)
1 parent 0df8303 commit bb3d818

6 files changed

Lines changed: 114 additions & 1 deletion

File tree

apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,47 @@ oboe::Result ActivityRecording::startPlayback() {
715715
return result;
716716
}
717717

718+
ActivityRecording::RecordingStats ActivityRecording::computeRecordingStats() {
719+
constexpr int chunkFrames = 512;
720+
721+
mRecording->rewind();
722+
723+
const int ch = mRecording->getChannelCount();
724+
auto buffer = std::make_unique<float[]>(chunkFrames * ch);
725+
726+
const int32_t totalFrames = mRecording->getSizeInFrames();
727+
int32_t frameIndex = 0;
728+
729+
RecordingStats recordingStats;
730+
731+
while (frameIndex < totalFrames) {
732+
const int framesToRead = std::min<int>(chunkFrames, totalFrames - frameIndex);
733+
const int framesRead = mRecording->read(buffer.get(), framesToRead);
734+
if (framesRead <= 0) break;
735+
736+
const int samplesRead = framesRead * ch;
737+
738+
for (int i = 0; i < samplesRead; ++i) {
739+
const double x = buffer[i];
740+
recordingStats.peakAbs = std::max(recordingStats.peakAbs, std::abs(x));
741+
recordingStats.sumSq += x * x;
742+
}
743+
recordingStats.n += samplesRead;
744+
745+
frameIndex += framesRead;
746+
747+
bool lastRemainingFramesRead = framesRead < framesToRead;
748+
if (lastRemainingFramesRead) break;
749+
}
750+
751+
return recordingStats;
752+
}
753+
754+
ActivityRecording::RecordingStats ActivityRecording::getRecordingStats() {
755+
return computeRecordingStats();
756+
}
757+
758+
718759
// ======================================================================= ActivityTapToTone
719760
void ActivityTapToTone::configureAfterOpen() {
720761
monoToMulti = std::make_unique<MonoToMultiConverter>(mChannelCount);

apps/OboeTester/app/src/main/cpp/NativeAudioContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,15 @@ class ActivityRecording : public ActivityTestInput {
456456
PlayRecordingCallback mPlayRecordingCallback;
457457
oboe::AudioStream *playbackStream = nullptr;
458458

459+
struct RecordingStats {
460+
double peakAbs = 0.0;
461+
double sumSq = 0.0;
462+
int64_t n = 0; // total samples
463+
};
464+
465+
RecordingStats computeRecordingStats();
466+
467+
ActivityRecording::RecordingStats getRecordingStats();
459468
};
460469

461470
/**

apps/OboeTester/app/src/main/cpp/jni-bridge.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ static jfieldID g_stretchModeField = nullptr;
5959
static jfieldID g_pitchField = nullptr;
6060
static jfieldID g_speedField = nullptr;
6161

62+
static jclass g_recordingStatsClass = nullptr;
63+
static jmethodID g_recordingStatsConstructor = nullptr;
64+
6265
JNIEXPORT jint JNICALL
6366
Java_com_mobileer_oboetester_OboeAudioStream_openNative(JNIEnv *env, jobject,
6467
jint nativeApi,
@@ -1117,6 +1120,16 @@ Java_com_mobileer_oboetester_ManualGlitchActivity_getRecentSamples(JNIEnv *env,
11171120
return numSamples;
11181121
}
11191122

1123+
JNIEXPORT jobject JNICALL
1124+
Java_com_mobileer_oboetester_RecorderActivity_getRecordingStatsJni(JNIEnv *env, jobject) {
1125+
1126+
ActivityRecording::RecordingStats params = engine.mActivityRecording.getRecordingStats();
1127+
1128+
return env->NewObject(g_recordingStatsClass, g_recordingStatsConstructor,
1129+
(jfloat)params.peakAbs,
1130+
(params.n > 0) ? (float)std::sqrt(params.sumSq / (float)params.n) : 0.0F);
1131+
}
1132+
11201133
JNIEXPORT void JNICALL
11211134
Java_com_mobileer_oboetester_TestAudioActivity_setDefaultAudioValues(JNIEnv *env, jclass clazz,
11221135
jint audio_manager_sample_rate,
@@ -1401,6 +1414,28 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
14011414
return JNI_ERR;
14021415
}
14031416

1417+
const char* recordingStatsClassName = "com/mobileer/oboetester/RecordingStats";
1418+
jclass localRecordingStatsClass = env->FindClass(recordingStatsClassName);
1419+
if (localRecordingStatsClass == nullptr) {
1420+
LOGE("JNI_OnLoad: Could not find class %s", recordingStatsClassName);
1421+
if (env->ExceptionCheck()) env->ExceptionDescribe();
1422+
return JNI_ERR;
1423+
}
1424+
g_recordingStatsClass = (jclass)env->NewGlobalRef(localRecordingStatsClass);
1425+
env->DeleteLocalRef(localRecordingStatsClass);
1426+
if (g_recordingStatsClass == nullptr) {
1427+
LOGE("JNI_OnLoad: Could not create global ref for %s", recordingStatsClassName);
1428+
return JNI_ERR;
1429+
}
1430+
1431+
g_recordingStatsConstructor = env->GetMethodID(
1432+
g_recordingStatsClass, "<init>", "(FF)V");
1433+
if (g_recordingStatsConstructor == nullptr) {
1434+
LOGE("JNI_OnLoad: Could not find constructor for %s", recordingStatsClassName);
1435+
if (env->ExceptionCheck()) env->ExceptionDescribe();
1436+
return JNI_ERR;
1437+
}
1438+
14041439
g_fallbackModeField = env->GetFieldID(g_playbackParametersClass, "mFallbackMode", "I");
14051440
g_stretchModeField = env->GetFieldID(g_playbackParametersClass, "mStretchMode", "I");
14061441
g_pitchField = env->GetFieldID(g_playbackParametersClass, "mPitch", "F");

apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.os.Bundle;
2020
import android.view.View;
2121
import android.widget.Button;
22+
import android.widget.TextView;
2223

2324
import java.io.IOException;
2425

@@ -34,6 +35,7 @@ public class RecorderActivity extends TestInputActivity {
3435
private Button mStopButton;
3536
private Button mPlayButton;
3637
private Button mShareButton;
38+
private TextView mStatusView;
3739
private boolean mGotRecording;
3840

3941
@Override
@@ -49,6 +51,7 @@ protected void onCreate(Bundle savedInstanceState) {
4951
mStopButton = (Button) findViewById(R.id.button_stop_record_play);
5052
mPlayButton = (Button) findViewById(R.id.button_start_playback);
5153
mShareButton = (Button) findViewById(R.id.button_share);
54+
mStatusView = (TextView) findViewById(R.id.status_view);
5255
mRecorderState = AUDIO_STATE_STOPPED;
5356
mGotRecording = false;
5457
updateButtons();
@@ -75,6 +78,19 @@ public void onStopRecordPlay(View view) {
7578
closeAudio();
7679
mRecorderState = AUDIO_STATE_STOPPED;
7780
updateButtons();
81+
82+
StringBuilder text = new StringBuilder();
83+
for (StreamContext streamContext: mStreamContexts) {
84+
RecordingStats recordingStats = getRecordingStatsJni();
85+
text
86+
.append("Peak amplitude: ")
87+
.append(recordingStats.peak)
88+
.append("\n")
89+
.append("Rms: ")
90+
.append(recordingStats.rms)
91+
.append("\n");
92+
}
93+
mStatusView.setText(text);
7894
}
7995

8096
public void onStartPlayback(View view) {
@@ -106,4 +122,5 @@ String getWaveTag() {
106122
return "recording";
107123
}
108124

125+
private native RecordingStats getRecordingStatsJni();
109126
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.mobileer.oboetester;
2+
3+
public final class RecordingStats {
4+
public final float peak;
5+
public final float rms;
6+
7+
public RecordingStats(float peak, float rms) {
8+
this.peak = peak;
9+
this.rms = rms;
10+
}
11+
}

apps/OboeTester/app/src/main/res/layout/activity_recorder.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
</LinearLayout>
9999

100100
<TextView
101-
android:id="@+id/statusView"
101+
android:id="@+id/status_view"
102102
android:layout_width="match_parent"
103103
android:layout_height="wrap_content"
104104
android:lines="3"

0 commit comments

Comments
 (0)