diff options
Diffstat (limited to 'apps/OboeTester/app/src/main')
12 files changed, 197 insertions, 48 deletions
diff --git a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp index 6ac37599..b90dfbc4 100644 --- a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp +++ b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp @@ -33,6 +33,7 @@ oboe::DataCallbackResult InputStreamCallbackAnalyzer::onAudioReady( void *audioData, int numFrames) { int32_t channelCount = audioStream->getChannelCount(); + printScheduler(); mInputConverter->convertToInternalOutput(numFrames * channelCount, audioData); float *floatData = (float *) mInputConverter->getOutputBuffer(); diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h index 02143a81..e04f0dbf 100644 --- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h +++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h @@ -52,6 +52,7 @@ #include "InputStreamCallbackAnalyzer.h" #include "MultiChannelRecording.h" #include "OboeStreamCallbackProxy.h" +#include "OboeTools.h" #include "PlayRecordingCallback.h" #include "SawPingGenerator.h" @@ -67,11 +68,6 @@ #define AMPLITUDE_SAW_PING 0.8 #define AMPLITUDE_IMPULSE 0.7 -#define NANOS_PER_MICROSECOND ((int64_t) 1000) -#define NANOS_PER_MILLISECOND (1000 * NANOS_PER_MICROSECOND) -#define NANOS_PER_SECOND (1000 * NANOS_PER_MILLISECOND) - -#define MILLISECONDS_PER_SECOND 1000 #define SECONDS_TO_RECORD 10 diff --git a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp index 7cf8ce98..2734d8a0 100644 --- a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp +++ b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp @@ -17,19 +17,8 @@ #include "common/OboeDebug.h" #include "OboeStreamCallbackProxy.h" -#include "synth/IncludeMeOnce.h" - bool OboeStreamCallbackProxy::mCallbackReturnStop = false; -int64_t OboeStreamCallbackProxy::getNanoseconds(clockid_t clockId) { - struct timespec time; - int result = clock_gettime(clockId, &time); - if (result < 0) { - return result; - } - return (time.tv_sec * 1e9) + time.tv_nsec; -} - oboe::DataCallbackResult OboeStreamCallbackProxy::onAudioReady( oboe::AudioStream *audioStream, void *audioData, @@ -37,6 +26,8 @@ oboe::DataCallbackResult OboeStreamCallbackProxy::onAudioReady( oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Stop; int64_t startTimeNanos = getNanoseconds(); + maybeHang(startTimeNanos); + if (mCpuAffinityMask != mPreviousMask) { uint32_t mask = mCpuAffinityMask; applyCpuAffinityMask(mask); @@ -62,6 +53,7 @@ oboe::DataCallbackResult OboeStreamCallbackProxy::onAudioReady( mSynthWorkload.renderStereo(buffer, numFrames); } + // Measure CPU load. int64_t currentTimeNanos = getNanoseconds(); // Sometimes we get a short callback when doing sample rate conversion. // Just ignore those to avoid noise. diff --git a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h index d72eaa96..bd8725d9 100644 --- a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h +++ b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h @@ -24,6 +24,7 @@ #include "oboe/Oboe.h" #include "synth/Synthesizer.h" #include "synth/SynthTools.h" +#include "OboeTesterStreamCallback.h" class DoubleStatistics { public: @@ -133,7 +134,7 @@ private: int mOffFrames = (int) (0.3 * 48000); }; -class OboeStreamCallbackProxy : public oboe::AudioStreamCallback { +class OboeStreamCallbackProxy : public OboeTesterStreamCallback { public: void setCallback(oboe::AudioStreamCallback *callback) { @@ -207,8 +208,6 @@ public: return mStatistics.dump(); } - static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC); - /** * @param cpuIndex * @return 0 on success or a negative errno @@ -250,11 +249,13 @@ private: oboe::AudioStreamCallback *mCallback = nullptr; static bool mCallbackReturnStop; + int64_t mCallbackCount = 0; std::atomic<int32_t> mFramesPerCallback{0}; std::atomic<uint32_t> mCpuAffinityMask{0}; std::atomic<uint32_t> mPreviousMask{0}; + }; #endif //NATIVEOBOE_OBOESTREAMCALLBACKPROXY_H diff --git a/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp b/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp index 583c9846..5109f67c 100644 --- a/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp +++ b/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp @@ -14,13 +14,18 @@ * limitations under the License. */ +#include <sched.h> +#include <cstring> #include "AudioStreamGateway.h" -#include "oboe/Oboe.h" #include "common/OboeDebug.h" -#include <sched.h> -#include <cstring> +#include "oboe/Oboe.h" +#include "OboeStreamCallbackProxy.h" #include "OboeTesterStreamCallback.h" +#include "OboeTools.h" +#include "synth/IncludeMeOnce.h" + +int32_t OboeTesterStreamCallback::mHangTimeMillis = 0; // Print if scheduler changes. void OboeTesterStreamCallback::printScheduler() { @@ -38,3 +43,44 @@ void OboeTesterStreamCallback::printScheduler() { } #endif } + +// Sleep to cause an XRun. Then reschedule. +void OboeTesterStreamCallback::maybeHang(const int64_t startNanos) { + if (mHangTimeMillis == 0) return; + + if (startNanos > mNextTimeToHang) { + LOGD("%s() start sleeping", __func__); + // Take short naps until it is time to wake up. + int64_t nowNanos = startNanos; + int64_t wakeupNanos = startNanos + (mHangTimeMillis * NANOS_PER_MILLISECOND); + while (nowNanos < wakeupNanos && mHangTimeMillis > 0) { + int32_t sleepTimeMicros = (int32_t) ((wakeupNanos - nowNanos) / 1000); + if (sleepTimeMicros == 0) break; + // The usleep() function can fail if it sleeps for more than one second. + // So sleep for several small intervals. + // This also allows us to exit the loop if mHangTimeMillis gets set to zero. + const int32_t maxSleepTimeMicros = 100 * 1000; + sleepTimeMicros = std::min(maxSleepTimeMicros, sleepTimeMicros); + usleep(sleepTimeMicros); + nowNanos = getNanoseconds(); + } + // Calculate when we hang again. + const int32_t minDurationMillis = 500; + const int32_t maxDurationMillis = std::max(10000, mHangTimeMillis * 2); + int32_t durationMillis = mHangTimeMillis * 10; + durationMillis = std::max(minDurationMillis, std::min(maxDurationMillis, durationMillis)); + mNextTimeToHang = startNanos + (durationMillis * NANOS_PER_MILLISECOND); + LOGD("%s() slept for %d msec, durationMillis = %d", __func__, + (int)((nowNanos - startNanos) / 1e6L), + durationMillis); + } +} + +int64_t OboeTesterStreamCallback::getNanoseconds(clockid_t clockId) { + struct timespec time; + int result = clock_gettime(clockId, &time); + if (result < 0) { + return result; + } + return (time.tv_sec * 1e9) + time.tv_nsec; +}
\ No newline at end of file diff --git a/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h b/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h index ec01fe5c..70a719ea 100644 --- a/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h +++ b/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h @@ -19,8 +19,11 @@ #include <unistd.h> #include <sys/types.h> +#include <sys/sysinfo.h> #include "flowgraph/FlowGraphNode.h" #include "oboe/Oboe.h" +#include "synth/Synthesizer.h" +#include "synth/SynthTools.h" class OboeTesterStreamCallback : public oboe::AudioStreamCallback { public: @@ -31,10 +34,24 @@ public: mPreviousScheduler = -1; } + static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC); + + /** + * Specify a sleep time that will hang the audio periodically. + * + * @param hangTimeMillis + */ + static void setHangTimeMillis(int hangTimeMillis) { + mHangTimeMillis = hangTimeMillis; + } + protected: - void printScheduler(); + void printScheduler(); + void maybeHang(int64_t nowNanos); - int mPreviousScheduler = -1; + int mPreviousScheduler = -1; + static int mHangTimeMillis; + int64_t mNextTimeToHang = 0; }; diff --git a/apps/OboeTester/app/src/main/cpp/OboeTools.h b/apps/OboeTester/app/src/main/cpp/OboeTools.h new file mode 100644 index 00000000..c8b47f84 --- /dev/null +++ b/apps/OboeTester/app/src/main/cpp/OboeTools.h @@ -0,0 +1,25 @@ +/* + * Copyright 2023 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 OBOETESTER_OBOETOOLS_H +#define OBOETESTER_OBOETOOLS_H + +#define NANOS_PER_MICROSECOND ((int64_t) 1000) +#define NANOS_PER_MILLISECOND (1000 * NANOS_PER_MICROSECOND) +#define NANOS_PER_SECOND (1000 * NANOS_PER_MILLISECOND) +#define MILLISECONDS_PER_SECOND 1000 + +#endif //OBOETESTER_OBOETOOLS_H diff --git a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp index e916dd0f..b46b8e63 100644 --- a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp +++ b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp @@ -575,6 +575,12 @@ Java_com_mobileer_oboetester_OboeAudioStream_setCallbackReturnStop(JNIEnv *env, } JNIEXPORT void JNICALL +Java_com_mobileer_oboetester_OboeAudioStream_setHangTimeMillis(JNIEnv *env, jclass type, + jint hangTimeMillis) { + OboeTesterStreamCallback::setHangTimeMillis(hangTimeMillis); +} + +JNIEXPORT void JNICALL Java_com_mobileer_oboetester_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type, jint callbackSize) { ActivityContext::callbackSize = callbackSize; diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java index 32078aaa..5c453e13 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java @@ -306,6 +306,8 @@ abstract class OboeAudioStream extends AudioStreamBase { public static native void setCallbackReturnStop(boolean b); + public static native void setHangTimeMillis(int hangTimeMillis); + public static native void setUseCallback(boolean checked); public static native void setCallbackSize(int callbackSize); diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java index 96ed24a0..680c5e8b 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java @@ -31,13 +31,17 @@ import android.os.Looper; import android.util.Log; import android.view.View; import android.view.WindowManager; +import android.widget.AdapterView; import android.widget.Button; import android.widget.CheckBox; +import android.widget.Spinner; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import com.mobileer.audio_device.CommunicationDeviceSpinner; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -90,6 +94,8 @@ abstract class TestAudioActivity extends Activity { private Button mCloseButton; private MyStreamSniffer mStreamSniffer; private CheckBox mCallbackReturnStopBox; + private Spinner mHangTimeSpinner; + // Only set in some activities protected CommunicationDeviceView mCommunicationDeviceView; private int mSampleRate; @@ -436,6 +442,24 @@ abstract class TestAudioActivity extends Activity { } OboeAudioStream.setCallbackReturnStop(false); + mHangTimeSpinner = (Spinner) findViewById(R.id.spinner_hang_time); + if (mHangTimeSpinner != null) { + mHangTimeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + String hangTimeText = (String) mHangTimeSpinner.getAdapter().getItem(position); + int hangTimeMillis = Integer.parseInt(hangTimeText); + Log.d(TAG, "Hang Time = " + hangTimeMillis + " msec"); + + OboeAudioStream.setHangTimeMillis(hangTimeMillis); + } + + public void onNothingSelected(AdapterView<?> parent) { + OboeAudioStream.setHangTimeMillis(0); + } + }); + } + OboeAudioStream.setHangTimeMillis(0); + mStreamSniffer = new MyStreamSniffer(); } @@ -486,8 +510,16 @@ abstract class TestAudioActivity extends Activity { } } + void clearHangTime() { + OboeAudioStream.setHangTimeMillis(0); + if (mHangTimeSpinner != null) { + mHangTimeSpinner.setSelection(0); + } + } + public void startAudio(View view) { Log.i(TAG, "startAudio() called ======================================="); + clearHangTime(); // start running try { startAudio(); } catch (Exception e) { diff --git a/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml b/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml index 9e8fe6cc..a34d40c4 100644 --- a/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml +++ b/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" android:layout_height="match_parent"> + android:layout_width="match_parent" + android:layout_height="match_parent"> <com.mobileer.oboetester.StreamConfigurationView android:id="@+id/streamConfiguration" @@ -31,75 +32,91 @@ <Button android:id="@+id/button_open" android:layout_width="0dp" - android:layout_weight="1" android:layout_height="wrap_content" + android:layout_weight="1" android:backgroundTint="@xml/button_color_selector" android:backgroundTintMode="src_atop" - android:textSize="12sp" android:onClick="openAudio" - android:text="@string/openAudio" /> + android:text="@string/openAudio" + android:textSize="12sp" /> <Button android:id="@+id/button_start" android:layout_width="0dp" - android:layout_weight="1" android:layout_height="wrap_content" + android:layout_weight="1" android:backgroundTint="@xml/button_color_selector" android:backgroundTintMode="src_atop" - android:textSize="12sp" android:onClick="startAudio" - android:text="@string/startAudio" /> + android:text="@string/startAudio" + android:textSize="12sp" /> <Button android:id="@+id/button_pause" android:layout_width="0dp" - android:layout_weight="1" android:layout_height="wrap_content" + android:layout_weight="1" android:backgroundTint="@xml/button_color_selector" android:backgroundTintMode="src_atop" - android:textSize="12sp" android:onClick="pauseAudio" - android:text="@string/pauseAudio" /> + android:text="@string/pauseAudio" + android:textSize="12sp" /> <Button android:id="@+id/button_stop" android:layout_width="0dp" - android:layout_weight="1" android:layout_height="wrap_content" + android:layout_weight="1" android:backgroundTint="@xml/button_color_selector" android:backgroundTintMode="src_atop" - android:textSize="12sp" android:onClick="stopAudio" - android:text="@string/stopAudio" /> + android:text="@string/stopAudio" + android:textSize="12sp" /> <Button android:id="@+id/button_release" android:layout_width="0dp" - android:layout_weight="1" android:layout_height="wrap_content" + android:layout_weight="1" android:backgroundTint="@xml/button_color_selector" android:backgroundTintMode="src_atop" - android:textSize="12sp" android:onClick="releaseAudio" - android:text="@string/releaseAudio" /> + android:text="@string/releaseAudio" + android:textSize="12sp" /> <Button android:id="@+id/button_close" android:layout_width="0dp" - android:layout_weight="1" android:layout_height="wrap_content" + android:layout_weight="1" android:backgroundTint="@xml/button_color_selector" android:backgroundTintMode="src_atop" - android:textSize="12sp" android:onClick="closeAudio" - android:text="@string/closeAudio" /> - + android:text="@string/closeAudio" + android:textSize="12sp" /> </LinearLayout> - <CheckBox - android:id="@+id/callbackReturnStop" - android:layout_width="wrap_content" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="callback returns STOP" /> + android:orientation="horizontal"> + + <CheckBox + android:id="@+id/callbackReturnStop" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="callback returns STOP" /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/hang_prompt" /> + + <Spinner + android:id="@+id/spinner_hang_time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:entries="@array/hang_times" /> + + </LinearLayout> </merge> diff --git a/apps/OboeTester/app/src/main/res/values/strings.xml b/apps/OboeTester/app/src/main/res/values/strings.xml index ddfc689b..00872151 100644 --- a/apps/OboeTester/app/src/main/res/values/strings.xml +++ b/apps/OboeTester/app/src/main/res/values/strings.xml @@ -186,6 +186,20 @@ <item>White Noise</item> </string-array> + <string name="hang_prompt">, Hang(ms)</string> + <string-array name="hang_times"> + <item>0</item> + <item>4</item> + <item>10</item> + <item>20</item> + <item>30</item> + <item>100</item> + <item>300</item> + <item>1000</item> + <item>2000</item> + <item>5000</item> + </string-array> + <string name="synth_sender_text">Select Sender for Synth</string> <string name="error_port_busy">Selected port is in use or unavailable.</string> <string name="port_open_ok">Port opened OK.</string> |