aboutsummaryrefslogtreecommitdiff
path: root/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/OboeTester/app/src/main/cpp/TestErrorCallback.h')
-rw-r--r--apps/OboeTester/app/src/main/cpp/TestErrorCallback.h113
1 files changed, 113 insertions, 0 deletions
diff --git a/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h b/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h
new file mode 100644
index 00000000..a7611fe4
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/TestErrorCallback.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2022 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_TEST_ERROR_CALLBACK_H
+#define OBOETESTER_TEST_ERROR_CALLBACK_H
+
+#include "oboe/Oboe.h"
+#include <thread>
+
+/**
+ * This code is an experiment to see if we can cause a crash from the ErrorCallback.
+ */
+class TestErrorCallback {
+public:
+
+ oboe::Result open();
+ oboe::Result start();
+ oboe::Result stop();
+ oboe::Result close();
+
+ int test();
+
+ int32_t getCallbackMagic() {
+ return mCallbackMagic.load();
+ }
+
+protected:
+
+ std::atomic<int32_t> mCallbackMagic{0};
+
+private:
+
+ void cleanup() {
+ mDataCallback.reset();
+ mErrorCallback.reset();
+ mStream.reset();
+ }
+
+ class MyDataCallback : public oboe::AudioStreamDataCallback { public:
+
+ oboe::DataCallbackResult onAudioReady(
+ oboe::AudioStream *audioStream,
+ void *audioData,
+ int32_t numFrames) override;
+
+ };
+
+ class MyErrorCallback : public oboe::AudioStreamErrorCallback {
+ public:
+
+ MyErrorCallback(TestErrorCallback *parent): mParent(parent) {}
+
+ virtual ~MyErrorCallback() {
+ // If the delete occurs before onErrorAfterClose() then this bad magic
+ // value will be seen by the Java test code, causing a failure.
+ // It is also possible that this code will just cause OboeTester to crash!
+ mMagic = 0xdeadbeef;
+ LOGE("%s() called", __func__);
+ }
+
+ void onErrorBeforeClose(oboe::AudioStream *oboeStream, oboe::Result error) override {
+ LOGE("%s() - error = %s, parent = %p",
+ __func__, oboe::convertToText(error), &mParent);
+ // Trigger a crash by "deleting" this callback object while in use!
+ // Do not try this at home. We are just trying to reproduce the crash
+ // reported in #1603.
+ std::thread t([this]() {
+ this->mParent->cleanup(); // Possibly delete stream and callback objects.
+ LOGE("onErrorBeforeClose called cleanup!");
+ });
+ t.detach();
+ // There is a race condition between the deleting thread and this thread.
+ // We do not want to add synchronization because the object is getting deleted
+ // and cannot be relied on.
+ // So we sleep here to give the deleting thread a chance to win the race.
+ usleep(10 * 1000);
+ }
+
+ void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override {
+ // The callback was probably deleted by now.
+ LOGE("%s() - error = %s, mMagic = 0x%08X",
+ __func__, oboe::convertToText(error), mMagic.load());
+ mParent->mCallbackMagic = mMagic.load();
+ }
+
+ private:
+ TestErrorCallback *mParent;
+ // This must match the value in TestErrorCallbackActivity.java
+ static constexpr int32_t kMagicGood = 0x600DCAFE;
+ std::atomic<int32_t> mMagic{kMagicGood};
+ };
+
+ std::shared_ptr<oboe::AudioStream> mStream;
+ std::shared_ptr<MyDataCallback> mDataCallback;
+ std::shared_ptr<MyErrorCallback> mErrorCallback;
+
+ static constexpr int kChannelCount = 2;
+};
+
+#endif //OBOETESTER_TEST_ERROR_CALLBACK_H