Skip to content

Commit 54070ea

Browse files
committed
OboeTester: Test multiple input and output streams
1 parent e5c061b commit 54070ea

12 files changed

Lines changed: 626 additions & 10 deletions

apps/OboeTester/app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@
9494
android:name=".TestDataPathsActivity"
9595
android:label="@string/title_data_paths"
9696
android:screenOrientation="portrait" />
97+
<activity
98+
android:name=".TestMultiStreamActivity"
99+
android:exported="true"
100+
android:label="Multi-Stream Test" />
97101
<activity
98102
android:name=".ExtraTestsActivity"
99103
android:exported="true"

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

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ class ActivityContext {
222222
return 0.0;
223223
}
224224

225+
virtual double getPeakLevel(int streamIndex, int channelIndex) {
226+
return 0.0;
227+
}
228+
225229
static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
226230
struct timespec time;
227231
int result = clock_gettime(clockId, &time);
@@ -867,6 +871,142 @@ class ActivityTestDisconnect : public ActivityContext {
867871
std::shared_ptr<oboe::flowgraph::SinkFloat> mSinkFloat;
868872
};
869873

874+
/**
875+
* Test multiple streams.
876+
*/
877+
class ActivityTestMultiStream : public ActivityContext {
878+
public:
879+
class MultiStreamCallback : public oboe::AudioStreamDataCallback {
880+
public:
881+
MultiStreamCallback() {
882+
for (int i = 0; i < 8; i++) mPeakLevels[i] = 0.0;
883+
}
884+
885+
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) override {
886+
int channelCount = audioStream->getChannelCount();
887+
if (channelCount > 8) channelCount = 8;
888+
889+
if (audioStream->getDirection() == oboe::Direction::Output) {
890+
int channelCount = audioStream->getChannelCount();
891+
float phaseIncrement = 440.0f * M_PI * 2 / (float)audioStream->getSampleRate();
892+
if (audioStream->getFormat() == oboe::AudioFormat::Float) {
893+
float *floatData = (float *) audioData;
894+
for (int i = 0; i < numFrames; i++) {
895+
float sample = sinf(mPhase) * 0.5f;
896+
mPhase += phaseIncrement;
897+
if (mPhase > M_PI * 2) mPhase -= (float)(M_PI * 2);
898+
for (int c = 0; c < channelCount; c++) {
899+
*floatData++ = sample;
900+
}
901+
}
902+
} else if (audioStream->getFormat() == oboe::AudioFormat::I16) {
903+
int16_t *shortData = (int16_t *) audioData;
904+
for (int i = 0; i < numFrames; i++) {
905+
float sample = sinf(mPhase) * 0.5f;
906+
mPhase += phaseIncrement;
907+
if (mPhase > M_PI * 2) mPhase -= (float)(M_PI * 2);
908+
for (int c = 0; c < channelCount; c++) {
909+
*shortData++ = (int16_t)(sample * 32767);
910+
}
911+
}
912+
} else if (audioStream->getFormat() == oboe::AudioFormat::I24) {
913+
uint8_t *byteData = (uint8_t *) audioData;
914+
for (int i = 0; i < numFrames; i++) {
915+
float sample = sinf(mPhase) * 0.5f;
916+
mPhase += phaseIncrement;
917+
if (mPhase > M_PI * 2) mPhase -= (float)(M_PI * 2);
918+
int32_t sample24 = (int32_t)(sample * 8388607);
919+
for (int c = 0; c < channelCount; c++) {
920+
*byteData++ = (uint8_t)(sample24 & 0xFF);
921+
*byteData++ = (uint8_t)((sample24 >> 8) & 0xFF);
922+
*byteData++ = (uint8_t)((sample24 >> 16) & 0xFF);
923+
}
924+
}
925+
}
926+
}
927+
928+
// Measure peak level for both input and output
929+
if (audioStream->getFormat() == oboe::AudioFormat::Float) {
930+
float *floatData = (float *) audioData;
931+
for (int i = 0; i < numFrames; i++) {
932+
for (int c = 0; c < channelCount; c++) {
933+
float sample = std::abs(*floatData++);
934+
if (sample > mPeakLevels[c]) mPeakLevels[c] = sample;
935+
}
936+
}
937+
} else if (audioStream->getFormat() == oboe::AudioFormat::I16) {
938+
int16_t *shortData = (int16_t *) audioData;
939+
for (int i = 0; i < numFrames; i++) {
940+
for (int c = 0; c < channelCount; c++) {
941+
float sample = std::abs(*shortData++) / 32768.0f;
942+
if (sample > mPeakLevels[c]) mPeakLevels[c] = sample;
943+
}
944+
}
945+
} else if (audioStream->getFormat() == oboe::AudioFormat::I24) {
946+
uint8_t *byteData = (uint8_t *) audioData;
947+
for (int i = 0; i < numFrames; i++) {
948+
for (int c = 0; c < channelCount; c++) {
949+
int32_t sample24 = (byteData[0]) | (byteData[1] << 8) | (byteData[2] << 16);
950+
if (sample24 & 0x800000) sample24 |= ~0xFFFFFF; // sign extend
951+
float sample = std::abs(sample24) / 8388608.0f;
952+
byteData += 3;
953+
if (sample > mPeakLevels[c]) mPeakLevels[c] = sample;
954+
}
955+
}
956+
}
957+
958+
return oboe::DataCallbackResult::Continue;
959+
}
960+
961+
double getPeakLevel(int index) {
962+
if (index < 0 || index >= 8) return 0.0;
963+
double peak = mPeakLevels[index];
964+
mPeakLevels[index] = 0.0;
965+
return peak;
966+
}
967+
private:
968+
float mPhase = 0.0f;
969+
double mPeakLevels[8];
970+
};
971+
972+
ActivityTestMultiStream() = default;
973+
974+
virtual ~ActivityTestMultiStream() = default;
975+
976+
void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override {
977+
std::shared_ptr<MultiStreamCallback> callback = std::make_shared<MultiStreamCallback>();
978+
mCallbacks.push_back(callback);
979+
builder.setDataCallback(callback);
980+
}
981+
982+
oboe::Result startStreams() override {
983+
oboe::Result result = oboe::Result::OK;
984+
for (auto entry : mOboeStreams) {
985+
std::shared_ptr<oboe::AudioStream> oboeStream = entry.second;
986+
if (oboeStream) {
987+
result = oboeStream->requestStart();
988+
if (result != oboe::Result::OK) break;
989+
}
990+
}
991+
return result;
992+
}
993+
994+
double getPeakLevel(int streamIndex, int channelIndex) override {
995+
std::shared_ptr<oboe::AudioStream> oboeStream = getStream(streamIndex);
996+
if (oboeStream) {
997+
oboe::AudioStreamDataCallback *callback = oboeStream->getDataCallback();
998+
if (callback) {
999+
MultiStreamCallback *myCallback = static_cast<MultiStreamCallback*>(callback);
1000+
return myCallback->getPeakLevel(channelIndex);
1001+
}
1002+
}
1003+
return 0.0;
1004+
}
1005+
1006+
private:
1007+
std::vector<std::shared_ptr<MultiStreamCallback>> mCallbacks;
1008+
};
1009+
8701010
/**
8711011
* Global context for native tests.
8721012
* Switch between various ActivityContexts.
@@ -910,6 +1050,9 @@ class NativeAudioContext {
9101050
case ActivityType::DataPath:
9111051
currentActivity = &mActivityDataPath;
9121052
break;
1053+
case ActivityType::TestMultiStream:
1054+
currentActivity = &mActivityTestMultiStream;
1055+
break;
9131056
}
9141057
}
9151058

@@ -926,6 +1069,7 @@ class NativeAudioContext {
9261069
ActivityGlitches mActivityGlitches;
9271070
ActivityDataPath mActivityDataPath;
9281071
ActivityTestDisconnect mActivityTestDisconnect;
1072+
ActivityTestMultiStream mActivityTestMultiStream;
9291073

9301074
private:
9311075

@@ -941,6 +1085,8 @@ class NativeAudioContext {
9411085
Glitches = 6,
9421086
TestDisconnect = 7,
9431087
DataPath = 8,
1088+
DynamicWorkload = 9,
1089+
TestMultiStream = 10,
9441090
};
9451091

9461092
ActivityType mActivityType = ActivityType::Undefined;

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ Java_com_mobileer_oboetester_OboeAudioStream_openNative(JNIEnv *env, jobject,
8585
jint spatializationBehavior,
8686
jstring packageName,
8787
jstring attributionTag);
88+
JNIEXPORT jint JNICALL
89+
Java_com_mobileer_oboetester_OboeAudioStream_startNative(JNIEnv *env, jobject, jint);
90+
JNIEXPORT jint JNICALL
91+
Java_com_mobileer_oboetester_OboeAudioStream_pauseNative(JNIEnv *env, jobject, jint);
92+
JNIEXPORT jint JNICALL
93+
Java_com_mobileer_oboetester_OboeAudioStream_stopNative(JNIEnv *env, jobject, jint);
94+
JNIEXPORT jint JNICALL
95+
Java_com_mobileer_oboetester_OboeAudioStream_flushNative(JNIEnv *env, jobject, jint);
8896
JNIEXPORT void JNICALL
8997
Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint);
9098

@@ -313,6 +321,39 @@ Java_com_mobileer_oboetester_OboeAudioStream_startPlaybackNative(JNIEnv *env, jo
313321
return (jint) engine.getCurrentActivity()->startPlayback();
314322
}
315323

324+
JNIEXPORT jint JNICALL
325+
Java_com_mobileer_oboetester_OboeAudioStream_startNative(JNIEnv *env, jobject, jint streamIndex) {
326+
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
327+
if (oboeStream) return (jint) oboeStream->requestStart();
328+
return (jint) oboe::Result::ErrorNull;
329+
}
330+
331+
JNIEXPORT jint JNICALL
332+
Java_com_mobileer_oboetester_OboeAudioStream_pauseNative(JNIEnv *env, jobject, jint streamIndex) {
333+
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
334+
if (oboeStream) return (jint) oboeStream->requestPause();
335+
return (jint) oboe::Result::ErrorNull;
336+
}
337+
338+
JNIEXPORT jint JNICALL
339+
Java_com_mobileer_oboetester_OboeAudioStream_stopNative(JNIEnv *env, jobject, jint streamIndex) {
340+
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
341+
if (oboeStream) return (jint) oboeStream->requestStop();
342+
return (jint) oboe::Result::ErrorNull;
343+
}
344+
345+
JNIEXPORT jint JNICALL
346+
Java_com_mobileer_oboetester_OboeAudioStream_flushNative(JNIEnv *env, jobject, jint streamIndex) {
347+
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
348+
if (oboeStream) return (jint) oboeStream->requestFlush();
349+
return (jint) oboe::Result::ErrorNull;
350+
}
351+
352+
JNIEXPORT jdouble JNICALL
353+
Java_com_mobileer_oboetester_OboeAudioStream_getPeakLevelNative(JNIEnv *env, jobject, jint streamIndex, jint channelIndex) {
354+
return engine.getCurrentActivity()->getPeakLevel(streamIndex, channelIndex);
355+
}
356+
316357
JNIEXPORT void JNICALL
317358
Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint streamIndex) {
318359
engine.getCurrentActivity()->close(streamIndex);

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
class AudioInputTester extends AudioStreamTester{
2222
private static AudioInputTester mInstance;
2323

24-
private AudioInputTester() {
24+
public AudioInputTester() {
2525
super();
2626
Log.i(TapToToneActivity.TAG, "create OboeAudioStream ---------");
2727

@@ -30,10 +30,7 @@ private AudioInputTester() {
3030
}
3131

3232
public static synchronized AudioInputTester getInstance() {
33-
if (mInstance == null) {
34-
mInstance = new AudioInputTester();
35-
}
36-
return mInstance;
33+
return new AudioInputTester();
3734
}
3835

3936
public native double getPeakLevel(int i);

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,10 @@ public class AudioOutputTester extends AudioStreamTester {
2525
private static AudioOutputTester mInstance;
2626

2727
public static synchronized AudioOutputTester getInstance() {
28-
if (mInstance == null) {
29-
mInstance = new AudioOutputTester();
30-
}
31-
return mInstance;
28+
return new AudioOutputTester();
3229
}
3330

34-
private AudioOutputTester() {
31+
public AudioOutputTester() {
3532
super();
3633
Log.i(TapToToneActivity.TAG, "create OboeAudioOutputStream ---------");
3734
mOboeAudioOutputStream = new OboeAudioOutputStream();

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,8 @@ public void onLaunchAudioWorkloadTestRunner(View view) {
5454
public void onLaunchReverseJniTest(View view) {
5555
launchTestActivity(ReverseJniActivity.class);
5656
}
57+
58+
public void onLaunchTestMultiStream(View view) {
59+
launchTestActivity(TestMultiStreamActivity.class);
60+
}
5761
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,21 @@ public void close() {
145145
}
146146
public native void close(int streamIndex);
147147

148+
public int start() { return startNative(mStreamIndex); }
149+
public native int startNative(int streamIndex);
150+
151+
public int pause() { return pauseNative(mStreamIndex); }
152+
public native int pauseNative(int streamIndex);
153+
154+
public int stop() { return stopNative(mStreamIndex); }
155+
public native int stopNative(int streamIndex);
156+
157+
public int flush() { return flushNative(mStreamIndex); }
158+
public native int flushNative(int streamIndex);
159+
160+
public double getPeakLevel(int channelIndex) { return getPeakLevelNative(mStreamIndex, channelIndex); }
161+
public native double getPeakLevelNative(int streamIndex, int channelIndex);
162+
148163
@Override
149164
public int getBufferCapacityInFrames() {
150165
return getBufferCapacityInFrames(mStreamIndex);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ abstract class TestAudioActivity extends AppCompatActivity implements AudioManag
9494
public static final int ACTIVITY_TEST_DISCONNECT = 7;
9595
public static final int ACTIVITY_DATA_PATHS = 8;
9696
public static final int ACTIVITY_DYNAMIC_WORKLOAD = 9;
97+
public static final int ACTIVITY_TEST_MULTI_STREAM = 10;
9798

9899
private static final int MP3_RES_ID = R.raw.sine441stereo;
99100
private static final AudioConfig MP3_FILE_CONFIG =
@@ -301,6 +302,9 @@ public int getServiceType() {
301302
| ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
302303
case ACTIVITY_DYNAMIC_WORKLOAD:
303304
return ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
305+
case ACTIVITY_TEST_MULTI_STREAM:
306+
return ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
307+
| ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
304308
default:
305309
Log.i(TAG, "getServiceType() called on unknown activity type " + getActivityType());
306310
return 0;

0 commit comments

Comments
 (0)