From 8b03b43476ae408bad18059f8f86ea0759f361ee Mon Sep 17 00:00:00 2001 From: Dmytro Bogovych Date: Tue, 27 Jan 2026 18:43:23 +0300 Subject: [PATCH] - remove Oboe test apps --- src/libs/oboe/CMakeLists.txt | 95 +- src/libs/oboe/Doxyfile | 4 +- src/libs/oboe/README.md | 8 +- src/libs/oboe/apps/OboeTester/.gitignore | 13 - .../apps/OboeTester/.google/packaging.yaml | 7 - src/libs/oboe/apps/OboeTester/README.md | 6 - .../oboe/apps/OboeTester/app/CMakeLists.txt | 34 - .../oboe/apps/OboeTester/app/build.gradle | 44 - .../app/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - src/libs/oboe/apps/OboeTester/app/gradlew | 172 -- src/libs/oboe/apps/OboeTester/app/gradlew.bat | 84 - .../oboe/apps/OboeTester/app/local.properties | 9 - .../apps/OboeTester/app/proguard-rules.pro | 17 - .../app/src/main/AndroidManifest.xml | 127 -- .../app/src/main/cpp/AudioStreamGateway.cpp | 39 - .../app/src/main/cpp/AudioStreamGateway.h | 55 - .../app/src/main/cpp/FormatConverterBox.cpp | 85 - .../app/src/main/cpp/FormatConverterBox.h | 101 - .../app/src/main/cpp/FullDuplexAnalyzer.cpp | 66 - .../app/src/main/cpp/FullDuplexAnalyzer.h | 64 - .../app/src/main/cpp/FullDuplexEcho.cpp | 46 - .../app/src/main/cpp/FullDuplexEcho.h | 57 - .../app/src/main/cpp/FullDuplexStream.cpp | 152 -- .../app/src/main/cpp/FullDuplexStream.h | 119 -- .../main/cpp/InputStreamCallbackAnalyzer.cpp | 42 - .../main/cpp/InputStreamCallbackAnalyzer.h | 87 - .../src/main/cpp/InterpolatingDelayLine.cpp | 42 - .../app/src/main/cpp/InterpolatingDelayLine.h | 48 - .../app/src/main/cpp/MultiChannelRecording.h | 161 -- .../app/src/main/cpp/NativeAudioContext.cpp | 702 ------- .../app/src/main/cpp/NativeAudioContext.h | 767 ------- .../src/main/cpp/OboeStreamCallbackProxy.cpp | 81 - .../src/main/cpp/OboeStreamCallbackProxy.h | 88 - .../src/main/cpp/OboeTesterStreamCallback.cpp | 40 - .../src/main/cpp/OboeTesterStreamCallback.h | 41 - .../src/main/cpp/PlayRecordingCallback.cpp | 33 - .../app/src/main/cpp/PlayRecordingCallback.h | 46 - .../app/src/main/cpp/SawPingGenerator.cpp | 69 - .../app/src/main/cpp/SawPingGenerator.h | 46 - .../src/main/cpp/analyzer/BaseSineAnalyzer.h | 203 -- .../src/main/cpp/analyzer/DataPathAnalyzer.h | 94 - .../src/main/cpp/analyzer/GlitchAnalyzer.h | 363 ---- .../src/main/cpp/analyzer/InfiniteRecording.h | 67 - .../src/main/cpp/analyzer/LatencyAnalyzer.h | 622 ------ .../src/main/cpp/analyzer/ManchesterEncoder.h | 98 - .../app/src/main/cpp/analyzer/PeakDetector.h | 68 - .../app/src/main/cpp/analyzer/PseudoRandom.h | 57 - .../main/cpp/analyzer/RandomPulseGenerator.h | 43 - .../cpp/analyzer/RoundedManchesterEncoder.h | 88 - .../app/src/main/cpp/android_debug.h | 41 - .../main/cpp/flowunits/ExponentialShape.cpp | 35 - .../src/main/cpp/flowunits/ExponentialShape.h | 70 - .../main/cpp/flowunits/ImpulseOscillator.cpp | 42 - .../src/main/cpp/flowunits/LinearShape.cpp | 36 - .../app/src/main/cpp/flowunits/LinearShape.h | 53 - .../src/main/cpp/flowunits/OscillatorBase.cpp | 26 - .../src/main/cpp/flowunits/OscillatorBase.h | 100 - .../main/cpp/flowunits/SawtoothOscillator.cpp | 39 - .../src/main/cpp/flowunits/SineOscillator.cpp | 42 - .../src/main/cpp/flowunits/SineOscillator.h | 34 - .../main/cpp/flowunits/TriangleOscillator.cpp | 40 - .../main/cpp/flowunits/TriangleOscillator.h | 39 - .../app/src/main/cpp/jni-bridge.cpp | 700 ------- .../app/src/main/cpp/unused/unused.h | 145 -- .../app/src/main/cpp/util/WaveFileWriter.cpp | 132 -- .../app/src/main/cpp/util/WaveFileWriter.h | 155 -- .../app/src/main/ic_launcher-playstore.png | Bin 31684 -> 0 bytes .../audio_device/AudioDeviceAdapter.java | 58 - .../AudioDeviceInfoConverter.java | 142 -- .../audio_device/AudioDeviceListEntry.java | 95 - .../audio_device/AudioDeviceSpinner.java | 127 -- .../mobileer/miditools/EventScheduler.java | 243 --- .../com/mobileer/miditools/MidiConstants.java | 102 - .../mobileer/miditools/MidiDeviceMonitor.java | 152 -- .../mobileer/miditools/MidiDispatcher.java | 95 - .../miditools/MidiEventScheduler.java | 118 -- .../mobileer/miditools/MidiEventThread.java | 89 - .../com/mobileer/miditools/MidiFramer.java | 111 -- .../miditools/MidiInputPortSelector.java | 92 - .../MidiOutputPortConnectionSelector.java | 91 - .../miditools/MidiOutputPortSelector.java | 102 - .../mobileer/miditools/MidiPortConnector.java | 203 -- .../mobileer/miditools/MidiPortSelector.java | 191 -- .../mobileer/miditools/MidiPortWrapper.java | 123 -- .../com/mobileer/miditools/MidiTools.java | 45 - .../mobileer/miditools/MusicKeyboardView.java | 384 ---- .../miditools/synth/AudioLatencyTuner.java | 235 --- .../miditools/synth/EnvelopeADSR.java | 115 -- .../miditools/synth/LatencyController.java | 77 - .../miditools/synth/SawOscillator.java | 73 - .../miditools/synth/SawOscillatorDPW.java | 52 - .../mobileer/miditools/synth/SawVoice.java | 65 - .../miditools/synth/SimpleAudioOutput.java | 214 -- .../miditools/synth/SineOscillator.java | 54 - .../mobileer/miditools/synth/SynthEngine.java | 315 --- .../mobileer/miditools/synth/SynthUnit.java | 35 - .../mobileer/miditools/synth/SynthVoice.java | 85 - .../mobileer/oboetester/AnalyzerActivity.java | 323 --- .../mobileer/oboetester/AudioInputTester.java | 40 - .../oboetester/AudioOutputTester.java | 53 - .../mobileer/oboetester/AudioQueryTools.java | 108 - .../oboetester/AudioRecordThread.java | 162 -- .../mobileer/oboetester/AudioStreamBase.java | 204 -- .../oboetester/AudioStreamTester.java | 52 - .../oboetester/AutomatedGlitchActivity.java | 114 -- .../oboetester/AutomatedTestRunner.java | 285 --- .../oboetester/BaseAutoGlitchActivity.java | 231 --- .../mobileer/oboetester/BufferSizeView.java | 215 -- .../oboetester/CachedTextViewLog.java | 72 - .../oboetester/CircularCaptureBuffer.java | 104 - .../oboetester/DeviceReportActivity.java | 171 -- .../com/mobileer/oboetester/EchoActivity.java | 215 -- .../mobileer/oboetester/ExponentialTaper.java | 67 - .../oboetester/ExternalTapToToneActivity.java | 148 -- .../oboetester/ExtraTestsActivity.java | 28 - .../com/mobileer/oboetester/FastButton.java | 105 - .../mobileer/oboetester/GlitchActivity.java | 366 ---- .../mobileer/oboetester/InputMarginView.java | 60 - .../com/mobileer/oboetester/MainActivity.java | 322 --- .../oboetester/ManualGlitchActivity.java | 229 --- .../oboetester/MicrophoneInfoConverter.java | 73 - .../mobileer/oboetester/MidiTapTester.java | 117 -- .../com/mobileer/oboetester/NativeEngine.java | 12 - .../mobileer/oboetester/NativeSniffer.java | 69 - .../oboetester/OboeAudioOutputStream.java | 34 - .../mobileer/oboetester/OboeAudioStream.java | 267 --- .../mobileer/oboetester/RecorderActivity.java | 109 - .../oboetester/RoundTripLatencyActivity.java | 462 ----- .../oboetester/StreamConfiguration.java | 445 ----- .../oboetester/StreamConfigurationView.java | 343 ---- .../oboetester/TapLatencyAnalyser.java | 118 -- .../oboetester/TapToToneActivity.java | 330 --- .../mobileer/oboetester/TapToToneTester.java | 198 -- .../oboetester/TestAudioActivity.java | 586 ------ .../oboetester/TestDataPathsActivity.java | 524 ----- .../oboetester/TestDisconnectActivity.java | 413 ---- .../oboetester/TestInputActivity.java | 247 --- .../oboetester/TestOutputActivity.java | 107 - .../oboetester/TestOutputActivityBase.java | 86 - .../mobileer/oboetester/VolumeBarView.java | 75 - .../com/mobileer/oboetester/WaveformView.java | 180 -- .../com/mobileer/oboetester/WorkloadView.java | 109 - .../src/main/res/drawable/button_shape.xml | 6 - .../res/drawable/ic_launcher_foreground.xml | 15 - .../res/layout/activity_auto_glitches.xml | 42 - .../main/res/layout/activity_data_paths.xml | 29 - .../res/layout/activity_device_report.xml | 23 - .../app/src/main/res/layout/activity_echo.xml | 90 - .../layout/activity_external_tap_to_tone.xml | 64 - .../main/res/layout/activity_extra_tests.xml | 35 - .../app/src/main/res/layout/activity_main.xml | 282 --- .../res/layout/activity_manual_glitches.xml | 104 - .../src/main/res/layout/activity_recorder.xml | 98 - .../main/res/layout/activity_rt_latency.xml | 99 - .../main/res/layout/activity_tap_to_tone.xml | 48 - .../res/layout/activity_test_disconnect.xml | 63 - .../main/res/layout/activity_test_input.xml | 38 - .../main/res/layout/activity_test_output.xml | 99 - .../app/src/main/res/layout/audio_devices.xml | 22 - .../src/main/res/layout/auto_test_runner.xml | 76 - .../src/main/res/layout/buffer_size_view.xml | 53 - .../src/main/res/layout/input_margin_view.xml | 54 - .../main/res/layout/merge_audio_common.xml | 89 - .../main/res/layout/merge_audio_simple.xml | 53 - .../main/res/layout/sample_fast_button.xml | 17 - .../app/src/main/res/layout/stream_config.xml | 302 --- .../app/src/main/res/layout/workload_view.xml | 20 - .../app/src/main/res/menu/menu_main.xml | 5 - .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5353 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 3342 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7478 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 12018 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9610 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 16879 -> 0 bytes .../app/src/main/res/values-v21/styles.xml | 5 - .../app/src/main/res/values-w600dp/dimens.xml | 8 - .../app/src/main/res/values/arrays.xml | 3 - .../src/main/res/values/attrs_fast_button.xml | 8 - .../src/main/res/values/attrs_waveform.xml | 22 - .../app/src/main/res/values/colors.xml | 23 - .../app/src/main/res/values/dimens.xml | 8 - .../app/src/main/res/values/strings.xml | 202 -- .../app/src/main/res/values/styles.xml | 8 - .../main/res/xml/button_color_selector.xml | 5 - .../app/src/main/res/xml/provider_paths.xml | 4 - .../src/main/res/xml/service_device_info.xml | 18 - src/libs/oboe/apps/OboeTester/build.gradle | 18 - .../apps/OboeTester/docs/AutomatedTesting.md | 179 -- src/libs/oboe/apps/OboeTester/docs/Build.md | 35 - .../apps/OboeTester/docs/PrivacyPolicy.md | 39 - src/libs/oboe/apps/OboeTester/docs/README.md | 19 - .../oboe/apps/OboeTester/docs/TestOutput.md | 30 - src/libs/oboe/apps/OboeTester/docs/Usage.md | 120 -- .../docs/images/auto_glitch_test.png | Bin 254985 -> 0 bytes .../docs/images/echo_input_output.png | Bin 188719 -> 0 bytes .../OboeTester/docs/images/main_activity.png | Bin 108219 -> 0 bytes .../apps/OboeTester/docs/images/recorder.png | Bin 144904 -> 0 bytes .../docs/images/round_trip_latency.png | Bin 199307 -> 0 bytes .../OboeTester/docs/images/tap_to_tone.png | Bin 177523 -> 0 bytes .../OboeTester/docs/images/test_glitches.png | Bin 212052 -> 0 bytes .../OboeTester/docs/images/test_input.png | Bin 144542 -> 0 bytes .../OboeTester/docs/images/test_output.png | Bin 121816 -> 0 bytes .../docs/images/test_output_running.png | Bin 159135 -> 0 bytes .../oboe/apps/OboeTester/gradle.properties | 18 - .../gradle/wrapper/gradle-wrapper.jar | Bin 49896 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - src/libs/oboe/apps/OboeTester/gradlew | 164 -- src/libs/oboe/apps/OboeTester/gradlew.bat | 90 - .../apps/OboeTester/scripts/dsp_timing.py | 239 --- src/libs/oboe/apps/OboeTester/settings.gradle | 1 - src/libs/oboe/apps/fxlab/.gitignore | 14 - src/libs/oboe/apps/fxlab/CONTRIBUTING.md | 16 - src/libs/oboe/apps/fxlab/LICENSE | 202 -- src/libs/oboe/apps/fxlab/README.md | 30 - src/libs/oboe/apps/fxlab/app/CMakeLists.txt | 79 - src/libs/oboe/apps/fxlab/app/build.gradle | 67 - .../fxlab/app/src/main/AndroidManifest.xml | 39 - .../fxlab/app/src/main/cpp/DuplexCallback.h | 80 - .../fxlab/app/src/main/cpp/DuplexEngine.cpp | 93 - .../fxlab/app/src/main/cpp/DuplexEngine.h | 64 - .../fxlab/app/src/main/cpp/FunctionList.h | 85 - .../app/src/main/cpp/effects/CombFilter.h | 53 - .../src/main/cpp/effects/DelayLineEffect.h | 79 - .../app/src/main/cpp/effects/DoublingEffect.h | 34 - .../app/src/main/cpp/effects/DriveControl.h | 41 - .../app/src/main/cpp/effects/EchoEffect.h | 33 - .../fxlab/app/src/main/cpp/effects/Effects.h | 61 - .../app/src/main/cpp/effects/FlangerEffect.h | 29 - .../main/cpp/effects/SingleFunctionEffects.h | 56 - .../app/src/main/cpp/effects/SlapbackEffect.h | 30 - .../app/src/main/cpp/effects/TremoloEffect.h | 43 - .../app/src/main/cpp/effects/VibratroEffect.h | 27 - .../src/main/cpp/effects/WhiteChorusEffect.h | 32 - .../cpp/effects/descrip/AllPassDescription.h | 48 - .../effects/descrip/DistortionDescription.h | 46 - .../cpp/effects/descrip/DoublingDescription.h | 33 - .../cpp/effects/descrip/EchoDescription.h | 48 - .../cpp/effects/descrip/EffectDescription.h | 107 - .../main/cpp/effects/descrip/FIRDescription.h | 46 - .../cpp/effects/descrip/FlangerDescription.h | 50 - .../cpp/effects/descrip/GainDescription.h | 50 - .../main/cpp/effects/descrip/IIRDescription.h | 50 - .../effects/descrip/OverdriveDescription.h | 51 - .../effects/descrip/PassthroughDescription.h | 48 - .../cpp/effects/descrip/SlapbackDescription.h | 50 - .../cpp/effects/descrip/TremoloDescription.h | 46 - .../cpp/effects/descrip/VibratoDescription.h | 47 - .../effects/descrip/WhiteChorusDescription.h | 49 - .../src/main/cpp/effects/utils/DelayLine.h | 44 - .../main/cpp/effects/utils/PhaseAccumulator.h | 41 - .../app/src/main/cpp/effects/utils/SineWave.h | 37 - .../src/main/cpp/effects/utils/WhiteNoise.h | 36 - .../fxlab/app/src/main/cpp/logging_macros.h | 46 - .../fxlab/app/src/main/cpp/native-lib.cpp | 159 -- .../fxlab/app/src/main/cpp/tests/.gitignore | 5 - .../app/src/main/cpp/tests/CMakeLists.txt | 15 - .../src/main/cpp/tests/DelayLineEffectTest.h | 52 - .../app/src/main/cpp/tests/DelayLineTest.h | 61 - .../fxlab/app/src/main/cpp/tests/TypeTests.h | 54 - .../app/src/main/cpp/tests/testEffects.cpp | 29 - .../mobileer/androidfxlab/EffectsAdapter.kt | 209 -- .../com/mobileer/androidfxlab/MainActivity.kt | 219 -- .../mobileer/androidfxlab/NativeInterface.kt | 110 - .../mobileer/androidfxlab/datatype/Effect.kt | 28 - .../datatype/EffectDescription.kt | 33 - .../androidfxlab/datatype/ParamDescription.kt | 23 - .../drawable-v24/ic_launcher_foreground.xml | 50 - .../app/src/main/res/drawable/ic_add.xml | 25 - .../ic_baseline_audio_is_disabled_24.xml | 10 - .../ic_baseline_audio_is_enabled_24.xml | 10 - .../drawable/ic_baseline_drag_indicator.xml | 25 - .../res/drawable/ic_launcher_background.xml | 90 - .../app/src/main/res/layout/activity_main.xml | 63 - .../app/src/main/res/layout/effect_header.xml | 65 - .../app/src/main/res/layout/effect_view.xml | 38 - .../app/src/main/res/layout/param_seek.xml | 59 - .../fxlab/app/src/main/res/menu/add_menu.xml | 19 - .../app/src/main/res/menu/toolbar_menu.xml | 12 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 21 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 21 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2963 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 4905 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2060 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2783 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4490 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 6895 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6387 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 10413 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9128 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 15132 -> 0 bytes .../fxlab/app/src/main/res/values/colors.xml | 23 - .../fxlab/app/src/main/res/values/strings.xml | 20 - .../fxlab/app/src/main/res/values/styles.xml | 27 - src/libs/oboe/apps/fxlab/build.gradle | 44 - src/libs/oboe/apps/fxlab/docs/Dev-Guide.md | 46 - .../oboe/apps/fxlab/docs/Presentation.pdf | Bin 1306300 -> 0 bytes src/libs/oboe/apps/fxlab/docs/README.md | 4 - src/libs/oboe/apps/fxlab/gradle.properties | 37 - .../fxlab/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - src/libs/oboe/apps/fxlab/gradlew | 172 -- src/libs/oboe/apps/fxlab/gradlew.bat | 84 - src/libs/oboe/apps/fxlab/screenshot.png | Bin 107694 -> 0 bytes src/libs/oboe/apps/fxlab/settings.gradle | 17 - src/libs/oboe/build_all_android.sh | 3 +- src/libs/oboe/docs/.nojekyll | 0 src/libs/oboe/docs/AndroidAudioHistory.md | 4 +- src/libs/oboe/docs/AppsUsingOboe.md | 3 - src/libs/oboe/docs/ChangeLog.md | 30 - src/libs/oboe/docs/FAQ.md | 10 +- src/libs/oboe/docs/FullGuide.md | 81 +- src/libs/oboe/docs/GettingStarted.md | 32 +- src/libs/oboe/docs/OpenSLESMigration.md | 18 +- src/libs/oboe/docs/PrivacyPolicy.md | 11 + src/libs/oboe/docs/README.md | 14 +- src/libs/oboe/docs/index.html | 11 - src/libs/oboe/docs/notes/README.md | 7 - src/libs/oboe/docs/notes/disconnect.md | 73 - src/libs/oboe/docs/notes/effects.md | 48 - src/libs/oboe/docs/notes/rlsbuffer.md | 71 - .../reference/_audio_stream_8h_source.html | 140 -- .../_audio_stream_base_8h_source.html | 145 -- .../_audio_stream_builder_8h_source.html | 143 -- .../_audio_stream_callback_8h_source.html | 93 - .../reference/_definitions_8h_source.html | 148 -- .../reference/_latency_tuner_8h_source.html | 92 - .../oboe/docs/reference/_oboe_8h_source.html | 82 - .../_result_with_value_8h_source.html | 93 - .../_stabilized_callback_8h_source.html | 93 - .../docs/reference/_utilities_8h_source.html | 91 - .../docs/reference/_version_8h_source.html | 89 - src/libs/oboe/docs/reference/annotated.html | 97 - src/libs/oboe/docs/reference/bc_s.png | Bin 676 -> 0 bytes src/libs/oboe/docs/reference/bdwn.png | Bin 147 -> 0 bytes src/libs/oboe/docs/reference/classes.html | 99 - .../classoboe_1_1_audio_stream-members.html | 185 -- .../reference/classoboe_1_1_audio_stream.html | 1653 --------------- .../reference/classoboe_1_1_audio_stream.png | Bin 629 -> 0 bytes ...assoboe_1_1_audio_stream_base-members.html | 132 -- .../classoboe_1_1_audio_stream_base.html | 1254 ------------ .../classoboe_1_1_audio_stream_base.png | Bin 892 -> 0 bytes ...oboe_1_1_audio_stream_builder-members.html | 162 -- .../classoboe_1_1_audio_stream_builder.html | 1162 ----------- .../classoboe_1_1_audio_stream_builder.png | Bin 673 -> 0 bytes ...boe_1_1_audio_stream_callback-members.html | 92 - .../classoboe_1_1_audio_stream_callback.html | 120 -- .../classoboe_1_1_audio_stream_callback.png | Bin 1489 -> 0 bytes ..._1_audio_stream_data_callback-members.html | 87 - ...ssoboe_1_1_audio_stream_data_callback.html | 196 -- ...assoboe_1_1_audio_stream_data_callback.png | Bin 1072 -> 0 bytes ...1_audio_stream_error_callback-members.html | 89 - ...soboe_1_1_audio_stream_error_callback.html | 260 --- ...ssoboe_1_1_audio_stream_error_callback.png | Bin 1077 -> 0 bytes ...boe_1_1_default_stream_values-members.html | 88 - .../classoboe_1_1_default_stream_values.html | 181 -- .../classoboe_1_1_latency_tuner-members.html | 94 - .../classoboe_1_1_latency_tuner.html | 321 --- .../classoboe_1_1_oboe_globals-members.html | 87 - .../reference/classoboe_1_1_oboe_globals.html | 130 -- ...assoboe_1_1_result_with_value-members.html | 93 - .../classoboe_1_1_result_with_value.html | 368 ---- ...soboe_1_1_stabilized_callback-members.html | 93 - .../classoboe_1_1_stabilized_callback.html | 299 --- .../classoboe_1_1_stabilized_callback.png | Bin 1481 -> 0 bytes src/libs/oboe/docs/reference/closed.png | Bin 132 -> 0 bytes src/libs/oboe/docs/reference/deprecated.html | 91 - .../dir_768f6301d9838e45d679001914ab2803.html | 82 - .../dir_d44c64559bbebec7f509842c48db8b23.html | 86 - src/libs/oboe/docs/reference/doc.png | Bin 746 -> 0 bytes src/libs/oboe/docs/reference/doxygen.css | 1764 ----------------- src/libs/oboe/docs/reference/doxygen.png | Bin 3779 -> 0 bytes src/libs/oboe/docs/reference/dynsections.js | 120 -- src/libs/oboe/docs/reference/files.html | 95 - src/libs/oboe/docs/reference/folderclosed.png | Bin 616 -> 0 bytes src/libs/oboe/docs/reference/folderopen.png | Bin 597 -> 0 bytes src/libs/oboe/docs/reference/functions.html | 554 ------ .../oboe/docs/reference/functions_func.html | 465 ----- .../oboe/docs/reference/functions_vars.html | 157 -- src/libs/oboe/docs/reference/hierarchy.html | 97 - src/libs/oboe/docs/reference/index.html | 80 - src/libs/oboe/docs/reference/jquery.js | 87 - src/libs/oboe/docs/reference/menu.js | 50 - src/libs/oboe/docs/reference/menudata.js | 90 - .../oboe/docs/reference/namespacemembers.html | 259 --- .../docs/reference/namespacemembers_enum.html | 118 -- .../docs/reference/namespacemembers_eval.html | 121 -- .../docs/reference/namespacemembers_func.html | 100 - .../docs/reference/namespacemembers_vars.html | 94 - .../oboe/docs/reference/namespaceoboe.html | 1079 ---------- src/libs/oboe/docs/reference/namespaces.html | 83 - src/libs/oboe/docs/reference/nav_f.png | Bin 153 -> 0 bytes src/libs/oboe/docs/reference/nav_g.png | Bin 95 -> 0 bytes src/libs/oboe/docs/reference/nav_h.png | Bin 98 -> 0 bytes src/libs/oboe/docs/reference/open.png | Bin 123 -> 0 bytes src/libs/oboe/docs/reference/pages.html | 83 - .../oboe/docs/reference/search/all_0.html | 30 - src/libs/oboe/docs/reference/search/all_0.js | 19 - .../oboe/docs/reference/search/all_1.html | 30 - src/libs/oboe/docs/reference/search/all_1.js | 4 - .../oboe/docs/reference/search/all_10.html | 30 - src/libs/oboe/docs/reference/search/all_10.js | 5 - .../oboe/docs/reference/search/all_11.html | 30 - src/libs/oboe/docs/reference/search/all_11.js | 9 - .../oboe/docs/reference/search/all_12.html | 30 - src/libs/oboe/docs/reference/search/all_12.js | 9 - .../oboe/docs/reference/search/all_13.html | 30 - src/libs/oboe/docs/reference/search/all_13.js | 9 - .../oboe/docs/reference/search/all_2.html | 30 - src/libs/oboe/docs/reference/search/all_2.js | 13 - .../oboe/docs/reference/search/all_3.html | 30 - src/libs/oboe/docs/reference/search/all_3.js | 7 - .../oboe/docs/reference/search/all_4.html | 30 - src/libs/oboe/docs/reference/search/all_4.js | 5 - .../oboe/docs/reference/search/all_5.html | 30 - src/libs/oboe/docs/reference/search/all_5.js | 9 - .../oboe/docs/reference/search/all_6.html | 30 - src/libs/oboe/docs/reference/search/all_6.js | 38 - .../oboe/docs/reference/search/all_7.html | 30 - src/libs/oboe/docs/reference/search/all_7.js | 17 - .../oboe/docs/reference/search/all_8.html | 30 - src/libs/oboe/docs/reference/search/all_8.js | 9 - .../oboe/docs/reference/search/all_9.html | 30 - src/libs/oboe/docs/reference/search/all_9.js | 6 - .../oboe/docs/reference/search/all_a.html | 30 - src/libs/oboe/docs/reference/search/all_a.js | 28 - .../oboe/docs/reference/search/all_b.html | 30 - src/libs/oboe/docs/reference/search/all_b.js | 8 - .../oboe/docs/reference/search/all_c.html | 30 - src/libs/oboe/docs/reference/search/all_c.js | 20 - .../oboe/docs/reference/search/all_d.html | 30 - src/libs/oboe/docs/reference/search/all_d.js | 7 - .../oboe/docs/reference/search/all_e.html | 30 - src/libs/oboe/docs/reference/search/all_e.js | 11 - .../oboe/docs/reference/search/all_f.html | 30 - src/libs/oboe/docs/reference/search/all_f.js | 42 - .../oboe/docs/reference/search/classes_0.html | 30 - .../oboe/docs/reference/search/classes_0.js | 9 - .../oboe/docs/reference/search/classes_1.html | 30 - .../oboe/docs/reference/search/classes_1.js | 4 - .../oboe/docs/reference/search/classes_2.html | 30 - .../oboe/docs/reference/search/classes_2.js | 4 - .../oboe/docs/reference/search/classes_3.html | 30 - .../oboe/docs/reference/search/classes_3.js | 4 - .../oboe/docs/reference/search/classes_4.html | 30 - .../oboe/docs/reference/search/classes_4.js | 4 - .../oboe/docs/reference/search/classes_5.html | 30 - .../oboe/docs/reference/search/classes_5.js | 4 - .../oboe/docs/reference/search/classes_6.html | 30 - .../oboe/docs/reference/search/classes_6.js | 5 - .../oboe/docs/reference/search/classes_7.html | 30 - .../oboe/docs/reference/search/classes_7.js | 4 - src/libs/oboe/docs/reference/search/close.png | Bin 273 -> 0 bytes .../oboe/docs/reference/search/enums_0.html | 30 - .../oboe/docs/reference/search/enums_0.js | 5 - .../oboe/docs/reference/search/enums_1.html | 30 - .../oboe/docs/reference/search/enums_1.js | 5 - .../oboe/docs/reference/search/enums_2.html | 30 - .../oboe/docs/reference/search/enums_2.js | 5 - .../oboe/docs/reference/search/enums_3.html | 30 - .../oboe/docs/reference/search/enums_3.js | 4 - .../oboe/docs/reference/search/enums_4.html | 30 - .../oboe/docs/reference/search/enums_4.js | 4 - .../oboe/docs/reference/search/enums_5.html | 30 - .../oboe/docs/reference/search/enums_5.js | 4 - .../oboe/docs/reference/search/enums_6.html | 30 - .../oboe/docs/reference/search/enums_6.js | 7 - .../oboe/docs/reference/search/enums_7.html | 30 - .../oboe/docs/reference/search/enums_7.js | 4 - .../docs/reference/search/enumvalues_0.html | 30 - .../docs/reference/search/enumvalues_0.js | 10 - .../docs/reference/search/enumvalues_1.html | 30 - .../docs/reference/search/enumvalues_1.js | 4 - .../docs/reference/search/enumvalues_2.html | 30 - .../docs/reference/search/enumvalues_2.js | 4 - .../docs/reference/search/enumvalues_3.html | 30 - .../docs/reference/search/enumvalues_3.js | 4 - .../docs/reference/search/enumvalues_4.html | 30 - .../docs/reference/search/enumvalues_4.js | 5 - .../docs/reference/search/enumvalues_5.html | 30 - .../docs/reference/search/enumvalues_5.js | 5 - .../docs/reference/search/enumvalues_6.html | 30 - .../docs/reference/search/enumvalues_6.js | 6 - .../docs/reference/search/enumvalues_7.html | 30 - .../docs/reference/search/enumvalues_7.js | 4 - .../docs/reference/search/enumvalues_8.html | 30 - .../docs/reference/search/enumvalues_8.js | 7 - .../docs/reference/search/enumvalues_9.html | 30 - .../docs/reference/search/enumvalues_9.js | 7 - .../docs/reference/search/enumvalues_a.html | 30 - .../docs/reference/search/enumvalues_a.js | 5 - .../docs/reference/search/enumvalues_b.html | 30 - .../docs/reference/search/enumvalues_b.js | 4 - .../docs/reference/search/enumvalues_c.html | 30 - .../docs/reference/search/enumvalues_c.js | 7 - .../docs/reference/search/enumvalues_d.html | 30 - .../docs/reference/search/enumvalues_d.js | 5 - .../docs/reference/search/enumvalues_e.html | 30 - .../docs/reference/search/enumvalues_e.js | 7 - .../docs/reference/search/functions_0.html | 30 - .../oboe/docs/reference/search/functions_0.js | 5 - .../docs/reference/search/functions_1.html | 30 - .../oboe/docs/reference/search/functions_1.js | 10 - .../docs/reference/search/functions_2.html | 30 - .../oboe/docs/reference/search/functions_2.js | 4 - .../docs/reference/search/functions_3.html | 30 - .../oboe/docs/reference/search/functions_3.js | 5 - .../docs/reference/search/functions_4.html | 30 - .../oboe/docs/reference/search/functions_4.js | 36 - .../docs/reference/search/functions_5.html | 30 - .../oboe/docs/reference/search/functions_5.js | 13 - .../docs/reference/search/functions_6.html | 30 - .../oboe/docs/reference/search/functions_6.js | 5 - .../docs/reference/search/functions_7.html | 30 - .../oboe/docs/reference/search/functions_7.js | 16 - .../docs/reference/search/functions_8.html | 30 - .../oboe/docs/reference/search/functions_8.js | 4 - .../docs/reference/search/functions_9.html | 30 - .../oboe/docs/reference/search/functions_9.js | 10 - .../docs/reference/search/functions_a.html | 30 - .../oboe/docs/reference/search/functions_a.js | 31 - .../docs/reference/search/functions_b.html | 30 - .../oboe/docs/reference/search/functions_b.js | 4 - .../docs/reference/search/functions_c.html | 30 - .../oboe/docs/reference/search/functions_c.js | 6 - .../docs/reference/search/functions_d.html | 30 - .../oboe/docs/reference/search/functions_d.js | 4 - .../docs/reference/search/functions_e.html | 30 - .../oboe/docs/reference/search/functions_e.js | 9 - .../oboe/docs/reference/search/mag_sel.png | Bin 465 -> 0 bytes .../docs/reference/search/namespaces_0.html | 30 - .../docs/reference/search/namespaces_0.js | 4 - .../oboe/docs/reference/search/nomatches.html | 12 - .../oboe/docs/reference/search/pages_0.html | 30 - .../oboe/docs/reference/search/pages_0.js | 4 - .../oboe/docs/reference/search/pages_1.html | 30 - .../oboe/docs/reference/search/pages_1.js | 4 - .../oboe/docs/reference/search/search.css | 271 --- src/libs/oboe/docs/reference/search/search.js | 814 -------- .../oboe/docs/reference/search/search_l.png | Bin 567 -> 0 bytes .../oboe/docs/reference/search/search_m.png | Bin 158 -> 0 bytes .../oboe/docs/reference/search/search_r.png | Bin 553 -> 0 bytes .../oboe/docs/reference/search/searchdata.js | 36 - .../docs/reference/search/variables_0.html | 30 - .../oboe/docs/reference/search/variables_0.js | 4 - .../docs/reference/search/variables_1.html | 30 - .../oboe/docs/reference/search/variables_1.js | 4 - .../docs/reference/search/variables_2.html | 30 - .../oboe/docs/reference/search/variables_2.js | 9 - .../docs/reference/search/variables_3.html | 30 - .../oboe/docs/reference/search/variables_3.js | 24 - .../docs/reference/search/variables_4.html | 30 - .../oboe/docs/reference/search/variables_4.js | 4 - .../docs/reference/search/variables_5.html | 30 - .../oboe/docs/reference/search/variables_5.js | 4 - .../docs/reference/search/variables_6.html | 30 - .../oboe/docs/reference/search/variables_6.js | 4 - .../docs/reference/search/variables_7.html | 30 - .../oboe/docs/reference/search/variables_7.js | 4 - src/libs/oboe/docs/reference/splitbar.png | Bin 314 -> 0 bytes ...tructoboe_1_1_frame_timestamp-members.html | 87 - .../structoboe_1_1_frame_timestamp.html | 102 - ...oe_1_1_stream_deleter_functor-members.html | 86 - ...structoboe_1_1_stream_deleter_functor.html | 99 - .../structoboe_1_1_version-members.html | 90 - .../reference/structoboe_1_1_version.html | 222 --- src/libs/oboe/docs/reference/sync_off.png | Bin 853 -> 0 bytes src/libs/oboe/docs/reference/sync_on.png | Bin 845 -> 0 bytes src/libs/oboe/docs/reference/tab_a.png | Bin 142 -> 0 bytes src/libs/oboe/docs/reference/tab_b.png | Bin 169 -> 0 bytes src/libs/oboe/docs/reference/tab_h.png | Bin 177 -> 0 bytes src/libs/oboe/docs/reference/tab_s.png | Bin 184 -> 0 bytes src/libs/oboe/docs/reference/tabs.css | 1 - .../{src/common => include/oboe}/AudioClock.h | 1 - src/libs/oboe/include/oboe/AudioStream.h | 403 +++- src/libs/oboe/include/oboe/AudioStreamBase.h | 167 +- .../oboe/include/oboe/AudioStreamBuilder.h | 344 +++- .../oboe/include/oboe/AudioStreamCallback.h | 104 +- src/libs/oboe/include/oboe/Definitions.h | 672 +++++++ .../{src/fifo => include/oboe}/FifoBuffer.h | 67 +- .../oboe}/FifoControllerBase.h | 46 +- src/libs/oboe/include/oboe/FullDuplexStream.h | 356 ++++ src/libs/oboe/include/oboe/Oboe.h | 9 +- src/libs/oboe/include/oboe/OboeExtensions.h | 69 + src/libs/oboe/include/oboe/ResultWithValue.h | 4 + .../oboe/include/oboe/StabilizedCallback.h | 2 +- src/libs/oboe/include/oboe/Utilities.h | 16 + src/libs/oboe/include/oboe/Version.h | 4 +- src/libs/oboe/prefab/oboe-VERSION.pom | 2 +- .../prefab/oboe-VERSION/AndroidManifest.xml | 6 +- src/libs/oboe/samples/LiveEffect/README.md | 2 + src/libs/oboe/samples/LiveEffect/build.gradle | 17 +- .../LiveEffect/src/main/AndroidManifest.xml | 31 +- .../LiveEffect/src/main/cpp/CMakeLists.txt | 4 +- .../LiveEffect/src/main/cpp/FullDuplexPass.h | 8 +- .../src/main/cpp/FullDuplexStream.cpp | 128 -- .../src/main/cpp/FullDuplexStream.h | 102 - .../src/main/cpp/LiveEffectEngine.cpp | 23 +- .../src/main/cpp/LiveEffectEngine.h | 2 +- .../DuplexStreamForegroundService.java | 92 + .../oboe/samples/liveEffect/MainActivity.java | 68 +- .../src/main/res/drawable/balance_seekbar.xml | 17 - .../src/main/res/layout-v21/activity_main.xml | 129 -- .../src/main/res/layout/activity_main.xml | 102 +- .../src/main/res/values-v21/styles.xml | 5 - .../LiveEffect/src/main/res/values/colors.xml | 3 +- .../LiveEffect/src/main/res/values/styles.xml | 9 +- src/libs/oboe/samples/MegaDrone/README.md | 6 +- src/libs/oboe/samples/MegaDrone/build.gradle | 18 +- .../MegaDrone/src/main/AndroidManifest.xml | 6 +- .../MegaDrone/src/main/cpp/CMakeLists.txt | 7 +- .../src/main/cpp/MegaDroneEngine.cpp | 42 +- .../MegaDrone/src/main/cpp/MegaDroneEngine.h | 5 +- .../oboe/samples/megadrone/MainActivity.java | 2 +- .../src/main/res/layout/activity_main.xml | 22 + .../MegaDrone/src/main/res/values/colors.xml | 2 +- .../MegaDrone/src/main/res/values/styles.xml | 3 +- src/libs/oboe/samples/README.md | 15 +- .../oboe/samples/RhythmGame/CMakeLists.txt | 8 +- src/libs/oboe/samples/RhythmGame/README.md | 8 +- src/libs/oboe/samples/RhythmGame/build.gradle | 22 +- .../RhythmGame/src/main/AndroidManifest.xml | 6 +- .../samples/RhythmGame/src/main/cpp/Game.cpp | 2 +- .../RhythmGame/src/main/cpp/GameConstants.h | 2 +- .../src/main/cpp/audio/AAssetDataSource.cpp | 2 +- .../RhythmGame/src/main/cpp/audio/Player.cpp | 2 +- .../src/main/cpp/utils/UtilityFunctions.cpp | 2 +- .../oboe/samples/rhythmgame/MainActivity.java | 2 +- .../src/main/res/layout/activity_main.xml | 40 + .../RhythmGame/src/main/res/values/colors.xml | 2 +- .../RhythmGame/src/main/res/values/styles.xml | 3 +- .../samples/RhythmGame/test/CMakeLists.txt | 4 +- .../oboe/samples/RhythmGame/test/run_tests.sh | 6 +- src/libs/oboe/samples/SoundBoard/README.md | 46 + src/libs/oboe/samples/SoundBoard/build.gradle | 59 + .../SoundBoard}/proguard-rules.pro | 0 .../samples/SoundBoard/soundboard_image.png | Bin 0 -> 52547 bytes .../SoundBoard/src/main/AndroidManifest.xml | 21 + .../SoundBoard/src/main/cpp/CMakeLists.txt | 29 + .../src/main/cpp/SoundBoardEngine.cpp | 130 ++ .../src/main/cpp/SoundBoardEngine.h | 65 + .../samples/SoundBoard/src/main/cpp/Synth.h | 94 + .../SoundBoard/src/main/cpp/native-lib.cpp | 91 + .../src/main/ic_launcher-playstore.png | Bin 0 -> 4673 bytes .../oboe/samples/soundboard/MainActivity.kt | 150 ++ .../oboe/samples/soundboard/MusicTileView.kt | 171 ++ .../oboe/samples/soundboard/NoteListener.kt} | 22 +- .../drawable-v24/ic_launcher_foreground.xml | 34 + .../res/drawable/ic_launcher_background.xml | 0 .../src/main/res/layout/activity_main.xml | 9 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 853 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 576 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 1200 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 1783 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 2993 bytes .../SoundBoard/src/main/res/values/colors.xml | 6 + .../src/main/res/values/strings.xml | 3 + .../SoundBoard/src/main/res/values/styles.xml | 11 + .../oboe/samples/audio-device/build.gradle | 15 +- .../audio-device/src/main/AndroidManifest.xml | 2 +- src/libs/oboe/samples/build.gradle | 18 +- src/libs/oboe/samples/drumthumper/README.md | 9 +- .../oboe/samples/drumthumper/build.gradle | 40 +- .../drumthumper/drumthumper-screenshot.png | Bin 0 -> 118282 bytes .../drumthumper/src/main/AndroidManifest.xml | 6 +- .../drumthumper/src/main/cpp/CMakeLists.txt | 7 +- .../src/main/cpp/DrumPlayerJNI.cpp | 24 +- .../plausibleaudio/drumthumper/DrumPlayer.kt | 41 +- .../drumthumper/DrumThumperActivity.kt | 90 +- .../plausibleaudio/drumthumper/TriggerPad.kt | 4 +- .../res/layout-land/drumthumper_activity.xml | 134 ++ .../main/res/layout/drumthumper_activity.xml | 136 +- .../src/main/res/values/colors.xml | 4 +- .../src/main/res/values/styles.xml | 3 +- src/libs/oboe/samples/gradle.properties | 5 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- src/libs/oboe/samples/hello-oboe/README.md | 2 +- src/libs/oboe/samples/hello-oboe/build.gradle | 20 +- .../hello-oboe/src/main/AndroidManifest.xml | 6 +- .../hello-oboe/src/main/cpp/CMakeLists.txt | 5 +- .../src/main/cpp/HelloOboeEngine.cpp | 115 +- .../hello-oboe/src/main/cpp/HelloOboeEngine.h | 26 +- .../hello-oboe/src/main/cpp/jni_bridge.cpp | 157 +- .../samples/hellooboe/BackgroundRunner.java | 56 + .../oboe/samples/hellooboe/MainActivity.java | 222 ++- .../samples/hellooboe/PlaybackEngine.java | 88 +- .../src/main/res/layout/activity_main.xml | 26 +- .../src/main/res/values-v21/styles.xml | 5 - .../hello-oboe/src/main/res/values/colors.xml | 6 + .../hello-oboe/src/main/res/values/styles.xml | 9 +- src/libs/oboe/samples/iolib/build.gradle | 19 +- .../iolib/src/main/AndroidManifest.xml | 3 +- .../samples/iolib/src/main/cpp/CMakeLists.txt | 2 +- .../main/cpp/player/OneShotSampleSource.cpp | 74 +- .../src/main/cpp/player/SampleBuffer.cpp | 29 +- .../iolib/src/main/cpp/player/SampleBuffer.h | 2 +- .../iolib/src/main/cpp/player/SampleSource.h | 21 +- .../src/main/cpp/player/SimpleMultiPlayer.cpp | 88 +- .../src/main/cpp/player/SimpleMultiPlayer.h | 61 +- .../app => samples/minimaloboe}/.gitignore | 0 src/libs/oboe/samples/minimaloboe/README.md | 19 + .../oboe/samples/minimaloboe/build.gradle | 75 + .../minimaloboe/minimaloboe-screenshot.png | Bin 0 -> 98980 bytes .../samples/minimaloboe/proguard-rules.pro | 21 + .../minimaloboe/src/main/AndroidManifest.xml | 24 + .../minimaloboe/src/main/cpp/CMakeLists.txt | 53 + .../src/main/cpp/MinimalOboeJNI.cpp | 66 + .../src/main/cpp/SimpleNoiseMaker.cpp | 92 + .../src/main/cpp/SimpleNoiseMaker.h | 71 + .../com/example/minimaloboe/AudioPlayer.kt | 84 + .../com/example/minimaloboe/MainActivity.kt | 115 ++ .../com/example/minimaloboe/ui/theme/Color.kt | 8 + .../com/example/minimaloboe/ui/theme/Shape.kt | 11 + .../com/example/minimaloboe/ui/theme/Theme.kt | 44 + .../com/example/minimaloboe/ui/theme/Type.kt | 21 + .../drawable-v24/ic_launcher_foreground.xml | 30 + .../res/drawable/ic_launcher_background.xml | 170 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 4 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 4 +- .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../src/main/res/values/colors.xml | 10 + .../src/main/res/values/strings.xml | 3 + .../src/main/res/values/themes.xml | 7 + src/libs/oboe/samples/parselib/build.gradle | 19 +- .../parselib/src/main/AndroidManifest.xml | 3 +- .../parselib/src/main/cpp/CMakeLists.txt | 2 +- .../parselib/src/main/cpp/wav/AudioEncoding.h | 2 + .../src/main/cpp/wav/WavStreamReader.cpp | 6 +- src/libs/oboe/samples/powerplay/.gitignore | 1 + src/libs/oboe/samples/powerplay/README.md | 3 + src/libs/oboe/samples/powerplay/build.gradle | 85 + .../oboe/samples/powerplay/proguard-rules.pro | 21 + .../powerplay/src/main/AndroidManifest.xml | 32 + .../powerplay/src/main/assets/song1.wav | Bin 0 -> 11953742 bytes .../powerplay/src/main/cpp/CMakeLists.txt | 68 + .../powerplay/src/main/cpp/PowerPlayJNI.cpp | 261 +++ .../src/main/cpp/PowerPlayMultiPlayer.cpp | 128 ++ .../src/main/cpp/PowerPlayMultiPlayer.h | 65 + .../oboe/samples/powerplay/MainActivity.kt | 538 +++++ .../engine/AudioForegroundService.kt | 124 ++ .../powerplay/engine/OboePerformanceMode.kt | 52 + .../powerplay/engine/PowerPlayAudioPlayer.kt | 123 ++ .../oboe/samples/powerplay/ui/theme/Color.kt | 19 + .../oboe/samples/powerplay/ui/theme/Shape.kt | 11 + .../oboe/samples/powerplay/ui/theme/Theme.kt | 18 + .../oboe/samples/powerplay/ui/theme/Type.kt | 17 + .../drawable-v24/ic_launcher_foreground.xml | 30 + .../src/main/res/drawable/album_art_1.jpeg | Bin 0 -> 391524 bytes .../res/drawable/ic_launcher_background.xml | 170 ++ .../src/main/res/drawable/ic_next.png | Bin 0 -> 5299 bytes .../src/main/res/drawable/ic_pause.png | Bin 0 -> 10406 bytes .../src/main/res/drawable/ic_play.png | Bin 0 -> 18549 bytes .../src/main/res/drawable/ic_previous.png | Bin 0 -> 5338 bytes .../main/res/drawable/vinyl_background.png | Bin 0 -> 561966 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../powerplay/src/main/res/values/colors.xml | 10 + .../powerplay/src/main/res/values/strings.xml | 3 + .../powerplay/src/main/res/values/themes.xml | 7 + src/libs/oboe/samples/settings.gradle | 3 + .../oboe/samples/shared/DefaultDataCallback.h | 1 - src/libs/oboe/samples/shared/Mixer.h | 32 +- src/libs/oboe/samples/shared/Oscillator.h | 2 +- src/libs/oboe/samples/shared/SynthSound.h | 109 + .../oboe/samples/shared/TappableAudioSource.h | 2 +- src/libs/oboe/src/aaudio/AAudioExtensions.h | 171 +- src/libs/oboe/src/aaudio/AAudioLoader.cpp | 272 ++- src/libs/oboe/src/aaudio/AAudioLoader.h | 159 +- .../oboe/src/aaudio/AudioStreamAAudio.cpp | 529 ++++- src/libs/oboe/src/aaudio/AudioStreamAAudio.h | 73 +- src/libs/oboe/src/common/AdpfWrapper.cpp | 277 +++ src/libs/oboe/src/common/AdpfWrapper.h | 173 ++ src/libs/oboe/src/common/AudioStream.cpp | 67 +- .../oboe/src/common/AudioStreamBuilder.cpp | 76 +- .../src/common/DataConversionFlowGraph.cpp | 15 +- src/libs/oboe/src/common/FilterAudioStream.h | 16 +- src/libs/oboe/src/common/OboeExtensions.cpp | 40 + src/libs/oboe/src/common/QuirksManager.cpp | 112 +- src/libs/oboe/src/common/QuirksManager.h | 3 + src/libs/oboe/src/common/SourceI16Caller.h | 3 +- src/libs/oboe/src/common/SourceI24Caller.h | 5 +- src/libs/oboe/src/common/SourceI32Caller.h | 3 +- .../oboe/src/common/StabilizedCallback.cpp | 18 +- src/libs/oboe/src/common/Trace.cpp | 83 +- src/libs/oboe/src/common/Trace.h | 51 +- src/libs/oboe/src/common/Utilities.cpp | 90 + src/libs/oboe/src/fifo/FifoBuffer.cpp | 4 +- src/libs/oboe/src/fifo/FifoController.cpp | 1 - src/libs/oboe/src/fifo/FifoController.h | 2 +- src/libs/oboe/src/fifo/FifoControllerBase.cpp | 2 +- .../oboe/src/fifo/FifoControllerIndirect.h | 2 +- .../src/flowgraph/ChannelCountConverter.cpp | 2 +- .../src/flowgraph/ChannelCountConverter.h | 6 +- src/libs/oboe/src/flowgraph/ClipToRange.h | 6 +- src/libs/oboe/src/flowgraph/FlowGraphNode.cpp | 2 +- src/libs/oboe/src/flowgraph/FlowGraphNode.h | 36 +- .../oboe/src/flowgraph/FlowgraphUtilities.h | 19 +- src/libs/oboe/src/flowgraph/Limiter.cpp | 67 + src/libs/oboe/src/flowgraph/Limiter.h | 64 + .../oboe/src/flowgraph/ManyToMultiConverter.h | 6 +- src/libs/oboe/src/flowgraph/MonoBlend.cpp | 46 + .../flowgraph/MonoBlend.h} | 35 +- .../src/flowgraph/MonoToMultiConverter.cpp | 2 - .../oboe/src/flowgraph/MonoToMultiConverter.h | 8 +- .../src/flowgraph/MultiToManyConverter.cpp | 47 + .../oboe/src/flowgraph/MultiToManyConverter.h | 49 + .../src/flowgraph/MultiToMonoConverter.cpp | 2 +- .../oboe/src/flowgraph/MultiToMonoConverter.h | 6 +- src/libs/oboe/src/flowgraph/RampLinear.h | 6 +- .../src/flowgraph/SampleRateConverter.cpp | 8 +- .../oboe/src/flowgraph/SampleRateConverter.h | 17 +- src/libs/oboe/src/flowgraph/SinkFloat.cpp | 3 - src/libs/oboe/src/flowgraph/SinkFloat.h | 6 +- src/libs/oboe/src/flowgraph/SinkI16.h | 6 +- src/libs/oboe/src/flowgraph/SinkI24.h | 6 +- src/libs/oboe/src/flowgraph/SinkI32.cpp | 8 +- src/libs/oboe/src/flowgraph/SinkI32.h | 6 +- src/libs/oboe/src/flowgraph/SinkI8_24.cpp | 55 + src/libs/oboe/src/flowgraph/SinkI8_24.h | 40 + src/libs/oboe/src/flowgraph/SourceFloat.cpp | 1 - src/libs/oboe/src/flowgraph/SourceFloat.h | 6 +- src/libs/oboe/src/flowgraph/SourceI16.cpp | 2 +- src/libs/oboe/src/flowgraph/SourceI16.h | 6 +- src/libs/oboe/src/flowgraph/SourceI24.cpp | 8 +- src/libs/oboe/src/flowgraph/SourceI24.h | 6 +- src/libs/oboe/src/flowgraph/SourceI32.cpp | 6 +- src/libs/oboe/src/flowgraph/SourceI32.h | 6 +- src/libs/oboe/src/flowgraph/SourceI8_24.cpp | 54 + .../flowgraph/SourceI8_24.h} | 32 +- .../resampler/HyperbolicCosineWindow.h | 7 +- .../src/flowgraph/resampler/IntegerRatio.cpp | 2 +- .../src/flowgraph/resampler/IntegerRatio.h | 12 +- .../src/flowgraph/resampler/KaiserWindow.h | 7 +- .../flowgraph/resampler/LinearResampler.cpp | 2 +- .../src/flowgraph/resampler/LinearResampler.h | 17 +- .../resampler/MultiChannelResampler.cpp | 22 +- .../resampler/MultiChannelResampler.h | 20 +- .../resampler/PolyphaseResampler.cpp | 7 +- .../flowgraph/resampler/PolyphaseResampler.h | 14 +- .../resampler/PolyphaseResamplerMono.cpp | 2 +- .../resampler/PolyphaseResamplerMono.h | 14 +- .../resampler/PolyphaseResamplerStereo.cpp | 2 +- .../resampler/PolyphaseResamplerStereo.h | 14 +- .../oboe/src/flowgraph/resampler/README.md | 8 +- .../resampler/ResamplerDefinitions.h} | 21 +- .../src/flowgraph/resampler/SincResampler.cpp | 53 +- .../src/flowgraph/resampler/SincResampler.h | 15 +- .../resampler/SincResamplerStereo.cpp | 14 +- .../flowgraph/resampler/SincResamplerStereo.h | 15 +- .../src/opensles/AudioInputStreamOpenSLES.cpp | 54 +- .../src/opensles/AudioInputStreamOpenSLES.h | 4 +- .../opensles/AudioOutputStreamOpenSLES.cpp | 93 +- .../src/opensles/AudioOutputStreamOpenSLES.h | 6 +- .../oboe/src/opensles/AudioStreamBuffered.cpp | 10 +- .../oboe/src/opensles/AudioStreamBuffered.h | 2 +- .../oboe/src/opensles/AudioStreamOpenSLES.cpp | 239 ++- .../oboe/src/opensles/AudioStreamOpenSLES.h | 38 +- src/libs/oboe/src/opensles/EngineOpenSLES.cpp | 119 +- src/libs/oboe/src/opensles/EngineOpenSLES.h | 42 + .../oboe/src/opensles/OpenSLESUtilities.cpp | 8 + .../oboe/src/opensles/OutputMixerOpenSLES.h | 3 +- src/libs/oboe/tests/CMakeLists.txt | 32 +- src/libs/oboe/tests/README | 1 - src/libs/oboe/tests/README.md | 20 +- .../tests/UnitTestRunner/app/build.gradle | 14 +- .../UnitTestRunner/app/src/main/.gitignore | 2 + .../app/src/main/AndroidManifest.xml | 7 +- .../tests/unittestrunner/MainActivity.java | 122 +- .../app/src/main/res/layout/activity_main.xml | 2 +- .../app/src/main/res/values/strings.xml | 2 +- .../oboe/tests/UnitTestRunner/build.gradle | 22 +- .../tests/UnitTestRunner/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- src/libs/oboe/tests/run_tests.sh | 38 +- src/libs/oboe/tests/testAAudio.cpp | 2 +- src/libs/oboe/tests/testAudioClock.cpp | 92 + src/libs/oboe/tests/testFlowgraph.cpp | 104 +- src/libs/oboe/tests/testFullDuplexStream.cpp | 206 ++ src/libs/oboe/tests/testResampler.cpp | 225 +++ src/libs/oboe/tests/testReturnStop.cpp | 110 +- .../oboe/tests/testReturnStopDeadlock.cpp | 161 ++ .../oboe/tests/testStreamClosedMethods.cpp | 110 +- .../oboe/tests/testStreamFramesProcessed.cpp | 41 +- src/libs/oboe/tests/testStreamOpen.cpp | 355 +++- src/libs/oboe/tests/testStreamStates.cpp | 4 +- src/libs/oboe/tests/testStreamStop.cpp | 130 ++ src/libs/oboe/tests/testStreamWaitState.cpp | 12 +- src/libs/oboe/tests/testUtilities.cpp | 2 +- src/libs/oboe/tests/testXRunBehaviour.cpp | 6 +- 910 files changed, 12513 insertions(+), 48290 deletions(-) delete mode 100644 src/libs/oboe/apps/OboeTester/.gitignore delete mode 100644 src/libs/oboe/apps/OboeTester/.google/packaging.yaml delete mode 100644 src/libs/oboe/apps/OboeTester/README.md delete mode 100644 src/libs/oboe/apps/OboeTester/app/CMakeLists.txt delete mode 100644 src/libs/oboe/apps/OboeTester/app/build.gradle delete mode 100644 src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.jar delete mode 100644 src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.properties delete mode 100644 src/libs/oboe/apps/OboeTester/app/gradlew delete mode 100644 src/libs/oboe/apps/OboeTester/app/gradlew.bat delete mode 100644 src/libs/oboe/apps/OboeTester/app/local.properties delete mode 100644 src/libs/oboe/apps/OboeTester/app/proguard-rules.pro delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/AndroidManifest.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/MultiChannelRecording.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/InfiniteRecording.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/ManchesterEncoder.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PeakDetector.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PseudoRandom.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RandomPulseGenerator.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RoundedManchesterEncoder.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/android_debug.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ImpulseOscillator.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SawtoothOscillator.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/unused/unused.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.cpp delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/ic_launcher-playstore.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceAdapter.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/EventScheduler.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiConstants.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDeviceMonitor.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDispatcher.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventScheduler.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventThread.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiFramer.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiInputPortSelector.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortConnectionSelector.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortSelector.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortConnector.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortSelector.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortWrapper.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiTools.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MusicKeyboardView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/AudioLatencyTuner.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/EnvelopeADSR.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/LatencyController.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillator.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillatorDPW.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawVoice.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SimpleAudioOutput.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SineOscillator.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthEngine.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthUnit.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthVoice.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/button_shape.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_echo.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_external_tap_to_tone.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_extra_tests.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_main.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_manual_glitches.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_recorder.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_rt_latency.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_tap_to_tone.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_test_disconnect.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_test_input.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_test_output.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/audio_devices.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/auto_test_runner.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/buffer_size_view.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/input_margin_view.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/merge_audio_common.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/merge_audio_simple.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/sample_fast_button.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/stream_config.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/layout/workload_view.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/menu/menu_main.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values-v21/styles.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values-w600dp/dimens.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/arrays.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/attrs_fast_button.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/attrs_waveform.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/colors.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/dimens.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/strings.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/values/styles.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/xml/button_color_selector.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/xml/provider_paths.xml delete mode 100644 src/libs/oboe/apps/OboeTester/app/src/main/res/xml/service_device_info.xml delete mode 100644 src/libs/oboe/apps/OboeTester/build.gradle delete mode 100644 src/libs/oboe/apps/OboeTester/docs/AutomatedTesting.md delete mode 100644 src/libs/oboe/apps/OboeTester/docs/Build.md delete mode 100644 src/libs/oboe/apps/OboeTester/docs/PrivacyPolicy.md delete mode 100644 src/libs/oboe/apps/OboeTester/docs/README.md delete mode 100644 src/libs/oboe/apps/OboeTester/docs/TestOutput.md delete mode 100644 src/libs/oboe/apps/OboeTester/docs/Usage.md delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/auto_glitch_test.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/echo_input_output.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/main_activity.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/recorder.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/round_trip_latency.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/tap_to_tone.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/test_glitches.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/test_input.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/test_output.png delete mode 100644 src/libs/oboe/apps/OboeTester/docs/images/test_output_running.png delete mode 100644 src/libs/oboe/apps/OboeTester/gradle.properties delete mode 100644 src/libs/oboe/apps/OboeTester/gradle/wrapper/gradle-wrapper.jar delete mode 100644 src/libs/oboe/apps/OboeTester/gradle/wrapper/gradle-wrapper.properties delete mode 100755 src/libs/oboe/apps/OboeTester/gradlew delete mode 100644 src/libs/oboe/apps/OboeTester/gradlew.bat delete mode 100644 src/libs/oboe/apps/OboeTester/scripts/dsp_timing.py delete mode 100644 src/libs/oboe/apps/OboeTester/settings.gradle delete mode 100644 src/libs/oboe/apps/fxlab/.gitignore delete mode 100644 src/libs/oboe/apps/fxlab/CONTRIBUTING.md delete mode 100644 src/libs/oboe/apps/fxlab/LICENSE delete mode 100644 src/libs/oboe/apps/fxlab/README.md delete mode 100644 src/libs/oboe/apps/fxlab/app/CMakeLists.txt delete mode 100644 src/libs/oboe/apps/fxlab/app/build.gradle delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/AndroidManifest.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/DuplexCallback.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/DuplexEngine.cpp delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/DuplexEngine.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/FunctionList.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/CombFilter.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/DelayLineEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/DoublingEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/DriveControl.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/EchoEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/Effects.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/FlangerEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/SingleFunctionEffects.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/SlapbackEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/TremoloEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/VibratroEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/WhiteChorusEffect.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/AllPassDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/DistortionDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/DoublingDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/EchoDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/EffectDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/FIRDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/FlangerDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/GainDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/IIRDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/OverdriveDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/PassthroughDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/SlapbackDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/TremoloDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/VibratoDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/descrip/WhiteChorusDescription.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/utils/DelayLine.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/utils/PhaseAccumulator.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/utils/SineWave.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/effects/utils/WhiteNoise.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/logging_macros.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/native-lib.cpp delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/tests/.gitignore delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/tests/CMakeLists.txt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/tests/DelayLineEffectTest.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/tests/DelayLineTest.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/tests/TypeTests.h delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/cpp/tests/testEffects.cpp delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/EffectsAdapter.kt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/MainActivity.kt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/NativeInterface.kt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/Effect.kt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/EffectDescription.kt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/java/com/mobileer/androidfxlab/datatype/ParamDescription.kt delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/drawable-v24/ic_launcher_foreground.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/drawable/ic_add.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/drawable/ic_baseline_audio_is_disabled_24.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/drawable/ic_baseline_audio_is_enabled_24.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/drawable/ic_baseline_drag_indicator.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/drawable/ic_launcher_background.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/layout/activity_main.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/layout/effect_header.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/layout/effect_view.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/layout/param_seek.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/menu/add_menu.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/menu/toolbar_menu.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/values/colors.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/values/strings.xml delete mode 100644 src/libs/oboe/apps/fxlab/app/src/main/res/values/styles.xml delete mode 100644 src/libs/oboe/apps/fxlab/build.gradle delete mode 100644 src/libs/oboe/apps/fxlab/docs/Dev-Guide.md delete mode 100644 src/libs/oboe/apps/fxlab/docs/Presentation.pdf delete mode 100644 src/libs/oboe/apps/fxlab/docs/README.md delete mode 100644 src/libs/oboe/apps/fxlab/gradle.properties delete mode 100644 src/libs/oboe/apps/fxlab/gradle/wrapper/gradle-wrapper.jar delete mode 100644 src/libs/oboe/apps/fxlab/gradle/wrapper/gradle-wrapper.properties delete mode 100755 src/libs/oboe/apps/fxlab/gradlew delete mode 100644 src/libs/oboe/apps/fxlab/gradlew.bat delete mode 100644 src/libs/oboe/apps/fxlab/screenshot.png delete mode 100644 src/libs/oboe/apps/fxlab/settings.gradle delete mode 100644 src/libs/oboe/docs/.nojekyll delete mode 100644 src/libs/oboe/docs/AppsUsingOboe.md delete mode 100644 src/libs/oboe/docs/ChangeLog.md create mode 100644 src/libs/oboe/docs/PrivacyPolicy.md delete mode 100644 src/libs/oboe/docs/index.html delete mode 100644 src/libs/oboe/docs/notes/README.md delete mode 100644 src/libs/oboe/docs/notes/disconnect.md delete mode 100644 src/libs/oboe/docs/notes/effects.md delete mode 100644 src/libs/oboe/docs/notes/rlsbuffer.md delete mode 100644 src/libs/oboe/docs/reference/_audio_stream_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_audio_stream_base_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_audio_stream_builder_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_audio_stream_callback_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_definitions_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_latency_tuner_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_oboe_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_result_with_value_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_stabilized_callback_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_utilities_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/_version_8h_source.html delete mode 100644 src/libs/oboe/docs/reference/annotated.html delete mode 100644 src/libs/oboe/docs/reference/bc_s.png delete mode 100644 src/libs/oboe/docs/reference/bdwn.png delete mode 100644 src/libs/oboe/docs/reference/classes.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream.png delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_base-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_base.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_base.png delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_builder-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_builder.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_builder.png delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_callback-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_callback.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_callback.png delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_data_callback-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_data_callback.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_data_callback.png delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_error_callback-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_error_callback.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_audio_stream_error_callback.png delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_default_stream_values-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_default_stream_values.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_latency_tuner-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_latency_tuner.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_oboe_globals-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_oboe_globals.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_result_with_value-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_result_with_value.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_stabilized_callback-members.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_stabilized_callback.html delete mode 100644 src/libs/oboe/docs/reference/classoboe_1_1_stabilized_callback.png delete mode 100644 src/libs/oboe/docs/reference/closed.png delete mode 100644 src/libs/oboe/docs/reference/deprecated.html delete mode 100644 src/libs/oboe/docs/reference/dir_768f6301d9838e45d679001914ab2803.html delete mode 100644 src/libs/oboe/docs/reference/dir_d44c64559bbebec7f509842c48db8b23.html delete mode 100644 src/libs/oboe/docs/reference/doc.png delete mode 100644 src/libs/oboe/docs/reference/doxygen.css delete mode 100644 src/libs/oboe/docs/reference/doxygen.png delete mode 100644 src/libs/oboe/docs/reference/dynsections.js delete mode 100644 src/libs/oboe/docs/reference/files.html delete mode 100644 src/libs/oboe/docs/reference/folderclosed.png delete mode 100644 src/libs/oboe/docs/reference/folderopen.png delete mode 100644 src/libs/oboe/docs/reference/functions.html delete mode 100644 src/libs/oboe/docs/reference/functions_func.html delete mode 100644 src/libs/oboe/docs/reference/functions_vars.html delete mode 100644 src/libs/oboe/docs/reference/hierarchy.html delete mode 100644 src/libs/oboe/docs/reference/index.html delete mode 100644 src/libs/oboe/docs/reference/jquery.js delete mode 100644 src/libs/oboe/docs/reference/menu.js delete mode 100644 src/libs/oboe/docs/reference/menudata.js delete mode 100644 src/libs/oboe/docs/reference/namespacemembers.html delete mode 100644 src/libs/oboe/docs/reference/namespacemembers_enum.html delete mode 100644 src/libs/oboe/docs/reference/namespacemembers_eval.html delete mode 100644 src/libs/oboe/docs/reference/namespacemembers_func.html delete mode 100644 src/libs/oboe/docs/reference/namespacemembers_vars.html delete mode 100644 src/libs/oboe/docs/reference/namespaceoboe.html delete mode 100644 src/libs/oboe/docs/reference/namespaces.html delete mode 100644 src/libs/oboe/docs/reference/nav_f.png delete mode 100644 src/libs/oboe/docs/reference/nav_g.png delete mode 100644 src/libs/oboe/docs/reference/nav_h.png delete mode 100644 src/libs/oboe/docs/reference/open.png delete mode 100644 src/libs/oboe/docs/reference/pages.html delete mode 100644 src/libs/oboe/docs/reference/search/all_0.html delete mode 100644 src/libs/oboe/docs/reference/search/all_0.js delete mode 100644 src/libs/oboe/docs/reference/search/all_1.html delete mode 100644 src/libs/oboe/docs/reference/search/all_1.js delete mode 100644 src/libs/oboe/docs/reference/search/all_10.html delete mode 100644 src/libs/oboe/docs/reference/search/all_10.js delete mode 100644 src/libs/oboe/docs/reference/search/all_11.html delete mode 100644 src/libs/oboe/docs/reference/search/all_11.js delete mode 100644 src/libs/oboe/docs/reference/search/all_12.html delete mode 100644 src/libs/oboe/docs/reference/search/all_12.js delete mode 100644 src/libs/oboe/docs/reference/search/all_13.html delete mode 100644 src/libs/oboe/docs/reference/search/all_13.js delete mode 100644 src/libs/oboe/docs/reference/search/all_2.html delete mode 100644 src/libs/oboe/docs/reference/search/all_2.js delete mode 100644 src/libs/oboe/docs/reference/search/all_3.html delete mode 100644 src/libs/oboe/docs/reference/search/all_3.js delete mode 100644 src/libs/oboe/docs/reference/search/all_4.html delete mode 100644 src/libs/oboe/docs/reference/search/all_4.js delete mode 100644 src/libs/oboe/docs/reference/search/all_5.html delete mode 100644 src/libs/oboe/docs/reference/search/all_5.js delete mode 100644 src/libs/oboe/docs/reference/search/all_6.html delete mode 100644 src/libs/oboe/docs/reference/search/all_6.js delete mode 100644 src/libs/oboe/docs/reference/search/all_7.html delete mode 100644 src/libs/oboe/docs/reference/search/all_7.js delete mode 100644 src/libs/oboe/docs/reference/search/all_8.html delete mode 100644 src/libs/oboe/docs/reference/search/all_8.js delete mode 100644 src/libs/oboe/docs/reference/search/all_9.html delete mode 100644 src/libs/oboe/docs/reference/search/all_9.js delete mode 100644 src/libs/oboe/docs/reference/search/all_a.html delete mode 100644 src/libs/oboe/docs/reference/search/all_a.js delete mode 100644 src/libs/oboe/docs/reference/search/all_b.html delete mode 100644 src/libs/oboe/docs/reference/search/all_b.js delete mode 100644 src/libs/oboe/docs/reference/search/all_c.html delete mode 100644 src/libs/oboe/docs/reference/search/all_c.js delete mode 100644 src/libs/oboe/docs/reference/search/all_d.html delete mode 100644 src/libs/oboe/docs/reference/search/all_d.js delete mode 100644 src/libs/oboe/docs/reference/search/all_e.html delete mode 100644 src/libs/oboe/docs/reference/search/all_e.js delete mode 100644 src/libs/oboe/docs/reference/search/all_f.html delete mode 100644 src/libs/oboe/docs/reference/search/all_f.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_0.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_0.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_1.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_1.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_2.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_2.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_3.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_3.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_4.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_4.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_5.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_5.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_6.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_6.js delete mode 100644 src/libs/oboe/docs/reference/search/classes_7.html delete mode 100644 src/libs/oboe/docs/reference/search/classes_7.js delete mode 100644 src/libs/oboe/docs/reference/search/close.png delete mode 100644 src/libs/oboe/docs/reference/search/enums_0.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_0.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_1.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_1.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_2.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_2.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_3.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_3.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_4.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_4.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_5.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_5.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_6.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_6.js delete mode 100644 src/libs/oboe/docs/reference/search/enums_7.html delete mode 100644 src/libs/oboe/docs/reference/search/enums_7.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_0.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_0.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_1.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_1.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_2.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_2.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_3.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_3.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_4.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_4.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_5.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_5.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_6.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_6.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_7.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_7.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_8.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_8.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_9.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_9.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_a.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_a.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_b.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_b.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_c.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_c.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_d.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_d.js delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_e.html delete mode 100644 src/libs/oboe/docs/reference/search/enumvalues_e.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_0.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_0.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_1.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_1.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_2.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_2.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_3.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_3.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_4.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_4.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_5.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_5.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_6.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_6.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_7.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_7.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_8.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_8.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_9.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_9.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_a.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_a.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_b.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_b.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_c.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_c.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_d.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_d.js delete mode 100644 src/libs/oboe/docs/reference/search/functions_e.html delete mode 100644 src/libs/oboe/docs/reference/search/functions_e.js delete mode 100644 src/libs/oboe/docs/reference/search/mag_sel.png delete mode 100644 src/libs/oboe/docs/reference/search/namespaces_0.html delete mode 100644 src/libs/oboe/docs/reference/search/namespaces_0.js delete mode 100644 src/libs/oboe/docs/reference/search/nomatches.html delete mode 100644 src/libs/oboe/docs/reference/search/pages_0.html delete mode 100644 src/libs/oboe/docs/reference/search/pages_0.js delete mode 100644 src/libs/oboe/docs/reference/search/pages_1.html delete mode 100644 src/libs/oboe/docs/reference/search/pages_1.js delete mode 100644 src/libs/oboe/docs/reference/search/search.css delete mode 100644 src/libs/oboe/docs/reference/search/search.js delete mode 100644 src/libs/oboe/docs/reference/search/search_l.png delete mode 100644 src/libs/oboe/docs/reference/search/search_m.png delete mode 100644 src/libs/oboe/docs/reference/search/search_r.png delete mode 100644 src/libs/oboe/docs/reference/search/searchdata.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_0.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_0.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_1.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_1.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_2.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_2.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_3.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_3.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_4.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_4.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_5.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_5.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_6.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_6.js delete mode 100644 src/libs/oboe/docs/reference/search/variables_7.html delete mode 100644 src/libs/oboe/docs/reference/search/variables_7.js delete mode 100644 src/libs/oboe/docs/reference/splitbar.png delete mode 100644 src/libs/oboe/docs/reference/structoboe_1_1_frame_timestamp-members.html delete mode 100644 src/libs/oboe/docs/reference/structoboe_1_1_frame_timestamp.html delete mode 100644 src/libs/oboe/docs/reference/structoboe_1_1_stream_deleter_functor-members.html delete mode 100644 src/libs/oboe/docs/reference/structoboe_1_1_stream_deleter_functor.html delete mode 100644 src/libs/oboe/docs/reference/structoboe_1_1_version-members.html delete mode 100644 src/libs/oboe/docs/reference/structoboe_1_1_version.html delete mode 100644 src/libs/oboe/docs/reference/sync_off.png delete mode 100644 src/libs/oboe/docs/reference/sync_on.png delete mode 100644 src/libs/oboe/docs/reference/tab_a.png delete mode 100644 src/libs/oboe/docs/reference/tab_b.png delete mode 100644 src/libs/oboe/docs/reference/tab_h.png delete mode 100644 src/libs/oboe/docs/reference/tab_s.png delete mode 100644 src/libs/oboe/docs/reference/tabs.css rename src/libs/oboe/{src/common => include/oboe}/AudioClock.h (95%) rename src/libs/oboe/{src/fifo => include/oboe}/FifoBuffer.h (63%) rename src/libs/oboe/{src/fifo => include/oboe}/FifoControllerBase.h (74%) create mode 100644 src/libs/oboe/include/oboe/FullDuplexStream.h create mode 100644 src/libs/oboe/include/oboe/OboeExtensions.h delete mode 100644 src/libs/oboe/samples/LiveEffect/src/main/cpp/FullDuplexStream.cpp delete mode 100644 src/libs/oboe/samples/LiveEffect/src/main/cpp/FullDuplexStream.h create mode 100644 src/libs/oboe/samples/LiveEffect/src/main/java/com/google/oboe/samples/liveEffect/DuplexStreamForegroundService.java delete mode 100644 src/libs/oboe/samples/LiveEffect/src/main/res/drawable/balance_seekbar.xml delete mode 100644 src/libs/oboe/samples/LiveEffect/src/main/res/layout-v21/activity_main.xml delete mode 100644 src/libs/oboe/samples/LiveEffect/src/main/res/values-v21/styles.xml create mode 100644 src/libs/oboe/samples/SoundBoard/README.md create mode 100644 src/libs/oboe/samples/SoundBoard/build.gradle rename src/libs/oboe/{apps/fxlab/app => samples/SoundBoard}/proguard-rules.pro (100%) create mode 100644 src/libs/oboe/samples/SoundBoard/soundboard_image.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/AndroidManifest.xml create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/cpp/CMakeLists.txt create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/cpp/SoundBoardEngine.cpp create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/cpp/SoundBoardEngine.h create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/cpp/Synth.h create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/cpp/native-lib.cpp create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/ic_launcher-playstore.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MainActivity.kt create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt rename src/libs/oboe/{apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SineVoice.java => samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/NoteListener.kt} (52%) create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/drawable-v24/ic_launcher_foreground.xml rename src/libs/oboe/{apps/OboeTester/app => samples/SoundBoard}/src/main/res/drawable/ic_launcher_background.xml (100%) create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/layout/activity_main.xml create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/values/colors.xml create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/values/strings.xml create mode 100644 src/libs/oboe/samples/SoundBoard/src/main/res/values/styles.xml create mode 100644 src/libs/oboe/samples/drumthumper/drumthumper-screenshot.png rename src/libs/oboe/samples/drumthumper/src/main/{java => kotlin}/com/plausibleaudio/drumthumper/DrumPlayer.kt (64%) rename src/libs/oboe/samples/drumthumper/src/main/{java => kotlin}/com/plausibleaudio/drumthumper/DrumThumperActivity.kt (75%) rename src/libs/oboe/samples/drumthumper/src/main/{java => kotlin}/com/plausibleaudio/drumthumper/TriggerPad.kt (99%) create mode 100644 src/libs/oboe/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/BackgroundRunner.java delete mode 100644 src/libs/oboe/samples/hello-oboe/src/main/res/values-v21/styles.xml create mode 100644 src/libs/oboe/samples/hello-oboe/src/main/res/values/colors.xml rename src/libs/oboe/{apps/fxlab/app => samples/minimaloboe}/.gitignore (100%) create mode 100644 src/libs/oboe/samples/minimaloboe/README.md create mode 100644 src/libs/oboe/samples/minimaloboe/build.gradle create mode 100644 src/libs/oboe/samples/minimaloboe/minimaloboe-screenshot.png create mode 100644 src/libs/oboe/samples/minimaloboe/proguard-rules.pro create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/AndroidManifest.xml create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/cpp/CMakeLists.txt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/cpp/MinimalOboeJNI.cpp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.cpp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/cpp/SimpleNoiseMaker.h create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/kotlin/com/example/minimaloboe/AudioPlayer.kt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/kotlin/com/example/minimaloboe/MainActivity.kt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/kotlin/com/example/minimaloboe/ui/theme/Color.kt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/kotlin/com/example/minimaloboe/ui/theme/Shape.kt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/kotlin/com/example/minimaloboe/ui/theme/Theme.kt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/kotlin/com/example/minimaloboe/ui/theme/Type.kt create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/drawable/ic_launcher_background.xml rename src/libs/oboe/{apps/OboeTester/app => samples/minimaloboe}/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (88%) rename src/libs/oboe/{apps/OboeTester/app => samples/minimaloboe}/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (88%) create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/values/colors.xml create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/values/strings.xml create mode 100644 src/libs/oboe/samples/minimaloboe/src/main/res/values/themes.xml create mode 100644 src/libs/oboe/samples/powerplay/.gitignore create mode 100644 src/libs/oboe/samples/powerplay/README.md create mode 100644 src/libs/oboe/samples/powerplay/build.gradle create mode 100644 src/libs/oboe/samples/powerplay/proguard-rules.pro create mode 100644 src/libs/oboe/samples/powerplay/src/main/AndroidManifest.xml create mode 100644 src/libs/oboe/samples/powerplay/src/main/assets/song1.wav create mode 100644 src/libs/oboe/samples/powerplay/src/main/cpp/CMakeLists.txt create mode 100644 src/libs/oboe/samples/powerplay/src/main/cpp/PowerPlayJNI.cpp create mode 100644 src/libs/oboe/samples/powerplay/src/main/cpp/PowerPlayMultiPlayer.cpp create mode 100644 src/libs/oboe/samples/powerplay/src/main/cpp/PowerPlayMultiPlayer.h create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/MainActivity.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/engine/AudioForegroundService.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/engine/OboePerformanceMode.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/engine/PowerPlayAudioPlayer.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/ui/theme/Color.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/ui/theme/Shape.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/ui/theme/Theme.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/kotlin/com/google/oboe/samples/powerplay/ui/theme/Type.kt create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/drawable/album_art_1.jpeg create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/drawable/ic_launcher_background.xml create mode 100755 src/libs/oboe/samples/powerplay/src/main/res/drawable/ic_next.png create mode 100755 src/libs/oboe/samples/powerplay/src/main/res/drawable/ic_pause.png create mode 100755 src/libs/oboe/samples/powerplay/src/main/res/drawable/ic_play.png create mode 100755 src/libs/oboe/samples/powerplay/src/main/res/drawable/ic_previous.png create mode 100755 src/libs/oboe/samples/powerplay/src/main/res/drawable/vinyl_background.png create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/values/colors.xml create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/values/strings.xml create mode 100644 src/libs/oboe/samples/powerplay/src/main/res/values/themes.xml create mode 100644 src/libs/oboe/samples/shared/SynthSound.h create mode 100644 src/libs/oboe/src/common/AdpfWrapper.cpp create mode 100644 src/libs/oboe/src/common/AdpfWrapper.h create mode 100644 src/libs/oboe/src/common/OboeExtensions.cpp create mode 100644 src/libs/oboe/src/flowgraph/Limiter.cpp create mode 100644 src/libs/oboe/src/flowgraph/Limiter.h create mode 100644 src/libs/oboe/src/flowgraph/MonoBlend.cpp rename src/libs/oboe/{apps/OboeTester/app/src/main/cpp/flowunits/ImpulseOscillator.h => src/flowgraph/MonoBlend.h} (52%) create mode 100644 src/libs/oboe/src/flowgraph/MultiToManyConverter.cpp create mode 100644 src/libs/oboe/src/flowgraph/MultiToManyConverter.h create mode 100644 src/libs/oboe/src/flowgraph/SinkI8_24.cpp create mode 100644 src/libs/oboe/src/flowgraph/SinkI8_24.h create mode 100644 src/libs/oboe/src/flowgraph/SourceI8_24.cpp rename src/libs/oboe/{apps/OboeTester/app/src/main/cpp/flowunits/SawtoothOscillator.h => src/flowgraph/SourceI8_24.h} (52%) rename src/libs/oboe/{apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioInputStream.java => src/flowgraph/resampler/ResamplerDefinitions.h} (57%) delete mode 100644 src/libs/oboe/tests/README create mode 100644 src/libs/oboe/tests/UnitTestRunner/app/src/main/.gitignore create mode 100644 src/libs/oboe/tests/testAudioClock.cpp create mode 100644 src/libs/oboe/tests/testFullDuplexStream.cpp create mode 100644 src/libs/oboe/tests/testResampler.cpp create mode 100644 src/libs/oboe/tests/testReturnStopDeadlock.cpp create mode 100644 src/libs/oboe/tests/testStreamStop.cpp diff --git a/src/libs/oboe/CMakeLists.txt b/src/libs/oboe/CMakeLists.txt index e1da0521..de9cd404 100644 --- a/src/libs/oboe/CMakeLists.txt +++ b/src/libs/oboe/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.22.1) # Set the name of the project and store it in PROJECT_NAME. Also set the following variables: # PROJECT_SOURCE_DIR (usually the root directory where Oboe has been cloned e.g.) @@ -9,49 +9,20 @@ project(oboe) set (oboe_sources src/aaudio/AAudioLoader.cpp src/aaudio/AudioStreamAAudio.cpp - src/common/AudioSourceCaller.cpp + src/common/AdpfWrapper.cpp src/common/AudioStream.cpp src/common/AudioStreamBuilder.cpp - src/common/DataConversionFlowGraph.cpp - src/common/FilterAudioStream.cpp src/common/FixedBlockAdapter.cpp src/common/FixedBlockReader.cpp src/common/FixedBlockWriter.cpp src/common/LatencyTuner.cpp - src/common/SourceFloatCaller.cpp - src/common/SourceI16Caller.cpp - src/common/SourceI24Caller.cpp - src/common/SourceI32Caller.cpp + src/common/OboeExtensions.cpp src/common/Utilities.cpp src/common/QuirksManager.cpp src/fifo/FifoBuffer.cpp src/fifo/FifoController.cpp src/fifo/FifoControllerBase.cpp src/fifo/FifoControllerIndirect.cpp - src/flowgraph/FlowGraphNode.cpp - src/flowgraph/ChannelCountConverter.cpp - src/flowgraph/ClipToRange.cpp - src/flowgraph/ManyToMultiConverter.cpp - src/flowgraph/MonoToMultiConverter.cpp - src/flowgraph/MultiToMonoConverter.cpp - src/flowgraph/RampLinear.cpp - src/flowgraph/SampleRateConverter.cpp - src/flowgraph/SinkFloat.cpp - src/flowgraph/SinkI16.cpp - src/flowgraph/SinkI24.cpp - src/flowgraph/SinkI32.cpp - src/flowgraph/SourceFloat.cpp - src/flowgraph/SourceI16.cpp - src/flowgraph/SourceI24.cpp - src/flowgraph/SourceI32.cpp - src/flowgraph/resampler/IntegerRatio.cpp - src/flowgraph/resampler/LinearResampler.cpp - src/flowgraph/resampler/MultiChannelResampler.cpp - src/flowgraph/resampler/PolyphaseResampler.cpp - src/flowgraph/resampler/PolyphaseResamplerMono.cpp - src/flowgraph/resampler/PolyphaseResamplerStereo.cpp - src/flowgraph/resampler/SincResampler.cpp - src/flowgraph/resampler/SincResamplerStereo.cpp src/opensles/AudioInputStreamOpenSLES.cpp src/opensles/AudioOutputStreamOpenSLES.cpp src/opensles/AudioStreamBuffered.cpp @@ -64,6 +35,55 @@ set (oboe_sources src/common/Version.cpp ) +set (data_conversion_sources + src/common/AudioSourceCaller.cpp + src/common/DataConversionFlowGraph.cpp + src/common/FilterAudioStream.cpp + src/common/SourceFloatCaller.cpp + src/common/SourceI16Caller.cpp + src/common/SourceI24Caller.cpp + src/common/SourceI32Caller.cpp + src/flowgraph/FlowGraphNode.cpp + src/flowgraph/ChannelCountConverter.cpp + src/flowgraph/ClipToRange.cpp + src/flowgraph/Limiter.cpp + src/flowgraph/ManyToMultiConverter.cpp + src/flowgraph/MonoBlend.cpp + src/flowgraph/MonoToMultiConverter.cpp + src/flowgraph/MultiToManyConverter.cpp + src/flowgraph/MultiToMonoConverter.cpp + src/flowgraph/RampLinear.cpp + src/flowgraph/SampleRateConverter.cpp + src/flowgraph/SinkFloat.cpp + src/flowgraph/SinkI16.cpp + src/flowgraph/SinkI24.cpp + src/flowgraph/SinkI32.cpp + src/flowgraph/SinkI8_24.cpp + src/flowgraph/SourceFloat.cpp + src/flowgraph/SourceI16.cpp + src/flowgraph/SourceI24.cpp + src/flowgraph/SourceI32.cpp + src/flowgraph/SourceI8_24.cpp + src/flowgraph/resampler/IntegerRatio.cpp + src/flowgraph/resampler/LinearResampler.cpp + src/flowgraph/resampler/MultiChannelResampler.cpp + src/flowgraph/resampler/PolyphaseResampler.cpp + src/flowgraph/resampler/PolyphaseResamplerMono.cpp + src/flowgraph/resampler/PolyphaseResamplerStereo.cpp + src/flowgraph/resampler/SincResampler.cpp + src/flowgraph/resampler/SincResamplerStereo.cpp +) + +# Option to disable data conversion features. Default is OFF (i.e., conversion is ON). +option(OBOE_DISABLE_CONVERSION "Exclude data conversion source files and features" OFF) + +if(OBOE_DISABLE_CONVERSION) + message(STATUS "Oboe: Data conversion is DISABLED.") +else() + message(STATUS "Oboe: Data conversion is ENABLED.") + list(APPEND oboe_sources ${data_conversion_sources}) +endif() + add_library(oboe ${oboe_sources}) # Specify directories which the compiler should look for headers @@ -81,13 +101,20 @@ target_compile_options(oboe -Wextra-semi -Wshadow -Wshadow-field - -Ofast + "$<$:-Ofast>" + "$<$:-O3>" "$<$:-Werror>") +target_compile_definitions(oboe PRIVATE $<$:DISABLE_CONVERSION=1>) + # Enable logging of D,V for debug builds target_compile_definitions(oboe PUBLIC $<$:OBOE_ENABLE_LOGGING=1>) +option(OBOE_DO_NOT_DEFINE_OPENSL_ES_CONSTANTS "Do not define OpenSLES constants" OFF) +target_compile_definitions(oboe PRIVATE $<$:DO_NOT_DEFINE_OPENSL_ES_CONSTANTS=1>) + target_link_libraries(oboe PRIVATE log OpenSLES) +target_link_options(oboe PRIVATE "-Wl,-z,max-page-size=16384") # When installing oboe put the libraries in the lib/ folder e.g. lib/arm64-v8a install(TARGETS oboe @@ -95,4 +122,4 @@ install(TARGETS oboe ARCHIVE DESTINATION lib/${ANDROID_ABI}) # Also install the headers -install(DIRECTORY include/oboe DESTINATION include) \ No newline at end of file +install(DIRECTORY include/oboe DESTINATION include) diff --git a/src/libs/oboe/Doxyfile b/src/libs/oboe/Doxyfile index f0e0be32..6b87a122 100644 --- a/src/libs/oboe/Doxyfile +++ b/src/libs/oboe/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Oboe" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.5 +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = docs +OUTPUT_DIRECTORY = ./docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and diff --git a/src/libs/oboe/README.md b/src/libs/oboe/README.md index 53b99e6a..37713380 100644 --- a/src/libs/oboe/README.md +++ b/src/libs/oboe/README.md @@ -15,11 +15,11 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps o ## Documentation - [Getting Started Guide](docs/GettingStarted.md) - [Full Guide to Oboe](docs/FullGuide.md) -- [API reference](https://google.github.io/oboe/reference) -- [Tech Notes](docs/notes/) +- [API reference](https://google.github.io/oboe) - [History of Audio features/bugs by Android version](docs/AndroidAudioHistory.md) - [Migration guide for apps using OpenSL ES](docs/OpenSLESMigration.md) - [Frequently Asked Questions](docs/FAQ.md) (FAQ) +- [Wiki](https://github.com/google/oboe/wiki) - [Our roadmap](https://github.com/google/oboe/milestones) - Vote on a feature/issue by adding a thumbs up to the first comment. ### Community @@ -27,8 +27,8 @@ Oboe is a C++ library which makes it easy to build high-performance audio apps o - StackOverflow: [#oboe](https://stackoverflow.com/questions/tagged/oboe) ## Testing -- [**OboeTester** app for measuring latency, glitches, etc.](https://github.com/google/oboe/tree/master/apps/OboeTester/docs) -- [Oboe unit tests](https://github.com/google/oboe/tree/master/tests) +- [**OboeTester** app for measuring latency, glitches, etc.](apps/OboeTester/docs) +- [Oboe unit tests](tests) ## Videos - [Getting started with Oboe](https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_duWv9IPNvx9YBudNMmLSa) diff --git a/src/libs/oboe/apps/OboeTester/.gitignore b/src/libs/oboe/apps/OboeTester/.gitignore deleted file mode 100644 index 7112e857..00000000 --- a/src/libs/oboe/apps/OboeTester/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build/ -.idea/ -/app/build/ -/app/release/ -/app/debug/ -/app/app.iml -*.iml -/app/externalNativeBuild/ diff --git a/src/libs/oboe/apps/OboeTester/.google/packaging.yaml b/src/libs/oboe/apps/OboeTester/.google/packaging.yaml deleted file mode 100644 index 815374af..00000000 --- a/src/libs/oboe/apps/OboeTester/.google/packaging.yaml +++ /dev/null @@ -1,7 +0,0 @@ -status: PUBLISHED -technologies: [Android, NDK] -categories: [NDK, C++] -languages: [C++, Java] -solutions: [Mobile] -github: googlesamples/android-ndk -license: apache2 diff --git a/src/libs/oboe/apps/OboeTester/README.md b/src/libs/oboe/apps/OboeTester/README.md deleted file mode 100644 index ebcd1068..00000000 --- a/src/libs/oboe/apps/OboeTester/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Oboe Tester - -OboeTester is an app that can be used to test many of the features of Oboe, AAudio and OpenSL ES. -It can also be used to measure device latency and glitches. - -# [OboeTester Documentation](docs) diff --git a/src/libs/oboe/apps/OboeTester/app/CMakeLists.txt b/src/libs/oboe/apps/OboeTester/app/CMakeLists.txt deleted file mode 100644 index 39cda1c9..00000000 --- a/src/libs/oboe/apps/OboeTester/app/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -cmake_minimum_required(VERSION 3.4.1) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -std=c++14 -DOBOE_NO_INCLUDE_AAUDIO -fvisibility=hidden") -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O2") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") - -link_directories(${CMAKE_CURRENT_LIST_DIR}/..) - -file(GLOB_RECURSE app_native_sources src/main/cpp/*) - -### Name must match loadLibrary() call in MainActivity.java -add_library(oboetester SHARED ${app_native_sources}) - -### INCLUDE OBOE LIBRARY ### - -# Set the path to the Oboe library directory -set (OBOE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) - -# Add the Oboe library as a subproject. Since Oboe is an out-of-tree source library we must also -# specify a binary directory -add_subdirectory(${OBOE_DIR} ./oboe-bin) - -# Specify the path to the Oboe header files and the source. -include_directories( - ${OBOE_DIR}/include - ${OBOE_DIR}/src -) - -### END OBOE INCLUDE SECTION ### - -# link to oboe -target_link_libraries(oboetester log oboe atomic) - -# bump 4 to resync CMake diff --git a/src/libs/oboe/apps/OboeTester/app/build.gradle b/src/libs/oboe/apps/OboeTester/app/build.gradle deleted file mode 100644 index 114827fc..00000000 --- a/src/libs/oboe/apps/OboeTester/app/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion 29 - defaultConfig { - applicationId = "com.mobileer.oboetester" - minSdkVersion 23 - targetSdkVersion 29 - // Also update the versions in the AndroidManifest.xml file. - versionCode 52 - versionName "2.1.2" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - externalNativeBuild { - cmake { - cppFlags "-std=c++14" - abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a" - } - } - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - debug { - jniDebuggable true - } - } - externalNativeBuild { - cmake { - path "CMakeLists.txt" - } - } -} - -dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support.constraint:constraint-layout:2.0.4' - - testImplementation 'junit:junit:4.13-beta-3' - implementation 'com.android.support:appcompat-v7:28.0.0' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' -} diff --git a/src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.jar b/src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index f6b961fd5a86aa5fbfe90f707c3138408be7c718..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54329 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

<5G2M1WZP5 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 F{|7XC?P&l2 diff --git a/src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.properties b/src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 7b8b3c06..00000000 --- a/src/libs/oboe/apps/OboeTester/app/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Thu Apr 11 16:29:30 PDT 2019 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip diff --git a/src/libs/oboe/apps/OboeTester/app/gradlew b/src/libs/oboe/apps/OboeTester/app/gradlew deleted file mode 100644 index cccdd3d5..00000000 --- a/src/libs/oboe/apps/OboeTester/app/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/src/libs/oboe/apps/OboeTester/app/gradlew.bat b/src/libs/oboe/apps/OboeTester/app/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/src/libs/oboe/apps/OboeTester/app/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/src/libs/oboe/apps/OboeTester/app/local.properties b/src/libs/oboe/apps/OboeTester/app/local.properties deleted file mode 100644 index 8a33ae0a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/local.properties +++ /dev/null @@ -1,9 +0,0 @@ -## This file must *NOT* be checked into Version Control Systems, -# as it contains information specific to your local configuration. -# -# Location of the SDK. This is only used by Gradle. -# For customization when using a Version Control System, please read the -# header note. -#Thu Apr 11 16:29:25 PDT 2019 -ndk.dir=/Users/philburk/Library/Android/sdk/ndk-bundle -sdk.dir=/Users/philburk/Library/Android/sdk diff --git a/src/libs/oboe/apps/OboeTester/app/proguard-rules.pro b/src/libs/oboe/apps/OboeTester/app/proguard-rules.pro deleted file mode 100644 index 7dc6c7fb..00000000 --- a/src/libs/oboe/apps/OboeTester/app/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /Users/gfan/dev/android-sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/AndroidManifest.xml b/src/libs/oboe/apps/OboeTester/app/src/main/AndroidManifest.xml deleted file mode 100644 index 3c9d1dd0..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp deleted file mode 100644 index c4735405..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 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. - */ - -#include -#include - -#include "common/OboeDebug.h" -#include "oboe/Oboe.h" -#include "AudioStreamGateway.h" - -using namespace oboe::flowgraph; - -oboe::DataCallbackResult AudioStreamGateway::onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) { - - printScheduler(); - - if (mAudioSink != nullptr) { - mAudioSink->read(audioData, numFrames); - } - - return oboe::DataCallbackResult::Continue; -} - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h deleted file mode 100644 index 0aaf429a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016 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 NATIVEOBOE_AUDIOGRAPHRUNNER_H -#define NATIVEOBOE_AUDIOGRAPHRUNNER_H - -#include -#include - -#include "flowgraph/FlowGraphNode.h" -#include "oboe/Oboe.h" -#include "OboeTesterStreamCallback.h" - -using namespace oboe::flowgraph; - -/** - * Bridge between an audio flowgraph and an audio device. - * Pass in an AudioSink and then pass - * this object to the AudioStreamBuilder as a callback. - */ -class AudioStreamGateway : public OboeTesterStreamCallback { -public: - virtual ~AudioStreamGateway() = default; - - void setAudioSink(std::shared_ptr sink) { - mAudioSink = sink; - } - - /** - * Called by Oboe when the stream is ready to process audio. - */ - oboe::DataCallbackResult onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) override; - -private: - - std::shared_ptr mAudioSink; -}; - - -#endif //NATIVEOBOE_AUDIOGRAPHRUNNER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp deleted file mode 100644 index dd9f324f..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2021 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. - */ - -#include "FormatConverterBox.h" - -FormatConverterBox::FormatConverterBox(int32_t numSamples, - oboe::AudioFormat inputFormat, - oboe::AudioFormat outputFormat) { - mInputFormat = inputFormat; - mOutputFormat = outputFormat; - - mInputBuffer = std::make_unique(numSamples * sizeof(int32_t)); - mOutputBuffer = std::make_unique(numSamples * sizeof(int32_t)); - - mSource.reset(); - switch (mInputFormat) { - case oboe::AudioFormat::I16: - mSource = std::make_unique(1); - break; - case oboe::AudioFormat::I24: - mSource = std::make_unique(1); - break; - case oboe::AudioFormat::I32: - mSource = std::make_unique(1); - break; - case oboe::AudioFormat::Float: - case oboe::AudioFormat::Invalid: - case oboe::AudioFormat::Unspecified: - mSource = std::make_unique(1); - break; - } - - mSink.reset(); - switch (mOutputFormat) { - case oboe::AudioFormat::I16: - mSink = std::make_unique(1); - break; - case oboe::AudioFormat::I24: - mSink = std::make_unique(1); - break; - case oboe::AudioFormat::I32: - mSink = std::make_unique(1); - break; - case oboe::AudioFormat::Float: - case oboe::AudioFormat::Invalid: - case oboe::AudioFormat::Unspecified: - mSink = std::make_unique(1); - break; - } - - if (mSource && mSink) { - mSource->output.connect(&mSink->input); - mSink->pullReset(); - } -} - -int32_t FormatConverterBox::convertInternalBuffers(int32_t numSamples) { - return convert(getOutputBuffer(), numSamples, getInputBuffer()); -} - -int32_t FormatConverterBox::convertToInternalOutput(int32_t numSamples, const void *inputBuffer) { - return convert(getOutputBuffer(), numSamples, inputBuffer); -} - -int32_t FormatConverterBox::convertFromInternalInput(void *outputBuffer, int32_t numSamples) { - return convert(outputBuffer, numSamples, getInputBuffer()); -} - -int32_t FormatConverterBox::convert(void *outputBuffer, int32_t numSamples, const void *inputBuffer) { - mSource->setData(inputBuffer, numSamples); - return mSink->read(outputBuffer, numSamples); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h deleted file mode 100644 index 782f9e0c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FormatConverterBox.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2021 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_FORMAT_CONVERTER_BOX_H -#define OBOETESTER_FORMAT_CONVERTER_BOX_H - -#include -#include - -#include "oboe/Oboe.h" -#include "flowgraph/SinkFloat.h" -#include "flowgraph/SinkI16.h" -#include "flowgraph/SinkI24.h" -#include "flowgraph/SinkI32.h" -#include "flowgraph/SourceFloat.h" -#include "flowgraph/SourceI16.h" -#include "flowgraph/SourceI24.h" -#include "flowgraph/SourceI32.h" - -/** - * Use flowgraph modules to convert between the various data formats. - * - * Note that this does not do channel conversions. - */ - -class FormatConverterBox { -public: - FormatConverterBox(int32_t numSamples, - oboe::AudioFormat inputFormat, - oboe::AudioFormat outputFormat); - - /** - * @return internal buffer used to store input data - */ - void *getOutputBuffer() { - return (void *) mOutputBuffer.get(); - }; - /** - * @return internal buffer used to store output data - */ - void *getInputBuffer() { - return (void *) mInputBuffer.get(); - }; - - /** Convert the data from inputFormat to outputFormat - * using both internal buffers. - */ - int32_t convertInternalBuffers(int32_t numSamples); - - /** - * Convert data from external buffer into internal output buffer. - * @param numSamples - * @param inputBuffer - * @return - */ - int32_t convertToInternalOutput(int32_t numSamples, const void *inputBuffer); - - /** - * - * Convert data from internal input buffer into external output buffer. - * @param outputBuffer - * @param numSamples - * @return - */ - int32_t convertFromInternalInput(void *outputBuffer, int32_t numSamples); - - /** - * Convert data formats between the specified external buffers. - * @param outputBuffer - * @param numSamples - * @param inputBuffer - * @return - */ - int32_t convert(void *outputBuffer, int32_t numSamples, const void *inputBuffer); - -private: - oboe::AudioFormat mInputFormat{oboe::AudioFormat::Invalid}; - oboe::AudioFormat mOutputFormat{oboe::AudioFormat::Invalid}; - - std::unique_ptr mInputBuffer; - std::unique_ptr mOutputBuffer; - - std::unique_ptr mSource; - std::unique_ptr mSink; -}; - - -#endif //OBOETESTER_FORMAT_CONVERTER_BOX_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp deleted file mode 100644 index e56d09b1..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#include "common/OboeDebug.h" -#include "FullDuplexAnalyzer.h" - -oboe::Result FullDuplexAnalyzer::start() { - getLoopbackProcessor()->setSampleRate(getOutputStream()->getSampleRate()); - getLoopbackProcessor()->prepareToTest(); - return FullDuplexStream::start(); -} - -oboe::DataCallbackResult FullDuplexAnalyzer::onBothStreamsReady( - const float *inputData, - int numInputFrames, - float *outputData, - int numOutputFrames) { - - int32_t inputStride = getInputStream()->getChannelCount(); - int32_t outputStride = getOutputStream()->getChannelCount(); - const float *inputFloat = inputData; - float *outputFloat = outputData; - - (void) getLoopbackProcessor()->process(inputFloat, inputStride, numInputFrames, - outputFloat, outputStride, numOutputFrames); - - // write the first channel of output and input to the stereo recorder - if (mRecording != nullptr) { - float buffer[2]; - int numBoth = std::min(numInputFrames, numOutputFrames); - for (int i = 0; i < numBoth; i++) { - buffer[0] = *outputFloat; - outputFloat += outputStride; - buffer[1] = *inputFloat; - inputFloat += inputStride; - mRecording->write(buffer, 1); - } - // Handle mismatch in in numFrames. - buffer[0] = 0.0f; // gap in output - for (int i = numBoth; i < numInputFrames; i++) { - buffer[1] = *inputFloat; - inputFloat += inputStride; - mRecording->write(buffer, 1); - } - buffer[1] = 0.0f; // gap in input - for (int i = numBoth; i < numOutputFrames; i++) { - buffer[0] = *outputFloat; - outputFloat += outputStride; - mRecording->write(buffer, 1); - } - } - return oboe::DataCallbackResult::Continue; -}; diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h deleted file mode 100644 index 3182ef92..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexAnalyzer.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2019 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_FULL_DUPLEX_ANALYZER_H -#define OBOETESTER_FULL_DUPLEX_ANALYZER_H - -#include -#include - -#include "oboe/Oboe.h" -#include "FullDuplexStream.h" -#include "analyzer/LatencyAnalyzer.h" -#include "MultiChannelRecording.h" - -class FullDuplexAnalyzer : public FullDuplexStream { -public: - FullDuplexAnalyzer(LoopbackProcessor *processor) - : mLoopbackProcessor(processor) { - setMNumInputBurstsCushion(1); - } - - /** - * Called when data is available on both streams. - * Caller should override this method. - */ - oboe::DataCallbackResult onBothStreamsReady( - const float *inputData, - int numInputFrames, - float *outputData, - int numOutputFrames - ) override; - - oboe::Result start() override; - - LoopbackProcessor *getLoopbackProcessor() { - return mLoopbackProcessor; - } - - void setRecording(MultiChannelRecording *recording) { - mRecording = recording; - } - -private: - MultiChannelRecording *mRecording = nullptr; - - LoopbackProcessor * const mLoopbackProcessor; -}; - - -#endif //OBOETESTER_FULL_DUPLEX_ANALYZER_H - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp deleted file mode 100644 index e17c7514..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#include "common/OboeDebug.h" -#include "FullDuplexEcho.h" - -oboe::Result FullDuplexEcho::start() { - int32_t delayFrames = (int32_t) (kMaxDelayTimeSeconds * getOutputStream()->getSampleRate()); - mDelayLine = std::make_unique(delayFrames); - return FullDuplexStream::start(); -} - -oboe::DataCallbackResult FullDuplexEcho::onBothStreamsReady( - const float *inputData, - int numInputFrames, - float *outputData, - int numOutputFrames) { - int32_t framesToEcho = std::min(numInputFrames, numOutputFrames); - float *inputFloat = (float *)inputData; - float *outputFloat = (float *)outputData; - // zero out entire output array - memset(outputFloat, 0, numOutputFrames * getOutputStream()->getBytesPerFrame()); - - int32_t inputStride = getInputStream()->getChannelCount(); - int32_t outputStride = getOutputStream()->getChannelCount(); - float delayFrames = mDelayTimeSeconds * getOutputStream()->getSampleRate(); - while (framesToEcho-- > 0) { - *outputFloat = mDelayLine->process(delayFrames, *inputFloat); // mono delay - inputFloat += inputStride; - outputFloat += outputStride; - } - return oboe::DataCallbackResult::Continue; -}; diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h deleted file mode 100644 index cbb69d7e..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2019 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_FULL_DUPLEX_ECHO_H -#define OBOETESTER_FULL_DUPLEX_ECHO_H - -#include -#include - -#include "oboe/Oboe.h" -#include "FullDuplexStream.h" -#include "InterpolatingDelayLine.h" - -class FullDuplexEcho : public FullDuplexStream { -public: - FullDuplexEcho() { - setMNumInputBurstsCushion(0); - } - - /** - * Called when data is available on both streams. - * Caller should override this method. - */ - oboe::DataCallbackResult onBothStreamsReady( - const float *inputData, - int numInputFrames, - float *outputData, - int numOutputFrames - ) override; - - oboe::Result start() override; - - void setDelayTime(double delayTimeSeconds) { - mDelayTimeSeconds = delayTimeSeconds; - } - -private: - std::unique_ptr mDelayLine; - static constexpr double kMaxDelayTimeSeconds = 4.0; - double mDelayTimeSeconds = kMaxDelayTimeSeconds; -}; - - -#endif //OBOETESTER_FULL_DUPLEX_ECHO_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp deleted file mode 100644 index 52e762e6..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#include "common/OboeDebug.h" -#include "FullDuplexStream.h" - -oboe::ResultWithValue FullDuplexStream::readInput(int32_t numFrames) { - oboe::ResultWithValue result = getInputStream()->read( - mInputConverter->getInputBuffer(), - numFrames, - 0 /* timeout */); - if (result == oboe::Result::OK) { - int32_t numSamples = result.value() * getInputStream()->getChannelCount(); - mInputConverter->convertInternalBuffers(numSamples); - } - return result; -} - -oboe::DataCallbackResult FullDuplexStream::onAudioReady( - oboe::AudioStream *outputStream, - void *audioData, - int numFrames) { - oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Continue; - int32_t actualFramesRead = 0; - - // Silence the output. - int32_t numBytes = numFrames * outputStream->getBytesPerFrame(); - memset(audioData, 0 /* value */, numBytes); - - if (mCountCallbacksToDrain > 0) { - // Drain the input. - int32_t totalFramesRead = 0; - do { - oboe::ResultWithValue result = readInput(numFrames); - if (!result) { - // Ignore errors because input stream may not be started yet. - break; - } - actualFramesRead = result.value(); - totalFramesRead += actualFramesRead; - } while (actualFramesRead > 0); - // Only counts if we actually got some data. - if (totalFramesRead > 0) { - mCountCallbacksToDrain--; - } - - } else if (mCountInputBurstsCushion > 0) { - // Let the input fill up a bit so we are not so close to the write pointer. - mCountInputBurstsCushion--; - - } else if (mCountCallbacksToDiscard > 0) { - mCountCallbacksToDiscard--; - // Ignore. Allow the input to reach to equilibrium with the output. - oboe::ResultWithValue resultAvailable = getInputStream()->getAvailableFrames(); - if (!resultAvailable) { - LOGE("%s() getAvailableFrames() returned %s\n", - __func__, convertToText(resultAvailable.error())); - callbackResult = oboe::DataCallbackResult::Stop; - } else { - int32_t framesAvailable = resultAvailable.value(); - if (framesAvailable >= mMinimumFramesBeforeRead) { - oboe::ResultWithValue resultRead = readInput(numFrames); - if (!resultRead) { - LOGE("%s() read() returned %s\n", __func__, convertToText(resultRead.error())); - callbackResult = oboe::DataCallbackResult::Stop; - } - } - } - } else { - int32_t framesRead = 0; - oboe::ResultWithValue resultAvailable = getInputStream()->getAvailableFrames(); - if (!resultAvailable) { - LOGE("%s() getAvailableFrames() returned %s\n", __func__, convertToText(resultAvailable.error())); - callbackResult = oboe::DataCallbackResult::Stop; - } else { - int32_t framesAvailable = resultAvailable.value(); - if (framesAvailable >= mMinimumFramesBeforeRead) { - // Read data into input buffer. - oboe::ResultWithValue resultRead = readInput(numFrames); - if (!resultRead) { - LOGE("%s() read() returned %s\n", __func__, convertToText(resultRead.error())); - callbackResult = oboe::DataCallbackResult::Stop; - } else { - framesRead = resultRead.value(); - } - } - } - - if (callbackResult == oboe::DataCallbackResult::Continue) { - callbackResult = onBothStreamsReady( - (const float *) mInputConverter->getOutputBuffer(), - framesRead, - (float *) mOutputConverter->getInputBuffer(), numFrames); - mOutputConverter->convertFromInternalInput( audioData, - numFrames * getOutputStream()->getChannelCount()); - } - } - - if (callbackResult == oboe::DataCallbackResult::Stop) { - getInputStream()->requestStop(); - } - - return callbackResult; -} - -oboe::Result FullDuplexStream::start() { - mCountCallbacksToDrain = kNumCallbacksToDrain; - mCountInputBurstsCushion = mNumInputBurstsCushion; - mCountCallbacksToDiscard = kNumCallbacksToDiscard; - - // Determine maximum size that could possibly be called. - int32_t bufferSize = getOutputStream()->getBufferCapacityInFrames() - * getOutputStream()->getChannelCount(); - mInputConverter = std::make_unique(bufferSize, - getInputStream()->getFormat(), - oboe::AudioFormat::Float); - mOutputConverter = std::make_unique(bufferSize, - oboe::AudioFormat::Float, - getOutputStream()->getFormat()); - - oboe::Result result = getInputStream()->requestStart(); - if (result != oboe::Result::OK) { - return result; - } - return getOutputStream()->requestStart(); -} - -oboe::Result FullDuplexStream::stop() { - getOutputStream()->requestStop(); // TODO result? - return getInputStream()->requestStop(); -} - -int32_t FullDuplexStream::getMNumInputBurstsCushion() const { - return mNumInputBurstsCushion; -} - -void FullDuplexStream::setMNumInputBurstsCushion(int32_t numBursts) { - FullDuplexStream::mNumInputBurstsCushion = numBursts; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h deleted file mode 100644 index dcfb6ea4..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/FullDuplexStream.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2019 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_FULL_DUPLEX_STREAM_H -#define OBOETESTER_FULL_DUPLEX_STREAM_H - -#include -#include - -#include "oboe/Oboe.h" - -#include "FormatConverterBox.h" - -class FullDuplexStream : public oboe::AudioStreamCallback { -public: - FullDuplexStream() {} - virtual ~FullDuplexStream() = default; - - void setInputStream(oboe::AudioStream *stream) { - mInputStream = stream; - } - - oboe::AudioStream *getInputStream() { - return mInputStream; - } - - void setOutputStream(oboe::AudioStream *stream) { - mOutputStream = stream; - } - oboe::AudioStream *getOutputStream() { - return mOutputStream; - } - - virtual oboe::Result start(); - - virtual oboe::Result stop(); - - oboe::ResultWithValue readInput(int32_t numFrames); - - /** - * Called when data is available on both streams. - * Caller should override this method. - */ - virtual oboe::DataCallbackResult onBothStreamsReady( - const float *inputData, - int numInputFrames, - float *outputData, - int numOutputFrames - ) = 0; - - /** - * Called by Oboe when the stream is ready to process audio. - */ - oboe::DataCallbackResult onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) override; - - int32_t getMNumInputBurstsCushion() const; - - /** - * Number of bursts to leave in the input buffer as a cushion. - * Typically 0 for latency measurements - * or 1 for glitch tests. - * - * @param mNumInputBurstsCushion - */ - void setMNumInputBurstsCushion(int32_t mNumInputBurstsCushion); - - void setMinimumFramesBeforeRead(int32_t numFrames) { - mMinimumFramesBeforeRead = numFrames; - } - - int32_t getMinimumFramesBeforeRead() const { - return mMinimumFramesBeforeRead; - } - -private: - - // TODO add getters and setters - static constexpr int32_t kNumCallbacksToDrain = 20; - static constexpr int32_t kNumCallbacksToDiscard = 30; - - // let input fill back up, usually 0 or 1 - int32_t mNumInputBurstsCushion = 0; - int32_t mMinimumFramesBeforeRead = 0; - - // We want to reach a state where the input buffer is empty and - // the output buffer is full. - // These are used in order. - // Drain several callback so that input is empty. - int32_t mCountCallbacksToDrain = kNumCallbacksToDrain; - // Let the input fill back up slightly so we don't run dry. - int32_t mCountInputBurstsCushion = mNumInputBurstsCushion; - // Discard some callbacks so the input and output reach equilibrium. - int32_t mCountCallbacksToDiscard = kNumCallbacksToDiscard; - - oboe::AudioStream *mInputStream = nullptr; - oboe::AudioStream *mOutputStream = nullptr; - - std::unique_ptr mInputConverter; - std::unique_ptr mOutputConverter; -}; - - -#endif //OBOETESTER_FULL_DUPLEX_STREAM_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp deleted file mode 100644 index b16b4666..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2015 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. - */ - -#include "common/OboeDebug.h" -#include "InputStreamCallbackAnalyzer.h" - -oboe::DataCallbackResult InputStreamCallbackAnalyzer::onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) { - int32_t channelCount = audioStream->getChannelCount(); - printScheduler(); - mInputConverter->convertToInternalOutput(numFrames * channelCount, audioData); - float *floatData = (float *) mInputConverter->getOutputBuffer(); - if (mRecording != nullptr) { - mRecording->write(floatData, numFrames); - } - int32_t sampleIndex = 0; - for (int iFrame = 0; iFrame < numFrames; iFrame++) { - for (int iChannel = 0; iChannel < channelCount; iChannel++) { - float sample = floatData[sampleIndex++]; - mPeakDetectors[iChannel].process(sample); - } - } - - audioStream->waitForAvailableFrames(mMinimumFramesBeforeRead, oboe::kNanosPerSecond); - - return oboe::DataCallbackResult::Continue; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h deleted file mode 100644 index 7dda1d6c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2016 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 NATIVEOBOE_INPUTSTREAMCALLBACKANALYZER_H -#define NATIVEOBOE_INPUTSTREAMCALLBACKANALYZER_H - -#include -#include - -// TODO #include "flowgraph/FlowGraph.h" -#include "oboe/Oboe.h" - -#include "analyzer/PeakDetector.h" -#include "FormatConverterBox.h" -#include "MultiChannelRecording.h" -#include "OboeTesterStreamCallback.h" - -constexpr int kMaxInputChannels = 8; - -class InputStreamCallbackAnalyzer : public OboeTesterStreamCallback { -public: - - void reset() { - for (auto detector : mPeakDetectors) { - detector.reset(); - } - OboeTesterStreamCallback::reset(); - } - - void setup(int32_t maxFramesPerCallback, - int32_t channelCount, - oboe::AudioFormat inputFormat) { - int32_t bufferSize = maxFramesPerCallback * channelCount; - mInputConverter = std::make_unique(bufferSize, - inputFormat, - oboe::AudioFormat::Float); - } - - /** - * Called by Oboe when the stream is ready to process audio. - */ - oboe::DataCallbackResult onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) override; - - void setRecording(MultiChannelRecording *recording) { - mRecording = recording; - } - - double getPeakLevel(int index) { - return mPeakDetectors[index].getLevel(); - } - - void setMinimumFramesBeforeRead(int32_t numFrames) { - mMinimumFramesBeforeRead = numFrames; - } - - int32_t getMinimumFramesBeforeRead() { - return mMinimumFramesBeforeRead; - } - -public: - PeakDetector mPeakDetectors[kMaxInputChannels]; - MultiChannelRecording *mRecording = nullptr; - -private: - - std::unique_ptr mInputConverter; - int32_t mMinimumFramesBeforeRead = 0; -}; - -#endif //NATIVEOBOE_INPUTSTREAMCALLBACKANALYZER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.cpp deleted file mode 100644 index e69c7112..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#include "common/OboeDebug.h" -#include "InterpolatingDelayLine.h" - -InterpolatingDelayLine::InterpolatingDelayLine(int32_t delaySize) { - mDelaySize = delaySize; - mDelayLine = std::make_unique(delaySize); -} - -float InterpolatingDelayLine::process(float delay, float input) { - float *writeAddress = mDelayLine.get() + mCursor; - *writeAddress = input; - mDelayLine.get()[mCursor] = input; - int32_t delayInt = std::min(mDelaySize - 1, (int32_t) delay); - int32_t readIndex = mCursor - delayInt; - if (readIndex < 0) { - readIndex += mDelaySize; - } - // TODO interpolate - float *readAddress = mDelayLine.get() + readIndex; - float output = *readAddress; - mCursor++; - if (mCursor >= mDelaySize) { - mCursor = 0; - } - return output; -}; diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.h deleted file mode 100644 index b3a510da..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/InterpolatingDelayLine.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2019 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_INTERPOLATING_DELAY_LINE_H -#define OBOETESTER_INTERPOLATING_DELAY_LINE_H - -#include -#include -#include - -#include "oboe/Oboe.h" -#include "FullDuplexStream.h" - -/** - * Monophonic delay line. - */ -class InterpolatingDelayLine { -public: - explicit InterpolatingDelayLine(int32_t delaySize); - - /** - * @param input sample to be written to the delay line - * @param delay number of samples to delay the output - * @return delayed value - */ - float process(float delay, float input); - -private: - std::unique_ptr mDelayLine; - int32_t mCursor = 0; - int32_t mDelaySize = 0; -}; - - -#endif //OBOETESTER_INTERPOLATING_DELAY_LINE_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/MultiChannelRecording.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/MultiChannelRecording.h deleted file mode 100644 index eed37435..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/MultiChannelRecording.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2015 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 NATIVEOBOE_MULTICHANNEL_RECORDING_H -#define NATIVEOBOE_MULTICHANNEL_RECORDING_H - -#include -#include -#include - -/** - * Store multi-channel audio data in float format. - * The most recent data will be saved. - * Old data may be overwritten. - * - * Note that this is not thread safe. Do not read and write from separate threads. - */ -class MultiChannelRecording { -public: - MultiChannelRecording(int32_t channelCount, int32_t maxFrames) - : mChannelCount(channelCount) - , mMaxFrames(maxFrames) { - mData = new float[channelCount * maxFrames]; - } - - ~MultiChannelRecording() { - delete[] mData; - } - - void rewind() { - mReadCursorFrames = mWriteCursorFrames - getSizeInFrames(); - } - - void clear() { - mReadCursorFrames = 0; - mWriteCursorFrames = 0; - } - - int32_t getChannelCount() { - return mChannelCount; - } - - int32_t getSizeInFrames() { - return (int32_t) std::min(mWriteCursorFrames, static_cast(mMaxFrames)); - } - - int32_t getReadIndex() { - return mReadCursorFrames % mMaxFrames; - } - int32_t getWriteIndex() { - return mWriteCursorFrames % mMaxFrames; - } - - /** - * Write numFrames from the short buffer into the recording. - * Overwrite old data if necessary. - * Convert shorts to floats. - * - * @param buffer - * @param numFrames - * @return number of frames actually written. - */ - int32_t write(int16_t *buffer, int32_t numFrames) { - int32_t framesLeft = numFrames; - while (framesLeft > 0) { - int32_t indexFrame = getWriteIndex(); - // contiguous writes - int32_t framesToEndOfBuffer = mMaxFrames - indexFrame; - int32_t framesNow = std::min(framesLeft, framesToEndOfBuffer); - int32_t numSamples = framesNow * mChannelCount; - int32_t sampleIndex = indexFrame * mChannelCount; - - for (int i = 0; i < numSamples; i++) { - mData[sampleIndex++] = *buffer++ * (1.0f / 32768); - } - - mWriteCursorFrames += framesNow; - framesLeft -= framesNow; - } - return numFrames - framesLeft; - } - - /** - * Write all numFrames from the float buffer into the recording. - * Overwrite old data if full. - * @param buffer - * @param numFrames - * @return number of frames actually written. - */ - int32_t write(float *buffer, int32_t numFrames) { - int32_t framesLeft = numFrames; - while (framesLeft > 0) { - int32_t indexFrame = getWriteIndex(); - // contiguous writes - int32_t framesToEnd = mMaxFrames - indexFrame; - int32_t framesNow = std::min(framesLeft, framesToEnd); - int32_t numSamples = framesNow * mChannelCount; - int32_t sampleIndex = indexFrame * mChannelCount; - - memcpy(&mData[sampleIndex], - buffer, - (numSamples * sizeof(float))); - buffer += numSamples; - mWriteCursorFrames += framesNow; - framesLeft -= framesNow; - } - return numFrames; - } - - /** - * Read numFrames from the recording into the buffer, if there is enough data. - * Start at the cursor position, aligned up to the next frame. - * @param buffer - * @param numFrames - * @return number of frames actually read. - */ - int32_t read(float *buffer, int32_t numFrames) { - int32_t framesRead = 0; - int32_t framesLeft = std::min(numFrames, - std::min(mMaxFrames, (int32_t)(mWriteCursorFrames - mReadCursorFrames))); - while (framesLeft > 0) { - int32_t indexFrame = getReadIndex(); - // contiguous reads - int32_t framesToEnd = mMaxFrames - indexFrame; - int32_t framesNow = std::min(framesLeft, framesToEnd); - int32_t numSamples = framesNow * mChannelCount; - int32_t sampleIndex = indexFrame * mChannelCount; - - memcpy(buffer, - &mData[sampleIndex], - (numSamples * sizeof(float))); - - mReadCursorFrames += framesNow; - framesLeft -= framesNow; - framesRead += framesNow; - } - return framesRead; - } - -private: - float *mData = nullptr; - int64_t mReadCursorFrames = 0; - int64_t mWriteCursorFrames = 0; // monotonically increasing - const int32_t mChannelCount; - const int32_t mMaxFrames; -}; - -#endif //NATIVEOBOE_MULTICHANNEL_RECORDING_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp deleted file mode 100644 index 2a70c19f..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright 2017 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. - */ - -// Set to 1 for debugging race condition #1180 with mAAudioStream. -// See also AudioStreamAAudio.cpp in Oboe. -// This was left in the code so that we could test the fix again easily in the future. -// We could not trigger the race condition without adding these get calls and the sleeps. -#define DEBUG_CLOSE_RACE 0 - -#include -#include -#if DEBUG_CLOSE_RACE -#include -#endif // DEBUG_CLOSE_RACE -#include - -#include -#include "util/WaveFileWriter.h" - -#include "NativeAudioContext.h" - -using namespace oboe; - -static oboe::AudioApi convertNativeApiToAudioApi(int nativeApi) { - switch (nativeApi) { - default: - case NATIVE_MODE_UNSPECIFIED: - return oboe::AudioApi::Unspecified; - case NATIVE_MODE_AAUDIO: - return oboe::AudioApi::AAudio; - case NATIVE_MODE_OPENSLES: - return oboe::AudioApi::OpenSLES; - } -} - -class MyOboeOutputStream : public WaveFileOutputStream { -public: - void write(uint8_t b) override { - mData.push_back(b); - } - - int32_t length() { - return (int32_t) mData.size(); - } - - uint8_t *getData() { - return mData.data(); - } - -private: - std::vector mData; -}; - -bool ActivityContext::mUseCallback = true; -int ActivityContext::callbackSize = 0; - -std::shared_ptr ActivityContext::getOutputStream() { - for (auto entry : mOboeStreams) { - std::shared_ptr oboeStream = entry.second; - if (oboeStream->getDirection() == oboe::Direction::Output) { - return oboeStream; - } - } - return nullptr; -} - -std::shared_ptr ActivityContext::getInputStream() { - for (auto entry : mOboeStreams) { - std::shared_ptr oboeStream = entry.second; - if (oboeStream != nullptr) { - if (oboeStream->getDirection() == oboe::Direction::Input) { - return oboeStream; - } - } - } - return nullptr; -} - -void ActivityContext::freeStreamIndex(int32_t streamIndex) { - mOboeStreams[streamIndex].reset(); - mOboeStreams.erase(streamIndex); -} - -int32_t ActivityContext::allocateStreamIndex() { - return mNextStreamHandle++; -} - -void ActivityContext::close(int32_t streamIndex) { - stopBlockingIOThread(); - std::shared_ptr oboeStream = getStream(streamIndex); - if (oboeStream != nullptr) { - oboeStream->close(); - LOGD("ActivityContext::%s() delete stream %d ", __func__, streamIndex); - freeStreamIndex(streamIndex); - } -} - -bool ActivityContext::isMMapUsed(int32_t streamIndex) { - std::shared_ptr oboeStream = getStream(streamIndex); - if (oboeStream == nullptr) return false; - if (oboeStream->getAudioApi() != AudioApi::AAudio) return false; - return AAudioExtensions::getInstance().isMMapUsed(oboeStream.get()); -} - -oboe::Result ActivityContext::pause() { - oboe::Result result = oboe::Result::OK; - stopBlockingIOThread(); - for (auto entry : mOboeStreams) { - std::shared_ptr oboeStream = entry.second; - result = oboeStream->requestPause(); - } - return result; -} - -oboe::Result ActivityContext::stopAllStreams() { - oboe::Result result = oboe::Result::OK; - stopBlockingIOThread(); - for (auto entry : mOboeStreams) { - std::shared_ptr oboeStream = entry.second; - result = oboeStream->requestStop(); - } - return result; -} - -void ActivityContext::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) { - // We needed the proxy because we did not know the channelCount when we setup the Builder. - if (mUseCallback) { - builder.setDataCallback(&oboeCallbackProxy); - } -} - -int ActivityContext::open(jint nativeApi, - jint sampleRate, - jint channelCount, - jint format, - jint sharingMode, - jint performanceMode, - jint inputPreset, - jint usage, - jint deviceId, - jint sessionId, - jint framesPerBurst, - jboolean channelConversionAllowed, - jboolean formatConversionAllowed, - jint rateConversionQuality, - jboolean isMMap, - jboolean isInput) { - - oboe::AudioApi audioApi = oboe::AudioApi::Unspecified; - switch (nativeApi) { - case NATIVE_MODE_UNSPECIFIED: - case NATIVE_MODE_AAUDIO: - case NATIVE_MODE_OPENSLES: - audioApi = convertNativeApiToAudioApi(nativeApi); - break; - default: - return (jint) oboe::Result::ErrorOutOfRange; - } - - int32_t streamIndex = allocateStreamIndex(); - if (streamIndex < 0) { - LOGE("ActivityContext::open() stream array full"); - return (jint) oboe::Result::ErrorNoFreeHandles; - } - - if (channelCount < 0 || channelCount > 256) { - LOGE("ActivityContext::open() channels out of range"); - return (jint) oboe::Result::ErrorOutOfRange; - } - - // Create an audio stream. - oboe::AudioStreamBuilder builder; - builder.setChannelCount(channelCount) - ->setDirection(isInput ? oboe::Direction::Input : oboe::Direction::Output) - ->setSharingMode((oboe::SharingMode) sharingMode) - ->setPerformanceMode((oboe::PerformanceMode) performanceMode) - ->setInputPreset((oboe::InputPreset)inputPreset) - ->setUsage((oboe::Usage)usage) - ->setDeviceId(deviceId) - ->setSessionId((oboe::SessionId) sessionId) - ->setSampleRate(sampleRate) - ->setFormat((oboe::AudioFormat) format) - ->setChannelConversionAllowed(channelConversionAllowed) - ->setFormatConversionAllowed(formatConversionAllowed) - ->setSampleRateConversionQuality((oboe::SampleRateConversionQuality) rateConversionQuality) - ; - if (mUseCallback) { - builder.setFramesPerCallback(callbackSize); - } - configureBuilder(isInput, builder); - - builder.setAudioApi(audioApi); - - // Temporarily set the AAudio MMAP policy to disable MMAP or not. - bool oldMMapEnabled = AAudioExtensions::getInstance().isMMapEnabled(); - AAudioExtensions::getInstance().setMMapEnabled(isMMap); - - // Record time for opening. - if (isInput) { - mInputOpenedAt = oboe::AudioClock::getNanoseconds(); - } else { - mOutputOpenedAt = oboe::AudioClock::getNanoseconds(); - } - // Open a stream based on the builder settings. - std::shared_ptr oboeStream; - Result result = builder.openStream(oboeStream); - AAudioExtensions::getInstance().setMMapEnabled(oldMMapEnabled); - if (result != Result::OK) { - freeStreamIndex(streamIndex); - streamIndex = -1; - } else { - mOboeStreams[streamIndex] = oboeStream; // save shared_ptr - - mChannelCount = oboeStream->getChannelCount(); // FIXME store per stream - mFramesPerBurst = oboeStream->getFramesPerBurst(); - mSampleRate = oboeStream->getSampleRate(); - - createRecording(); - - finishOpen(isInput, oboeStream.get()); - } - - if (!mUseCallback) { - int numSamples = getFramesPerBlock() * mChannelCount; - dataBuffer = std::make_unique(numSamples); - } - - return (result != Result::OK) ? (int)result : streamIndex; -} - -oboe::Result ActivityContext::start() { - oboe::Result result = oboe::Result::OK; - std::shared_ptr inputStream = getInputStream(); - std::shared_ptr outputStream = getOutputStream(); - if (inputStream == nullptr && outputStream == nullptr) { - LOGD("%s() - no streams defined", __func__); - return oboe::Result::ErrorInvalidState; // not open - } - - configureForStart(); - - audioStreamGateway.reset(); - result = startStreams(); - - if (!mUseCallback && result == oboe::Result::OK) { - // Instead of using the callback, start a thread that writes the stream. - threadEnabled.store(true); - dataThread = new std::thread(threadCallback, this); - } - -#if DEBUG_CLOSE_RACE - // Also put a sleep for 400 msec in AudioStreamAAudio::updateFramesRead(). - if (outputStream != nullptr) { - std::thread raceDebugger([outputStream]() { - while (outputStream->getState() != StreamState::Closed) { - int64_t framesRead = outputStream->getFramesRead(); - LOGD("raceDebugger, framesRead = %d, state = %d", - (int) framesRead, (int) outputStream->getState()); - } - }); - raceDebugger.detach(); - } -#endif // DEBUG_CLOSE_RACE - - return result; -} - -int32_t ActivityContext::saveWaveFile(const char *filename) { - if (mRecording == nullptr) { - LOGW("ActivityContext::saveWaveFile(%s) but no recording!", filename); - return -1; - } - if (mRecording->getSizeInFrames() == 0) { - LOGW("ActivityContext::saveWaveFile(%s) but no frames!", filename); - return -2; - } - MyOboeOutputStream outStream; - WaveFileWriter writer(&outStream); - - writer.setFrameRate(mSampleRate); - writer.setSamplesPerFrame(mRecording->getChannelCount()); - writer.setBitsPerSample(24); - float buffer[mRecording->getChannelCount()]; - // Read samples from start to finish. - mRecording->rewind(); - for (int32_t frameIndex = 0; frameIndex < mRecording->getSizeInFrames(); frameIndex++) { - mRecording->read(buffer, 1 /* numFrames */); - for (int32_t i = 0; i < mRecording->getChannelCount(); i++) { - writer.write(buffer[i]); - } - } - writer.close(); - - if (outStream.length() > 0) { - auto myfile = std::ofstream(filename, std::ios::out | std::ios::binary); - myfile.write((char *) outStream.getData(), outStream.length()); - myfile.close(); - } - - return outStream.length(); -} - -double ActivityContext::getTimestampLatency(int32_t streamIndex) { - std::shared_ptr oboeStream = getStream(streamIndex); - if (oboeStream != nullptr) { - auto result = oboeStream->calculateLatencyMillis(); - return (!result) ? -1.0 : result.value(); - } - return -1.0; -} - -// =================================================================== ActivityTestOutput -void ActivityTestOutput::close(int32_t streamIndex) { - ActivityContext::close(streamIndex); - manyToMulti.reset(nullptr); - monoToMulti.reset(nullptr); - mSinkFloat.reset(); - mSinkI16.reset(); - mSinkI24.reset(); - mSinkI32.reset(); -} - -void ActivityTestOutput::setChannelEnabled(int channelIndex, bool enabled) { - if (manyToMulti == nullptr) { - return; - } - if (enabled) { - switch (mSignalType) { - case SignalType::Sine: - sineOscillators[channelIndex].frequency.disconnect(); - sineOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get()); - break; - case SignalType::Sawtooth: - sawtoothOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get()); - break; - case SignalType::FreqSweep: - mLinearShape.output.connect(&sineOscillators[channelIndex].frequency); - sineOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get()); - break; - case SignalType::PitchSweep: - mExponentialShape.output.connect(&sineOscillators[channelIndex].frequency); - sineOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get()); - break; - default: - break; - } - } else { - manyToMulti->inputs[channelIndex]->disconnect(); - } -} - -void ActivityTestOutput::configureForStart() { - manyToMulti = std::make_unique(mChannelCount); - - mSinkFloat = std::make_shared(mChannelCount); - mSinkI16 = std::make_shared(mChannelCount); - mSinkI24 = std::make_shared(mChannelCount); - mSinkI32 = std::make_shared(mChannelCount); - - std::shared_ptr outputStream = getOutputStream(); - - mTriangleOscillator.setSampleRate(outputStream->getSampleRate()); - mTriangleOscillator.frequency.setValue(1.0/kSweepPeriod); - mTriangleOscillator.amplitude.setValue(1.0); - mTriangleOscillator.setPhase(-1.0); - - mLinearShape.setMinimum(0.0); - mLinearShape.setMaximum(outputStream->getSampleRate() * 0.5); // Nyquist - - mExponentialShape.setMinimum(110.0); - mExponentialShape.setMaximum(outputStream->getSampleRate() * 0.5); // Nyquist - - mTriangleOscillator.output.connect(&(mLinearShape.input)); - mTriangleOscillator.output.connect(&(mExponentialShape.input)); - { - double frequency = 330.0; - for (int i = 0; i < mChannelCount; i++) { - sineOscillators[i].setSampleRate(outputStream->getSampleRate()); - sineOscillators[i].frequency.setValue(frequency); - frequency *= 4.0 / 3.0; // each sine is at a higher frequency - sineOscillators[i].amplitude.setValue(AMPLITUDE_SINE); - setChannelEnabled(i, true); - } - } - - manyToMulti->output.connect(&(mSinkFloat.get()->input)); - manyToMulti->output.connect(&(mSinkI16.get()->input)); - manyToMulti->output.connect(&(mSinkI24.get()->input)); - manyToMulti->output.connect(&(mSinkI32.get()->input)); - - mSinkFloat->pullReset(); - mSinkI16->pullReset(); - mSinkI24->pullReset(); - mSinkI32->pullReset(); - - configureStreamGateway(); -} - -void ActivityTestOutput::configureStreamGateway() { - std::shared_ptr outputStream = getOutputStream(); - if (outputStream->getFormat() == oboe::AudioFormat::I16) { - audioStreamGateway.setAudioSink(mSinkI16); - } else if (outputStream->getFormat() == oboe::AudioFormat::I24) { - audioStreamGateway.setAudioSink(mSinkI24); - } else if (outputStream->getFormat() == oboe::AudioFormat::I32) { - audioStreamGateway.setAudioSink(mSinkI32); - } else if (outputStream->getFormat() == oboe::AudioFormat::Float) { - audioStreamGateway.setAudioSink(mSinkFloat); - } - - if (mUseCallback) { - oboeCallbackProxy.setCallback(&audioStreamGateway); - } -} - -void ActivityTestOutput::runBlockingIO() { - int32_t framesPerBlock = getFramesPerBlock(); - oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Continue; - - std::shared_ptr oboeStream = getOutputStream(); - if (oboeStream == nullptr) { - LOGE("%s() : no stream found\n", __func__); - return; - } - - while (threadEnabled.load() - && callbackResult == oboe::DataCallbackResult::Continue) { - // generate output by calling the callback - callbackResult = audioStreamGateway.onAudioReady(oboeStream.get(), - dataBuffer.get(), - framesPerBlock); - - auto result = oboeStream->write(dataBuffer.get(), - framesPerBlock, - NANOS_PER_SECOND); - - if (!result) { - LOGE("%s() returned %s\n", __func__, convertToText(result.error())); - break; - } - int32_t framesWritten = result.value(); - if (framesWritten < framesPerBlock) { - LOGE("%s() : write() wrote %d of %d\n", __func__, framesWritten, framesPerBlock); - break; - } - } -} - -// ======================================================================= ActivityTestInput -void ActivityTestInput::configureForStart() { - mInputAnalyzer.reset(); - if (mUseCallback) { - oboeCallbackProxy.setCallback(&mInputAnalyzer); - } - mInputAnalyzer.setRecording(mRecording.get()); -} - -void ActivityTestInput::runBlockingIO() { - int32_t framesPerBlock = getFramesPerBlock(); - oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Continue; - - std::shared_ptr oboeStream = getInputStream(); - if (oboeStream == nullptr) { - LOGE("%s() : no stream found\n", __func__); - return; - } - - while (threadEnabled.load() - && callbackResult == oboe::DataCallbackResult::Continue) { - - // Avoid glitches by waiting until there is extra data in the FIFO. - auto err = oboeStream->waitForAvailableFrames(mMinimumFramesBeforeRead, kNanosPerSecond); - if (!err) break; - - // read from input - auto result = oboeStream->read(dataBuffer.get(), - framesPerBlock, - NANOS_PER_SECOND); - if (!result) { - LOGE("%s() : read() returned %s\n", __func__, convertToText(result.error())); - break; - } - int32_t framesRead = result.value(); - if (framesRead < framesPerBlock) { // timeout? - LOGE("%s() : read() read %d of %d\n", __func__, framesRead, framesPerBlock); - break; - } - - // analyze input - callbackResult = mInputAnalyzer.onAudioReady(oboeStream.get(), - dataBuffer.get(), - framesRead); - } -} - -oboe::Result ActivityRecording::stopPlayback() { - oboe::Result result = oboe::Result::OK; - if (playbackStream != nullptr) { - result = playbackStream->requestStop(); - playbackStream->close(); - mPlayRecordingCallback.setRecording(nullptr); - delete playbackStream; - playbackStream = nullptr; - } - return result; -} - -oboe::Result ActivityRecording::startPlayback() { - stop(); - oboe::AudioStreamBuilder builder; - builder.setChannelCount(mChannelCount) - ->setSampleRate(mSampleRate) - ->setFormat(oboe::AudioFormat::Float) - ->setCallback(&mPlayRecordingCallback) - ->setAudioApi(oboe::AudioApi::OpenSLES); - oboe::Result result = builder.openStream(&playbackStream); - if (result != oboe::Result::OK) { - delete playbackStream; - playbackStream = nullptr; - } else if (playbackStream != nullptr) { - if (mRecording != nullptr) { - mRecording->rewind(); - mPlayRecordingCallback.setRecording(mRecording.get()); - result = playbackStream->requestStart(); - } - } - return result; -} - -// ======================================================================= ActivityTapToTone -void ActivityTapToTone::configureForStart() { - monoToMulti = std::make_unique(mChannelCount); - - mSinkFloat = std::make_shared(mChannelCount); - mSinkI16 = std::make_shared(mChannelCount); - mSinkI24 = std::make_shared(mChannelCount); - mSinkI32 = std::make_shared(mChannelCount); - - std::shared_ptr outputStream = getOutputStream(); - sawPingGenerator.setSampleRate(outputStream->getSampleRate()); - sawPingGenerator.frequency.setValue(FREQUENCY_SAW_PING); - sawPingGenerator.amplitude.setValue(AMPLITUDE_SAW_PING); - - sawPingGenerator.output.connect(&(monoToMulti->input)); - monoToMulti->output.connect(&(mSinkFloat.get()->input)); - monoToMulti->output.connect(&(mSinkI16.get()->input)); - monoToMulti->output.connect(&(mSinkI24.get()->input)); - monoToMulti->output.connect(&(mSinkI32.get()->input)); - - mSinkFloat->pullReset(); - mSinkI16->pullReset(); - mSinkI24->pullReset(); - mSinkI32->pullReset(); - - configureStreamGateway(); -} - -// ======================================================================= ActivityRoundTripLatency -void ActivityFullDuplex::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) { - if (isInput) { - // Ideally the output streams should be opened first. - std::shared_ptr outputStream = getOutputStream(); - if (outputStream != nullptr) { - // Make sure the capacity is bigger than two bursts. - int32_t burst = outputStream->getFramesPerBurst(); - builder.setBufferCapacityInFrames(2 * burst); - } - } -} - -// ======================================================================= ActivityEcho -void ActivityEcho::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) { - ActivityFullDuplex::configureBuilder(isInput, builder); - - if (mFullDuplexEcho.get() == nullptr) { - mFullDuplexEcho = std::make_unique(); - } - // only output uses a callback, input is polled - if (!isInput) { - builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy); - oboeCallbackProxy.setCallback(mFullDuplexEcho.get()); - } -} - -void ActivityEcho::finishOpen(bool isInput, oboe::AudioStream *oboeStream) { - if (isInput) { - mFullDuplexEcho->setInputStream(oboeStream); - } else { - mFullDuplexEcho->setOutputStream(oboeStream); - } -} - -// ======================================================================= ActivityRoundTripLatency -void ActivityRoundTripLatency::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) { - ActivityFullDuplex::configureBuilder(isInput, builder); - - if (mFullDuplexLatency.get() == nullptr) { - mFullDuplexLatency = std::make_unique(&mEchoAnalyzer); - } - if (!isInput) { - // only output uses a callback, input is polled - builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy); - oboeCallbackProxy.setCallback(mFullDuplexLatency.get()); - } -} - -void ActivityRoundTripLatency::finishOpen(bool isInput, AudioStream *oboeStream) { - if (isInput) { - mFullDuplexLatency->setInputStream(oboeStream); - mFullDuplexLatency->setRecording(mRecording.get()); - } else { - mFullDuplexLatency->setOutputStream(oboeStream); - } -} - -// ======================================================================= ActivityGlitches -void ActivityGlitches::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) { - ActivityFullDuplex::configureBuilder(isInput, builder); - - if (mFullDuplexGlitches.get() == nullptr) { - mFullDuplexGlitches = std::make_unique(&mGlitchAnalyzer); - } - if (!isInput) { - // only output uses a callback, input is polled - builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy); - oboeCallbackProxy.setCallback(mFullDuplexGlitches.get()); - } -} - -void ActivityGlitches::finishOpen(bool isInput, oboe::AudioStream *oboeStream) { - if (isInput) { - mFullDuplexGlitches->setInputStream(oboeStream); - mFullDuplexGlitches->setRecording(mRecording.get()); - } else { - mFullDuplexGlitches->setOutputStream(oboeStream); - } -} - -// ======================================================================= ActivityDataPath -void ActivityDataPath::configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) { - ActivityFullDuplex::configureBuilder(isInput, builder); - - if (mFullDuplexDataPath.get() == nullptr) { - mFullDuplexDataPath = std::make_unique(&mDataPathAnalyzer); - } - if (!isInput) { - // only output uses a callback, input is polled - builder.setCallback((oboe::AudioStreamCallback *) &oboeCallbackProxy); - oboeCallbackProxy.setCallback(mFullDuplexDataPath.get()); - } -} - -void ActivityDataPath::finishOpen(bool isInput, oboe::AudioStream *oboeStream) { - if (isInput) { - mFullDuplexDataPath->setInputStream(oboeStream); - mFullDuplexDataPath->setRecording(mRecording.get()); - } else { - mFullDuplexDataPath->setOutputStream(oboeStream); - } -} - -// =================================================================== ActivityTestDisconnect -void ActivityTestDisconnect::close(int32_t streamIndex) { - ActivityContext::close(streamIndex); - mSinkFloat.reset(); -} - -void ActivityTestDisconnect::configureForStart() { - std::shared_ptr outputStream = getOutputStream(); - std::shared_ptr inputStream = getInputStream(); - if (outputStream) { - mSinkFloat = std::make_unique(mChannelCount); - sineOscillator = std::make_unique(); - monoToMulti = std::make_unique(mChannelCount); - - sineOscillator->setSampleRate(outputStream->getSampleRate()); - sineOscillator->frequency.setValue(440.0); - sineOscillator->amplitude.setValue(AMPLITUDE_SINE); - sineOscillator->output.connect(&(monoToMulti->input)); - - monoToMulti->output.connect(&(mSinkFloat->input)); - mSinkFloat->pullReset(); - audioStreamGateway.setAudioSink(mSinkFloat); - } else if (inputStream) { - audioStreamGateway.setAudioSink(nullptr); - } - oboeCallbackProxy.setCallback(&audioStreamGateway); -} - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h deleted file mode 100644 index f20be28f..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Copyright 2015 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 NATIVEOBOE_NATIVEAUDIOCONTEXT_H -#define NATIVEOBOE_NATIVEAUDIOCONTEXT_H - -#include -#include -#include -#include -#include - -#include "common/OboeDebug.h" -#include "oboe/Oboe.h" - -#include "aaudio/AAudioExtensions.h" -#include "AudioStreamGateway.h" - -#include "flowunits/ImpulseOscillator.h" -#include "flowgraph/ManyToMultiConverter.h" -#include "flowgraph/MonoToMultiConverter.h" -#include "flowgraph/SinkFloat.h" -#include "flowgraph/SinkI16.h" -#include "flowgraph/SinkI24.h" -#include "flowgraph/SinkI32.h" -#include "flowunits/ExponentialShape.h" -#include "flowunits/LinearShape.h" -#include "flowunits/SineOscillator.h" -#include "flowunits/SawtoothOscillator.h" -#include "flowunits/TriangleOscillator.h" - -#include "FullDuplexAnalyzer.h" -#include "FullDuplexEcho.h" -#include "FullDuplexStream.h" -#include "analyzer/GlitchAnalyzer.h" -#include "analyzer/DataPathAnalyzer.h" -#include "InputStreamCallbackAnalyzer.h" -#include "MultiChannelRecording.h" -#include "OboeStreamCallbackProxy.h" -#include "PlayRecordingCallback.h" -#include "SawPingGenerator.h" - -// These must match order in strings.xml and in StreamConfiguration.java -#define NATIVE_MODE_UNSPECIFIED 0 -#define NATIVE_MODE_OPENSLES 1 -#define NATIVE_MODE_AAUDIO 2 - -#define MAX_SINE_OSCILLATORS 8 -#define AMPLITUDE_SINE 1.0 -#define AMPLITUDE_SAWTOOTH 0.5 -#define FREQUENCY_SAW_PING 800.0 -#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 SECONDS_TO_RECORD 10 - -/** - * Abstract base class that corresponds to a test at the Java level. - */ -class ActivityContext { -public: - - ActivityContext() {} - - virtual ~ActivityContext() = default; - - std::shared_ptr getStream(int32_t streamIndex) { - auto it = mOboeStreams.find(streamIndex); - if (it != mOboeStreams.end()) { - return it->second; - } else { - return nullptr; - } - } - - virtual void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder); - - /** - * Open a stream with the given parameters. - * @param nativeApi - * @param sampleRate - * @param channelCount - * @param format - * @param sharingMode - * @param performanceMode - * @param inputPreset - * @param deviceId - * @param sessionId - * @param framesPerBurst - * @param channelConversionAllowed - * @param formatConversionAllowed - * @param rateConversionQuality - * @param isMMap - * @param isInput - * @return stream ID - */ - int open(jint nativeApi, - jint sampleRate, - jint channelCount, - jint format, - jint sharingMode, - jint performanceMode, - jint inputPreset, - jint usage, - jint deviceId, - jint sessionId, - jint framesPerBurst, - jboolean channelConversionAllowed, - jboolean formatConversionAllowed, - jint rateConversionQuality, - jboolean isMMap, - jboolean isInput); - - virtual void close(int32_t streamIndex); - - virtual void configureForStart() {} - - oboe::Result start(); - - oboe::Result pause(); - - oboe::Result stopAllStreams(); - - virtual oboe::Result stop() { - return stopAllStreams(); - } - - double getCpuLoad() { - return oboeCallbackProxy.getCpuLoad(); - } - - void setWorkload(double workload) { - oboeCallbackProxy.setWorkload(workload); - } - - virtual oboe::Result startPlayback() { - return oboe::Result::OK; - } - - virtual oboe::Result stopPlayback() { - return oboe::Result::OK; - } - - virtual void runBlockingIO() {}; - - static void threadCallback(ActivityContext *context) { - context->runBlockingIO(); - } - - void stopBlockingIOThread() { - if (dataThread != nullptr) { - // stop a thread that runs in place of the callback - threadEnabled.store(false); // ask thread to exit its loop - dataThread->join(); - dataThread = nullptr; - } - } - - virtual double getPeakLevel(int index) { - return 0.0; - } - - static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) { - struct timespec time; - int result = clock_gettime(clockId, &time); - if (result < 0) { - return result; - } - return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec; - } - - // Calculate time between beginning and when frame[0] occurred. - int32_t calculateColdStartLatencyMillis(int32_t sampleRate, - int64_t beginTimeNanos, - int64_t timeStampPosition, - int64_t timestampNanos) const { - int64_t elapsedNanos = NANOS_PER_SECOND * (timeStampPosition / (double) sampleRate); - int64_t timeOfFrameZero = timestampNanos - elapsedNanos; - int64_t coldStartLatencyNanos = timeOfFrameZero - beginTimeNanos; - return coldStartLatencyNanos / NANOS_PER_MILLISECOND; - } - - int32_t getColdStartInputMillis() { - std::shared_ptr oboeStream = getInputStream(); - if (oboeStream != nullptr) { - int64_t framesRead = oboeStream->getFramesRead(); - if (framesRead > 0) { - // Base latency on the time that frame[0] would have been received by the app. - int64_t nowNanos = getNanoseconds(); - return calculateColdStartLatencyMillis(oboeStream->getSampleRate(), - mInputOpenedAt, - framesRead, - nowNanos); - } - } - return -1; - } - - int32_t getColdStartOutputMillis() { - std::shared_ptr oboeStream = getOutputStream(); - if (oboeStream != nullptr) { - auto result = oboeStream->getTimestamp(CLOCK_MONOTONIC); - if (result) { - auto frameTimestamp = result.value(); - // Calculate the time that frame[0] would have been played by the speaker. - int64_t position = frameTimestamp.position; - int64_t timestampNanos = frameTimestamp.timestamp; - return calculateColdStartLatencyMillis(oboeStream->getSampleRate(), - mOutputOpenedAt, - position, - timestampNanos); - } - } - return -1; - } - - /** - * Trigger a sound or impulse. - * @param enabled - */ - virtual void trigger() {} - - bool isMMapUsed(int32_t streamIndex); - - int32_t getFramesPerBlock() { - return (callbackSize == 0) ? mFramesPerBurst : callbackSize; - } - - int64_t getCallbackCount() { - return oboeCallbackProxy.getCallbackCount(); - } - - oboe::Result getLastErrorCallbackResult() { - std::shared_ptr stream = getOutputStream(); - if (stream == nullptr) { - stream = getInputStream(); - } - return stream ? oboe::Result::ErrorNull : stream->getLastErrorCallbackResult(); - } - - int32_t getFramesPerCallback() { - return oboeCallbackProxy.getFramesPerCallback(); - } - - virtual void setChannelEnabled(int channelIndex, bool enabled) {} - - virtual void setSignalType(int signalType) {} - - virtual int32_t saveWaveFile(const char *filename); - - virtual void setMinimumFramesBeforeRead(int32_t numFrames) {} - - static bool mUseCallback; - static int callbackSize; - - double getTimestampLatency(int32_t streamIndex); - -protected: - std::shared_ptr getInputStream(); - std::shared_ptr getOutputStream(); - int32_t allocateStreamIndex(); - void freeStreamIndex(int32_t streamIndex); - - virtual void createRecording() { - mRecording = std::make_unique(mChannelCount, - SECONDS_TO_RECORD * mSampleRate); - } - - virtual void finishOpen(bool isInput, oboe::AudioStream *oboeStream) {} - - virtual oboe::Result startStreams() = 0; - - std::unique_ptr dataBuffer{}; - - AudioStreamGateway audioStreamGateway; - OboeStreamCallbackProxy oboeCallbackProxy; - - std::unique_ptr mRecording{}; - - int32_t mNextStreamHandle = 0; - std::unordered_map> mOboeStreams; - int32_t mFramesPerBurst = 0; // TODO per stream - int32_t mChannelCount = 0; // TODO per stream - int32_t mSampleRate = 0; // TODO per stream - - std::atomic threadEnabled{false}; - std::thread *dataThread = nullptr; // FIXME never gets deleted - -private: - int64_t mInputOpenedAt = 0; - int64_t mOutputOpenedAt = 0; -}; - -/** - * Test a single input stream. - */ -class ActivityTestInput : public ActivityContext { -public: - - ActivityTestInput() {} - virtual ~ActivityTestInput() = default; - - void configureForStart() override; - - double getPeakLevel(int index) override { - return mInputAnalyzer.getPeakLevel(index); - } - - void runBlockingIO() override; - - void setMinimumFramesBeforeRead(int32_t numFrames) override { - mInputAnalyzer.setMinimumFramesBeforeRead(numFrames); - mMinimumFramesBeforeRead = numFrames; - } - - int32_t getMinimumFramesBeforeRead() const { - return mMinimumFramesBeforeRead; - } - -protected: - - oboe::Result startStreams() override { - mInputAnalyzer.reset(); - mInputAnalyzer.setup(getInputStream()->getFramesPerBurst(), - getInputStream()->getChannelCount(), - getInputStream()->getFormat()); - return getInputStream()->requestStart(); - } - - InputStreamCallbackAnalyzer mInputAnalyzer; - int32_t mMinimumFramesBeforeRead = 0; -}; - -/** - * Record a configured input stream and play it back some simple way. - */ -class ActivityRecording : public ActivityTestInput { -public: - - ActivityRecording() {} - virtual ~ActivityRecording() = default; - - oboe::Result stop() override { - - oboe::Result resultStopPlayback = stopPlayback(); - oboe::Result resultStopAudio = ActivityContext::stop(); - - return (resultStopPlayback != oboe::Result::OK) ? resultStopPlayback : resultStopAudio; - } - - oboe::Result startPlayback() override; - - oboe::Result stopPlayback() override; - - PlayRecordingCallback mPlayRecordingCallback; - oboe::AudioStream *playbackStream = nullptr; - -}; - -/** - * Test a single output stream. - */ -class ActivityTestOutput : public ActivityContext { -public: - ActivityTestOutput() - : sineOscillators(MAX_SINE_OSCILLATORS) - , sawtoothOscillators(MAX_SINE_OSCILLATORS) {} - - virtual ~ActivityTestOutput() = default; - - void close(int32_t streamIndex) override; - - oboe::Result startStreams() override { - return getOutputStream()->start(); - } - - void configureForStart() override; - - virtual void configureStreamGateway(); - - void runBlockingIO() override; - - void setChannelEnabled(int channelIndex, bool enabled) override; - - // WARNING - must match order in strings.xml and OboeAudioOutputStream.java - enum SignalType { - Sine = 0, - Sawtooth = 1, - FreqSweep = 2, - PitchSweep = 3, - WhiteNoise = 4 - }; - - void setSignalType(int signalType) override { - mSignalType = (SignalType) signalType; - } - -protected: - SignalType mSignalType = SignalType::Sine; - - std::vector sineOscillators; - std::vector sawtoothOscillators; - static constexpr float kSweepPeriod = 10.0; // for triangle up and down - - // A triangle LFO is shaped into either a linear or an exponential range. - TriangleOscillator mTriangleOscillator; - LinearShape mLinearShape; - ExponentialShape mExponentialShape; - - std::unique_ptr manyToMulti; - std::unique_ptr monoToMulti; - std::shared_ptr mSinkFloat; - std::shared_ptr mSinkI16; - std::shared_ptr mSinkI24; - std::shared_ptr mSinkI32; -}; - -/** - * Generate a short beep with a very short attack. - * This is used by Java to measure output latency. - */ -class ActivityTapToTone : public ActivityTestOutput { -public: - ActivityTapToTone() {} - virtual ~ActivityTapToTone() = default; - - void configureForStart() override; - - virtual void trigger() override { - sawPingGenerator.trigger(); - } - - SawPingGenerator sawPingGenerator; -}; - -/** - * Activity that uses synchronized input/output streams. - */ -class ActivityFullDuplex : public ActivityContext { -public: - - void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; - - virtual int32_t getState() { return -1; } - virtual int32_t getResult() { return -1; } - virtual bool isAnalyzerDone() { return false; } - - void setMinimumFramesBeforeRead(int32_t numFrames) override { - getFullDuplexAnalyzer()->setMinimumFramesBeforeRead(numFrames); - } - - virtual FullDuplexAnalyzer *getFullDuplexAnalyzer() = 0; - - int32_t getResetCount() { - return getFullDuplexAnalyzer()->getLoopbackProcessor()->getResetCount(); - } - -protected: - void createRecording() override { - mRecording = std::make_unique(2, // output and input - SECONDS_TO_RECORD * mSampleRate); - } -}; - -/** - * Echo input to output through a delay line. - */ -class ActivityEcho : public ActivityFullDuplex { -public: - - oboe::Result startStreams() override { - return mFullDuplexEcho->start(); - } - - void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; - - void setDelayTime(double delayTimeSeconds) { - if (mFullDuplexEcho) { - mFullDuplexEcho->setDelayTime(delayTimeSeconds); - } - } - - FullDuplexAnalyzer *getFullDuplexAnalyzer() override { - return (FullDuplexAnalyzer *) mFullDuplexEcho.get(); - } - -protected: - void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; - -private: - std::unique_ptr mFullDuplexEcho{}; -}; - -/** - * Measure Round Trip Latency - */ -class ActivityRoundTripLatency : public ActivityFullDuplex { -public: - - oboe::Result startStreams() override { - mAnalyzerLaunched = false; - return mFullDuplexLatency->start(); - } - - void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; - - LatencyAnalyzer *getLatencyAnalyzer() { - return &mEchoAnalyzer; - } - - int32_t getState() override { - return getLatencyAnalyzer()->getState(); - } - - int32_t getResult() override { - return getLatencyAnalyzer()->getState(); // TODO This does not look right. - } - - bool isAnalyzerDone() override { - if (!mAnalyzerLaunched) { - mAnalyzerLaunched = launchAnalysisIfReady(); - } - return mEchoAnalyzer.isDone(); - } - - FullDuplexAnalyzer *getFullDuplexAnalyzer() override { - return (FullDuplexAnalyzer *) mFullDuplexLatency.get(); - } - - static void analyzeData(PulseLatencyAnalyzer *analyzer) { - analyzer->analyze(); - } - - bool launchAnalysisIfReady() { - // Are we ready to do the analysis? - if (mEchoAnalyzer.hasEnoughData()) { - // Crunch the numbers on a separate thread. - std::thread t(analyzeData, &mEchoAnalyzer); - t.detach(); - return true; - } - return false; - } - -protected: - void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; - -private: - std::unique_ptr mFullDuplexLatency{}; - - PulseLatencyAnalyzer mEchoAnalyzer; - bool mAnalyzerLaunched = false; -}; - -/** - * Measure Glitches - */ -class ActivityGlitches : public ActivityFullDuplex { -public: - - oboe::Result startStreams() override { - return mFullDuplexGlitches->start(); - } - - void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; - - GlitchAnalyzer *getGlitchAnalyzer() { - return &mGlitchAnalyzer; - } - - int32_t getState() override { - return getGlitchAnalyzer()->getState(); - } - - int32_t getResult() override { - return getGlitchAnalyzer()->getResult(); - } - - bool isAnalyzerDone() override { - return mGlitchAnalyzer.isDone(); - } - - FullDuplexAnalyzer *getFullDuplexAnalyzer() override { - return (FullDuplexAnalyzer *) mFullDuplexGlitches.get(); - } - -protected: - void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; - -private: - std::unique_ptr mFullDuplexGlitches{}; - GlitchAnalyzer mGlitchAnalyzer; -}; - -/** - * Measure Data Path - */ -class ActivityDataPath : public ActivityFullDuplex { -public: - - oboe::Result startStreams() override { - return mFullDuplexDataPath->start(); - } - - void configureBuilder(bool isInput, oboe::AudioStreamBuilder &builder) override; - - void configureForStart() override { - std::shared_ptr outputStream = getOutputStream(); - int32_t capacityInFrames = outputStream->getBufferCapacityInFrames(); - int32_t burstInFrames = outputStream->getFramesPerBurst(); - int32_t capacityInBursts = capacityInFrames / burstInFrames; - int32_t sizeInBursts = std::max(2, capacityInBursts / 2); - // Set size of buffer to minimize underruns. - auto result = outputStream->setBufferSizeInFrames(sizeInBursts * burstInFrames); - static_cast(result); // Avoid unused variable. - LOGD("ActivityDataPath: %s() capacity = %d, burst = %d, size = %d", - __func__, capacityInFrames, burstInFrames, result.value()); - } - - DataPathAnalyzer *getDataPathAnalyzer() { - return &mDataPathAnalyzer; - } - - FullDuplexAnalyzer *getFullDuplexAnalyzer() override { - return (FullDuplexAnalyzer *) mFullDuplexDataPath.get(); - } - -protected: - void finishOpen(bool isInput, oboe::AudioStream *oboeStream) override; - -private: - std::unique_ptr mFullDuplexDataPath{}; - - DataPathAnalyzer mDataPathAnalyzer; -}; - -/** - * Test a single output stream. - */ -class ActivityTestDisconnect : public ActivityContext { -public: - ActivityTestDisconnect() {} - - virtual ~ActivityTestDisconnect() = default; - - void close(int32_t streamIndex) override; - - oboe::Result startStreams() override { - std::shared_ptr outputStream = getOutputStream(); - if (outputStream) { - return outputStream->start(); - } - - std::shared_ptr inputStream = getInputStream(); - if (inputStream) { - return inputStream->start(); - } - return oboe::Result::ErrorNull; - } - - void configureForStart() override; - -private: - std::unique_ptr sineOscillator; - std::unique_ptr monoToMulti; - std::shared_ptr mSinkFloat; -}; - -/** - * Switch between various - */ -class NativeAudioContext { -public: - - ActivityContext *getCurrentActivity() { - return currentActivity; - }; - - void setActivityType(int activityType) { - mActivityType = (ActivityType) activityType; - switch(mActivityType) { - default: - case ActivityType::Undefined: - case ActivityType::TestOutput: - currentActivity = &mActivityTestOutput; - break; - case ActivityType::TestInput: - currentActivity = &mActivityTestInput; - break; - case ActivityType::TapToTone: - currentActivity = &mActivityTapToTone; - break; - case ActivityType::RecordPlay: - currentActivity = &mActivityRecording; - break; - case ActivityType::Echo: - currentActivity = &mActivityEcho; - break; - case ActivityType::RoundTripLatency: - currentActivity = &mActivityRoundTripLatency; - break; - case ActivityType::Glitches: - currentActivity = &mActivityGlitches; - break; - case ActivityType::TestDisconnect: - currentActivity = &mActivityTestDisconnect; - break; - case ActivityType::DataPath: - currentActivity = &mActivityDataPath; - break; - } - } - - void setDelayTime(double delayTimeMillis) { - mActivityEcho.setDelayTime(delayTimeMillis); - } - - ActivityTestOutput mActivityTestOutput; - ActivityTestInput mActivityTestInput; - ActivityTapToTone mActivityTapToTone; - ActivityRecording mActivityRecording; - ActivityEcho mActivityEcho; - ActivityRoundTripLatency mActivityRoundTripLatency; - ActivityGlitches mActivityGlitches; - ActivityDataPath mActivityDataPath; - ActivityTestDisconnect mActivityTestDisconnect; - - -private: - - // WARNING - must match definitions in TestAudioActivity.java - enum ActivityType { - Undefined = -1, - TestOutput = 0, - TestInput = 1, - TapToTone = 2, - RecordPlay = 3, - Echo = 4, - RoundTripLatency = 5, - Glitches = 6, - TestDisconnect = 7, - DataPath = 8, - }; - - ActivityType mActivityType = ActivityType::Undefined; - ActivityContext *currentActivity = &mActivityTestOutput; - -}; - -#endif //NATIVEOBOE_NATIVEAUDIOCONTEXT_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp deleted file mode 100644 index 14f82349..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2017 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. - */ - -#include "common/OboeDebug.h" -#include "OboeStreamCallbackProxy.h" - -// Linear congruential random number generator. -static uint32_t s_random16() { - static uint32_t seed = 1234; - seed = ((seed * 31421) + 6927) & 0x0FFFF; - return seed; -} - -/** - * The random number generator is good for burning CPU because the compiler cannot - * easily optimize away the computation. - * @param workload number of times to execute the loop - * @return a white noise value between -1.0 and +1.0 - */ -static float s_burnCPU(int32_t workload) { - uint32_t random = 0; - for (int32_t i = 0; i < workload; i++) { - for (int32_t j = 0; j < 10; j++) { - random = random ^ s_random16(); - } - } - return (random - 32768) * (1.0 / 32768); -} - -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, - int numFrames) { - oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Stop; - int64_t startTimeNanos = getNanoseconds(); - - mCallbackCount++; - mFramesPerCallback = numFrames; - - if (mCallbackReturnStop) { - return oboe::DataCallbackResult::Stop; - } - - s_burnCPU((int32_t)(mWorkload * kWorkloadScaler * numFrames)); - - if (mCallback != nullptr) { - callbackResult = mCallback->onAudioReady(audioStream, audioData, numFrames); - } - - // Update CPU load - double calculationTime = (double)(getNanoseconds() - startTimeNanos); - double inverseRealTime = audioStream->getSampleRate() / (1.0e9 * numFrames); - double currentCpuLoad = calculationTime * inverseRealTime; // avoid a divide - mCpuLoad = (mCpuLoad * 0.95) + (currentCpuLoad * 0.05); // simple low pass filter - - return callbackResult; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h deleted file mode 100644 index 058b725f..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2017 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 NATIVEOBOE_OBOESTREAMCALLBACKPROXY_H -#define NATIVEOBOE_OBOESTREAMCALLBACKPROXY_H - -#include -#include - -#include "oboe/Oboe.h" - -class OboeStreamCallbackProxy : public oboe::AudioStreamCallback { -public: - - void setCallback(oboe::AudioStreamCallback *callback) { - mCallback = callback; - setCallbackCount(0); - } - - static void setCallbackReturnStop(bool b) { - mCallbackReturnStop = b; - } - - int64_t getCallbackCount() { - return mCallbackCount; - } - - void setCallbackCount(int64_t count) { - mCallbackCount = count; - } - - int32_t getFramesPerCallback() { - return mFramesPerCallback.load(); - } - - /** - * Called when the stream is ready to process audio. - */ - oboe::DataCallbackResult onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) override; - - /** - * Specify the amount of artificial workload that will waste CPU cycles - * and increase the CPU load. - * @param workload typically ranges from 0.0 to 100.0 - */ - void setWorkload(double workload) { - mWorkload = std::max(0.0, workload); - } - - double getWorkload() const { - return mWorkload; - } - - double getCpuLoad() const { - return mCpuLoad; - } - - static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC); - -private: - static constexpr int32_t kWorkloadScaler = 500; - double mWorkload = 0.0; - std::atomic mCpuLoad{0}; - - oboe::AudioStreamCallback *mCallback = nullptr; - static bool mCallbackReturnStop; - int64_t mCallbackCount = 0; - std::atomic mFramesPerCallback{0}; -}; - - -#endif //NATIVEOBOE_OBOESTREAMCALLBACKPROXY_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp deleted file mode 100644 index aab60abe..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 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. - */ - - -#include "AudioStreamGateway.h" -#include "oboe/Oboe.h" -#include "common/OboeDebug.h" -#include -#include -#include "OboeTesterStreamCallback.h" - -// Print if scheduler changes. -void OboeTesterStreamCallback::printScheduler() { -#if OBOE_ENABLE_LOGGING - int scheduler = sched_getscheduler(gettid()); - if (scheduler != mPreviousScheduler) { - int schedulerType = scheduler & 0xFFFF; // mask off high flags - LOGD("callback CPU scheduler = 0x%08x = %s", - scheduler, - ((schedulerType == SCHED_FIFO) ? "SCHED_FIFO" : - ((schedulerType == SCHED_OTHER) ? "SCHED_OTHER" : - ((schedulerType == SCHED_RR) ? "SCHED_RR" : "UNKNOWN"))) - ); - mPreviousScheduler = scheduler; - } -#endif -} \ No newline at end of file diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h deleted file mode 100644 index ec01fe5c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/OboeTesterStreamCallback.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020 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_STREAM_CALLBACK_H -#define OBOETESTER_STREAM_CALLBACK_H - -#include -#include -#include "flowgraph/FlowGraphNode.h" -#include "oboe/Oboe.h" - -class OboeTesterStreamCallback : public oboe::AudioStreamCallback { -public: - virtual ~OboeTesterStreamCallback() = default; - - // Call this before starting. - void reset() { - mPreviousScheduler = -1; - } - -protected: - void printScheduler(); - - int mPreviousScheduler = -1; -}; - - -#endif //OBOETESTER_STREAM_CALLBACK_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.cpp deleted file mode 100644 index f878306e..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#include "PlayRecordingCallback.h" - -/** - * Called when the stream is ready to process audio. - */ -oboe::DataCallbackResult PlayRecordingCallback::onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames) { - float *floatData = (float *)audioData; - // Read stored data into the buffer provided. - int32_t framesRead = mRecording->read(floatData, numFrames); - // LOGI("%s() framesRead = %d, numFrames = %d", __func__, framesRead, numFrames); - return framesRead > 0 - ? oboe::DataCallbackResult::Continue - : oboe::DataCallbackResult::Stop; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.h deleted file mode 100644 index 8ea49ea7..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/PlayRecordingCallback.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018 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 NATIVEOBOE_PLAY_RECORDING_CALLBACK_H -#define NATIVEOBOE_PLAY_RECORDING_CALLBACK_H - -#include "oboe/Oboe.h" - -#include "MultiChannelRecording.h" - -class PlayRecordingCallback : public oboe::AudioStreamCallback { -public: - PlayRecordingCallback() {} - ~PlayRecordingCallback() = default; - - void setRecording(MultiChannelRecording *recording) { - mRecording = recording; - } - - /** - * Called when the stream is ready to process audio. - */ - oboe::DataCallbackResult onAudioReady( - oboe::AudioStream *audioStream, - void *audioData, - int numFrames); - -private: - MultiChannelRecording *mRecording = nullptr; -}; - - -#endif //NATIVEOBOE_PLAYRECORDINGCALLBACK_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp deleted file mode 100644 index 3220df22..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2015 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. - */ - -#include -#include "common/OboeDebug.h" -#include "oboe/Definitions.h" -#include "SawPingGenerator.h" - -using namespace oboe::flowgraph; - -SawPingGenerator::SawPingGenerator() - : OscillatorBase() - , mRequestCount(0) - , mAcknowledgeCount(0) - , mLevel(0.0f) { -} - -SawPingGenerator::~SawPingGenerator() { } - -void SawPingGenerator::reset() { - FlowGraphNode::reset(); - mAcknowledgeCount.store(mRequestCount.load()); -} - -int32_t SawPingGenerator::onProcess(int numFrames) { - - const float *frequencies = frequency.getBuffer(); - const float *amplitudes = amplitude.getBuffer(); - float *buffer = output.getBuffer(); - - if (mRequestCount.load() > mAcknowledgeCount.load()) { - mPhase = -1.0f; - mLevel = 1.0; - mAcknowledgeCount++; - } - - // Check level to prevent numeric underflow. - if (mLevel > 0.000001) { - for (int i = 0; i < numFrames; i++) { - float sawtooth = incrementPhase(frequencies[i]); - *buffer++ = (float) (sawtooth * mLevel * amplitudes[i]); - mLevel *= 0.999; - } - } else { - for (int i = 0; i < numFrames; i++) { - *buffer++ = 0.0f; - } - } - - return numFrames; -} - -void SawPingGenerator::trigger() { - mRequestCount++; -} - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h deleted file mode 100644 index f1f5e5b3..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 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 NATIVEOBOE_SAWPINGGENERATOR_H -#define NATIVEOBOE_SAWPINGGENERATOR_H - -#include -#include -#include - -#include "flowgraph/FlowGraphNode.h" -#include "flowunits/OscillatorBase.h" - -class SawPingGenerator : public OscillatorBase { -public: - SawPingGenerator(); - - virtual ~SawPingGenerator(); - - int32_t onProcess(int numFrames) override; - - void trigger(); - - void reset() override; - -private: - std::atomic mRequestCount; // external thread increments this to request a beep - std::atomic mAcknowledgeCount; // audio thread sets this to acknowledge - double mLevel; -}; - - -#endif //NATIVEOBOE_SAWPINGGENERATOR_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h deleted file mode 100644 index 6601f19b..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/BaseSineAnalyzer.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2020 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 ANALYZER_BASE_SINE_ANALYZER_H -#define ANALYZER_BASE_SINE_ANALYZER_H - -#include -#include -#include -#include - -#include "InfiniteRecording.h" -#include "LatencyAnalyzer.h" - -/** - * Output a steady sine wave and analyze the return signal. - * - * Use a cosine transform to measure the predicted magnitude and relative phase of the - * looped back sine wave. Then generate a predicted signal and compare with the actual signal. - */ -class BaseSineAnalyzer : public LoopbackProcessor { -public: - - BaseSineAnalyzer() - : LoopbackProcessor() - , mInfiniteRecording(64 * 1024) {} - - - virtual bool isOutputEnabled() { return true; } - - void setMagnitude(double magnitude) { - mMagnitude = magnitude; - mScaledTolerance = mMagnitude * mTolerance; - } - - double getPhaseOffset() { - return mPhaseOffset; - } - - double getMagnitude() const { - return mMagnitude; - } - - void setInputChannel(int inputChannel) { - mInputChannel = inputChannel; - } - - int getInputChannel() const { - return mInputChannel; - } - - void setOutputChannel(int outputChannel) { - mOutputChannel = outputChannel; - } - - int getOutputChannel() const { - return mOutputChannel; - } - - void setNoiseAmplitude(double noiseAmplitude) { - mNoiseAmplitude = noiseAmplitude; - } - - double getNoiseAmplitude() const { - return mNoiseAmplitude; - } - - double getTolerance() { - return mTolerance; - } - - void setTolerance(double tolerance) { - mTolerance = tolerance; - } - - // advance and wrap phase - void incrementOutputPhase() { - mOutputPhase += mPhaseIncrement; - if (mOutputPhase > M_PI) { - mOutputPhase -= (2.0 * M_PI); - } - } - - /** - * @param frameData upon return, contains the reference sine wave - * @param channelCount - */ - result_code processOutputFrame(float *frameData, int channelCount) override { - float output = 0.0f; - // Output sine wave so we can measure it. - if (isOutputEnabled()) { - float sinOut = sinf(mOutputPhase); - incrementOutputPhase(); - output = (sinOut * mOutputAmplitude) - + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude); - // ALOGD("sin(%f) = %f, %f\n", mOutputPhase, sinOut, mPhaseIncrement); - } - for (int i = 0; i < channelCount; i++) { - frameData[i] = (i == mOutputChannel) ? output : 0.0f; - } - return RESULT_OK; - } - - /** - * Calculate the magnitude of the component of the input signal - * that matches the analysis frequency. - * Also calculate the phase that we can use to create a - * signal that matches that component. - * The phase will be between -PI and +PI. - */ - double calculateMagnitudePhase(double *phasePtr = nullptr) { - if (mFramesAccumulated == 0) { - return 0.0; - } - double sinMean = mSinAccumulator / mFramesAccumulated; - double cosMean = mCosAccumulator / mFramesAccumulated; - double magnitude = 2.0 * sqrt((sinMean * sinMean) + (cosMean * cosMean)); - if (phasePtr != nullptr) { - double phase = M_PI_2 - atan2(sinMean, cosMean); - *phasePtr = phase; - } - return magnitude; - } - - bool transformSample(float sample, float referencePhase) { - // Track incoming signal and slowly adjust magnitude to account - // for drift in the DRC or AGC. - mSinAccumulator += sample * sinf(referencePhase); - mCosAccumulator += sample * cosf(referencePhase); - mFramesAccumulated++; - // Must be a multiple of the period or the calculation will not be accurate. - if (mFramesAccumulated == mSinePeriod) { - const double coefficient = 0.1; - double magnitude = calculateMagnitudePhase(&mPhaseOffset); - // One pole averaging filter. - setMagnitude((mMagnitude * (1.0 - coefficient)) + (magnitude * coefficient)); - return true; - } else { - return false; - } - } - - // reset the sine wave detector - virtual void resetAccumulator() { - mFramesAccumulated = 0; - mSinAccumulator = 0.0; - mCosAccumulator = 0.0; - } - - void reset() override { - LoopbackProcessor::reset(); - resetAccumulator(); - } - - void prepareToTest() override { - LoopbackProcessor::prepareToTest(); - mSinePeriod = getSampleRate() / kTargetGlitchFrequency; - mOutputPhase = 0.0f; - mInverseSinePeriod = 1.0 / mSinePeriod; - mPhaseIncrement = 2.0 * M_PI * mInverseSinePeriod; - } - -protected: - static constexpr int32_t kTargetGlitchFrequency = 1000; - - int32_t mSinePeriod = 1; // this will be set before use - double mInverseSinePeriod = 1.0; - double mPhaseIncrement = 0.0; - double mOutputPhase = 0.0; - double mOutputAmplitude = 0.75; - // If this jumps around then we are probably just hearing noise. - double mPhaseOffset = 0.0; - double mMagnitude = 0.0; - int32_t mFramesAccumulated = 0; - double mSinAccumulator = 0.0; - double mCosAccumulator = 0.0; - double mScaledTolerance = 0.0; - - InfiniteRecording mInfiniteRecording; - -private: - int32_t mInputChannel = 0; - int32_t mOutputChannel = 0; - float mTolerance = 0.10; // scaled from 0.0 to 1.0 - - float mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC. - PseudoRandom mWhiteNoise; -}; - -#endif //ANALYZER_BASE_SINE_ANALYZER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h deleted file mode 100644 index 9d42be57..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/DataPathAnalyzer.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2020 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 ANALYZER_DATA_PATH_ANALYZER_H -#define ANALYZER_DATA_PATH_ANALYZER_H - -#include -#include -#include -#include -#include - -#include "BaseSineAnalyzer.h" -#include "InfiniteRecording.h" -#include "LatencyAnalyzer.h" - -/** - * Output a steady sine wave and analyze the return signal. - * - * Use a cosine transform to measure the predicted magnitude and relative phase of the - * looped back sine wave. - */ -class DataPathAnalyzer : public BaseSineAnalyzer { -public: - - DataPathAnalyzer() : BaseSineAnalyzer() { - // Add a little bit of noise to reduce blockage by speaker protection and DRC. - setNoiseAmplitude(0.05); - } - - /** - * @param frameData contains microphone data with sine signal feedback - * @param channelCount - */ - result_code processInputFrame(const float *frameData, int /* channelCount */) override { - result_code result = RESULT_OK; - - float sample = frameData[getInputChannel()]; - mInfiniteRecording.write(sample); - - if (transformSample(sample, mOutputPhase)) { - resetAccumulator(); - } - - // Update MaxMagnitude if we are locked. - double diff = abs(mPhaseOffset - mPreviousPhaseOffset); - if (diff < mPhaseTolerance) { - mMaxMagnitude = std::max(mMagnitude, mMaxMagnitude); - } - mPreviousPhaseOffset = mPhaseOffset; - return result; - } - - std::string analyze() override { - std::stringstream report; - report << "DataPathAnalyzer ------------------\n"; - report << LOOPBACK_RESULT_TAG "sine.magnitude = " << std::setw(8) - << mMagnitude << "\n"; - report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8) - << mFramesAccumulated << "\n"; - report << LOOPBACK_RESULT_TAG "sine.period = " << std::setw(8) - << mSinePeriod << "\n"; - return report.str(); - } - - void reset() override { - BaseSineAnalyzer::reset(); - mPreviousPhaseOffset = 999.0; // Arbitrary high offset to prevent early lock. - mMaxMagnitude = 0.0; - } - - double getMaxMagnitude() { - return mMaxMagnitude; - } - -private: - double mPreviousPhaseOffset = 0.0; - double mPhaseTolerance = 2 * M_PI / 48; - double mMaxMagnitude = 0.0; -}; -#endif // ANALYZER_DATA_PATH_ANALYZER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h deleted file mode 100644 index d005b9a9..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/GlitchAnalyzer.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) 2017 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 ANALYZER_GLITCH_ANALYZER_H -#define ANALYZER_GLITCH_ANALYZER_H - -#include -#include -#include -#include - -#include "InfiniteRecording.h" -#include "LatencyAnalyzer.h" -#include "BaseSineAnalyzer.h" -#include "PseudoRandom.h" - -/** - * Output a steady sine wave and analyze the return signal. - * - * Use a cosine transform to measure the predicted magnitude and relative phase of the - * looped back sine wave. Then generate a predicted signal and compare with the actual signal. - */ -class GlitchAnalyzer : public BaseSineAnalyzer { -public: - - GlitchAnalyzer() : BaseSineAnalyzer() {} - - int32_t getState() const { - return mState; - } - - double getPeakAmplitude() const { - return mPeakFollower.getLevel(); - } - - int32_t getGlitchCount() const { - return mGlitchCount; - } - - int32_t getStateFrameCount(int state) const { - return mStateFrameCounters[state]; - } - - double getSignalToNoiseDB() { - static const double threshold = 1.0e-14; - if (mMeanSquareSignal < threshold || mMeanSquareNoise < threshold) { - return 0.0; - } else { - double signalToNoise = mMeanSquareSignal / mMeanSquareNoise; // power ratio - double signalToNoiseDB = 10.0 * log(signalToNoise); - if (signalToNoiseDB < MIN_SNR_DB) { - ALOGD("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.", - MIN_SNR_DB); - setResult(ERROR_VOLUME_TOO_LOW); - } - return signalToNoiseDB; - } - } - - std::string analyze() override { - std::stringstream report; - report << "GlitchAnalyzer ------------------\n"; - report << LOOPBACK_RESULT_TAG "peak.amplitude = " << std::setw(8) - << getPeakAmplitude() << "\n"; - report << LOOPBACK_RESULT_TAG "sine.magnitude = " << std::setw(8) - << mMagnitude << "\n"; - report << LOOPBACK_RESULT_TAG "rms.noise = " << std::setw(8) - << mMeanSquareNoise << "\n"; - report << LOOPBACK_RESULT_TAG "signal.to.noise.db = " << std::setw(8) - << getSignalToNoiseDB() << "\n"; - report << LOOPBACK_RESULT_TAG "frames.accumulated = " << std::setw(8) - << mFramesAccumulated << "\n"; - report << LOOPBACK_RESULT_TAG "sine.period = " << std::setw(8) - << mSinePeriod << "\n"; - report << LOOPBACK_RESULT_TAG "test.state = " << std::setw(8) - << mState << "\n"; - report << LOOPBACK_RESULT_TAG "frame.count = " << std::setw(8) - << mFrameCounter << "\n"; - // Did we ever get a lock? - bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0); - if (!gotLock) { - report << "ERROR - failed to lock on reference sine tone.\n"; - setResult(ERROR_NO_LOCK); - } else { - // Only print if meaningful. - report << LOOPBACK_RESULT_TAG "glitch.count = " << std::setw(8) - << mGlitchCount << "\n"; - report << LOOPBACK_RESULT_TAG "max.glitch = " << std::setw(8) - << mMaxGlitchDelta << "\n"; - if (mGlitchCount > 0) { - report << "ERROR - number of glitches > 0\n"; - setResult(ERROR_GLITCHES); - } - } - return report.str(); - } - - void printStatus() override { - ALOGD("st = %d, #gl = %3d,", mState, mGlitchCount); - } - - /** - * @param frameData contains microphone data with sine signal feedback - * @param channelCount - */ - result_code processInputFrame(const float *frameData, int /* channelCount */) override { - result_code result = RESULT_OK; - - float sample = frameData[0]; - float peak = mPeakFollower.process(sample); - mInfiniteRecording.write(sample); - - // Force a periodic glitch to test the detector! - if (mForceGlitchDuration > 0) { - if (mForceGlitchCounter == 0) { - ALOGE("%s: force a glitch!!", __func__); - mForceGlitchCounter = getSampleRate(); - } else if (mForceGlitchCounter <= mForceGlitchDuration) { - // Force an abrupt offset. - sample += (sample > 0.0) ? -0.5f : 0.5f; - } - --mForceGlitchCounter; - } - - mStateFrameCounters[mState]++; // count how many frames we are in each state - - switch (mState) { - case STATE_IDLE: - mDownCounter--; - if (mDownCounter <= 0) { - mState = STATE_IMMUNE; - mDownCounter = IMMUNE_FRAME_COUNT; - mInputPhase = 0.0; // prevent spike at start - mOutputPhase = 0.0; - } - break; - - case STATE_IMMUNE: - mDownCounter--; - if (mDownCounter <= 0) { - mState = STATE_WAITING_FOR_SIGNAL; - } - break; - - case STATE_WAITING_FOR_SIGNAL: - if (peak > mThreshold) { - mState = STATE_WAITING_FOR_LOCK; - //ALOGD("%5d: switch to STATE_WAITING_FOR_LOCK", mFrameCounter); - resetAccumulator(); - } - break; - - case STATE_WAITING_FOR_LOCK: - mSinAccumulator += sample * sinf(mInputPhase); - mCosAccumulator += sample * cosf(mInputPhase); - mFramesAccumulated++; - // Must be a multiple of the period or the calculation will not be accurate. - if (mFramesAccumulated == mSinePeriod * PERIODS_NEEDED_FOR_LOCK) { - setMagnitude(calculateMagnitudePhase(&mPhaseOffset)); -// ALOGD("%s() mag = %f, offset = %f, prev = %f", -// __func__, mMagnitude, mPhaseOffset, mPreviousPhaseOffset); - if (mMagnitude > mThreshold) { - if (abs(mPhaseOffset) < kMaxPhaseError) { - mState = STATE_LOCKED; -// ALOGD("%5d: switch to STATE_LOCKED", mFrameCounter); - } - // Adjust mInputPhase to match measured phase - mInputPhase += mPhaseOffset; - } - resetAccumulator(); - } - incrementInputPhase(); - break; - - case STATE_LOCKED: { - // Predict next sine value - double predicted = sinf(mInputPhase) * mMagnitude; - double diff = predicted - sample; - double absDiff = fabs(diff); - mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff); - if (absDiff > mScaledTolerance) { - result = ERROR_GLITCHES; - onGlitchStart(); -// LOGI("diff glitch detected, absDiff = %g", absDiff); - } else { - mSumSquareSignal += predicted * predicted; - mSumSquareNoise += diff * diff; - - - // Track incoming signal and slowly adjust magnitude to account - // for drift in the DRC or AGC. - // Must be a multiple of the period or the calculation will not be accurate. - if (transformSample(sample, mInputPhase)) { - mMeanSquareNoise = mSumSquareNoise * mInverseSinePeriod; - mMeanSquareSignal = mSumSquareSignal * mInverseSinePeriod; - resetAccumulator(); - - if (abs(mPhaseOffset) > kMaxPhaseError) { - result = ERROR_GLITCHES; - onGlitchStart(); - ALOGD("phase glitch detected, phaseOffset = %g", mPhaseOffset); - } else if (mMagnitude < mThreshold) { - result = ERROR_GLITCHES; - onGlitchStart(); - ALOGD("magnitude glitch detected, mMagnitude = %g", mMagnitude); - } - } - } - incrementInputPhase(); - } break; - - case STATE_GLITCHING: { - // Predict next sine value - mGlitchLength++; - double predicted = sinf(mInputPhase) * mMagnitude; - double diff = predicted - sample; - double absDiff = fabs(diff); - mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff); - if (absDiff < mScaledTolerance) { // close enough? - // If we get a full sine period of non-glitch samples in a row then consider the glitch over. - // We don't want to just consider a zero crossing the end of a glitch. - if (mNonGlitchCount++ > mSinePeriod) { - onGlitchEnd(); - } - } else { - mNonGlitchCount = 0; - if (mGlitchLength > (4 * mSinePeriod)) { - relock(); - } - } - incrementInputPhase(); - } break; - - case NUM_STATES: // not a real state - break; - } - - mFrameCounter++; - - return result; - } - - // advance and wrap phase - void incrementInputPhase() { - mInputPhase += mPhaseIncrement; - if (mInputPhase > M_PI) { - mInputPhase -= (2.0 * M_PI); - } - } - - bool isOutputEnabled() override { return mState != STATE_IDLE; } - - void onGlitchStart() { - mGlitchCount++; -// ALOGD("%5d: STARTED a glitch # %d", mFrameCounter, mGlitchCount); - mState = STATE_GLITCHING; - mGlitchLength = 1; - mNonGlitchCount = 0; - mLastGlitchPosition = mInfiniteRecording.getTotalWritten(); - } - - void onGlitchEnd() { -// ALOGD("%5d: ENDED a glitch # %d, length = %d", mFrameCounter, mGlitchCount, mGlitchLength); - mState = STATE_LOCKED; - resetAccumulator(); - } - - // reset the sine wave detector - void resetAccumulator() override { - BaseSineAnalyzer::resetAccumulator(); - mSumSquareSignal = 0.0; - mSumSquareNoise = 0.0; - } - - void relock() { -// ALOGD("relock: %d because of a very long %d glitch", mFrameCounter, mGlitchLength); - mState = STATE_WAITING_FOR_LOCK; - resetAccumulator(); - } - - void reset() override { - BaseSineAnalyzer::reset(); - mState = STATE_IDLE; - mDownCounter = IDLE_FRAME_COUNT; - } - - void prepareToTest() override { - BaseSineAnalyzer::prepareToTest(); - mGlitchCount = 0; - mMaxGlitchDelta = 0.0; - for (int i = 0; i < NUM_STATES; i++) { - mStateFrameCounters[i] = 0; - } - } - - int32_t getLastGlitch(float *buffer, int32_t length) { - return mInfiniteRecording.readFrom(buffer, mLastGlitchPosition - 32, length); - } - -private: - - // These must match the values in GlitchActivity.java - enum sine_state_t { - STATE_IDLE, // beginning - STATE_IMMUNE, // ignoring input, waiting fo HW to settle - STATE_WAITING_FOR_SIGNAL, // looking for a loud signal - STATE_WAITING_FOR_LOCK, // trying to lock onto the phase of the sine - STATE_LOCKED, // locked on the sine wave, looking for glitches - STATE_GLITCHING, // locked on the sine wave but glitching - NUM_STATES - }; - - enum constants { - // Arbitrary durations, assuming 48000 Hz - IDLE_FRAME_COUNT = 48 * 100, - IMMUNE_FRAME_COUNT = 48 * 100, - PERIODS_NEEDED_FOR_LOCK = 8, - MIN_SNR_DB = 65 - }; - - static constexpr double kMaxPhaseError = M_PI * 0.05; - - double mThreshold = 0.005; - - int32_t mStateFrameCounters[NUM_STATES]; - sine_state_t mState = STATE_IDLE; - int64_t mLastGlitchPosition; - - double mInputPhase = 0.0; - double mMaxGlitchDelta = 0.0; - int32_t mGlitchCount = 0; - int32_t mNonGlitchCount = 0; - int32_t mGlitchLength = 0; - int mDownCounter = IDLE_FRAME_COUNT; - int32_t mFrameCounter = 0; - - int32_t mForceGlitchDuration = 0; // if > 0 then force a glitch for debugging - int32_t mForceGlitchCounter = 4 * 48000; // count down and trigger at zero - - // measure background noise continuously as a deviation from the expected signal - double mSumSquareSignal = 0.0; - double mSumSquareNoise = 0.0; - double mMeanSquareSignal = 0.0; - double mMeanSquareNoise = 0.0; - - PeakDetector mPeakFollower; -}; - - -#endif //ANALYZER_GLITCH_ANALYZER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/InfiniteRecording.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/InfiniteRecording.h deleted file mode 100644 index c02c0025..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/InfiniteRecording.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2019 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_INFINITE_RECORDING_H -#define OBOETESTER_INFINITE_RECORDING_H - -#include -#include - -/** - * Record forever. Keep last data. - */ -template -class InfiniteRecording { -public: - InfiniteRecording(size_t maxSamples) - : mMaxSamples(maxSamples) { - mData = std::make_unique(mMaxSamples); - } - - int32_t readFrom(T *buffer, size_t position, size_t count) { - const size_t maxPosition = mWritten.load(); - position = std::min(position, maxPosition); - size_t numToRead = std::min(count, mMaxSamples); - numToRead = std::min(numToRead, maxPosition - position); - if (numToRead == 0) return 0; - // We may need to read in two parts if it wraps. - const size_t offset = position % mMaxSamples; - const size_t firstReadSize = std::min(numToRead, mMaxSamples - offset); // till end - std::copy(&mData[offset], &mData[offset + firstReadSize], buffer); - if (firstReadSize < numToRead) { - // Second read needed. - std::copy(&mData[0], &mData[numToRead - firstReadSize], &buffer[firstReadSize]); - } - return numToRead; - } - - void write(T sample) { - const size_t position = mWritten.load(); - const size_t offset = position % mMaxSamples; - mData[offset] = sample; - mWritten++; - } - - int64_t getTotalWritten() { - return mWritten.load(); - } - -private: - std::unique_ptr mData; - std::atomic mWritten{0}; - const size_t mMaxSamples; -}; -#endif //OBOETESTER_INFINITE_RECORDING_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h deleted file mode 100644 index 45169794..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/LatencyAnalyzer.h +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -/** - * Tools for measuring latency and for detecting glitches. - * These classes are pure math and can be used with any audio system. - */ - -#ifndef ANALYZER_LATENCY_ANALYZER_H -#define ANALYZER_LATENCY_ANALYZER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PeakDetector.h" -#include "PseudoRandom.h" -#include "RandomPulseGenerator.h" - -// This is used when the code is in Oboe. -#ifndef ALOGD -#define ALOGD LOGD -#define ALOGE LOGE -#define ALOGW LOGW -#endif - -#define LOOPBACK_RESULT_TAG "RESULT: " - -static constexpr int32_t kDefaultSampleRate = 48000; -static constexpr int32_t kMillisPerSecond = 1000; // by definition -static constexpr int32_t kMaxLatencyMillis = 1000; // arbitrary and generous -static constexpr double kMinimumConfidence = 0.2; - -struct LatencyReport { - int32_t latencyInFrames = 0.0; - double confidence = 0.0; - - void reset() { - latencyInFrames = 0; - confidence = 0.0; - } -}; - -// Calculate a normalized cross correlation. -static double calculateNormalizedCorrelation(const float *a, - const float *b, - int windowSize) { - double correlation = 0.0; - double sumProducts = 0.0; - double sumSquares = 0.0; - - // Correlate a against b. - for (int i = 0; i < windowSize; i++) { - float s1 = a[i]; - float s2 = b[i]; - // Use a normalized cross-correlation. - sumProducts += s1 * s2; - sumSquares += ((s1 * s1) + (s2 * s2)); - } - - if (sumSquares >= 1.0e-9) { - correlation = 2.0 * sumProducts / sumSquares; - } - return correlation; -} - -static double calculateRootMeanSquare(float *data, int32_t numSamples) { - double sum = 0.0; - for (int32_t i = 0; i < numSamples; i++) { - float sample = data[i]; - sum += sample * sample; - } - return sqrt(sum / numSamples); -} - -/** - * Monophonic recording with processing. - */ -class AudioRecording -{ -public: - - void allocate(int maxFrames) { - mData = std::make_unique(maxFrames); - mMaxFrames = maxFrames; - } - - // Write SHORT data from the first channel. - int32_t write(const int16_t *inputData, int32_t inputChannelCount, int32_t numFrames) { - // stop at end of buffer - if ((mFrameCounter + numFrames) > mMaxFrames) { - numFrames = mMaxFrames - mFrameCounter; - } - for (int i = 0; i < numFrames; i++) { - mData[mFrameCounter++] = inputData[i * inputChannelCount] * (1.0f / 32768); - } - return numFrames; - } - - // Write FLOAT data from the first channel. - int32_t write(const float *inputData, int32_t inputChannelCount, int32_t numFrames) { - // stop at end of buffer - if ((mFrameCounter + numFrames) > mMaxFrames) { - numFrames = mMaxFrames - mFrameCounter; - } - for (int i = 0; i < numFrames; i++) { - mData[mFrameCounter++] = inputData[i * inputChannelCount]; - } - return numFrames; - } - - // Write FLOAT data from the first channel. - int32_t write(float sample) { - // stop at end of buffer - if (mFrameCounter < mMaxFrames) { - mData[mFrameCounter++] = sample; - return 1; - } - return 0; - } - - void clear() { - mFrameCounter = 0; - } - int32_t size() const { - return mFrameCounter; - } - - bool isFull() const { - return mFrameCounter >= mMaxFrames; - } - - float *getData() const { - return mData.get(); - } - - void setSampleRate(int32_t sampleRate) { - mSampleRate = sampleRate; - } - - int32_t getSampleRate() const { - return mSampleRate; - } - - /** - * Square the samples so they are all positive and so the peaks are emphasized. - */ - void square() { - float *x = mData.get(); - for (int i = 0; i < mFrameCounter; i++) { - x[i] *= x[i]; - } - } - - /** - * Amplify a signal so that the peak matches the specified target. - * - * @param target final max value - * @return gain applied to signal - */ - float normalize(float target) { - float maxValue = 1.0e-9f; - for (int i = 0; i < mFrameCounter; i++) { - maxValue = std::max(maxValue, abs(mData[i])); - } - float gain = target / maxValue; - for (int i = 0; i < mFrameCounter; i++) { - mData[i] *= gain; - } - return gain; - } - -private: - std::unique_ptr mData; - int32_t mFrameCounter = 0; - int32_t mMaxFrames = 0; - int32_t mSampleRate = kDefaultSampleRate; // common default -}; - -static int measureLatencyFromPulse(AudioRecording &recorded, - AudioRecording &pulse, - LatencyReport *report) { - - report->latencyInFrames = 0; - report->confidence = 0.0; - - int numCorrelations = recorded.size() - pulse.size(); - if (numCorrelations < 10) { - ALOGE("%s() recording too small = %d frames\n", __func__, recorded.size()); - return -1; - } - std::unique_ptr correlations= std::make_unique(numCorrelations); - - // Correlate pulse against the recorded data. - for (int i = 0; i < numCorrelations; i++) { - float correlation = (float) calculateNormalizedCorrelation(&recorded.getData()[i], - &pulse.getData()[0], - pulse.size()); - correlations[i] = correlation; - } - - // Find highest peak in correlation array. - float peakCorrelation = 0.0; - int peakIndex = -1; - for (int i = 0; i < numCorrelations; i++) { - float value = abs(correlations[i]); - if (value > peakCorrelation) { - peakCorrelation = value; - peakIndex = i; - } - } - if (peakIndex < 0) { - ALOGE("%s() no signal for correlation\n", __func__); - return -2; - } -#if 0 - // Dump correlation data for charting. - else { - const int margin = 50; - int startIndex = std::max(0, peakIndex - margin); - int endIndex = std::min(numCorrelations - 1, peakIndex + margin); - for (int index = startIndex; index < endIndex; index++) { - ALOGD("Correlation, %d, %f", index, correlations[index]); - } - } -#endif - - report->latencyInFrames = peakIndex; - report->confidence = peakCorrelation; - - return 0; -} - -// ==================================================================================== -class LoopbackProcessor { -public: - virtual ~LoopbackProcessor() = default; - - enum result_code { - RESULT_OK = 0, - ERROR_NOISY = -99, - ERROR_VOLUME_TOO_LOW, - ERROR_VOLUME_TOO_HIGH, - ERROR_CONFIDENCE, - ERROR_INVALID_STATE, - ERROR_GLITCHES, - ERROR_NO_LOCK - }; - - virtual void prepareToTest() { - reset(); - } - - virtual void reset() { - mResult = 0; - mResetCount++; - } - - virtual result_code processInputFrame(const float *frameData, int channelCount) = 0; - virtual result_code processOutputFrame(float *frameData, int channelCount) = 0; - - void process(const float *inputData, int inputChannelCount, int numInputFrames, - float *outputData, int outputChannelCount, int numOutputFrames) { - int numBoth = std::min(numInputFrames, numOutputFrames); - // Process one frame at a time. - for (int i = 0; i < numBoth; i++) { - processInputFrame(inputData, inputChannelCount); - inputData += inputChannelCount; - processOutputFrame(outputData, outputChannelCount); - outputData += outputChannelCount; - } - // If there is more input than output. - for (int i = numBoth; i < numInputFrames; i++) { - processInputFrame(inputData, inputChannelCount); - inputData += inputChannelCount; - } - // If there is more output than input. - for (int i = numBoth; i < numOutputFrames; i++) { - processOutputFrame(outputData, outputChannelCount); - outputData += outputChannelCount; - } - } - - virtual std::string analyze() = 0; - - virtual void printStatus() {}; - - int32_t getResult() { - return mResult; - } - - void setResult(int32_t result) { - mResult = result; - } - - virtual bool isDone() { - return false; - } - - virtual int save(const char *fileName) { - (void) fileName; - return -1; - } - - virtual int load(const char *fileName) { - (void) fileName; - return -1; - } - - virtual void setSampleRate(int32_t sampleRate) { - mSampleRate = sampleRate; - } - - int32_t getSampleRate() const { - return mSampleRate; - } - - int32_t getResetCount() const { - return mResetCount; - } - - /** Called when not enough input frames could be read after synchronization. - */ - virtual void onInsufficientRead() { - reset(); - } - -protected: - int32_t mResetCount = 0; - -private: - int32_t mSampleRate = kDefaultSampleRate; - int32_t mResult = 0; -}; - -class LatencyAnalyzer : public LoopbackProcessor { -public: - - LatencyAnalyzer() : LoopbackProcessor() {} - virtual ~LatencyAnalyzer() = default; - - virtual int32_t getProgress() const = 0; - - virtual int getState() = 0; - - // @return latency in frames - virtual int32_t getMeasuredLatency() = 0; - - virtual double getMeasuredConfidence() = 0; - - virtual double getBackgroundRMS() = 0; - - virtual double getSignalRMS() = 0; - -}; - -// ==================================================================================== -/** - * Measure latency given a loopback stream data. - * Use an encoded bit train as the sound source because it - * has an unambiguous correlation value. - * Uses a state machine to cycle through various stages. - * - */ -class PulseLatencyAnalyzer : public LatencyAnalyzer { -public: - - PulseLatencyAnalyzer() : LatencyAnalyzer() { - int32_t maxLatencyFrames = getSampleRate() * kMaxLatencyMillis / kMillisPerSecond; - int32_t numPulseBits = getSampleRate() * kPulseLengthMillis - / (kFramesPerEncodedBit * kMillisPerSecond); - int32_t pulseLength = numPulseBits * kFramesPerEncodedBit; - mFramesToRecord = pulseLength + maxLatencyFrames; - mAudioRecording.allocate(mFramesToRecord); - mAudioRecording.setSampleRate(getSampleRate()); - generateRandomPulse(pulseLength); - } - - void generateRandomPulse(int32_t pulseLength) { - mPulse.allocate(pulseLength); - RandomPulseGenerator pulser(kFramesPerEncodedBit); - for (int i = 0; i < pulseLength; i++) { - mPulse.write(pulser.nextFloat()); - } - } - - int getState() override { - return mState; - } - - void setSampleRate(int32_t sampleRate) override { - LoopbackProcessor::setSampleRate(sampleRate); - mAudioRecording.setSampleRate(sampleRate); - } - - void reset() override { - LoopbackProcessor::reset(); - mState = STATE_MEASURE_BACKGROUND; - mDownCounter = (int32_t) (getSampleRate() * kBackgroundMeasurementLengthSeconds); - mLoopCounter = 0; - - mPulseCursor = 0; - mBackgroundSumSquare = 0.0f; - mBackgroundSumCount = 0; - mBackgroundRMS = 0.0f; - mSignalRMS = 0.0f; - - mAudioRecording.clear(); - mLatencyReport.reset(); - } - - bool hasEnoughData() { - return mAudioRecording.isFull(); - } - - bool isDone() override { - return mState == STATE_DONE; - } - - int32_t getProgress() const override { - return mAudioRecording.size(); - } - - std::string analyze() override { - std::stringstream report; - report << "PulseLatencyAnalyzer ---------------\n"; - report << LOOPBACK_RESULT_TAG "test.state = " - << std::setw(8) << mState << "\n"; - report << LOOPBACK_RESULT_TAG "test.state.name = " - << convertStateToText(mState) << "\n"; - report << LOOPBACK_RESULT_TAG "background.rms = " - << std::setw(8) << mBackgroundRMS << "\n"; - - int32_t newResult = RESULT_OK; - if (mState != STATE_GOT_DATA) { - report << "WARNING - Bad state. Check volume on device.\n"; - // setResult(ERROR_INVALID_STATE); - } else { - float gain = mAudioRecording.normalize(1.0f); - measureLatencyFromPulse(mAudioRecording, - mPulse, - &mLatencyReport); - - if (mLatencyReport.confidence < kMinimumConfidence) { - report << " ERROR - confidence too low!"; - newResult = ERROR_CONFIDENCE; - } else { - mSignalRMS = calculateRootMeanSquare( - &mAudioRecording.getData()[mLatencyReport.latencyInFrames], mPulse.size()) - / gain; - } - double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames - / getSampleRate(); - report << LOOPBACK_RESULT_TAG "latency.frames = " << std::setw(8) - << mLatencyReport.latencyInFrames << "\n"; - report << LOOPBACK_RESULT_TAG "latency.msec = " << std::setw(8) - << latencyMillis << "\n"; - report << LOOPBACK_RESULT_TAG "latency.confidence = " << std::setw(8) - << mLatencyReport.confidence << "\n"; - } - mState = STATE_DONE; - if (getResult() == RESULT_OK) { - setResult(newResult); - } - - return report.str(); - } - - int32_t getMeasuredLatency() override { - return mLatencyReport.latencyInFrames; - } - - double getMeasuredConfidence() override { - return mLatencyReport.confidence; - } - - double getBackgroundRMS() override { - return mBackgroundRMS; - } - - double getSignalRMS() override { - return mSignalRMS; - } - - bool isRecordingComplete() { - return mState == STATE_GOT_DATA; - } - - void printStatus() override { - ALOGD("latency: st = %d = %s", mState, convertStateToText(mState)); - } - - result_code processInputFrame(const float *frameData, int channelCount) override { - echo_state nextState = mState; - mLoopCounter++; - - switch (mState) { - case STATE_MEASURE_BACKGROUND: - // Measure background RMS on channel 0 - mBackgroundSumSquare += frameData[0] * frameData[0]; - mBackgroundSumCount++; - mDownCounter--; - if (mDownCounter <= 0) { - mBackgroundRMS = sqrtf(mBackgroundSumSquare / mBackgroundSumCount); - nextState = STATE_IN_PULSE; - mPulseCursor = 0; - } - break; - - case STATE_IN_PULSE: - // Record input until the mAudioRecording is full. - mAudioRecording.write(frameData, channelCount, 1); - if (hasEnoughData()) { - nextState = STATE_GOT_DATA; - } - break; - - case STATE_GOT_DATA: - case STATE_DONE: - default: - break; - } - - mState = nextState; - return RESULT_OK; - } - - result_code processOutputFrame(float *frameData, int channelCount) override { - switch (mState) { - case STATE_IN_PULSE: - if (mPulseCursor < mPulse.size()) { - float pulseSample = mPulse.getData()[mPulseCursor++]; - for (int i = 0; i < channelCount; i++) { - frameData[i] = pulseSample; - } - } else { - for (int i = 0; i < channelCount; i++) { - frameData[i] = 0; - } - } - break; - - case STATE_MEASURE_BACKGROUND: - case STATE_GOT_DATA: - case STATE_DONE: - default: - for (int i = 0; i < channelCount; i++) { - frameData[i] = 0.0f; // silence - } - break; - } - - return RESULT_OK; - } - -private: - - enum echo_state { - STATE_MEASURE_BACKGROUND, - STATE_IN_PULSE, - STATE_GOT_DATA, // must match RoundTripLatencyActivity.java - STATE_DONE, - }; - - const char *convertStateToText(echo_state state) { - switch (state) { - case STATE_MEASURE_BACKGROUND: - return "INIT"; - case STATE_IN_PULSE: - return "PULSE"; - case STATE_GOT_DATA: - return "GOT_DATA"; - case STATE_DONE: - return "DONE"; - } - return "UNKNOWN"; - } - - int32_t mDownCounter = 500; - int32_t mLoopCounter = 0; - echo_state mState = STATE_MEASURE_BACKGROUND; - - static constexpr int32_t kFramesPerEncodedBit = 8; // multiple of 2 - static constexpr int32_t kPulseLengthMillis = 500; - static constexpr double kBackgroundMeasurementLengthSeconds = 0.5; - - AudioRecording mPulse; - int32_t mPulseCursor = 0; - - double mBackgroundSumSquare = 0.0; - int32_t mBackgroundSumCount = 0; - double mBackgroundRMS = 0.0; - double mSignalRMS = 0.0; - int32_t mFramesToRecord = 0; - - AudioRecording mAudioRecording; // contains only the input after starting the pulse - LatencyReport mLatencyReport; -}; - -#endif // ANALYZER_LATENCY_ANALYZER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/ManchesterEncoder.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/ManchesterEncoder.h deleted file mode 100644 index 0a4bd5b2..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/ManchesterEncoder.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2019 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 ANALYZER_MANCHESTER_ENCODER_H -#define ANALYZER_MANCHESTER_ENCODER_H - -#include - -/** - * Encode bytes using Manchester Coding scheme. - * - * Manchester Code is self clocking. - * There is a transition in the middle of every bit. - * Zero is high then low. - * One is low then high. - * - * This avoids having long DC sections that would droop when - * passed though analog circuits with AC coupling. - * - * IEEE 802.3 compatible. - */ - -class ManchesterEncoder { -public: - ManchesterEncoder(int samplesPerPulse) - : mSamplesPerPulse(samplesPerPulse) - , mSamplesPerPulseHalf(samplesPerPulse / 2) - , mCursor(samplesPerPulse) { - } - - virtual ~ManchesterEncoder() = default; - - /** - * This will be called when the next byte is needed. - * @return - */ - virtual uint8_t onNextByte() = 0; - - /** - * Generate the next floating point sample. - * @return - */ - virtual float nextFloat() { - advanceSample(); - if (mCurrentBit) { - return (mCursor < mSamplesPerPulseHalf) ? -1.0f : 1.0f; // one - } else { - return (mCursor < mSamplesPerPulseHalf) ? 1.0f : -1.0f; // zero - } - } - -protected: - /** - * This will be called when a new bit is ready to be encoded. - * It can be used to prepare the encoded samples. - * @param current - */ - virtual void onNextBit(bool /* current */) {}; - - void advanceSample() { - // Are we ready for a new bit? - if (++mCursor >= mSamplesPerPulse) { - mCursor = 0; - if (mBitsLeft == 0) { - mCurrentByte = onNextByte(); - mBitsLeft = 8; - } - --mBitsLeft; - mCurrentBit = (mCurrentByte >> mBitsLeft) & 1; - onNextBit(mCurrentBit); - } - } - - bool getCurrentBit() { - return mCurrentBit; - } - - const int mSamplesPerPulse; - const int mSamplesPerPulseHalf; - int mCursor; - int mBitsLeft = 0; - uint8_t mCurrentByte = 0; - bool mCurrentBit = false; -}; -#endif //ANALYZER_MANCHESTER_ENCODER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PeakDetector.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PeakDetector.h deleted file mode 100644 index 4b3b4e71..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PeakDetector.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 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 ANALYZER_PEAK_DETECTOR_H -#define ANALYZER_PEAK_DETECTOR_H - -#include - -/** - * Measure a peak envelope by rising with the peaks, - * and decaying exponentially after each peak. - * The absolute value of the input signal is used. - */ -class PeakDetector { -public: - - void reset() { - mLevel = 0.0; - } - - double process(double input) { - mLevel *= mDecay; // exponential decay - input = fabs(input); - // never fall below the input signal - if (input > mLevel) { - mLevel = input; - } - return mLevel; - } - - double getLevel() const { - return mLevel; - } - - double getDecay() const { - return mDecay; - } - - /** - * Multiply the level by this amount on every iteration. - * This provides an exponential decay curve. - * A value just under 1.0 is best, for example, 0.99; - * @param decay scale level for each input - */ - void setDecay(double decay) { - mDecay = decay; - } - -private: - static constexpr double kDefaultDecay = 0.99f; - - double mLevel = 0.0; - double mDecay = kDefaultDecay; -}; -#endif //ANALYZER_PEAK_DETECTOR_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PseudoRandom.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PseudoRandom.h deleted file mode 100644 index 1c4938cb..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/PseudoRandom.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2017 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 ANALYZER_PSEUDORANDOM_H -#define ANALYZER_PSEUDORANDOM_H - -#include - -class PseudoRandom { -public: - PseudoRandom(int64_t seed = 99887766) - : mSeed(seed) - {} - - /** - * Returns the next random double from -1.0 to 1.0 - * - * @return value from -1.0 to 1.0 - */ - double nextRandomDouble() { - return nextRandomInteger() * (0.5 / (((int32_t)1) << 30)); - } - - /** Calculate random 32 bit number using linear-congruential method - * with known real-time performance. - */ - int32_t nextRandomInteger() { -#if __has_builtin(__builtin_mul_overflow) && __has_builtin(__builtin_add_overflow) - int64_t prod; - // Use values for 64-bit sequence from MMIX by Donald Knuth. - __builtin_mul_overflow(mSeed, (int64_t)6364136223846793005, &prod); - __builtin_add_overflow(prod, (int64_t)1442695040888963407, &mSeed); -#else - mSeed = (mSeed * (int64_t)6364136223846793005) + (int64_t)1442695040888963407; -#endif - return (int32_t) (mSeed >> 32); // The higher bits have a longer sequence. - } - -private: - int64_t mSeed; -}; - -#endif //ANALYZER_PSEUDORANDOM_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RandomPulseGenerator.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RandomPulseGenerator.h deleted file mode 100644 index 030050b4..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RandomPulseGenerator.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 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 ANALYZER_RANDOM_PULSE_GENERATOR_H -#define ANALYZER_RANDOM_PULSE_GENERATOR_H - -#include -#include "RoundedManchesterEncoder.h" - -/** - * Encode random ones and zeros using Manchester Code per IEEE 802.3. - */ -class RandomPulseGenerator : public RoundedManchesterEncoder { -public: - RandomPulseGenerator(int samplesPerPulse) - : RoundedManchesterEncoder(samplesPerPulse) { - } - - virtual ~RandomPulseGenerator() = default; - - /** - * This will be called when the next byte is needed. - * @return random byte - */ - uint8_t onNextByte() override { - return static_cast(rand()); - } -}; - -#endif //ANALYZER_RANDOM_PULSE_GENERATOR_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RoundedManchesterEncoder.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RoundedManchesterEncoder.h deleted file mode 100644 index f2eba840..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/analyzer/RoundedManchesterEncoder.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2019 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 ANALYZER_ROUNDED_MANCHESTER_ENCODER_H -#define ANALYZER_ROUNDED_MANCHESTER_ENCODER_H - -#include -#include -#include -#include "ManchesterEncoder.h" - -/** - * Encode bytes using Manchester Code. - * Round the edges using a half cosine to reduce ringing caused by a hard edge. - */ - -class RoundedManchesterEncoder : public ManchesterEncoder { -public: - RoundedManchesterEncoder(int samplesPerPulse) - : ManchesterEncoder(samplesPerPulse) { - int rampSize = samplesPerPulse / 4; - mZeroAfterZero = std::make_unique(samplesPerPulse); - mZeroAfterOne = std::make_unique(samplesPerPulse); - - int sampleIndex = 0; - for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) { - float phase = (rampIndex + 1) * M_PI / rampSize; - float sample = -cosf(phase); - mZeroAfterZero[sampleIndex] = sample; - mZeroAfterOne[sampleIndex] = 1.0f; - sampleIndex++; - } - for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) { - mZeroAfterZero[sampleIndex] = 1.0f; - mZeroAfterOne[sampleIndex] = 1.0f; - sampleIndex++; - } - for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) { - float phase = (rampIndex + 1) * M_PI / rampSize; - float sample = cosf(phase); - mZeroAfterZero[sampleIndex] = sample; - mZeroAfterOne[sampleIndex] = sample; - sampleIndex++; - } - for (int rampIndex = 0; rampIndex < rampSize; rampIndex++) { - mZeroAfterZero[sampleIndex] = -1.0f; - mZeroAfterOne[sampleIndex] = -1.0f; - sampleIndex++; - } - } - - void onNextBit(bool current) override { - // Do we need to use the rounded edge? - mCurrentSamples = (current ^ mPreviousBit) - ? mZeroAfterOne.get() - : mZeroAfterZero.get(); - mPreviousBit = current; - } - - float nextFloat() override { - advanceSample(); - float output = mCurrentSamples[mCursor]; - if (getCurrentBit()) output = -output; - return output; - } - -private: - - bool mPreviousBit = false; - float *mCurrentSamples = nullptr; - std::unique_ptr mZeroAfterZero; - std::unique_ptr mZeroAfterOne; -}; - -#endif //ANALYZER_ROUNDED_MANCHESTER_ENCODER_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/android_debug.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/android_debug.h deleted file mode 100644 index ff8687a6..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/android_debug.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2015 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 NATIVE_AUDIO_ANDROID_DEBUG_H_H -#define NATIVE_AUDIO_ANDROID_DEBUG_H_H -#include - -#if 1 - -#define MODULE_NAME "OboeAudio" -#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, MODULE_NAME, __VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, MODULE_NAME, __VA_ARGS__) -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, MODULE_NAME, __VA_ARGS__) -#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, MODULE_NAME, __VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, MODULE_NAME, __VA_ARGS__) -#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, MODULE_NAME, __VA_ARGS__) - -#else - -#define LOGV(...) -#define LOGD(...) -#define LOGI(...) -#define LOGW(...) -#define LOGE(...) -#define LOGF(...) -#endif - -#endif //NATIVE_AUDIO_ANDROID_DEBUG_H_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp deleted file mode 100644 index 4614306a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#include - -#include "ExponentialShape.h" - -ExponentialShape::ExponentialShape() - : FlowGraphFilter(1) { -} - -int32_t ExponentialShape::onProcess(int32_t numFrames) { - float *inputs = input.getBuffer(); - float *outputs = output.getBuffer(); - - for (int i = 0; i < numFrames; i++) { - float normalizedPhase = (inputs[i] * 0.5) + 0.5; - outputs[i] = mMinimum * powf(mRatio, normalizedPhase); - } - - return numFrames; -} \ No newline at end of file diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.h deleted file mode 100644 index 4c28e519..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ExponentialShape.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2019 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_EXPONENTIAL_SHAPE_H -#define OBOETESTER_EXPONENTIAL_SHAPE_H - -#include "flowgraph/FlowGraphNode.h" - -/** - * Generate a exponential sweep between min and max. - * - * The waveform is not band-limited so it will have aliasing artifacts at higher frequencies. - */ -class ExponentialShape : public oboe::flowgraph::FlowGraphFilter { -public: - ExponentialShape(); - - int32_t onProcess(int32_t numFrames) override; - - float getMinimum() const { - return mMinimum; - } - - /** - * The minimum and maximum should not span zero. - * They should both be positive or both negative. - * - * @param minimum - */ - void setMinimum(float minimum) { - mMinimum = minimum; - mRatio = mMaximum / mMinimum; - } - - float getMaximum() const { - return mMaximum; - } - - /** - * The minimum and maximum should not span zero. - * They should both be positive or both negative. - * - * @param maximum - */ - void setMaximum(float maximum) { - mMaximum = maximum; - mRatio = mMaximum / mMinimum; - } - -private: -float mMinimum = 0.0; -float mMaximum = 1.0; -float mRatio = 1.0; -}; - -#endif //OBOETESTER_EXPONENTIAL_SHAPE_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ImpulseOscillator.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ImpulseOscillator.cpp deleted file mode 100644 index 60cf31d8..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/ImpulseOscillator.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#include -#include - -#include "ImpulseOscillator.h" - -ImpulseOscillator::ImpulseOscillator() - : OscillatorBase() { -} - -int32_t ImpulseOscillator::onProcess(int32_t numFrames) { - const float *frequencies = frequency.getBuffer(); - const float *amplitudes = amplitude.getBuffer(); - float *buffer = output.getBuffer(); - - for (int i = 0; i < numFrames; i++) { - float value = 0.0f; - mPhase += mFrequencyToPhaseIncrement * frequencies[i]; - if (mPhase >= 1.0f) { - value = amplitudes[i]; // spike - mPhase -= 2.0f; - } - *buffer++ = value; - } - - return numFrames; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp deleted file mode 100644 index 5bcc2aae..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2019 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. - */ - - -#include "LinearShape.h" - -using namespace oboe::flowgraph; - -LinearShape::LinearShape() - : FlowGraphFilter(1) { -} - -int32_t LinearShape::onProcess(int numFrames) { - float *inputs = input.getBuffer(); - float *outputs = output.getBuffer(); - - for (int i = 0; i < numFrames; i++) { - float normalizedPhase = (inputs[i] * 0.5f) + 0.5f; // from 0.0 to 1.0 - outputs[i] = mMinimum + (normalizedPhase * (mMaximum - mMinimum)); - } - - return numFrames; -} \ No newline at end of file diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h deleted file mode 100644 index 238870f5..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2019 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_LINEAR_SHAPE_H -#define OBOETESTER_LINEAR_SHAPE_H - -#include "flowgraph/FlowGraphNode.h" - -/** - * Convert an input between -1.0 and +1.0 to a linear region between min and max. - */ -class LinearShape : public oboe::flowgraph::FlowGraphFilter { -public: - LinearShape(); - - int32_t onProcess(int numFrames) override; - - float getMinimum() const { - return mMinimum; - } - - void setMinimum(float minimum) { - mMinimum = minimum; - } - - float getMaximum() const { - return mMaximum; - } - - void setMaximum(float maximum) { - mMaximum = maximum; - } - -private: - float mMinimum = 0.0; - float mMaximum = 1.0; -}; - -#endif //OBOETESTER_LINEAR_SHAPE_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.cpp deleted file mode 100644 index 380447a9..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#include "OscillatorBase.h" - -using namespace oboe::flowgraph; - -OscillatorBase::OscillatorBase() - : frequency(*this, 1) - , amplitude(*this, 1) - , output(*this, 1) { - setSampleRate(48000); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.h deleted file mode 100644 index d3f2f459..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/OscillatorBase.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2018 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 NATIVEOBOE_OSCILLATORBASE_H -#define NATIVEOBOE_OSCILLATORBASE_H - -#include "flowgraph/FlowGraphNode.h" - -/** - * Base class for various oscillators. - * The oscillator has a phase that ranges from -1.0 to +1.0. - * That makes it easier to implement simple algebraic waveforms. - * - * Subclasses must implement onProcess(). - * - * This module has "frequency" and "amplitude" ports for control. - */ - -class OscillatorBase : public oboe::flowgraph::FlowGraphNode { -public: - OscillatorBase(); - - virtual ~OscillatorBase() = default; - - void setSampleRate(float sampleRate) { - mSampleRate = sampleRate; - mFrequencyToPhaseIncrement = 2.0f / sampleRate; // -1 to +1 is a range of 2 - } - - float getSampleRate() { - return mSampleRate; - } - - /** - * This can be used to set the initial phase of an oscillator before starting. - * This is mostly used with an LFO. - * Calling this while the oscillator is running will cause sharp pops. - * @param phase between -1.0 and +1.0 - */ - void setPhase(float phase) { - mPhase = phase; - } - - float getPhase() { - return mPhase; - } - - /** - * Control the frequency of the oscillator in Hz. - */ - oboe::flowgraph::FlowGraphPortFloatInput frequency; - - /** - * Control the linear amplitude of the oscillator. - * Silence is 0.0. - * A typical full amplitude would be 1.0. - */ - oboe::flowgraph::FlowGraphPortFloatInput amplitude; - - oboe::flowgraph::FlowGraphPortFloatOutput output; - -protected: - /** - * Increment phase based on frequency in Hz. - * Frequency may be positive or negative. - * - * Frequency should not exceed +/- Nyquist Rate. - * Nyquist Rate is sampleRate/2. - */ - float incrementPhase(float frequency) { - mPhase += frequency * mFrequencyToPhaseIncrement; - // Wrap phase in the range of -1 to +1 - if (mPhase >= 1.0f) { - mPhase -= 2.0f; - } else if (mPhase < -1.0f) { - mPhase += 2.0f; - } - return mPhase; - } - - float mPhase = 0.0f; // phase that ranges from -1.0 to +1.0 - float mSampleRate = 0.0f; - float mFrequencyToPhaseIncrement = 0.0f; // scaler for converting frequency to phase increment -}; - - -#endif //NATIVEOBOE_OSCILLATORBASE_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SawtoothOscillator.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SawtoothOscillator.cpp deleted file mode 100644 index 37e27529..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SawtoothOscillator.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 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. - */ - -#include -#include - -#include "SawtoothOscillator.h" - -SawtoothOscillator::SawtoothOscillator() - : OscillatorBase() { -} - -int32_t SawtoothOscillator::onProcess(int32_t numFrames) { - const float *frequencies = frequency.getBuffer(); - const float *amplitudes = amplitude.getBuffer(); - float *buffer = output.getBuffer(); - - // Use the phase directly as a non-band-limited "sawtooth". - // WARNING: This will generate unpleasant aliasing artifacts at higher frequencies. - for (int i = 0; i < numFrames; i++) { - float phase = incrementPhase(frequencies[i]); // phase ranges from -1 to +1 - *buffer++ = phase * amplitudes[i]; - } - - return numFrames; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.cpp deleted file mode 100644 index e8ae9c7b..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2015 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. - */ - -#include -#include - -#include "SineOscillator.h" - -/* - * This calls sinf() so it is not very efficient. - * A more efficient implementation might use a wave-table or a polynomial. - */ -SineOscillator::SineOscillator() - : OscillatorBase() { -} - -int32_t SineOscillator::onProcess(int32_t numFrames) { - const float *frequencies = frequency.getBuffer(); - const float *amplitudes = amplitude.getBuffer(); - float *buffer = output.getBuffer(); - - // Generate sine wave. - for (int i = 0; i < numFrames; i++) { - float phase = incrementPhase(frequencies[i]); // phase ranges from -1 to +1 - *buffer++ = sinf(phase * M_PI) * amplitudes[i]; - } - - return numFrames; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.h deleted file mode 100644 index 54f7ff7b..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/SineOscillator.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 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 FLOWGRAPH_SINE_OSCILLATOR_H -#define FLOWGRAPH_SINE_OSCILLATOR_H - -#include - -#include "OscillatorBase.h" - -/** - * Oscillator that generates a sine wave at the specified frequency and amplitude. - */ -class SineOscillator : public OscillatorBase { -public: - SineOscillator(); - - int32_t onProcess(int32_t numFrames) override; -}; - -#endif //FLOWGRAPH_SINE_OSCILLATOR_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.cpp deleted file mode 100644 index a3de01ce..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 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. - */ - -#include -#include - -#include "TriangleOscillator.h" - -TriangleOscillator::TriangleOscillator() - : OscillatorBase() { -} - -int32_t TriangleOscillator::onProcess(int32_t numFrames) { - const float *frequencies = frequency.getBuffer(); - const float *amplitudes = amplitude.getBuffer(); - float *buffer = output.getBuffer(); - - // Use the phase directly as a non-band-limited "triangle". - // WARNING: This will generate unpleasant aliasing artifacts at higher frequencies. - for (int i = 0; i < numFrames; i++) { - float phase = incrementPhase(frequencies[i]); // phase ranges from -1 to +1 - float triangle = 2.0f * ((phase < 0.0f) ? (0.5f + phase): (0.5f - phase)); - *buffer++ = triangle * amplitudes[i]; - } - - return numFrames; -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.h deleted file mode 100644 index 9e4c5d5c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/flowunits/TriangleOscillator.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2019 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 FLOWGRAPH_TRIANGLE_OSCILLATOR_H -#define FLOWGRAPH_TRIANGLE_OSCILLATOR_H - -#include - -#include "OscillatorBase.h" - -/** - * Oscillator that generates a triangle wave at the specified frequency and amplitude. - * - * The triangle output rises from -1 to +1 when the phase is between -1 and 0. - * The triangle output falls from +1 to 11 when the phase is between 0 and +1. - * - * The waveform is not band-limited so it will have aliasing artifacts at higher frequencies. - */ -class TriangleOscillator : public OscillatorBase { -public: - TriangleOscillator(); - - int32_t onProcess(int32_t numFrames) override; -}; - -#endif //FLOWGRAPH_TRIANGLE_OSCILLATOR_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp deleted file mode 100644 index 231064f2..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright 2015 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. - */ - -#define MODULE_NAME "OboeTester" - -#include -#include -#include -#include -#include - -#include "common/OboeDebug.h" -#include "oboe/Oboe.h" - -#include "NativeAudioContext.h" - -NativeAudioContext engine; - -/*********************************************************************************/ -/********************** JNI Prototypes *****************************************/ -/*********************************************************************************/ -extern "C" { - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_openNative(JNIEnv *env, jobject, - jint nativeApi, - jint sampleRate, - jint channelCount, - jint format, - jint sharingMode, - jint performanceMode, - jint inputPreset, - jint usage, - jint deviceId, - jint sessionId, - jint framesPerBurst, - jboolean channelConversionAllowed, - jboolean formatConversionAllowed, - jint rateConversionQuality, - jboolean isMMap, - jboolean isInput); -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint); - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setThresholdInFrames(JNIEnv *env, jobject, jint, jint); -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getThresholdInFrames(JNIEnv *env, jobject, jint); -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getBufferCapacityInFrames(JNIEnv *env, jobject, jint); -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setNativeApi(JNIEnv *env, jobject, jint, jint); - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setUseCallback(JNIEnv *env, jclass type, - jboolean useCallback); -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setCallbackReturnStop(JNIEnv *env, - jclass type, - jboolean b); -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type, - jint callbackSize); - -// ================= OboeAudioOutputStream ================================ - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioOutputStream_trigger(JNIEnv *env, jobject); -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioOutputStream_setToneType(JNIEnv *env, jobject, jint); -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioOutputStream_setAmplitude(JNIEnv *env, jobject, jdouble); - -/*********************************************************************************/ -/********************** JNI Implementations *************************************/ -/*********************************************************************************/ - -JNIEXPORT jboolean JNICALL -Java_com_mobileer_oboetester_NativeEngine_isMMapSupported(JNIEnv *env, jclass type) { - return oboe::AAudioExtensions::getInstance().isMMapSupported(); -} - -JNIEXPORT jboolean JNICALL -Java_com_mobileer_oboetester_NativeEngine_isMMapExclusiveSupported(JNIEnv *env, jclass type) { - return oboe::AAudioExtensions::getInstance().isMMapExclusiveSupported(); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_NativeEngine_setWorkaroundsEnabled(JNIEnv *env, jclass type, - jboolean enabled) { - oboe::OboeGlobals::setWorkaroundsEnabled(enabled); -} - -JNIEXPORT jboolean JNICALL -Java_com_mobileer_oboetester_NativeEngine_areWorkaroundsEnabled(JNIEnv *env, - jclass type) { - return oboe::OboeGlobals::areWorkaroundsEnabled(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_openNative( - JNIEnv *env, jobject synth, - jint nativeApi, - jint sampleRate, - jint channelCount, - jint format, - jint sharingMode, - jint performanceMode, - jint inputPreset, - jint usage, - jint deviceId, - jint sessionId, - jint framesPerBurst, - jboolean channelConversionAllowed, - jboolean formatConversionAllowed, - jint rateConversionQuality, - jboolean isMMap, - jboolean isInput) { - LOGD("OboeAudioStream_openNative: sampleRate = %d, framesPerBurst = %d", sampleRate, framesPerBurst); - - return (jint) engine.getCurrentActivity()->open(nativeApi, - sampleRate, - channelCount, - format, - sharingMode, - performanceMode, - inputPreset, - usage, - deviceId, - sessionId, - framesPerBurst, - channelConversionAllowed, - formatConversionAllowed, - rateConversionQuality, - isMMap, - isInput); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_TestAudioActivity_startNative(JNIEnv *env, jobject) { - return (jint) engine.getCurrentActivity()->start(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_TestAudioActivity_pauseNative(JNIEnv *env, jobject) { - return (jint) engine.getCurrentActivity()->pause(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_TestAudioActivity_stopNative(JNIEnv *env, jobject) { - return (jint) engine.getCurrentActivity()->stop(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_TestAudioActivity_getFramesPerCallback(JNIEnv *env, jobject) { - return (jint) engine.getCurrentActivity()->getFramesPerCallback(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_startPlaybackNative(JNIEnv *env, jobject) { - return (jint) engine.getCurrentActivity()->startPlayback(); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint streamIndex) { - engine.getCurrentActivity()->close(streamIndex); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setBufferSizeInFrames( - JNIEnv *env, jobject, jint streamIndex, jint threshold) { - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - auto result = oboeStream->setBufferSizeInFrames(threshold); - return (!result) - ? (jint) result.error() - : (jint) result.value(); - } - return (jint) oboe::Result::ErrorNull; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getBufferSizeInFrames( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getBufferSizeInFrames(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getBufferCapacityInFrames( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getBufferCapacityInFrames(); - } - return result; -} - -static int convertAudioApiToNativeApi(oboe::AudioApi audioApi) { - switch(audioApi) { - case oboe::AudioApi::Unspecified: - return NATIVE_MODE_UNSPECIFIED; - case oboe::AudioApi::OpenSLES: - return NATIVE_MODE_OPENSLES; - case oboe::AudioApi::AAudio: - return NATIVE_MODE_AAUDIO; - default: - return -1; - } -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getNativeApi( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - oboe::AudioApi audioApi = oboeStream->getAudioApi(); - result = convertAudioApiToNativeApi(audioApi); - LOGD("OboeAudioStream_getNativeApi got %d", result); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getSampleRate( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getSampleRate(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getSharingMode( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = (jint) oboeStream->getSharingMode(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getPerformanceMode( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = (jint) oboeStream->getPerformanceMode(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getInputPreset( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = (jint) oboeStream->getInputPreset(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getFramesPerBurst( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getFramesPerBurst(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getChannelCount( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getChannelCount(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getFormat(JNIEnv *env, jobject instance, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = (jint) oboeStream->getFormat(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getUsage(JNIEnv *env, jobject instance, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = (jint) oboeStream->getUsage(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getDeviceId( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getDeviceId(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getSessionId( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getSessionId(); - } - return result; -} - -JNIEXPORT jlong JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getFramesWritten( - JNIEnv *env, jobject, jint streamIndex) { - jlong result = (jint) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getFramesWritten(); - } - return result; -} - -JNIEXPORT jlong JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getFramesRead( - JNIEnv *env, jobject, jint streamIndex) { - jlong result = (jlong) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - result = oboeStream->getFramesRead(); - } - return result; -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getXRunCount( - JNIEnv *env, jobject, jint streamIndex) { - jint result = (jlong) oboe::Result::ErrorNull; - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - auto oboeResult = oboeStream->getXRunCount(); - if (!oboeResult) { - result = (jint) oboeResult.error(); - } else { - result = oboeResult.value(); - } - } - return result; -} - -JNIEXPORT jlong JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getCallbackCount( - JNIEnv *env, jobject) { - return engine.getCurrentActivity()->getCallbackCount(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getLastErrorCallbackResult( - JNIEnv *env, jobject, jint streamIndex) { - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - return (jint) oboeStream->getLastErrorCallbackResult(); - } - return 0; -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getTimestampLatency(JNIEnv *env, - jobject instance, - jint streamIndex) { - return engine.getCurrentActivity()->getTimestampLatency(streamIndex); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getCpuLoad(JNIEnv *env, jobject instance, jint streamIndex) { - return engine.getCurrentActivity()->getCpuLoad(); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setWorkload( - JNIEnv *env, jobject, jdouble workload) { - engine.getCurrentActivity()->setWorkload(workload); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getState(JNIEnv *env, jobject instance, jint streamIndex) { - std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); - if (oboeStream != nullptr) { - auto state = oboeStream->getState(); - if (state != oboe::StreamState::Starting && state != oboe::StreamState::Started) { - oboe::Result result = oboeStream->waitForStateChange( - oboe::StreamState::Uninitialized, - &state, 0); - - if (result != oboe::Result::OK){ - if (result == oboe::Result::ErrorClosed) { - state = oboe::StreamState::Closed; - } else if (result == oboe::Result::ErrorDisconnected){ - state = oboe::StreamState::Disconnected; - } else { - state = oboe::StreamState::Unknown; - } - } - } - return (jint) state; - } - return -1; -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_AudioInputTester_getPeakLevel(JNIEnv *env, - jobject instance, - jint index) { - return engine.getCurrentActivity()->getPeakLevel(index); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setUseCallback(JNIEnv *env, jclass type, - jboolean useCallback) { - ActivityContext::mUseCallback = useCallback; -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setCallbackReturnStop(JNIEnv *env, jclass type, - jboolean b) { - OboeStreamCallbackProxy::setCallbackReturnStop(b); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_setCallbackSize(JNIEnv *env, jclass type, - jint callbackSize) { - ActivityContext::callbackSize = callbackSize; -} - -JNIEXPORT jboolean JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_isMMap(JNIEnv *env, jobject instance, jint streamIndex) { - return engine.getCurrentActivity()->isMMapUsed(streamIndex); -} - -// ================= OboeAudioOutputStream ================================ - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioOutputStream_trigger( - JNIEnv *env, jobject) { - engine.getCurrentActivity()->trigger(); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioOutputStream_setChannelEnabled( - JNIEnv *env, jobject, jint channelIndex, jboolean enabled) { - engine.getCurrentActivity()->setChannelEnabled(channelIndex, enabled); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_OboeAudioOutputStream_setSignalType( - JNIEnv *env, jobject, jint signalType) { - engine.getCurrentActivity()->setSignalType(signalType); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_OboeAudioStream_getOboeVersionNumber(JNIEnv *env, - jclass type) { - return OBOE_VERSION_NUMBER; -} - -// ========================================================================== -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_TestAudioActivity_setActivityType(JNIEnv *env, - jobject instance, - jint activityType) { - engine.setActivityType(activityType); -} - -// ========================================================================== -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_TestInputActivity_saveWaveFile(JNIEnv *env, - jobject instance, - jstring fileName) { - const char *str = env->GetStringUTFChars(fileName, nullptr); - LOGD("nativeSaveFile(%s)", str); - jint result = engine.getCurrentActivity()->saveWaveFile(str); - env->ReleaseStringUTFChars(fileName, str); - return result; -} - -// ========================================================================== -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_TestInputActivity_setMinimumFramesBeforeRead(JNIEnv *env, - jobject instance, - jint numFrames) { - engine.getCurrentActivity()->setMinimumFramesBeforeRead(numFrames); -} - -// ========================================================================== -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_EchoActivity_setDelayTime(JNIEnv *env, - jobject instance, - jdouble delayTimeSeconds) { - engine.setDelayTime(delayTimeSeconds); -} - -JNIEXPORT int JNICALL -Java_com_mobileer_oboetester_EchoActivity_getColdStartInputMillis(JNIEnv *env, - jobject instance) { - return engine.getCurrentActivity()->getColdStartInputMillis(); -} - -JNIEXPORT int JNICALL -Java_com_mobileer_oboetester_EchoActivity_getColdStartOutputMillis(JNIEnv *env, - jobject instance) { - return engine.getCurrentActivity()->getColdStartOutputMillis(); -} - -// ========================================================================== -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_RoundTripLatencyActivity_getAnalyzerProgress(JNIEnv *env, - jobject instance) { - return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getProgress(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_RoundTripLatencyActivity_getMeasuredLatency(JNIEnv *env, - jobject instance) { - return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getMeasuredLatency(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_RoundTripLatencyActivity_getMeasuredConfidence(JNIEnv *env, - jobject instance) { - return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getMeasuredConfidence(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_RoundTripLatencyActivity_getBackgroundRMS(JNIEnv *env, - jobject instance) { - return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getBackgroundRMS(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_RoundTripLatencyActivity_getSignalRMS(JNIEnv *env, - jobject instance) { - return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getSignalRMS(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_AnalyzerActivity_getMeasuredResult(JNIEnv *env, - jobject instance) { - return engine.mActivityRoundTripLatency.getLatencyAnalyzer()->getResult(); -} - -// ========================================================================== -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_AnalyzerActivity_getAnalyzerState(JNIEnv *env, - jobject instance) { - return ((ActivityFullDuplex *)engine.getCurrentActivity())->getState(); -} - -JNIEXPORT jboolean JNICALL -Java_com_mobileer_oboetester_AnalyzerActivity_isAnalyzerDone(JNIEnv *env, - jobject instance) { - return ((ActivityFullDuplex *)engine.getCurrentActivity())->isAnalyzerDone(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_AnalyzerActivity_getResetCount(JNIEnv *env, - jobject instance) { - return ((ActivityFullDuplex *)engine.getCurrentActivity())->getResetCount(); -} - -// ========================================================================== -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_GlitchActivity_getGlitchCount(JNIEnv *env, - jobject instance) { - return engine.mActivityGlitches.getGlitchAnalyzer()->getGlitchCount(); -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_GlitchActivity_getStateFrameCount(JNIEnv *env, - jobject instance, - jint state) { - return engine.mActivityGlitches.getGlitchAnalyzer()->getStateFrameCount(state); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_GlitchActivity_getSignalToNoiseDB(JNIEnv *env, - jobject instance) { - return engine.mActivityGlitches.getGlitchAnalyzer()->getSignalToNoiseDB(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_GlitchActivity_getPeakAmplitude(JNIEnv *env, - jobject instance) { - return engine.mActivityGlitches.getGlitchAnalyzer()->getPeakAmplitude(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_TestDataPathsActivity_getMagnitude(JNIEnv *env, - jobject instance) { - return engine.mActivityDataPath.getDataPathAnalyzer()->getMagnitude(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_TestDataPathsActivity_getMaxMagnitude(JNIEnv *env, - jobject instance) { - return engine.mActivityDataPath.getDataPathAnalyzer()->getMaxMagnitude(); -} - -JNIEXPORT jdouble JNICALL -Java_com_mobileer_oboetester_TestDataPathsActivity_getPhase(JNIEnv *env, - jobject instance) { - return engine.mActivityDataPath.getDataPathAnalyzer()->getPhaseOffset(); -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_GlitchActivity_setTolerance(JNIEnv *env, - jobject instance, - jfloat tolerance) { - if (engine.mActivityGlitches.getGlitchAnalyzer()) { - engine.mActivityGlitches.getGlitchAnalyzer()->setTolerance(tolerance); - } -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_GlitchActivity_setInputChannelNative(JNIEnv *env, - jobject instance, - jint channel) { - if (engine.mActivityGlitches.getGlitchAnalyzer()) { - engine.mActivityGlitches.getGlitchAnalyzer()->setInputChannel(channel); - } - if (engine.mActivityDataPath.getDataPathAnalyzer()) { - engine.mActivityDataPath.getDataPathAnalyzer()->setInputChannel(channel); - } -} - -JNIEXPORT void JNICALL -Java_com_mobileer_oboetester_GlitchActivity_setOutputChannelNative(JNIEnv *env, - jobject instance, - jint channel) { - if (engine.mActivityGlitches.getGlitchAnalyzer()) { - engine.mActivityGlitches.getGlitchAnalyzer()->setOutputChannel(channel); - } - if (engine.mActivityDataPath.getDataPathAnalyzer()) { - engine.mActivityDataPath.getDataPathAnalyzer()->setOutputChannel(channel); - } -} - -JNIEXPORT jint JNICALL -Java_com_mobileer_oboetester_ManualGlitchActivity_getGlitch(JNIEnv *env, jobject instance, - jfloatArray waveform_) { - float *waveform = env->GetFloatArrayElements(waveform_, nullptr); - jsize length = env->GetArrayLength(waveform_); - jsize numSamples = 0; - auto *analyzer = engine.mActivityGlitches.getGlitchAnalyzer(); - if (analyzer) { - numSamples = analyzer->getLastGlitch(waveform, length); - } - - env->ReleaseFloatArrayElements(waveform_, waveform, 0); - return numSamples; -} - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/unused/unused.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/unused/unused.h deleted file mode 100644 index f1fcd0a2..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/unused/unused.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2017 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_UNUSED_H -#define OBOETESTER_UNUSED_H - -// Store this code for later use. -#if 0 - -/* - -FIR filter designed with -http://t-filter.appspot.com - -sampling frequency: 48000 Hz - -* 0 Hz - 8000 Hz - gain = 1.2 - desired ripple = 5 dB - actual ripple = 5.595266169703693 dB - -* 12000 Hz - 20000 Hz - gain = 0 - desired attenuation = -40 dB - actual attenuation = -37.58691566571914 dB - -*/ - -#define FILTER_TAP_NUM 11 - -static const float sFilterTaps8000[FILTER_TAP_NUM] = { - -0.05944219353343189f, - -0.07303434839503208f, - -0.037690487672689066f, - 0.1870480506596512f, - 0.3910337357836833f, - 0.5333672385425637f, - 0.3910337357836833f, - 0.1870480506596512f, - -0.037690487672689066f, - -0.07303434839503208f, - -0.05944219353343189f -}; - -class LowPassFilter { -public: - - /* - * Filter one input sample. - * @return filtered output - */ - float filter(float input) { - float output = 0.0f; - mX[mCursor] = input; - // Index backwards over x. - int xIndex = mCursor + FILTER_TAP_NUM; - // Write twice so we avoid having to wrap in the middle of the convolution. - mX[xIndex] = input; - for (int i = 0; i < FILTER_TAP_NUM; i++) { - output += sFilterTaps8000[i] * mX[xIndex--]; - } - if (++mCursor >= FILTER_TAP_NUM) { - mCursor = 0; - } - return output; - } - - /** - * @return true if PASSED - */ - bool test() { - // Measure the impulse of the filter at different phases so we exercise - // all the wraparound cases in the FIR. - for (int offset = 0; offset < (FILTER_TAP_NUM * 2); offset++ ) { - // LOGD("LowPassFilter: cursor = %d\n", mCursor); - // Offset by one each time. - if (filter(0.0f) != 0.0f) { - LOGD("ERROR: filter should return 0.0 before impulse response\n"); - return false; - } - for (int i = 0; i < FILTER_TAP_NUM; i++) { - float output = filter((i == 0) ? 1.0f : 0.0f); // impulse - if (output != sFilterTaps8000[i]) { - LOGD("ERROR: filter should return impulse response\n"); - return false; - } - } - for (int i = 0; i < FILTER_TAP_NUM; i++) { - if (filter(0.0f) != 0.0f) { - LOGD("ERROR: filter should return 0.0 after impulse response\n"); - return false; - } - } - } - return true; - } - -private: - float mX[FILTER_TAP_NUM * 2]{}; // twice as big as needed to avoid wrapping - int32_t mCursor = 0; -}; - -/** - * Low pass filter the recording using a simple FIR filter. - * Note that the lowpass filter cutoff tracks the sample rate. - * That is OK because the impulse width is a fixed number of samples. - */ -void lowPassFilter() { - for (int i = 0; i < mFrameCounter; i++) { - mData[i] = mLowPassFilter.filter(mData[i]); - } -} - -/** - * Remove DC offset using a one-pole one-zero IIR filter. - */ -void dcBlocker() { - const float R = 0.996; // narrow notch at zero Hz - float x1 = 0.0; - float y1 = 0.0; - for (int i = 0; i < mFrameCounter; i++) { - const float x = mData[i]; - const float y = x - x1 + (R * y1); - mData[i] = y; - y1 = y; - x1 = x; - } -} -#endif - -#endif //OBOETESTER_UNUSED_H diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.cpp b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.cpp deleted file mode 100644 index 5744d8f5..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#include "WaveFileWriter.h" - -void WaveFileWriter::WaveFileWriter::write(float value) { - if (!headerWritten) { - writeHeader(); - } - if (bitsPerSample == 24) { - writePCM24(value); - } else { - writePCM16(value); - } -} - -void WaveFileWriter::write(float *buffer, int32_t startSample, int32_t numSamples) { - for (int32_t i = 0; i < numSamples; i++) { - write(buffer[startSample + i]); - } -} - -void WaveFileWriter::writeIntLittle(int32_t n) { - writeByte(n); - writeByte(n >> 8); - writeByte(n >> 16); - writeByte(n >> 24); -} - -void WaveFileWriter::writeShortLittle(int16_t n) { - writeByte(n); - writeByte(n >> 8); -} - -void WaveFileWriter::writeFormatChunk() { - int32_t bytesPerSample = (bitsPerSample + 7) / 8; - - writeByte('f'); - writeByte('m'); - writeByte('t'); - writeByte(' '); - writeIntLittle(16); // chunk size - writeShortLittle(WAVE_FORMAT_PCM); - writeShortLittle((int16_t) mSamplesPerFrame); - writeIntLittle(mFrameRate); - // bytes/second - writeIntLittle(mFrameRate * mSamplesPerFrame * bytesPerSample); - // block align - writeShortLittle((int16_t) (mSamplesPerFrame * bytesPerSample)); - writeShortLittle((int16_t) bitsPerSample); -} - -void WaveFileWriter::writeDataChunkHeader() { - writeByte('d'); - writeByte('a'); - writeByte('t'); - writeByte('a'); - // Maximum size is not strictly correct but is commonly used - // when we do not know the final size. - writeIntLittle(INT32_MAX); -} - -void WaveFileWriter::writeHeader() { - writeRiffHeader(); - writeFormatChunk(); - writeDataChunkHeader(); - headerWritten = true; -} - -// Write lower 8 bits. Upper bits ignored. -void WaveFileWriter::writeByte(uint8_t b) { - mOutputStream->write(b); - bytesWritten += 1; -} - -void WaveFileWriter::writePCM24(float value) { - // Offset before casting so that we can avoid using floor(). - // Also round by adding 0.5 so that very small signals go to zero. - float temp = (PCM24_MAX * value) + 0.5 - PCM24_MIN; - int32_t sample = ((int) temp) + PCM24_MIN; - // clip to 24-bit range - if (sample > PCM24_MAX) { - sample = PCM24_MAX; - } else if (sample < PCM24_MIN) { - sample = PCM24_MIN; - } - // encode as little-endian - writeByte(sample); // little end - writeByte(sample >> 8); // middle - writeByte(sample >> 16); // big end -} - -void WaveFileWriter::writePCM16(float value) { - // Offset before casting so that we can avoid using floor(). - // Also round by adding 0.5 so that very small signals go to zero. - float temp = (INT16_MAX * value) + 0.5 - INT16_MIN; - int32_t sample = ((int) temp) + INT16_MIN; - if (sample > INT16_MAX) { - sample = INT16_MAX; - } else if (sample < INT16_MIN) { - sample = INT16_MIN; - } - writeByte(sample); // little end - writeByte(sample >> 8); // big end -} - -void WaveFileWriter::writeRiffHeader() { - writeByte('R'); - writeByte('I'); - writeByte('F'); - writeByte('F'); - // Maximum size is not strictly correct but is commonly used - // when we do not know the final size. - writeIntLittle(INT32_MAX); - writeByte('W'); - writeByte('A'); - writeByte('V'); - writeByte('E'); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h b/src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h deleted file mode 100644 index 0fe7d335..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/cpp/util/WaveFileWriter.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2019 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. - */ - -// Based on the WaveFileWriter in Java from the open source JSyn library by Phil Burk -// https://github.com/philburk/jsyn/blob/master/src/com/jsyn/util/WaveFileWriter.java - -#ifndef UTIL_WAVE_FILE_WRITER -#define UTIL_WAVE_FILE_WRITER - -#include -#include - -class WaveFileOutputStream { -public: - virtual ~WaveFileOutputStream() = default; - virtual void write(uint8_t b) = 0; -}; - -/** - * Write audio data to a WAV file. - * - *

- * 
- * WaveFileWriter writer = new WaveFileWriter(waveFileOutputStream);
- * writer.setFrameRate(48000);
- * writer.setBitsPerSample(24);
- * writer.write(floatArray, 0, numSamples);
- * writer.close();
- * 
- * 
- * - */ -class WaveFileWriter { -public: - - /** - * Create an object that will write a WAV file image to the specified stream. - * - * @param outputStream stream to receive the bytes - * @throws FileNotFoundException - */ - WaveFileWriter(WaveFileOutputStream *outputStream) { - mOutputStream = outputStream; - } - - /** - * @param frameRate default is 44100 - */ - void setFrameRate(int32_t frameRate) { - mFrameRate = frameRate; - } - - int32_t getFrameRate() const { - return mFrameRate; - } - - /** - * For stereo, set this to 2. Default is mono = 1. - * Also known as ChannelCount - */ - void setSamplesPerFrame(int32_t samplesPerFrame) { - mSamplesPerFrame = samplesPerFrame; - } - - int32_t getSamplesPerFrame() const { - return mSamplesPerFrame; - } - - /** Only 16 or 24 bit samples supported at the moment. Default is 16. */ - void setBitsPerSample(int32_t bits) { - assert((bits == 16) || (bits == 24)); - bitsPerSample = bits; - } - - int32_t getBitsPerSample() const { - return bitsPerSample; - } - - void close() { - } - - /** Write single audio data value to the WAV file. */ - void write(float value); - - /** - * Write a buffer to the WAV file. - */ - void write(float *buffer, int32_t startSample, int32_t numSamples); - -private: - /** - * Write a 32 bit integer to the stream in Little Endian format. - */ - void writeIntLittle(int32_t n); - - /** - * Write a 16 bit integer to the stream in Little Endian format. - */ - void writeShortLittle(int16_t n); - - /** - * Write an 'fmt ' chunk to the WAV file containing the given information. - */ - void writeFormatChunk(); - - /** - * Write a 'data' chunk header to the WAV file. This should be followed by call to - * writeShortLittle() to write the data to the chunk. - */ - void writeDataChunkHeader(); - - /** - * Write a simple WAV header for PCM data. - */ - void writeHeader(); - - // Write lower 8 bits. Upper bits ignored. - void writeByte(uint8_t b); - - void writePCM24(float value); - - void writePCM16(float value); - - /** - * Write a 'RIFF' file header and a 'WAVE' ID to the WAV file. - */ - void writeRiffHeader(); - - static constexpr int WAVE_FORMAT_PCM = 1; - WaveFileOutputStream *mOutputStream = nullptr; - int32_t mFrameRate = 48000; - int32_t mSamplesPerFrame = 1; - int32_t bitsPerSample = 16; - int32_t bytesWritten = 0; - bool headerWritten = false; - static constexpr int32_t PCM24_MIN = -(1 << 23); - static constexpr int32_t PCM24_MAX = (1 << 23) - 1; - -}; - -#endif /* UTIL_WAVE_FILE_WRITER */ - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/ic_launcher-playstore.png b/src/libs/oboe/apps/OboeTester/app/src/main/ic_launcher-playstore.png deleted file mode 100644 index 3e81c2c0232b49c6a5d570891b8cf847d62767d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31684 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 tVQ=J4>VNAkV?lm8 { - - public AudioDeviceAdapter(Context context) { - super(context, R.layout.audio_devices); - } - - @NonNull - @Override - public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - return getDropDownView(position, convertView, parent); - } - - @Override - public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - View rowView = convertView; - if (rowView == null) { - LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - rowView = inflater.inflate(R.layout.audio_devices, parent, false); - } - - TextView deviceName = (TextView) rowView.findViewById(R.id.device_name); - AudioDeviceListEntry deviceInfo = getItem(position); - deviceName.setText(deviceInfo.getName()); - - return rowView; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java deleted file mode 100644 index 38ca0517..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceInfoConverter.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.mobileer.audio_device; -/* - * Copyright 2017 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. - */ - -import android.media.AudioDeviceInfo; - -public class AudioDeviceInfoConverter { - - /** - * Converts an {@link AudioDeviceInfo} object into a human readable representation - * - * @param adi The AudioDeviceInfo object to be converted to a String - * @return String containing all the information from the AudioDeviceInfo object - */ - public static String toString(AudioDeviceInfo adi){ - - StringBuilder sb = new StringBuilder(); - sb.append("Id: "); - sb.append(adi.getId()); - - sb.append("\nProduct name: "); - sb.append(adi.getProductName()); - - sb.append("\nType: "); - sb.append(typeToString(adi.getType())); - - sb.append("\nIs source: "); - sb.append((adi.isSource() ? "Yes" : "No")); - - sb.append("\nIs sink: "); - sb.append((adi.isSink() ? "Yes" : "No")); - - sb.append("\nChannel counts: "); - int[] channelCounts = adi.getChannelCounts(); - sb.append(intArrayToString(channelCounts)); - - sb.append("\nChannel masks: "); - int[] channelMasks = adi.getChannelMasks(); - sb.append(intArrayToString(channelMasks)); - - sb.append("\nChannel index masks: "); - int[] channelIndexMasks = adi.getChannelIndexMasks(); - sb.append(intArrayToString(channelIndexMasks)); - - sb.append("\nEncodings: "); - int[] encodings = adi.getEncodings(); - sb.append(intArrayToString(encodings)); - - sb.append("\nSample Rates: "); - int[] sampleRates = adi.getSampleRates(); - sb.append(intArrayToString(sampleRates)); - sb.append("\n"); - return sb.toString(); - } - - /** - * Converts an integer array into a string where each int is separated by a space - * - * @param integerArray the integer array to convert to a string - * @return string containing all the integer values separated by spaces - */ - private static String intArrayToString(int[] integerArray){ - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < integerArray.length; i++){ - sb.append(integerArray[i]); - if (i != integerArray.length -1) sb.append(" "); - } - return sb.toString(); - } - - /** - * Converts the value from {@link AudioDeviceInfo#getType()} into a human - * readable string - * @param type One of the {@link AudioDeviceInfo}.TYPE_* values - * e.g. AudioDeviceInfo.TYPE_BUILT_IN_SPEAKER - * @return string which describes the type of audio device - */ - static String typeToString(int type){ - switch (type) { - case AudioDeviceInfo.TYPE_AUX_LINE: - return "auxiliary line-level connectors"; - case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP: - return "Bluetooth A2DP"; - case AudioDeviceInfo.TYPE_BLUETOOTH_SCO: - return "Bluetooth telephony SCO"; - case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE: - return "built-in earpiece"; - case AudioDeviceInfo.TYPE_BUILTIN_MIC: - return "built-in microphone"; - case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER: - return "built-in speaker"; - case 0x18: // AudioDeviceInfo.TYPE_BUILTIN_SPEAKER_SAFE: - return "built-in speaker safe"; - case AudioDeviceInfo.TYPE_BUS: - return "BUS"; - case AudioDeviceInfo.TYPE_DOCK: - return "DOCK"; - case AudioDeviceInfo.TYPE_FM: - return "FM"; - case AudioDeviceInfo.TYPE_FM_TUNER: - return "FM tuner"; - case AudioDeviceInfo.TYPE_HDMI: - return "HDMI"; - case AudioDeviceInfo.TYPE_HDMI_ARC: - return "HDMI audio return channel"; - case AudioDeviceInfo.TYPE_IP: - return "IP"; - case AudioDeviceInfo.TYPE_LINE_ANALOG: - return "line analog"; - case AudioDeviceInfo.TYPE_LINE_DIGITAL: - return "line digital"; - case AudioDeviceInfo.TYPE_TELEPHONY: - return "telephony"; - case AudioDeviceInfo.TYPE_TV_TUNER: - return "TV tuner"; - case AudioDeviceInfo.TYPE_USB_ACCESSORY: - return "USB accessory"; - case AudioDeviceInfo.TYPE_USB_DEVICE: - return "USB device"; - case AudioDeviceInfo.TYPE_WIRED_HEADPHONES: - return "wired headphones"; - case AudioDeviceInfo.TYPE_WIRED_HEADSET: - return "wired headset"; - default: - case AudioDeviceInfo.TYPE_UNKNOWN: - return "unknown=" + type; - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java deleted file mode 100644 index a0ea1837..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceListEntry.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.mobileer.audio_device; -/* - * Copyright 2017 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. - */ - -import android.annotation.TargetApi; -import android.media.AudioDeviceInfo; -import android.media.AudioManager; - -import java.util.List; -import java.util.Vector; - -/** - * POJO which represents basic information for an audio device. - * - * Example: id: 8, deviceName: "built-in speaker" - */ -public class AudioDeviceListEntry { - - private int mId; - private String mName; - - public AudioDeviceListEntry(int deviceId, String deviceName){ - mId = deviceId; - mName = deviceName; - } - - public int getId() { - return mId; - } - - public String getName(){ - return mName; - } - - public String toString(){ - return getName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AudioDeviceListEntry that = (AudioDeviceListEntry) o; - - if (mId != that.mId) return false; - return mName != null ? mName.equals(that.mName) : that.mName == null; - } - - @Override - public int hashCode() { - int result = mId; - result = 31 * result + (mName != null ? mName.hashCode() : 0); - return result; - } - - /** - * Create a list of AudioDeviceListEntry objects from a list of AudioDeviceInfo objects. - * - * @param devices A list of {@Link AudioDeviceInfo} objects - * @param directionType Only audio devices with this direction will be included in the list. - * Valid values are GET_DEVICES_ALL, GET_DEVICES_OUTPUTS and - * GET_DEVICES_INPUTS. - * @return A list of AudioDeviceListEntry objects - */ - @TargetApi(23) - static List createListFrom(AudioDeviceInfo[] devices, int directionType){ - - List listEntries = new Vector<>(); - for (AudioDeviceInfo info : devices) { - if (directionType == AudioManager.GET_DEVICES_ALL || - (directionType == AudioManager.GET_DEVICES_OUTPUTS && info.isSink()) || - (directionType == AudioManager.GET_DEVICES_INPUTS && info.isSource())) { - listEntries.add(new AudioDeviceListEntry(info.getId(), - info.getId() + ": " + - info.getProductName() + " " + - AudioDeviceInfoConverter.typeToString(info.getType()))); - } - } - return listEntries; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java deleted file mode 100644 index 3c4390ae..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/audio_device/AudioDeviceSpinner.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.mobileer.audio_device; -/* - * Copyright 2017 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. - */ - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Resources.Theme; -import android.media.AudioDeviceCallback; -import android.media.AudioDeviceInfo; -import android.media.AudioManager; -import android.util.AttributeSet; -import android.widget.Spinner; - -import com.mobileer.oboetester.R; - -import java.util.List; - -public class AudioDeviceSpinner extends Spinner { - - private static final int AUTO_SELECT_DEVICE_ID = 0; - private static final String TAG = AudioDeviceSpinner.class.getName(); - private int mDirectionType; - private AudioDeviceAdapter mDeviceAdapter; - private AudioManager mAudioManager; - private Context mContext; - - public AudioDeviceSpinner(Context context){ - super(context); - setup(context); - } - - public AudioDeviceSpinner(Context context, int mode){ - super(context, mode); - setup(context); - } - - public AudioDeviceSpinner(Context context, AttributeSet attrs){ - super(context, attrs); - setup(context); - } - - public AudioDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr){ - super(context, attrs, defStyleAttr); - setup(context); - } - - public AudioDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode){ - super(context, attrs, defStyleAttr, mode); - setup(context); - } - - public AudioDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes, int mode){ - super(context, attrs, defStyleAttr, defStyleRes, mode); - setup(context); - } - - public AudioDeviceSpinner(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes, int mode, Theme popupTheme){ - super(context, attrs, defStyleAttr, defStyleRes, mode, popupTheme); - setup(context); - } - - private void setup(Context context){ - mContext = context; - - mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - - mDeviceAdapter = new AudioDeviceAdapter(context); - setAdapter(mDeviceAdapter); - - // Add a default entry to the list and select it - mDeviceAdapter.add(new AudioDeviceListEntry(AUTO_SELECT_DEVICE_ID, - mContext.getString(R.string.auto_select))); - setSelection(0); - - } - - @TargetApi(23) - public void setDirectionType(int directionType){ - this.mDirectionType = directionType; - setupAudioDeviceCallback(); - } - - @TargetApi(23) - private void setupAudioDeviceCallback(){ - - // Note that we will immediately receive a call to onDevicesAdded with the list of - // devices which are currently connected. - mAudioManager.registerAudioDeviceCallback(new AudioDeviceCallback() { - @Override - public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { - List deviceList = - AudioDeviceListEntry.createListFrom(addedDevices, mDirectionType); - if (deviceList.size() > 0){ - // Prevent duplicate entries caused by b/80138804 - for (AudioDeviceListEntry entry : deviceList){ - mDeviceAdapter.remove(entry); - } - mDeviceAdapter.addAll(deviceList); - } - } - - public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { - List deviceList = - AudioDeviceListEntry.createListFrom(removedDevices, mDirectionType); - for (AudioDeviceListEntry entry : deviceList){ - mDeviceAdapter.remove(entry); - } - setSelection(0); - } - }, null); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/EventScheduler.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/EventScheduler.java deleted file mode 100644 index 29f5b186..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/EventScheduler.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import java.util.SortedMap; -import java.util.TreeMap; - -/** - * Store SchedulableEvents in a timestamped buffer. - * Events may be written in any order. - * Events will be read in sorted order. - * Events with the same timestamp will be read in the order they were added. - * - * Only one Thread can write into the buffer. - * And only one Thread can read from the buffer. - */ -public class EventScheduler { - private static final long NANOS_PER_MILLI = 1000000; - - private final Object lock = new Object(); - private SortedMap mEventBuffer; - // This does not have to be guarded. It is only set by the writing thread. - // If the reader sees a null right before being set then that is OK. - private FastEventQueue mEventPool = null; - private static final int MAX_POOL_SIZE = 200; - - public EventScheduler() { - mEventBuffer = new TreeMap(); - } - - // If we keep at least one node in the list then it can be atomic - // and non-blocking. - private class FastEventQueue { - // One thread takes from the beginning of the list. - volatile SchedulableEvent mFirst; - // A second thread returns events to the end of the list. - volatile SchedulableEvent mLast; - volatile long mEventsAdded; - volatile long mEventsRemoved; - - FastEventQueue(SchedulableEvent event) { - mFirst = event; - mLast = mFirst; - mEventsAdded = 1; // Always created with one event added. Never empty. - mEventsRemoved = 0; // None removed yet. - } - - int size() { - return (int)(mEventsAdded - mEventsRemoved); - } - - /** - * Do not call this unless there is more than one event - * in the list. - * @return first event in the list - */ - public SchedulableEvent remove() { - // Take first event. - mEventsRemoved++; - SchedulableEvent event = mFirst; - mFirst = event.mNext; - return event; - } - - /** - * @param event - */ - public void add(SchedulableEvent event) { - event.mNext = null; - mLast.mNext = event; - mLast = event; - mEventsAdded++; - } - } - - /** - * Base class for events that can be stored in the EventScheduler. - */ - public static class SchedulableEvent { - private long mTimestamp; - private SchedulableEvent mNext = null; - - /** - * @param timestamp - */ - public SchedulableEvent(long timestamp) { - mTimestamp = timestamp; - } - - /** - * @return timestamp - */ - public long getTimestamp() { - return mTimestamp; - } - - /** - * The timestamp should not be modified when the event is in the - * scheduling buffer. - */ - public void setTimestamp(long timestamp) { - mTimestamp = timestamp; - } - } - - /** - * Get an event from the pool. - * Always leave at least one event in the pool. - * @return event or null - */ - public SchedulableEvent removeEventfromPool() { - SchedulableEvent event = null; - if (mEventPool != null && (mEventPool.size() > 1)) { - event = mEventPool.remove(); - } - return event; - } - - /** - * Return events to a pool so they can be reused. - * - * @param event - */ - public void addEventToPool(SchedulableEvent event) { - if (mEventPool == null) { - mEventPool = new FastEventQueue(event); // add event to pool - // If we already have enough items in the pool then just - // drop the event. This prevents unbounded memory leaks. - } else if (mEventPool.size() < MAX_POOL_SIZE) { - mEventPool.add(event); - } - } - - /** - * Add an event to the scheduler. Events with the same time will be - * processed in order. - * - * @param event - */ - public void add(SchedulableEvent event) { - synchronized (lock) { - FastEventQueue list = mEventBuffer.get(event.getTimestamp()); - if (list == null) { - long lowestTime = mEventBuffer.isEmpty() ? Long.MAX_VALUE - : mEventBuffer.firstKey(); - list = new FastEventQueue(event); - mEventBuffer.put(event.getTimestamp(), list); - // If the event we added is earlier than the previous earliest - // event then notify any threads waiting for the next event. - if (event.getTimestamp() < lowestTime) { - lock.notify(); - } - } else { - list.add(event); - } - } - } - - // Caller must synchronize on lock before calling. - private SchedulableEvent removeNextEventLocked(long lowestTime) { - SchedulableEvent event; - FastEventQueue list = mEventBuffer.get(lowestTime); - // Remove list from tree if this is the last node. - if ((list.size() == 1)) { - mEventBuffer.remove(lowestTime); - } - event = list.remove(); - return event; - } - - /** - * Check to see if any scheduled events are ready to be processed. - * - * @param timestamp - * @return next event or null if none ready - */ - public SchedulableEvent getNextEvent(long time) { - SchedulableEvent event = null; - synchronized (lock) { - if (!mEventBuffer.isEmpty()) { - long lowestTime = mEventBuffer.firstKey(); - // Is it time for this list to be processed? - if (lowestTime <= time) { - event = removeNextEventLocked(lowestTime); - } - } - } - // Log.i(TAG, "getNextEvent: event = " + event); - return event; - } - - /** - * Return the next available event or wait until there is an event ready to - * be processed. This method assumes that the timestamps are in nanoseconds - * and that the current time is System.nanoTime(). - * - * @return event - * @throws InterruptedException - */ - public SchedulableEvent waitNextEvent() throws InterruptedException { - SchedulableEvent event = null; - while (true) { - long millisToWait = Integer.MAX_VALUE; - synchronized (lock) { - if (!mEventBuffer.isEmpty()) { - long now = System.nanoTime(); - long lowestTime = mEventBuffer.firstKey(); - // Is it time for the earliest list to be processed? - if (lowestTime <= now) { - event = removeNextEventLocked(lowestTime); - break; - } else { - // Figure out how long to sleep until next event. - long nanosToWait = lowestTime - now; - // Add 1 millisecond so we don't wake up before it is - // ready. - millisToWait = 1 + (nanosToWait / NANOS_PER_MILLI); - // Clip 64-bit value to 32-bit max. - if (millisToWait > Integer.MAX_VALUE) { - millisToWait = Integer.MAX_VALUE; - } - } - } - lock.wait((int) millisToWait); - } - } - return event; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiConstants.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiConstants.java deleted file mode 100644 index 978a0ce2..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiConstants.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools; - -/** - * MIDI related constants and static methods. - * These values are defined in the MIDI Standard 1.0 - * available from the MIDI Manufacturers Association. - */ -public class MidiConstants { - protected final static String TAG = "MidiTools"; - public static final byte STATUS_COMMAND_MASK = (byte) 0xF0; - public static final byte STATUS_CHANNEL_MASK = (byte) 0x0F; - - // Channel voice messages. - public static final byte STATUS_NOTE_OFF = (byte) 0x80; - public static final byte STATUS_NOTE_ON = (byte) 0x90; - public static final byte STATUS_POLYPHONIC_AFTERTOUCH = (byte) 0xA0; - public static final byte STATUS_CONTROL_CHANGE = (byte) 0xB0; - public static final byte STATUS_PROGRAM_CHANGE = (byte) 0xC0; - public static final byte STATUS_CHANNEL_PRESSURE = (byte) 0xD0; - public static final byte STATUS_PITCH_BEND = (byte) 0xE0; - - // System Common Messages. - public static final byte STATUS_SYSTEM_EXCLUSIVE = (byte) 0xF0; - public static final byte STATUS_MIDI_TIME_CODE = (byte) 0xF1; - public static final byte STATUS_SONG_POSITION = (byte) 0xF2; - public static final byte STATUS_SONG_SELECT = (byte) 0xF3; - public static final byte STATUS_TUNE_REQUEST = (byte) 0xF6; - public static final byte STATUS_END_SYSEX = (byte) 0xF7; - - // System Real-Time Messages - public static final byte STATUS_TIMING_CLOCK = (byte) 0xF8; - public static final byte STATUS_START = (byte) 0xFA; - public static final byte STATUS_CONTINUE = (byte) 0xFB; - public static final byte STATUS_STOP = (byte) 0xFC; - public static final byte STATUS_ACTIVE_SENSING = (byte) 0xFE; - public static final byte STATUS_RESET = (byte) 0xFF; - - /** Number of bytes in a message nc from 8c to Ec */ - public final static int CHANNEL_BYTE_LENGTHS[] = { 3, 3, 3, 3, 2, 2, 3 }; - - /** Number of bytes in a message Fn from F0 to FF */ - public final static int SYSTEM_BYTE_LENGTHS[] = { 1, 2, 3, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1 }; - - /** - * MIDI messages, except for SysEx, are 1,2 or 3 bytes long. - * You can tell how long a MIDI message is from the first status byte. - * Do not call this for SysEx, which has variable length. - * @param statusByte - * @return number of bytes in a complete message, zero if data byte passed - */ - public static int getBytesPerMessage(byte statusByte) { - // Java bytes are signed so we need to mask off the high bits - // to get a value between 0 and 255. - int statusInt = statusByte & 0xFF; - if (statusInt >= 0xF0) { - // System messages use low nibble for size. - return SYSTEM_BYTE_LENGTHS[statusInt & 0x0F]; - } else if(statusInt >= 0x80) { - // Channel voice messages use high nibble for size. - return CHANNEL_BYTE_LENGTHS[(statusInt >> 4) - 8]; - } else { - return 0; // data byte - } - } - - /** - * @param msg - * @param offset - * @param count - * @return true if the entire message is ActiveSensing commands - */ - public static boolean isAllActiveSensing(byte[] msg, int offset, - int count) { - // Count bytes that are not active sensing. - int goodBytes = 0; - for (int i = 0; i < count; i++) { - byte b = msg[offset + i]; - if (b != MidiConstants.STATUS_ACTIVE_SENSING) { - goodBytes++; - } - } - return (goodBytes == 0); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDeviceMonitor.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDeviceMonitor.java deleted file mode 100644 index 32b9257d..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDeviceMonitor.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiDeviceStatus; -import android.media.midi.MidiManager; -import android.media.midi.MidiManager.DeviceCallback; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; - -import java.util.HashMap; -import java.util.Map; - -/** - * Manage a list a of DeviceCallbacks that are called when a MIDI Device is - * plugged in or unplugged. - * - * This class is used to workaround a bug in the M release of the Android MIDI API. - * The MidiManager.unregisterDeviceCallback() method was not working. So if an app - * was rotated, and the Activity destroyed and recreated, the DeviceCallbacks would - * accumulate in the MidiServer. This would result in multiple callbacks whenever a - * device was added. This class allow an app to register and unregister multiple times - * using a local list of callbacks. It registers a single callback, which stays registered - * until the app is dead. - * - * This code checks to see if the N release is being used. N has a fix for the bug. - * For N, the register and unregister calls are passed directly to the MidiManager. - * - * Note that this code is not thread-safe. It should only be called from the UI thread. - */ -public class MidiDeviceMonitor { - public final static String TAG = "MidiDeviceMonitor"; - - private static MidiDeviceMonitor mInstance; - private MidiManager mMidiManager; - private HashMap mCallbacks = new HashMap(); - private MyDeviceCallback mMyDeviceCallback; - // We only need the workaround for versions before N. - private boolean mUseProxy = Build.VERSION.SDK_INT <= Build.VERSION_CODES.M; - - // Use an inner class so we do not clutter the API of MidiDeviceMonitor - // with public DeviceCallback methods. - protected class MyDeviceCallback extends DeviceCallback { - - @Override - public void onDeviceAdded(final MidiDeviceInfo device) { - // Call all of the locally registered callbacks. - for(Map.Entry item : mCallbacks.entrySet()) { - final DeviceCallback callback = item.getKey(); - Handler handler = item.getValue(); - if(handler == null) { - callback.onDeviceAdded(device); - } else { - handler.post(new Runnable() { - @Override - public void run() { - callback.onDeviceAdded(device); - } - }); - } - } - } - - @Override - public void onDeviceRemoved(final MidiDeviceInfo device) { - for(Map.Entry item : mCallbacks.entrySet()) { - final DeviceCallback callback = item.getKey(); - Handler handler = item.getValue(); - if(handler == null) { - callback.onDeviceRemoved(device); - } else { - handler.post(new Runnable() { - @Override - public void run() { - callback.onDeviceRemoved(device); - } - }); - } - } - } - - @Override - public void onDeviceStatusChanged(final MidiDeviceStatus status) { - for(Map.Entry item : mCallbacks.entrySet()) { - final DeviceCallback callback = item.getKey(); - Handler handler = item.getValue(); - if(handler == null) { - callback.onDeviceStatusChanged(status); - } else { - handler.post(new Runnable() { - @Override - public void run() { - callback.onDeviceStatusChanged(status); - } - }); - } - } - } - } - - private MidiDeviceMonitor(MidiManager midiManager) { - mMidiManager = midiManager; - if (mUseProxy) { - Log.i(TAG,"Running on M so we need to use the workaround."); - mMyDeviceCallback = new MyDeviceCallback(); - mMidiManager.registerDeviceCallback(mMyDeviceCallback, - new Handler(Looper.getMainLooper())); - } - } - - public synchronized static MidiDeviceMonitor getInstance(MidiManager midiManager) { - if (mInstance == null) { - mInstance = new MidiDeviceMonitor(midiManager); - } - return mInstance; - } - - public void registerDeviceCallback(DeviceCallback callback, Handler handler) { - if (mUseProxy) { - // Keep our own list of callbacks. - mCallbacks.put(callback, handler); - } else { - mMidiManager.registerDeviceCallback(callback, handler); - } - } - - public void unregisterDeviceCallback(DeviceCallback callback) { - if (mUseProxy) { - mCallbacks.remove(callback); - } else { - // This works on N or later. - mMidiManager.unregisterDeviceCallback(callback); - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDispatcher.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDispatcher.java deleted file mode 100644 index 73de71ec..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiDispatcher.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiReceiver; -import android.media.midi.MidiSender; - -import java.io.IOException; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Utility class for dispatching MIDI data to a list of {@link android.media.midi.MidiReceiver}s. - * This class subclasses {@link android.media.midi.MidiReceiver} and dispatches any data it receives - * to its receiver list. Any receivers that throw an exception upon receiving data will - * be automatically removed from the receiver list, but no IOException will be returned - * from the dispatcher's {@link android.media.midi.MidiReceiver#onReceive} in that case. - */ -public final class MidiDispatcher extends MidiReceiver { - - private final CopyOnWriteArrayList mReceivers - = new CopyOnWriteArrayList(); - - private final MidiSender mSender = new MidiSender() { - /** - * Called to connect a {@link android.media.midi.MidiReceiver} to the sender - * - * @param receiver the receiver to connect - */ - @Override - public void onConnect(MidiReceiver receiver) { - mReceivers.add(receiver); - } - - /** - * Called to disconnect a {@link android.media.midi.MidiReceiver} from the sender - * - * @param receiver the receiver to disconnect - */ - @Override - public void onDisconnect(MidiReceiver receiver) { - mReceivers.remove(receiver); - } - }; - - /** - * Returns the number of {@link android.media.midi.MidiReceiver}s this dispatcher contains. - * @return the number of receivers - */ - public int getReceiverCount() { - return mReceivers.size(); - } - - /** - * Returns a {@link android.media.midi.MidiSender} which is used to add and remove - * {@link android.media.midi.MidiReceiver}s - * to the dispatcher's receiver list. - * @return the dispatcher's MidiSender - */ - public MidiSender getSender() { - return mSender; - } - - @Override - public void onSend(byte[] msg, int offset, int count, long timestamp) throws IOException { - for (MidiReceiver receiver : mReceivers) { - try { - receiver.send(msg, offset, count, timestamp); - } catch (IOException e) { - // if the receiver fails we remove the receiver but do not propagate the exception - mReceivers.remove(receiver); - } - } - } - - @Override - public void flush() throws IOException { - for (MidiReceiver receiver : mReceivers) { - receiver.flush(); - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventScheduler.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventScheduler.java deleted file mode 100644 index 610e1ec4..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventScheduler.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiReceiver; - -import java.io.IOException; - -/** - * Add MIDI Events to an EventScheduler - */ -public class MidiEventScheduler extends EventScheduler { - // Maintain a pool of scheduled events to reduce memory allocation. - // This pool increases performance by about 14%. - private final static int POOL_EVENT_SIZE = 16; - private MidiReceiver mReceiver = new SchedulingReceiver(); - - private class SchedulingReceiver extends MidiReceiver - { - /** - * Store these bytes in the EventScheduler to be delivered at the specified - * time. - */ - @Override - public void onSend(byte[] msg, int offset, int count, long timestamp) - throws IOException { - MidiEvent event = createScheduledEvent(msg, offset, count, timestamp); - if (event != null) { - add(event); - } - } - } - - public static class MidiEvent extends SchedulableEvent { - public int count = 0; - public byte[] data; - - private MidiEvent(int count) { - super(0); - data = new byte[count]; - } - - private MidiEvent(byte[] msg, int offset, int count, long timestamp) { - super(timestamp); - data = new byte[count]; - System.arraycopy(msg, offset, data, 0, count); - this.count = count; - } - - @Override - public String toString() { - String text = "Event: "; - for (int i = 0; i < count; i++) { - text += data[i] + ", "; - } - return text; - } - } - - /** - * Create an event that contains the message. - */ - private MidiEvent createScheduledEvent(byte[] msg, int offset, int count, - long timestamp) { - MidiEvent event; - if (count > POOL_EVENT_SIZE) { - event = new MidiEvent(msg, offset, count, timestamp); - } else { - event = (MidiEvent) removeEventfromPool(); - if (event == null) { - event = new MidiEvent(POOL_EVENT_SIZE); - } - System.arraycopy(msg, offset, event.data, 0, count); - event.count = count; - event.setTimestamp(timestamp); - } - return event; - } - - /** - * Return events to a pool so they can be reused. - * - * @param event - */ - @Override - public void addEventToPool(SchedulableEvent event) { - // Make sure the event is suitable for the pool. - if (event instanceof MidiEvent) { - MidiEvent midiEvent = (MidiEvent) event; - if (midiEvent.data.length == POOL_EVENT_SIZE) { - super.addEventToPool(event); - } - } - } - - /** - * This MidiReceiver will write date to the scheduling buffer. - * @return the MidiReceiver - */ - public MidiReceiver getReceiver() { - return mReceiver; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventThread.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventThread.java deleted file mode 100644 index 0cad5623..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiEventThread.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiSender; -import android.util.Log; - -import java.io.IOException; - -public class MidiEventThread extends MidiEventScheduler { - - private EventThread mEventThread; - MidiDispatcher mDispatcher = new MidiDispatcher(); - - class EventThread extends Thread { - private boolean go = true; - - @Override - public void run() { - while (go) { - try { - MidiEvent event = (MidiEvent) waitNextEvent(); - try { - Log.i(MidiConstants.TAG, "Fire event " + event.data[0] + " at " - + event.getTimestamp()); - mDispatcher.send(event.data, 0, - event.count, event.getTimestamp()); - } catch (IOException e) { - e.printStackTrace(); - } - // Put event back in the pool for future use. - addEventToPool(event); - } catch (InterruptedException e) { - // OK, this is how we stop the thread. - } - } - } - - /** - * Asynchronously tell the thread to stop. - */ - public void requestStop() { - go = false; - interrupt(); - } - } - - public void start() { - stop(); - mEventThread = new EventThread(); - mEventThread.start(); - } - - /** - * Asks the thread to stop then waits for it to stop. - */ - public void stop() { - if (mEventThread != null) { - mEventThread.requestStop(); - try { - mEventThread.join(500); - } catch (InterruptedException e) { - Log.e(MidiConstants.TAG, - "Interrupted while waiting for MIDI EventScheduler thread to stop."); - } finally { - mEventThread = null; - } - } - } - - public MidiSender getSender() { - return mDispatcher.getSender(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiFramer.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiFramer.java deleted file mode 100644 index f196cb79..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiFramer.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiReceiver; - -import java.io.IOException; - -/** - * Convert stream of arbitrary MIDI bytes into discrete messages. - * - * Parses the incoming bytes and then posts individual messages to the receiver - * specified in the constructor. Short messages of 1-3 bytes will be complete. - * System Exclusive messages may be posted in pieces. - * - * Resolves Running Status and interleaved System Real-Time messages. - */ -public class MidiFramer extends MidiReceiver { - private MidiReceiver mReceiver; - private byte[] mBuffer = new byte[3]; - private int mCount; - private byte mRunningStatus; - private int mNeeded; - private boolean mInSysEx; - - public MidiFramer(MidiReceiver receiver) { - mReceiver = receiver; - } - - /* - * @see android.midi.MidiReceiver#onSend(byte[], int, int, long) - */ - @Override - public void onSend(byte[] data, int offset, int count, long timestamp) - throws IOException { - int sysExStartOffset = (mInSysEx ? offset : -1); - - for (int i = 0; i < count; i++) { - final byte currentByte = data[offset]; - final int currentInt = currentByte & 0xFF; - if (currentInt >= 0x80) { // status byte? - if (currentInt < 0xF0) { // channel message? - mRunningStatus = currentByte; - mCount = 1; - mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1; - } else if (currentInt < 0xF8) { // system common? - if (currentInt == 0xF0 /* SysEx Start */) { - // Log.i(TAG, "SysEx Start"); - mInSysEx = true; - sysExStartOffset = offset; - } else if (currentInt == 0xF7 /* SysEx End */) { - // Log.i(TAG, "SysEx End"); - if (mInSysEx) { - mReceiver.send(data, sysExStartOffset, - offset - sysExStartOffset + 1, timestamp); - mInSysEx = false; - sysExStartOffset = -1; - } - } else { - mBuffer[0] = currentByte; - mRunningStatus = 0; - mCount = 1; - mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1; - } - } else { // real-time? - // Single byte message interleaved with other data. - if (mInSysEx) { - mReceiver.send(data, sysExStartOffset, - offset - sysExStartOffset, timestamp); - sysExStartOffset = offset + 1; - } - mReceiver.send(data, offset, 1, timestamp); - } - } else { // data byte - if (!mInSysEx) { - mBuffer[mCount++] = currentByte; - if (--mNeeded == 0) { - if (mRunningStatus != 0) { - mBuffer[0] = mRunningStatus; - } - mReceiver.send(mBuffer, 0, mCount, timestamp); - mNeeded = MidiConstants.getBytesPerMessage(mBuffer[0]) - 1; - mCount = 1; - } - } - } - ++offset; - } - - // send any accumulatedSysEx data - if (sysExStartOffset >= 0 && sysExStartOffset < offset) { - mReceiver.send(data, sysExStartOffset, - offset - sysExStartOffset, timestamp); - } - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiInputPortSelector.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiInputPortSelector.java deleted file mode 100644 index 818c6888..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiInputPortSelector.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.app.Activity; -import android.media.midi.MidiDevice; -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiInputPort; -import android.media.midi.MidiManager; -import android.media.midi.MidiReceiver; -import android.util.Log; - -import java.io.IOException; - -/** - * Manages a Spinner for selecting a MidiInputPort. - */ -public class MidiInputPortSelector extends MidiPortSelector { - - private MidiInputPort mInputPort; - private MidiDevice mOpenDevice; - - /** - * @param midiManager - * @param activity - * @param spinnerId ID from the layout resource - */ - public MidiInputPortSelector(MidiManager midiManager, Activity activity, - int spinnerId) { - super(midiManager, activity, spinnerId, MidiDeviceInfo.PortInfo.TYPE_INPUT); - } - - @Override - public void onPortSelected(final MidiPortWrapper wrapper) { - close(); - final MidiDeviceInfo info = wrapper.getDeviceInfo(); - if (info != null) { - mMidiManager.openDevice(info, new MidiManager.OnDeviceOpenedListener() { - @Override - public void onDeviceOpened(MidiDevice device) { - if (device == null) { - Log.e(MidiConstants.TAG, "could not open " + info); - } else { - mOpenDevice = device; - mInputPort = mOpenDevice.openInputPort( - wrapper.getPortIndex()); - if (mInputPort == null) { - Log.e(MidiConstants.TAG, "could not open input port on " + info); - } - } - } - }, null); - // Don't run the callback on the UI thread because openInputPort might take a while. - } - } - - public MidiReceiver getReceiver() { - return mInputPort; - } - - @Override - public void onClose() { - try { - if (mInputPort != null) { - Log.i(MidiConstants.TAG, "MidiInputPortSelector.onClose() - close port"); - mInputPort.close(); - } - mInputPort = null; - if (mOpenDevice != null) { - mOpenDevice.close(); - } - mOpenDevice = null; - } catch (IOException e) { - Log.e(MidiConstants.TAG, "cleanup failed", e); - } - super.onClose(); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortConnectionSelector.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortConnectionSelector.java deleted file mode 100644 index e3959cac..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortConnectionSelector.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.app.Activity; -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiManager; -import android.util.Log; - -import java.io.IOException; - -/** - * Select an output port and connect it to a destination input port. - */ -public class MidiOutputPortConnectionSelector extends MidiPortSelector { - public final static String TAG = "MidiOutputPortConnectionSelector"; - private MidiPortConnector mSynthConnector; - private MidiDeviceInfo mDestinationDeviceInfo; - private int mDestinationPortIndex; - private MidiPortWrapper mLastWrapper; - private MidiPortConnector.OnPortsConnectedListener mConnectedListener; - - /** - * Create a selector for connecting to the destination input port. - * - * @param midiManager - * @param activity - * @param spinnerId - * @param destinationDeviceInfo - * @param destinationPortIndex - */ - public MidiOutputPortConnectionSelector(MidiManager midiManager, - Activity activity, int spinnerId, - MidiDeviceInfo destinationDeviceInfo, int destinationPortIndex) { - super(midiManager, activity, spinnerId, - MidiDeviceInfo.PortInfo.TYPE_OUTPUT); - mDestinationDeviceInfo = destinationDeviceInfo; - mDestinationPortIndex = destinationPortIndex; - } - - @Override - public void onPortSelected(final MidiPortWrapper wrapper) { - if(!wrapper.equals(mLastWrapper)) { - onClose(); - if (wrapper.getDeviceInfo() != null) { - mSynthConnector = new MidiPortConnector(mMidiManager); - mSynthConnector.connectToDevicePort(wrapper.getDeviceInfo(), - wrapper.getPortIndex(), mDestinationDeviceInfo, - mDestinationPortIndex, - // not safe on UI thread - mConnectedListener, null); - } - } - mLastWrapper = wrapper; - } - - @Override - public void onClose() { - try { - if (mSynthConnector != null) { - mSynthConnector.close(); - mSynthConnector = null; - } - } catch (IOException e) { - Log.e(MidiConstants.TAG, "Exception in closeSynthResources()", e); - } - super.onClose(); - } - - /** - * @param connectedListener - */ - public void setConnectedListener( - MidiPortConnector.OnPortsConnectedListener connectedListener) { - mConnectedListener = connectedListener; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortSelector.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortSelector.java deleted file mode 100644 index 1272f8c2..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiOutputPortSelector.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.app.Activity; -import android.media.midi.MidiDevice; -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiManager; -import android.media.midi.MidiOutputPort; -import android.media.midi.MidiSender; -import android.util.Log; - -import java.io.IOException; - -/** - * Manages a Spinner for selecting a MidiOutputPort. - */ -public class MidiOutputPortSelector extends MidiPortSelector { - public final static String TAG = "MidiOutputPortSelector"; - private MidiOutputPort mOutputPort; - private MidiDispatcher mDispatcher = new MidiDispatcher(); - private MidiDevice mOpenDevice; - - /** - * @param midiManager - * @param activity - * @param spinnerId ID from the layout resource - */ - public MidiOutputPortSelector(MidiManager midiManager, Activity activity, - int spinnerId) { - super(midiManager, activity, spinnerId, MidiDeviceInfo.PortInfo.TYPE_OUTPUT); - } - - @Override - public void onPortSelected(final MidiPortWrapper wrapper) { - close(); - - final MidiDeviceInfo info = wrapper.getDeviceInfo(); - if (info != null) { - mMidiManager.openDevice(info, new MidiManager.OnDeviceOpenedListener() { - - @Override - public void onDeviceOpened(MidiDevice device) { - if (device == null) { - Log.e(MidiConstants.TAG, "could not open " + info); - } else { - mOpenDevice = device; - mOutputPort = device.openOutputPort(wrapper.getPortIndex()); - if (mOutputPort == null) { - Log.e(MidiConstants.TAG, - "could not open output port for " + info); - return; - } - mOutputPort.connect(mDispatcher); - } - } - }, null); - // Don't run the callback on the UI thread because openOutputPort might take a while. - } - } - - @Override - public void onClose() { - try { - if (mOutputPort != null) { - mOutputPort.disconnect(mDispatcher); - } - mOutputPort = null; - if (mOpenDevice != null) { - mOpenDevice.close(); - } - mOpenDevice = null; - } catch (IOException e) { - Log.e(MidiConstants.TAG, "cleanup failed", e); - } - super.onClose(); - } - - /** - * You can connect your MidiReceivers to this sender. The user will then select which output - * port will send messages through this MidiSender. - * @return a MidiSender that will send the messages from the selected port. - */ - public MidiSender getSender() { - return mDispatcher.getSender(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortConnector.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortConnector.java deleted file mode 100644 index ebff022e..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortConnector.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiDevice; -import android.media.midi.MidiDevice.MidiConnection; -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiInputPort; -import android.media.midi.MidiManager; -import android.os.Handler; -import android.util.Log; - -import java.io.IOException; - -/** - * Tool for connecting MIDI ports on two remote devices. - */ -public class MidiPortConnector { - private final MidiManager mMidiManager; - private MidiDevice mSourceDevice; - private MidiDevice mDestinationDevice; - private MidiConnection mConnection; - - /** - * @param midiManager - */ - public MidiPortConnector(MidiManager midiManager) { - mMidiManager = midiManager; - } - - public void close() throws IOException { - if (mConnection != null) { - Log.i(MidiConstants.TAG, - "MidiPortConnector closing connection " + mConnection); - mConnection.close(); - mConnection = null; - } - if (mSourceDevice != null) { - mSourceDevice.close(); - mSourceDevice = null; - } - if (mDestinationDevice != null) { - mDestinationDevice.close(); - mDestinationDevice = null; - } - } - - private void safeClose() { - try { - close(); - } catch (IOException e) { - Log.e(MidiConstants.TAG, "could not close resources", e); - } - } - - /** - * Listener class used for receiving the results of - * {@link #connectToDevicePort} - */ - public interface OnPortsConnectedListener { - /** - * Called to respond to a {@link #connectToDevicePort} request - * - * @param connection - * a {@link MidiConnection} that represents the connected - * ports, or null if connection failed - */ - abstract public void onPortsConnected(MidiConnection connection); - } - - /** - * Open two devices and connect their ports. - * - * @param sourceDeviceInfo - * @param sourcePortIndex - * @param destinationDeviceInfo - * @param destinationPortIndex - */ - public void connectToDevicePort(final MidiDeviceInfo sourceDeviceInfo, - final int sourcePortIndex, - final MidiDeviceInfo destinationDeviceInfo, - final int destinationPortIndex) { - connectToDevicePort(sourceDeviceInfo, sourcePortIndex, - destinationDeviceInfo, destinationPortIndex, null, null); - } - - /** - * Open two devices and connect their ports. - * Then notify listener of the result. - * - * @param sourceDeviceInfo - * @param sourcePortIndex - * @param destinationDeviceInfo - * @param destinationPortIndex - * @param listener - * @param handler - */ - public void connectToDevicePort(final MidiDeviceInfo sourceDeviceInfo, - final int sourcePortIndex, - final MidiDeviceInfo destinationDeviceInfo, - final int destinationPortIndex, - final OnPortsConnectedListener listener, final Handler handler) { - safeClose(); - mMidiManager.openDevice(destinationDeviceInfo, - new MidiManager.OnDeviceOpenedListener() { - @Override - public void onDeviceOpened(MidiDevice destinationDevice) { - if (destinationDevice == null) { - Log.e(MidiConstants.TAG, - "could not open " + destinationDeviceInfo); - if (listener != null) { - listener.onPortsConnected(null); - } - } else { - mDestinationDevice = destinationDevice; - Log.i(MidiConstants.TAG, - "connectToDevicePort opened " - + destinationDeviceInfo); - // Destination device was opened so go to next step. - MidiInputPort destinationInputPort = destinationDevice - .openInputPort(destinationPortIndex); - if (destinationInputPort != null) { - Log.i(MidiConstants.TAG, - "connectToDevicePort opened port on " - + destinationDeviceInfo); - connectToDevicePort(sourceDeviceInfo, - sourcePortIndex, - destinationInputPort, - listener, handler); - } else { - Log.e(MidiConstants.TAG, - "could not open port on " - + destinationDeviceInfo); - safeClose(); - if (listener != null) { - listener.onPortsConnected(null); - } - } - } - } - }, handler); - } - - - /** - * Open a source device and connect its output port to the - * destinationInputPort. - * - * @param sourceDeviceInfo - * @param sourcePortIndex - * @param destinationInputPort - */ - private void connectToDevicePort(final MidiDeviceInfo sourceDeviceInfo, - final int sourcePortIndex, - final MidiInputPort destinationInputPort, - final OnPortsConnectedListener listener, final Handler handler) { - mMidiManager.openDevice(sourceDeviceInfo, - new MidiManager.OnDeviceOpenedListener() { - @Override - public void onDeviceOpened(MidiDevice device) { - if (device == null) { - Log.e(MidiConstants.TAG, - "could not open " + sourceDeviceInfo); - safeClose(); - if (listener != null) { - listener.onPortsConnected(null); - } - } else { - Log.i(MidiConstants.TAG, - "connectToDevicePort opened " - + sourceDeviceInfo); - // Device was opened so connect the ports. - mSourceDevice = device; - mConnection = device.connectPorts( - destinationInputPort, sourcePortIndex); - if (mConnection == null) { - Log.e(MidiConstants.TAG, "could not connect to " - + sourceDeviceInfo); - safeClose(); - } - if (listener != null) { - listener.onPortsConnected(mConnection); - } - } - } - }, handler); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortSelector.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortSelector.java deleted file mode 100644 index f0205147..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortSelector.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.app.Activity; -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiDeviceStatus; -import android.media.midi.MidiManager; -import android.media.midi.MidiManager.DeviceCallback; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; - -import java.util.HashSet; - -/** - * Base class that uses a Spinner to select available MIDI ports. - */ -public abstract class MidiPortSelector extends DeviceCallback { - private int mType = MidiDeviceInfo.PortInfo.TYPE_INPUT; - protected ArrayAdapter mAdapter; - protected HashSet mBusyPorts = new HashSet(); - private Spinner mSpinner; - protected MidiManager mMidiManager; - protected Activity mActivity; - private MidiPortWrapper mCurrentWrapper; - - /** - * @param midiManager - * @param activity - * @param spinnerId - * ID from the layout resource - * @param type - * TYPE_INPUT or TYPE_OUTPUT - */ - public MidiPortSelector(MidiManager midiManager, Activity activity, - int spinnerId, int type) { - mMidiManager = midiManager; - mActivity = activity; - mType = type; - mAdapter = new ArrayAdapter(activity, - android.R.layout.simple_spinner_item); - mAdapter.setDropDownViewResource( - android.R.layout.simple_spinner_dropdown_item); - mAdapter.add(new MidiPortWrapper(null, 0, 0)); - - mSpinner = (Spinner) activity.findViewById(spinnerId); - mSpinner.setOnItemSelectedListener( - new AdapterView.OnItemSelectedListener() { - - public void onItemSelected(AdapterView parent, View view, - int pos, long id) { - mCurrentWrapper = mAdapter.getItem(pos); - onPortSelected(mCurrentWrapper); - } - - public void onNothingSelected(AdapterView parent) { - onPortSelected(null); - mCurrentWrapper = null; - } - }); - mSpinner.setAdapter(mAdapter); - - MidiDeviceMonitor.getInstance(mMidiManager).registerDeviceCallback(this, - new Handler(Looper.getMainLooper())); - - MidiDeviceInfo[] infos = mMidiManager.getDevices(); - for (MidiDeviceInfo info : infos) { - onDeviceAdded(info); - } - } - - /** - * Set to no port selected. - */ - public void clearSelection() { - mSpinner.setSelection(0); - } - - private int getInfoPortCount(final MidiDeviceInfo info) { - int portCount = (mType == MidiDeviceInfo.PortInfo.TYPE_INPUT) - ? info.getInputPortCount() : info.getOutputPortCount(); - return portCount; - } - - @Override - public void onDeviceAdded(final MidiDeviceInfo info) { - int portCount = getInfoPortCount(info); - for (int i = 0; i < portCount; ++i) { - MidiPortWrapper wrapper = new MidiPortWrapper(info, mType, i); - mAdapter.add(wrapper); - Log.i(MidiConstants.TAG, wrapper + " was added to " + this); - mAdapter.notifyDataSetChanged(); - } - } - - @Override - public void onDeviceRemoved(final MidiDeviceInfo info) { - int portCount = getInfoPortCount(info); - for (int i = 0; i < portCount; ++i) { - MidiPortWrapper wrapper = new MidiPortWrapper(info, mType, i); - MidiPortWrapper currentWrapper = mCurrentWrapper; - mAdapter.remove(wrapper); - // If the currently selected port was removed then select no port. - if (wrapper.equals(currentWrapper)) { - clearSelection(); - } - mAdapter.notifyDataSetChanged(); - Log.i(MidiConstants.TAG, wrapper + " was removed"); - } - } - - @Override - public void onDeviceStatusChanged(final MidiDeviceStatus status) { - // If an input port becomes busy then remove it from the menu. - // If it becomes free then add it back to the menu. - if (mType == MidiDeviceInfo.PortInfo.TYPE_INPUT) { - MidiDeviceInfo info = status.getDeviceInfo(); - Log.i(MidiConstants.TAG, "MidiPortSelector.onDeviceStatusChanged status = " + status - + ", mType = " + mType - + ", activity = " + mActivity.getPackageName() - + ", info = " + info); - // Look for transitions from free to busy. - int portCount = info.getInputPortCount(); - for (int i = 0; i < portCount; ++i) { - MidiPortWrapper wrapper = new MidiPortWrapper(info, mType, i); - if (!wrapper.equals(mCurrentWrapper)) { - if (status.isInputPortOpen(i)) { // busy? - if (!mBusyPorts.contains(wrapper)) { - // was free, now busy - mBusyPorts.add(wrapper); - mAdapter.remove(wrapper); - mAdapter.notifyDataSetChanged(); - } - } else { - if (mBusyPorts.remove(wrapper)) { - // was busy, now free - mAdapter.add(wrapper); - mAdapter.notifyDataSetChanged(); - } - } - } - } - } - } - - /** - * Implement this method to handle the user selecting a port on a device. - * - * @param wrapper - */ - public abstract void onPortSelected(MidiPortWrapper wrapper); - - /** - * Implement this method to clean up any open resources. - */ - public void onClose() { - } - - /** - * Implement this method to clean up any open resources. - */ - public void onDestroy() { - MidiDeviceMonitor.getInstance(mMidiManager).unregisterDeviceCallback(this); - } - - /** - * - */ - public void close() { - onClose(); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortWrapper.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortWrapper.java deleted file mode 100644 index bf48d779..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiPortWrapper.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools; - -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiDeviceInfo.PortInfo; - -public class MidiPortWrapper { - private MidiDeviceInfo mInfo; - private int mPortIndex; - private int mType; - private String mString; - - /** - * Wrapper for a MIDI device and port description. - * @param info - * @param portType - * @param portIndex - */ - public MidiPortWrapper(MidiDeviceInfo info, int portType, int portIndex) { - mInfo = info; - mType = portType; - mPortIndex = portIndex; - } - - private void updateString() { - if (mInfo == null) { - mString = "- - - - - -"; - } else { - StringBuilder sb = new StringBuilder(); - String name = mInfo.getProperties() - .getString(MidiDeviceInfo.PROPERTY_NAME); - if (name == null) { - name = mInfo.getProperties() - .getString(MidiDeviceInfo.PROPERTY_MANUFACTURER) + ", " - + mInfo.getProperties() - .getString(MidiDeviceInfo.PROPERTY_PRODUCT); - } - sb.append("#" + mInfo.getId()); - sb.append(", ").append(name); - PortInfo portInfo = findPortInfo(); - sb.append("[" + mPortIndex + "]"); - if (portInfo != null) { - sb.append(", ").append(portInfo.getName()); - } else { - sb.append(", null"); - } - mString = sb.toString(); - } - } - - /** - * @param info - * @param portIndex - * @return - */ - private PortInfo findPortInfo() { - PortInfo[] ports = mInfo.getPorts(); - for (PortInfo portInfo : ports) { - if (portInfo.getPortNumber() == mPortIndex - && portInfo.getType() == mType) { - return portInfo; - } - } - return null; - } - - public int getPortIndex() { - return mPortIndex; - } - - public MidiDeviceInfo getDeviceInfo() { - return mInfo; - } - - @Override - public String toString() { - if (mString == null) { - updateString(); - } - return mString; - } - - @Override - public boolean equals(Object other) { - if (other == null) - return false; - if (!(other instanceof MidiPortWrapper)) - return false; - MidiPortWrapper otherWrapper = (MidiPortWrapper) other; - if (mPortIndex != otherWrapper.mPortIndex) - return false; - if (mType != otherWrapper.mType) - return false; - if (mInfo == null) - return (otherWrapper.mInfo == null); - return mInfo.equals(otherWrapper.mInfo); - } - - @Override - public int hashCode() { - int hashCode = 1; - hashCode = 31 * hashCode + mPortIndex; - hashCode = 31 * hashCode + mType; - hashCode = 31 * hashCode + mInfo.hashCode(); - return hashCode; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiTools.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiTools.java deleted file mode 100644 index c759c0cd..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MidiTools.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ -package com.mobileer.miditools; - -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiManager; - -/** - * Miscellaneous tools for Android MIDI. - */ -public class MidiTools { - - /** - * @return a device that matches the manufacturer and product or null - */ - public static MidiDeviceInfo findDevice(MidiManager midiManager, - String manufacturer, String product) { - for (MidiDeviceInfo info : midiManager.getDevices()) { - String deviceManufacturer = info.getProperties() - .getString(MidiDeviceInfo.PROPERTY_MANUFACTURER); - if ((manufacturer != null) - && manufacturer.equals(deviceManufacturer)) { - String deviceProduct = info.getProperties() - .getString(MidiDeviceInfo.PROPERTY_PRODUCT); - if ((product != null) && product.equals(deviceProduct)) { - return info; - } - } - } - return null; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MusicKeyboardView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MusicKeyboardView.java deleted file mode 100644 index e9eee7fa..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/MusicKeyboardView.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * View that displays a traditional piano style keyboard. Finger presses are reported to a - * MusicKeyListener. Keys that pressed are highlighted. Running a finger along the top of the - * keyboard will only hit black keys. Running a finger along the bottom of the keyboard will only - * hit white keys. - */ -public class MusicKeyboardView extends View { - // Adjust proportions of the keys. - private static final int WHITE_KEY_GAP = 10; - private static final int PITCH_MIDDLE_C = 60; - private static final int NOTES_PER_OCTAVE = 12; - private static final int[] WHITE_KEY_OFFSETS = { - 0, 2, 4, 5, 7, 9, 11 - }; - private static final double BLACK_KEY_HEIGHT_FACTOR = 0.60; - private static final double BLACK_KEY_WIDTH_FACTOR = 0.6; - private static final double BLACK_KEY_OFFSET_FACTOR = 0.18; - - private static final int[] BLACK_KEY_HORIZONTAL_OFFSETS = { - -1, 1, -1, 0, 1 - }; - private static final boolean[] NOTE_IN_OCTAVE_IS_BLACK = { - false, true, - false, true, - false, false, true, - false, true, - false, true, - false - }; - - // Preferences - private int mNumKeys; - private int mNumPortraitKeys = NOTES_PER_OCTAVE + 1; - private int mNumLandscapeKeys = (2 * NOTES_PER_OCTAVE) + 1; - private int mNumWhiteKeys = 15; - - // Geometry. - private int mWidth; - private int mHeight; - private int mWhiteKeyWidth; - private double mBlackKeyWidth; - // Y position of bottom of black keys. - private int mBlackBottom; - private Rect[] mBlackKeyRectangles; - - // Keyboard state - private boolean[] mNotesOnByPitch = new boolean[128]; - - // Appearance - private Paint mShadowPaint; - private Paint mBlackOnKeyPaint; - private Paint mBlackOffKeyPaint; - private Paint mWhiteOnKeyPaint; - private Paint mWhiteOffKeyPaint; - private boolean mLegato = true; - - private HashMap mFingerMap = new HashMap(); - // Note number for the left most key. - private int mLowestPitch = PITCH_MIDDLE_C - NOTES_PER_OCTAVE; - private ArrayList mListeners = new ArrayList(); - - /** Implement this to receive keyboard events. */ - public interface MusicKeyListener { - /** This will be called when a key is pressed. */ - public void onKeyDown(int keyIndex); - - /** This will be called when a key is pressed. */ - public void onKeyUp(int keyIndex); - } - - public MusicKeyboardView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - void init() { - mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mShadowPaint.setStyle(Paint.Style.FILL); - mShadowPaint.setColor(0xFF707070); - - mBlackOnKeyPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBlackOnKeyPaint.setStyle(Paint.Style.FILL); - mBlackOnKeyPaint.setColor(0xFF2020E0); - - mBlackOffKeyPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBlackOffKeyPaint.setStyle(Paint.Style.FILL); - mBlackOffKeyPaint.setColor(0xFF202020); - - mWhiteOnKeyPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mWhiteOnKeyPaint.setStyle(Paint.Style.FILL); - mWhiteOnKeyPaint.setColor(0xFF6060F0); - - mWhiteOffKeyPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mWhiteOffKeyPaint.setStyle(Paint.Style.FILL); - mWhiteOffKeyPaint.setColor(0xFFF0F0F0); - - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mWidth = w; - mHeight = h; - mNumKeys = (mHeight > mWidth) ? mNumPortraitKeys : mNumLandscapeKeys; - mNumWhiteKeys = 0; - // Count white keys. - for (int i = 0; i < mNumKeys; i++) { - int pitch = mLowestPitch + i; - if (!isPitchBlack(pitch)) { - mNumWhiteKeys++; - } - } - - mWhiteKeyWidth = mWidth / mNumWhiteKeys; - mBlackKeyWidth = mWhiteKeyWidth * BLACK_KEY_WIDTH_FACTOR; - mBlackBottom = (int) (mHeight * BLACK_KEY_HEIGHT_FACTOR); - - makeBlackRectangles(); - } - - private void makeBlackRectangles() { - int top = 0; - ArrayList rectangles = new ArrayList(); - - int whiteKeyIndex = 0; - int blackKeyIndex = 0; - for (int i = 0; i < mNumKeys; i++) { - int x = mWhiteKeyWidth * whiteKeyIndex; - int pitch = mLowestPitch + i; - int note = pitch % NOTES_PER_OCTAVE; - if (NOTE_IN_OCTAVE_IS_BLACK[note]) { - double offset = BLACK_KEY_OFFSET_FACTOR - * BLACK_KEY_HORIZONTAL_OFFSETS[blackKeyIndex % 5]; - int left = (int) (x - mBlackKeyWidth * (0.6 - offset)); - left += WHITE_KEY_GAP / 2; - int right = (int) (left + mBlackKeyWidth); - Rect rect = new Rect(left, top, right, mBlackBottom); - rectangles.add(rect); - blackKeyIndex++; - } else { - whiteKeyIndex++; - } - } - mBlackKeyRectangles = rectangles.toArray(new Rect[0]); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - int whiteKeyIndex = 0; - canvas.drawRect(0, 0, mWidth, mHeight, mShadowPaint); - // Draw white keys first. - for (int i = 0; i < mNumKeys; i++) { - int pitch = mLowestPitch + i; - int note = pitch % NOTES_PER_OCTAVE; - if (!NOTE_IN_OCTAVE_IS_BLACK[note]) { - int x = (mWhiteKeyWidth * whiteKeyIndex) + (WHITE_KEY_GAP / 2); - Paint paint = mNotesOnByPitch[pitch] ? mWhiteOnKeyPaint - : mWhiteOffKeyPaint; - canvas.drawRect(x, 0, x + mWhiteKeyWidth - WHITE_KEY_GAP, mHeight, - paint); - whiteKeyIndex++; - } - } - // Then draw black keys over the white keys. - int blackKeyIndex = 0; - for (int i = 0; i < mNumKeys; i++) { - int pitch = mLowestPitch + i; - int note = pitch % NOTES_PER_OCTAVE; - if (NOTE_IN_OCTAVE_IS_BLACK[note]) { - Rect r = mBlackKeyRectangles[blackKeyIndex]; - Paint paint = mNotesOnByPitch[pitch] ? mBlackOnKeyPaint - : mBlackOffKeyPaint; - canvas.drawRect(r, paint); - blackKeyIndex++; - } - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - super.onTouchEvent(event); - int action = event.getActionMasked(); - // Track individual fingers. - int pointerIndex = event.getActionIndex(); - int id = event.getPointerId(pointerIndex); - // Get the pointer's current position - float x = event.getX(pointerIndex); - float y = event.getY(pointerIndex); - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - onFingerDown(id, x, y); - break; - case MotionEvent.ACTION_MOVE: - onFingerMove(id, x, y); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - onFingerUp(id, x, y); - break; - } - // Must return true or we do not get the ACTION_MOVE and - // ACTION_UP events. - return true; - } - - private void onFingerDown(int id, float x, float y) { - int pitch = xyToPitch(x, y); - fireKeyDown(pitch); - mFingerMap.put(id, pitch); - } - - private void onFingerMove(int id, float x, float y) { - Integer previousPitch = mFingerMap.get(id); - if (previousPitch != null) { - int pitch = -1; - if (y < mBlackBottom) { - // Only hit black keys if above line. - pitch = xyToBlackPitch(x, y); - } else { - pitch = xToWhitePitch(x); - } - // Did we change to a new key. - if ((pitch >= 0) && (pitch != previousPitch)) { - if (mLegato) { - fireKeyDown(pitch); - fireKeyUp(previousPitch); - } else { - fireKeyUp(previousPitch); - fireKeyDown(pitch); - } - mFingerMap.put(id, pitch); - } - } - } - - private void onFingerUp(int id, float x, float y) { - Integer previousPitch = mFingerMap.get(id); - if (previousPitch != null) { - fireKeyUp(previousPitch); - mFingerMap.remove(id); - } else { - int pitch = xyToPitch(x, y); - fireKeyUp(pitch); - } - } - - private void fireKeyDown(int pitch) { - for (MusicKeyListener listener : mListeners) { - listener.onKeyDown(pitch); - } - mNotesOnByPitch[pitch] = true; - invalidate(); - } - - private void fireKeyUp(int pitch) { - for (MusicKeyListener listener : mListeners) { - listener.onKeyUp(pitch); - } - mNotesOnByPitch[pitch] = false; - invalidate(); - } - - private int xyToPitch(float x, float y) { - int pitch = -1; - if (y < mBlackBottom) { - pitch = xyToBlackPitch(x, y); - } - if (pitch < 0) { - pitch = xToWhitePitch(x); - } - return pitch; - } - - private boolean isPitchBlack(int pitch) { - int note = pitch % NOTES_PER_OCTAVE; - return NOTE_IN_OCTAVE_IS_BLACK[note]; - } - - // Convert x to MIDI pitch. Ignores black keys. - private int xToWhitePitch(float x) { - int whiteKeyIndex = (int) (x / mWhiteKeyWidth); - int octave = whiteKeyIndex / WHITE_KEY_OFFSETS.length; - int indexInOctave = whiteKeyIndex - (octave * WHITE_KEY_OFFSETS.length); - int pitch = mLowestPitch + (octave * NOTES_PER_OCTAVE) + - WHITE_KEY_OFFSETS[indexInOctave]; - return pitch; - } - - // Convert x to MIDI pitch. Ignores white keys. - private int xyToBlackPitch(float x, float y) { - int result = -1; - int blackKeyIndex = 0; - for (int i = 0; i < mNumKeys; i++) { - int pitch = mLowestPitch + i; - if (isPitchBlack(pitch)) { - Rect rect = mBlackKeyRectangles[blackKeyIndex]; - if (rect.contains((int) x, (int) y)) { - result = pitch; - break; - } - blackKeyIndex++; - } - } - return result; - } - - public void addMusicKeyListener(MusicKeyListener musicKeyListener) { - mListeners.add(musicKeyListener); - } - - public void removeMusicKeyListener(MusicKeyListener musicKeyListener) { - mListeners.remove(musicKeyListener); - } - - /** - * Set the pitch of the lowest, leftmost key. If you set it to a black key then it will get - * adjusted upwards to a white key. Forces a redraw. - */ - public void setLowestPitch(int pitch) { - if (isPitchBlack(pitch)) { - pitch++; // force to next white key - } - mLowestPitch = pitch; - postInvalidate(); - } - - public int getLowestPitch() { - return mLowestPitch; - } - - /** - * Set the number of white keys in portrait mode. - */ - public void setNumPortraitKeys(int numPortraitKeys) { - mNumPortraitKeys = numPortraitKeys; - postInvalidate(); - } - - public int getNumPortraitKeys() { - return mNumPortraitKeys; - } - - /** - * Set the number of white keys in landscape mode. - */ - public void setNumLandscapeKeys(int numLandscapeKeys) { - mNumLandscapeKeys = numLandscapeKeys; - postInvalidate(); - } - - public int getNumLandscapeKeys() { - return mNumLandscapeKeys; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/AudioLatencyTuner.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/AudioLatencyTuner.java deleted file mode 100644 index dd512688..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/AudioLatencyTuner.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools.synth; - -import android.media.AudioAttributes; -import android.media.AudioTrack; -import android.util.Log; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Optimize the buffer size for an AudioTrack based on the underrun count. - *

- * This feature was added in N. So we check for the methods using reflection. - * If you are targeting N or later then you could just call the new methods directly. - */ -public class AudioLatencyTuner { - private static final String TAG = "AudioLatencyTuner"; - private static final int STATE_PRIMING = 0; - private static final int STATE_LOWERING = 1; - private static final int STATE_RAISING = 2; - - private static boolean mLowLatencySupported; // N or later? - - // These are found using reflection. - private static int mFlagLowLatency; // AudioAttributes.FLAG_LOW_LATENCY - private static Method mSetBufferSizeMethod = null; - private static Method mGetBufferCapacityMethod = null; - private static Method mGetUnderrunCountMethod = null; - - private final int mInitialSize; - private final AudioTrack mAudioTrack; - private final int mFramesPerBlock; - - private int mState = STATE_PRIMING; - private int mPreviousUnderrunCount; - - static { - reflectAdvancedMethods(); - } - - public AudioLatencyTuner(AudioTrack track, int framesPerBlock) { - mAudioTrack = track; - mInitialSize = track.getBufferSizeInFrames(); - mFramesPerBlock = framesPerBlock; - reset(); - } - - /** - * Use Java reflection to find the methods added in the N release. - */ - private static void reflectAdvancedMethods() { - try { - Field field = AudioAttributes.class.getField("FLAG_LOW_LATENCY"); - mFlagLowLatency = field.getInt(AudioAttributes.class); - mLowLatencySupported = true; - } catch (NoSuchFieldException e) { - mLowLatencySupported = false; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - - Method[] methods = AudioTrack.class.getMethods(); - - for (Method method : methods) { - if (method.getName().equals("setBufferSizeInFrames")) { - mSetBufferSizeMethod = method; - break; - } - } - - for (Method method : methods) { - if (method.getName().equals("getBufferCapacity")) { - mGetBufferCapacityMethod = method; - break; - } - } - - for (Method method : methods) { - if (method.getName().equals("getXRunCount")) { - mGetUnderrunCountMethod = method; - break; - } - } - } - - /** - * @return number of times the audio buffer underflowed and glitched. - */ - public int getUnderrunCount() { - // Call using reflection. - if (mGetUnderrunCountMethod != null && mAudioTrack != null) { - try { - Object result = mGetUnderrunCountMethod.invoke(mAudioTrack); - int count = ((Integer) result).intValue(); - return count; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - return 0; - } - - /** - * @return allocated size of the buffer - */ - public int getBufferCapacityInFrames() { - if (mGetBufferCapacityMethod != null) { - try { - Object result = mGetBufferCapacityMethod.invoke(mAudioTrack); - int size = ((Integer) result).intValue(); - return size; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - return mInitialSize; - } - - /** - * Set the amount of the buffer capacity that we want to use. - * Lower values will reduce latency but may cause glitches. - * Note that you may not get the size you asked for. - * - * @return actual size of the buffer - */ - public int setBufferSizeInFrames(int thresholdFrames) { - if (mSetBufferSizeMethod != null) { - try { - Object result = mSetBufferSizeMethod.invoke(mAudioTrack, thresholdFrames); - int actual = ((Integer) result).intValue(); - return actual; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - return mInitialSize; - } - - public int getBufferSizeInFrames() { - return mAudioTrack.getBufferSizeInFrames(); - } - - public static boolean isLowLatencySupported() { - return mLowLatencySupported; - } - - public static int getLowLatencyFlag() { - return mFlagLowLatency; - } - - public void reset() { - mState = STATE_PRIMING; - mPreviousUnderrunCount = 0; - setBufferSizeInFrames(mInitialSize); - } - - /** - * This should be called after every write(). - * It will lower the latency until there are underruns. - * Then it raises the latency until the underruns stop. - */ - public void update() { - if (!mLowLatencySupported) { - return; - } - int nextState = mState; - int underrunCount; - switch (mState) { - case STATE_PRIMING: - if (mAudioTrack.getPlaybackHeadPosition() > (8 * mFramesPerBlock)) { - nextState = STATE_LOWERING; - mPreviousUnderrunCount = getUnderrunCount(); - } - break; - case STATE_LOWERING: - underrunCount = getUnderrunCount(); - if (underrunCount > mPreviousUnderrunCount) { - nextState = STATE_RAISING; - } else { - if (incrementThreshold(-1)) { - // If we hit bottom then start raising it back up. - nextState = STATE_RAISING; - } - } - mPreviousUnderrunCount = underrunCount; - break; - case STATE_RAISING: - underrunCount = getUnderrunCount(); - if (underrunCount > mPreviousUnderrunCount) { - incrementThreshold(1); - } - mPreviousUnderrunCount = underrunCount; - break; - } - mState = nextState; - } - - /** - * Raise or lower the buffer size in blocks. - * @return true if the size did not change - */ - private boolean incrementThreshold(int deltaBlocks) { - int original = getBufferSizeInFrames(); - int numBlocks = original / mFramesPerBlock; - numBlocks += deltaBlocks; - int target = numBlocks * mFramesPerBlock; - int actual = setBufferSizeInFrames(target); - Log.i(TAG, "Buffer size changed from " + original + " to " + actual); - return actual == original; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/EnvelopeADSR.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/EnvelopeADSR.java deleted file mode 100644 index a80d85d5..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/EnvelopeADSR.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -/** - * Very simple Attack, Decay, Sustain, Release envelope with linear ramps. - * - * Times are in seconds. - */ -public class EnvelopeADSR extends SynthUnit { - private static final int IDLE = 0; - private static final int ATTACK = 1; - private static final int DECAY = 2; - private static final int SUSTAIN = 3; - private static final int RELEASE = 4; - private static final int FINISHED = 5; - private static final float MIN_TIME = 0.001f; - - private float mAttackRate; - private float mRreleaseRate; - private float mSustainLevel; - private float mDecayRate; - private float mCurrent; - private int mSstate = IDLE; - private int mSamplerate; - - public EnvelopeADSR( int sampleRate) { - mSamplerate = sampleRate; - setAttackTime(0.003f); - setDecayTime(0.08f); - setSustainLevel(0.3f); - setReleaseTime(1.0f); - } - - - - public void setAttackTime(float time) { - if (time < MIN_TIME) - time = MIN_TIME; - mAttackRate = 1.0f / (mSamplerate * time); - } - - public void setDecayTime(float time) { - if (time < MIN_TIME) - time = MIN_TIME; - mDecayRate = 1.0f / (mSamplerate * time); - } - - public void setSustainLevel(float level) { - if (level < 0.0f) - level = 0.0f; - mSustainLevel = level; - } - - public void setReleaseTime(float time) { - if (time < MIN_TIME) - time = MIN_TIME; - mRreleaseRate = 1.0f / (mSamplerate * time); - } - - public void on() { - mSstate = ATTACK; - } - - public void off() { - mSstate = RELEASE; - } - - @Override - public float render() { - switch (mSstate) { - case ATTACK: - mCurrent += mAttackRate; - if (mCurrent > 1.0f) { - mCurrent = 1.0f; - mSstate = DECAY; - } - break; - case DECAY: - mCurrent -= mDecayRate; - if (mCurrent < mSustainLevel) { - mCurrent = mSustainLevel; - mSstate = SUSTAIN; - } - break; - case RELEASE: - mCurrent -= mRreleaseRate; - if (mCurrent < 0.0f) { - mCurrent = 0.0f; - mSstate = FINISHED; - } - break; - } - return mCurrent; - } - - public boolean isDone() { - return mSstate == FINISHED; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/LatencyController.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/LatencyController.java deleted file mode 100644 index 21f7406a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/LatencyController.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -package com.mobileer.miditools.synth; - -/** - * Abstract control over the audio latency. - */ -public abstract class LatencyController { - private boolean mLowLatencyEnabled; - private boolean mAutoSizeEnabled; - - public void setLowLatencyEnabled(boolean enabled) { - mLowLatencyEnabled = enabled; - } - - public boolean isLowLatencyEnabled() { - return mLowLatencyEnabled; - } - - /** - * If true then adjust latency to lowest value that does not produce underruns. - * - * @param enabled - */ - public void setAutoSizeEnabled(boolean enabled) { - mAutoSizeEnabled = enabled; - } - - public boolean isAutoSizeEnabled() { - return mAutoSizeEnabled; - } - - /** - * @return true if this version supports the LOW_LATENCY flag - */ - public abstract boolean isLowLatencySupported(); - - /** - * The amount of the buffer capacity that is being used. - * @return - */ - public abstract int getBufferSizeInFrames(); - - /** - * The allocated size of the buffer. - * @return - */ - public abstract int getBufferCapacityInFrames(); - - public abstract int getUnderrunCount(); - - /** - * When the output is running, the LOW_LATENCY flag cannot be set. - * @return - */ - public abstract boolean isRunning(); - - /** - * Calculate the percentage of time that the a CPU is calculating data. - * @return percent CPU load - */ - public abstract int getCpuLoad(); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillator.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillator.java deleted file mode 100644 index d3936604..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillator.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -public class SawOscillator extends SynthUnit { - private float mPhase = 0.0f; - private float mPhaseIncrement = 0.01f; - private float mFrequency = 0.0f; - private float mFrequencyScaler = 1.0f; - private float mAmplitude = 1.0f; - - public void setPitch(float pitch) { - float freq = (float) pitchToFrequency(pitch); - setFrequency(freq); - } - - public void setFrequency(float frequency) { - mFrequency = frequency; - updatePhaseIncrement(); - } - - private void updatePhaseIncrement() { - mPhaseIncrement = 2.0f * mFrequency * mFrequencyScaler / 48000.0f; - } - - public void setAmplitude(float amplitude) { - mAmplitude = amplitude; - } - - public float getAmplitude() { - return mAmplitude; - } - - public float getFrequencyScaler() { - return mFrequencyScaler; - } - - public void setFrequencyScaler(float frequencyScaler) { - mFrequencyScaler = frequencyScaler; - updatePhaseIncrement(); - } - - float incrementWrapPhase() { - mPhase += mPhaseIncrement; - while (mPhase > 1.0) { - mPhase -= 2.0; - } - while (mPhase < -1.0) { - mPhase += 2.0; - } - return mPhase; - } - - @Override - public float render() { - return incrementWrapPhase() * mAmplitude; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillatorDPW.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillatorDPW.java deleted file mode 100644 index 7c7af8d1..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawOscillatorDPW.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -/** - * Band limited sawtooth oscillator. - * This will have very little aliasing at high frequencies. - */ -public class SawOscillatorDPW extends SawOscillator { - private float mZ1 = 0.0f; // delayed values - private float mZ2 = 0.0f; - private float mScaler; // frequency dependent scaler - private final static float VERY_LOW_FREQ = 0.0000001f; - - @Override - public void setFrequency(float freq) { - /* Calculate scaling based on frequency. */ - freq = Math.abs(freq); - super.setFrequency(freq); - if (freq < VERY_LOW_FREQ) { - mScaler = (float) (0.125 * 44100 / VERY_LOW_FREQ); - } else { - mScaler = (float) (0.125 * 44100 / freq); - } - } - - @Override - public float render() { - float phase = incrementWrapPhase(); - /* Square the raw sawtooth. */ - float squared = phase * phase; - float diffed = squared - mZ2; - mZ2 = mZ1; - mZ1 = squared; - return diffed * mScaler * getAmplitude(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawVoice.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawVoice.java deleted file mode 100644 index 958dae0d..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SawVoice.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -/** - * Sawtooth oscillator with an ADSR. - */ -public class SawVoice extends SynthVoice { - private SawOscillator mOscillator; - private EnvelopeADSR mEnvelope; - - public SawVoice(int sampleRate) { - mOscillator = createOscillator(); - mEnvelope = new EnvelopeADSR(sampleRate); - } - - protected SawOscillator createOscillator() { - return new SawOscillator(); - } - - @Override - public void noteOn(int noteIndex, int velocity) { - super.noteOn(noteIndex, velocity); - mOscillator.setPitch(noteIndex); - mOscillator.setAmplitude(getAmplitude()); - mEnvelope.on(); - } - - @Override - public void noteOff() { - super.noteOff(); - mEnvelope.off(); - } - - @Override - public void setFrequencyScaler(float scaler) { - mOscillator.setFrequencyScaler(scaler); - } - - @Override - public float render() { - float output = mOscillator.render() * mEnvelope.render(); - return output; - } - - @Override - public boolean isDone() { - return mEnvelope.isDone(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SimpleAudioOutput.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SimpleAudioOutput.java deleted file mode 100644 index 20643859..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SimpleAudioOutput.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -package com.mobileer.miditools.synth; - -import android.annotation.TargetApi; -import android.media.AudioAttributes; -import android.media.AudioFormat; -import android.media.AudioTrack; -import android.os.Build; -import android.util.Log; - -/** - * Simple base class for implementing audio output for examples. - * This can be sub-classed for experimentation or to redirect audio output. - */ -public class SimpleAudioOutput { - - private static final String TAG = "SimpleAudioOutput"; - public static final int SAMPLES_PER_FRAME = 2; - public static final int BYTES_PER_SAMPLE = 4; // float - public static final int BYTES_PER_FRAME = SAMPLES_PER_FRAME * BYTES_PER_SAMPLE; - // Arbitrary weighting factor for CPU load filter. Higher number for slower response. - private static final int LOAD_FILTER_SHIFT = 6; - private static final int LOAD_FILTER_SCALER = (1< 0) { - load = (int) ((filteredCpuInterval * 100) / filteredTotalInterval); - } - return load; - } - } - - /** - * Create an audio track then call play(). - */ - public void start(int framesPerBlock) { - stop(); - mAudioTrack = createAudioTrack(); - - mLatencyTuner = new AudioLatencyTuner(mAudioTrack, framesPerBlock); - // Use frame rate chosen by the AudioTrack so that we can get a - // low latency fast mixer track. - mFrameRate = mAudioTrack.getSampleRate(); - // AudioTrack will wait until it has enough data before starting. - mAudioTrack.play(); - previousBeginTime = 0; - filteredCpuInterval = 0; - filteredTotalInterval = 0; - } - - @TargetApi(Build.VERSION_CODES.M) - protected AudioTrack createAudioTrack() { - AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC); - boolean doLowLatency = (AudioLatencyTuner.isLowLatencySupported() - && mLatencyController.isLowLatencyEnabled()); - if (doLowLatency) { - Log.i(TAG, "createAudioTrack() using FLAG_LOW_LATENCY"); - attributesBuilder.setFlags(AudioLatencyTuner.getLowLatencyFlag()); - } - AudioAttributes attributes = attributesBuilder.build(); - - AudioFormat format = new AudioFormat.Builder() - .setEncoding(AudioFormat.ENCODING_PCM_FLOAT) - .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) - .build(); - AudioTrack.Builder builder = new AudioTrack.Builder() - .setAudioAttributes(attributes) - .setAudioFormat(format); - if (doLowLatency) { - // Start with a bigger buffer because we can lower it later. - int bufferSizeInFrames = LOW_LATENCY_BUFFER_CAPACITY_IN_FRAMES; - builder.setBufferSizeInBytes(bufferSizeInFrames * BYTES_PER_FRAME); - } - AudioTrack track = builder.build(); - if (track == null) { - throw new RuntimeException("Could not make the Audio Track! attributes = " - + attributes + ", format = " + format); - } - return track; - } - - public int write(float[] buffer, int offset, int length) { - endCpuLoadInterval(); - int result = mAudioTrack.write(buffer, offset, length, - AudioTrack.WRITE_BLOCKING); - beginCpuLoadInterval(); - if (result > 0 && mLatencyController.isAutoSizeEnabled()) { - mLatencyTuner.update(); - } - return result; - } - - private void endCpuLoadInterval() { - long now = System.nanoTime(); - if (previousBeginTime > 0) { - long elapsed = now - previousBeginTime; - // recursive low pass filter - filteredCpuInterval = ((filteredCpuInterval * LOAD_FILTER_SCALER) + elapsed) - >> LOAD_FILTER_SHIFT; - } - - } - private void beginCpuLoadInterval() { - long now = System.nanoTime(); - if (previousBeginTime > 0) { - long elapsed = now - previousBeginTime; - // recursive low pass filter - filteredTotalInterval = ((filteredTotalInterval * LOAD_FILTER_SCALER) + elapsed) - >> LOAD_FILTER_SHIFT; - } - previousBeginTime = now; - } - - public void stop() { - if (mAudioTrack != null) { - mAudioTrack.stop(); - mAudioTrack.release(); - mAudioTrack = null; - } - } - - public int getFrameRate() { - return mFrameRate; - } - - public LatencyController getLatencyController() { - return mLatencyController; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SineOscillator.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SineOscillator.java deleted file mode 100644 index 6e77f77c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SineOscillator.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -/** - * Sinewave oscillator. - */ -public class SineOscillator extends SawOscillator { - // Factorial constants. - private static final float IF3 = 1.0f / (2 * 3); - private static final float IF5 = IF3 / (4 * 5); - private static final float IF7 = IF5 / (6 * 7); - private static final float IF9 = IF7 / (8 * 9); - private static final float IF11 = IF9 / (10 * 11); - - /** - * Calculate sine using Taylor expansion. Do not use values outside the range. - * - * @param currentPhase in the range of -1.0 to +1.0 for one cycle - */ - public static float fastSin(float currentPhase) { - - /* Wrap phase back into region where results are more accurate. */ - float yp = (currentPhase > 0.5f) ? 1.0f - currentPhase - : ((currentPhase < (-0.5f)) ? (-1.0f) - currentPhase : currentPhase); - - float x = (float) (yp * Math.PI); - float x2 = (x * x); - /* Taylor expansion out to x**11/11! factored into multiply-adds */ - return x * (x2 * (x2 * (x2 * (x2 * ((x2 * (-IF11)) + IF9) - IF7) + IF5) - IF3) + 1); - } - - @Override - public float render() { - // Convert raw sawtooth to sine. - float phase = incrementWrapPhase(); - return fastSin(phase) * getAmplitude(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthEngine.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthEngine.java deleted file mode 100644 index 1e1c3a8b..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthEngine.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -import android.media.midi.MidiReceiver; -import android.util.Log; - -import com.mobileer.miditools.MidiConstants; -import com.mobileer.miditools.MidiEventScheduler; -import com.mobileer.miditools.MidiFramer; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.Iterator; - -/** - * Very simple polyphonic, single channel synthesizer. It runs a background - * thread that processes MIDI events and synthesizes audio. - */ -public class SynthEngine extends MidiReceiver { - - private static final String TAG = "SynthEngine"; - // 64 is the greatest common divisor of 192 and 128 - private static final int DEFAULT_FRAMES_PER_BLOCK = 64; - private static final int SAMPLES_PER_FRAME = 2; - - private volatile boolean mThreadEnabled; - private Thread mThread; - private float[] mBuffer = null; - private float mFrequencyScaler = 1.0f; - private float mBendRange = 2.0f; // semitones - private int mProgram; - - private ArrayList mFreeVoices = new ArrayList(); - private Hashtable - mVoices = new Hashtable(); - private MidiEventScheduler mEventScheduler; - private MidiFramer mFramer; - private MidiReceiver mReceiver = new MyReceiver(); - private SimpleAudioOutput mAudioOutput; - private int mSampleRate; - private int mFramesPerBlock = DEFAULT_FRAMES_PER_BLOCK; - private int mMidiByteCount; - - public SynthEngine() { - this(new SimpleAudioOutput()); - } - - public SynthEngine(SimpleAudioOutput audioOutput) { - mAudioOutput = audioOutput; - mReceiver = new MyReceiver(); - mFramer = new MidiFramer(mReceiver); - } - - public SimpleAudioOutput getAudioOutput() { - return mAudioOutput; - } - - /* This will be called when MIDI data arrives. */ - @Override - public void onSend(byte[] data, int offset, int count, long timestamp) - throws IOException { - if (mEventScheduler != null) { - if (!MidiConstants.isAllActiveSensing(data, offset, count)) { - mEventScheduler.getReceiver().send(data, offset, count, - timestamp); - } - } - mMidiByteCount += count; - } - - /** - * Call this before the engine is started. - * @param framesPerBlock - */ - public void setFramesPerBlock(int framesPerBlock) { - mFramesPerBlock = framesPerBlock; - } - - - private class MyReceiver extends MidiReceiver { - @Override - public void onSend(byte[] data, int offset, int count, long timestamp) - throws IOException { - byte command = (byte) (data[0] & MidiConstants.STATUS_COMMAND_MASK); - int channel = (byte) (data[0] & MidiConstants.STATUS_CHANNEL_MASK); - switch (command) { - case MidiConstants.STATUS_NOTE_OFF: - noteOff(channel, data[1], data[2]); - break; - case MidiConstants.STATUS_NOTE_ON: - noteOn(channel, data[1], data[2]); - break; - case MidiConstants.STATUS_PITCH_BEND: - int bend = (data[2] << 7) + data[1]; - pitchBend(channel, bend); - break; - case MidiConstants.STATUS_PROGRAM_CHANGE: - mProgram = data[1]; - mFreeVoices.clear(); - break; - default: - logMidiMessage(data, offset, count); - break; - } - } - } - - class MyRunnable implements Runnable { - @Override - public void run() { - try { - mAudioOutput.start(mFramesPerBlock); - mSampleRate = mAudioOutput.getFrameRate(); // rate is now valid - if (mBuffer == null) { - mBuffer = new float[mFramesPerBlock * SAMPLES_PER_FRAME]; - } - onLoopStarted(); - // The safest way to exit from a thread is to check a variable. - while (mThreadEnabled) { - processMidiEvents(); - generateBuffer(); - float[] buffer = mBuffer; - mAudioOutput.write(buffer, 0, buffer.length); - onBufferCompleted(mFramesPerBlock); - } - } catch (Exception e) { - Log.e(TAG, "SynthEngine background thread exception.", e); - } finally { - onLoopEnded(); - mAudioOutput.stop(); - } - } - } - - /** - * This is called from the synthesis thread before it starts looping. - */ - public void onLoopStarted() { - } - - /** - * This is called once at the end of each synthesis loop. - * - * @param framesPerBuffer - */ - public void onBufferCompleted(int framesPerBuffer) { - } - - /** - * This is called from the synthesis thread when it stops looping. - */ - public void onLoopEnded() { - } - - /** - * Assume message has been aligned to the start of a MIDI message. - * - * @param data - * @param offset - * @param count - */ - public void logMidiMessage(byte[] data, int offset, int count) { - String text = "Received: "; - for (int i = 0; i < count; i++) { - text += String.format("0x%02X, ", data[offset + i]); - } - Log.i(TAG, text); - } - - /** - * @throws IOException - * - */ - private void processMidiEvents() throws IOException { - long now = System.nanoTime(); // TODO use audio presentation time - MidiEventScheduler.MidiEvent event = (MidiEventScheduler.MidiEvent) mEventScheduler.getNextEvent(now); - while (event != null) { - mFramer.send(event.data, 0, event.count, event.getTimestamp()); - mEventScheduler.addEventToPool(event); - event = (MidiEventScheduler.MidiEvent) mEventScheduler.getNextEvent(now); - } - } - - /** - * Mix the output of each active voice into a buffer. - */ - private void generateBuffer() { - float[] buffer = mBuffer; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = 0.0f; - } - Iterator iterator = mVoices.values().iterator(); - while (iterator.hasNext()) { - SynthVoice voice = iterator.next(); - if (voice.isDone()) { - iterator.remove(); - // mFreeVoices.add(voice); - } else { - voice.mix(buffer, SAMPLES_PER_FRAME, 0.25f); - } - } - } - - public void noteOff(int channel, int noteIndex, int velocity) { - SynthVoice voice = mVoices.get(noteIndex); - if (voice != null) { - voice.noteOff(); - } - } - - public void allNotesOff() { - Iterator iterator = mVoices.values().iterator(); - while (iterator.hasNext()) { - SynthVoice voice = iterator.next(); - voice.noteOff(); - } - } - - /** - * Create a SynthVoice. - */ - public SynthVoice createVoice(int program) { - // For every odd program number use a sine wave. - if ((program & 1) == 1) { - return new SineVoice(mSampleRate); - } else { - return new SawVoice(mSampleRate); - } - } - - /** - * - * @param channel - * @param noteIndex - * @param velocity - */ - public void noteOn(int channel, int noteIndex, int velocity) { - if (velocity == 0) { - noteOff(channel, noteIndex, velocity); - } else { - mVoices.remove(noteIndex); - SynthVoice voice; - if (mFreeVoices.size() > 0) { - voice = mFreeVoices.remove(mFreeVoices.size() - 1); - } else { - voice = createVoice(mProgram); - } - voice.setFrequencyScaler(mFrequencyScaler); - voice.noteOn(noteIndex, velocity); - mVoices.put(noteIndex, voice); - } - } - - public void pitchBend(int channel, int bend) { - double semitones = (mBendRange * (bend - 0x2000)) / 0x2000; - mFrequencyScaler = (float) Math.pow(2.0, semitones / 12.0); - Iterator iterator = mVoices.values().iterator(); - while (iterator.hasNext()) { - SynthVoice voice = iterator.next(); - voice.setFrequencyScaler(mFrequencyScaler); - } - } - - /** - * Start the synthesizer. - */ - public void start() { - stop(); - mThreadEnabled = true; - mThread = new Thread(new MyRunnable()); - mEventScheduler = new MidiEventScheduler(); - mThread.start(); - } - - /** - * Stop the synthesizer. - */ - public void stop() { - mThreadEnabled = false; - if (mThread != null) { - try { - mThread.interrupt(); - mThread.join(500); - } catch (InterruptedException e) { - // OK, just stopping safely. - } - mThread = null; - mEventScheduler = null; - } - } - - public LatencyController getLatencyController() { - return mAudioOutput.getLatencyController(); - } - - public int getMidiByteCount() { - return mMidiByteCount; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthUnit.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthUnit.java deleted file mode 100644 index 1b6c30fb..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthUnit.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -public abstract class SynthUnit { - - private static final double CONCERT_A_PITCH = 69.0; - private static final double CONCERT_A_FREQUENCY = 440.0; - - /** - * @param pitch - * MIDI pitch in semitones - * @return frequency - */ - public static double pitchToFrequency(double pitch) { - double semitones = pitch - CONCERT_A_PITCH; - return CONCERT_A_FREQUENCY * Math.pow(2.0, semitones / 12.0); - } - - public abstract float render(); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthVoice.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthVoice.java deleted file mode 100644 index 6b6b7f84..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/miditools/synth/SynthVoice.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -package com.mobileer.miditools.synth; - -/** - * Base class for a polyphonic synthesizer voice. - */ -public abstract class SynthVoice { - private int mNoteIndex; - private float mAmplitude; - public static final int STATE_OFF = 0; - public static final int STATE_ON = 1; - private int mState = STATE_OFF; - - public SynthVoice() { - mNoteIndex = -1; - } - - public void noteOn(int noteIndex, int velocity) { - mState = STATE_ON; - this.mNoteIndex = noteIndex; - setAmplitude(velocity / 128.0f); - } - - public void noteOff() { - mState = STATE_OFF; - } - - /** - * Add the output of this voice to an output buffer. - * - * @param outputBuffer - * @param samplesPerFrame - * @param level - */ - public void mix(float[] outputBuffer, int samplesPerFrame, float level) { - int numFrames = outputBuffer.length / samplesPerFrame; - for (int i = 0; i < numFrames; i++) { - float output = render(); - int offset = i * samplesPerFrame; - for (int jf = 0; jf < samplesPerFrame; jf++) { - outputBuffer[offset + jf] += output * level; - } - } - } - - public abstract float render(); - - public boolean isDone() { - return mState == STATE_OFF; - } - - public int getNoteIndex() { - return mNoteIndex; - } - - public float getAmplitude() { - return mAmplitude; - } - - public void setAmplitude(float amplitude) { - this.mAmplitude = amplitude; - } - - /** - * @param scaler - */ - public void setFrequencyScaler(float scaler) { - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java deleted file mode 100644 index b2b6f0bf..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AnalyzerActivity.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 2018 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. - */ - -package com.mobileer.oboetester; - -import android.Manifest; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import android.widget.Toast; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; - -/** - * Activity to measure latency on a full duplex stream. - */ -public class AnalyzerActivity extends TestInputActivity { - - private static final int MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE = 1001; - - public static final String KEY_IN_SHARING = "in_sharing"; - public static final String KEY_OUT_SHARING = "out_sharing"; - public static final String VALUE_SHARING_EXCLUSIVE = "exclusive"; - public static final String VALUE_SHARING_SHARED = "shared"; - - public static final String KEY_IN_PERF = "in_perf"; - public static final String KEY_OUT_PERF = "out_perf"; - public static final String VALUE_PERF_LOW_LATENCY = "lowlat"; - public static final String VALUE_PERF_POWERSAVE = "powersave"; - public static final String VALUE_PERF_NONE = "none"; - - public static final String KEY_IN_CHANNELS = "in_channels"; - public static final String KEY_OUT_CHANNELS = "out_channels"; - public static final int VALUE_DEFAULT_CHANNELS = 2; - - public static final String KEY_SAMPLE_RATE = "sample_rate"; - public static final int VALUE_DEFAULT_SAMPLE_RATE = 48000; - - protected static final String KEY_FILE_NAME = "file"; - protected static final String KEY_BUFFER_BURSTS = "buffer_bursts"; - - public static final String VALUE_UNSPECIFIED = "unspecified"; - public static final String KEY_IN_API = "in_api"; - public static final String KEY_OUT_API = "out_api"; - public static final String VALUE_API_AAUDIO = "aaudio"; - public static final String VALUE_API_OPENSLES = "opensles"; - - AudioOutputTester mAudioOutTester; - protected BufferSizeView mBufferSizeView; - protected String mResultFileName; - private String mTestResults; - - // Note that these string must match the enum result_code in LatencyAnalyzer.h - String resultCodeToString(int resultCode) { - switch (resultCode) { - case 0: - return "OK"; - case -99: - return "ERROR_NOISY"; - case -98: - return "ERROR_VOLUME_TOO_LOW"; - case -97: - return "ERROR_VOLUME_TOO_HIGH"; - case -96: - return "ERROR_CONFIDENCE"; - case -95: - return "ERROR_INVALID_STATE"; - case -94: - return "ERROR_GLITCHES"; - case -93: - return "ERROR_NO_LOCK"; - default: - return "UNKNOWN"; - } - } - - public native int getAnalyzerState(); - public native boolean isAnalyzerDone(); - public native int getMeasuredResult(); - public native int getResetCount(); - - @NonNull - protected String getCommonTestReport() { - StringBuffer report = new StringBuffer(); - // Add some extra information for the remote tester. - report.append("build.fingerprint = " + Build.FINGERPRINT + "\n"); - try { - PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0); - report.append(String.format("test.version = %s\n", pinfo.versionName)); - report.append(String.format("test.version.code = %d\n", pinfo.versionCode)); - } catch (PackageManager.NameNotFoundException e) { - } - report.append("time.millis = " + System.currentTimeMillis() + "\n"); - - // INPUT - report.append(mAudioInputTester.actualConfiguration.dump()); - AudioStreamBase inStream = mAudioInputTester.getCurrentAudioStream(); - report.append(String.format("in.burst.frames = %d\n", inStream.getFramesPerBurst())); - report.append(String.format("in.xruns = %d\n", inStream.getXRunCount())); - - // OUTPUT - report.append(mAudioOutTester.actualConfiguration.dump()); - AudioStreamBase outStream = mAudioOutTester.getCurrentAudioStream(); - report.append(String.format("out.burst.frames = %d\n", outStream.getFramesPerBurst())); - int bufferSize = outStream.getBufferSizeInFrames(); - report.append(String.format("out.buffer.size.frames = %d\n", bufferSize)); - int bufferCapacity = outStream.getBufferCapacityInFrames(); - report.append(String.format("out.buffer.capacity.frames = %d\n", bufferCapacity)); - report.append(String.format("out.xruns = %d\n", outStream.getXRunCount())); - - return report.toString(); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mAudioOutTester = addAudioOutputTester(); - mBufferSizeView = (BufferSizeView) findViewById(R.id.buffer_size_view); - } - - @Override - protected void resetConfiguration() { - super.resetConfiguration(); - mAudioOutTester.reset(); - - StreamContext streamContext = getFirstInputStreamContext(); - if (streamContext != null) { - if (streamContext.configurationView != null) { - streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT); - streamContext.configurationView.setFormatConversionAllowed(true); - } - } - streamContext = getFirstOutputStreamContext(); - if (streamContext != null) { - if (streamContext.configurationView != null) { - streamContext.configurationView.setFormat(StreamConfiguration.AUDIO_FORMAT_PCM_FLOAT); - streamContext.configurationView.setFormatConversionAllowed(true); - } - } - } - - @Override - public void openAudio() throws IOException { - super.openAudio(); - if (mBufferSizeView != null) { - mBufferSizeView.onStreamOpened((OboeAudioStream) mAudioOutTester.getCurrentAudioStream()); - } - } - - public void onStreamClosed() { - Toast.makeText(getApplicationContext(), - "Stream was closed or disconnected!", - Toast.LENGTH_SHORT) - .show(); - stopAudioTest(); - } - - public void stopAudioTest() { - } - - private int getApiFromText(String text) { - if (VALUE_API_AAUDIO.equals(text)) { - return StreamConfiguration.NATIVE_API_AAUDIO; - } else if (VALUE_API_OPENSLES.equals(text)) { - return StreamConfiguration.NATIVE_API_OPENSLES; - } else { - return StreamConfiguration.NATIVE_API_UNSPECIFIED; - } - } - - private int getPerfFromText(String text) { - if (VALUE_PERF_NONE.equals(text)) { - return StreamConfiguration.PERFORMANCE_MODE_NONE; - } else if (VALUE_PERF_POWERSAVE.equals(text)) { - return StreamConfiguration.PERFORMANCE_MODE_POWER_SAVING; - } else { - return StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY; - } - } - - private int getSharingFromText(String text) { - if (VALUE_SHARING_SHARED.equals(text)) { - return StreamConfiguration.SHARING_MODE_SHARED; - } else { - return StreamConfiguration.SHARING_MODE_EXCLUSIVE; - } - } - - void configureStreamsFromBundle(Bundle bundle) { - // Configure settings - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - - requestedInConfig.reset(); - requestedOutConfig.reset(); - - // OpenSL ES or AAudio API - String text = bundle.getString(KEY_IN_API, VALUE_UNSPECIFIED); - int audioApi = getApiFromText(text); - requestedInConfig.setNativeApi(audioApi); - text = bundle.getString(KEY_OUT_API, VALUE_UNSPECIFIED); - audioApi = getApiFromText(text); - requestedOutConfig.setNativeApi(audioApi); - - // channnels - int inChannels = bundle.getInt(KEY_IN_CHANNELS, VALUE_DEFAULT_CHANNELS); - requestedInConfig.setChannelCount(inChannels); - int outChannels = bundle.getInt(KEY_OUT_CHANNELS, VALUE_DEFAULT_CHANNELS); - requestedOutConfig.setChannelCount(outChannels); - - // performance mode - text = bundle.getString(KEY_IN_PERF, VALUE_PERF_LOW_LATENCY); - int perfMode = getPerfFromText(text); - requestedInConfig.setPerformanceMode(perfMode); - text = bundle.getString(KEY_OUT_PERF, VALUE_PERF_LOW_LATENCY); - perfMode = getPerfFromText(text); - requestedOutConfig.setPerformanceMode(perfMode); - - int sampleRate = bundle.getInt(KEY_SAMPLE_RATE, VALUE_DEFAULT_SAMPLE_RATE); - requestedInConfig.setSampleRate(sampleRate); - requestedOutConfig.setSampleRate(sampleRate); - - text = bundle.getString(KEY_IN_SHARING, VALUE_SHARING_EXCLUSIVE); - int sharingMode = getSharingFromText(text); - requestedInConfig.setSharingMode(sharingMode); - text = bundle.getString(KEY_OUT_SHARING, VALUE_SHARING_EXCLUSIVE); - sharingMode = getSharingFromText(text); - requestedOutConfig.setSharingMode(sharingMode); - } - - void writeTestResultIfPermitted(String resultString) { - // Here, thisActivity is the current activity - if (ContextCompat.checkSelfPermission(this, - Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - mTestResults = resultString; - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE); - } else { - // Permission has already been granted - writeTestResult(resultString); - } - } - - void maybeWriteTestResult(String resultString) { - if (mResultFileName == null) return; - writeTestResultIfPermitted(resultString); - } - - @Override - public void onRequestPermissionsResult(int requestCode, - String[] permissions, - int[] grantResults) { - switch (requestCode) { - case MY_PERMISSIONS_REQUEST_EXTERNAL_STORAGE: { - // If request is cancelled, the result arrays are empty. - if (grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - writeTestResult(mTestResults); - } else { - showToast("Writing external storage needed for test results."); - } - return; - } - } - } - - private void writeTestInBackground(final String resultString) { - new Thread() { - public void run() { - writeTestResult(resultString); - } - }.start(); - } - - // Run this in a background thread. - private void writeTestResult(String resultString) { - File resultFile = new File(mResultFileName); - Writer writer = null; - try { - writer = new OutputStreamWriter(new FileOutputStream(resultFile)); - writer.write(resultString); - } catch ( - IOException e) { - e.printStackTrace(); - showErrorToast(" writing result file. " + e.getMessage()); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - mResultFileName = null; - } - - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java deleted file mode 100644 index a03824bf..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioInputTester.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.util.Log; - -class AudioInputTester extends AudioStreamTester{ - private static AudioInputTester mInstance; - - private AudioInputTester() { - super(); - Log.i(TapToToneActivity.TAG, "create OboeAudioStream ---------"); - - mCurrentAudioStream = new OboeAudioInputStream(); - requestedConfiguration.setDirection(StreamConfiguration.DIRECTION_INPUT); - } - - public static synchronized AudioInputTester getInstance() { - if (mInstance == null) { - mInstance = new AudioInputTester(); - } - return mInstance; - } - - public native double getPeakLevel(int i); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java deleted file mode 100644 index 18d26843..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioOutputTester.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.util.Log; - -public class AudioOutputTester extends AudioStreamTester { - - protected OboeAudioOutputStream mOboeAudioOutputStream; - - private static AudioOutputTester mInstance; - - public static synchronized AudioOutputTester getInstance() { - if (mInstance == null) { - mInstance = new AudioOutputTester(); - } - return mInstance; - } - - private AudioOutputTester() { - super(); - Log.i(TapToToneActivity.TAG, "create OboeAudioOutputStream ---------"); - mOboeAudioOutputStream = new OboeAudioOutputStream(); - mCurrentAudioStream = mOboeAudioOutputStream; - requestedConfiguration.setDirection(StreamConfiguration.DIRECTION_OUTPUT); - } - - public void trigger() { - mOboeAudioOutputStream.trigger(); - } - - public void setChannelEnabled(int channelIndex, boolean enabled) { - mOboeAudioOutputStream.setChannelEnabled(channelIndex, enabled); - } - - public void setSignalType(int type) { - mOboeAudioOutputStream.setSignalType(type); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java deleted file mode 100644 index 7e488bb7..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioQueryTools.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.content.pm.PackageManager; -import android.media.AudioManager; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -public class AudioQueryTools { - private static String GETPROP_EXECUTABLE_PATH = "/system/bin/getprop"; - - public static String getSystemProperty(String propName) { - Process process = null; - BufferedReader bufferedReader = null; - try { - process = new ProcessBuilder().command(GETPROP_EXECUTABLE_PATH, propName).redirectErrorStream(true).start(); - bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); - String line = bufferedReader.readLine(); - if (line == null){ - line = ""; //prop not set - } - return line; - } catch (Exception e) { - return ""; - } finally{ - if (bufferedReader != null){ - try { - bufferedReader.close(); - } catch (IOException e) {} - } - if (process != null){ - process.destroy(); - } - } - } - - public static String getAudioFeatureReport(PackageManager packageManager) { - StringBuffer report = new StringBuffer(); - report.append("\nProAudio Feature : " - + packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO)); - report.append("\nLowLatency Feature : " - + packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY)); - report.append("\nMIDI Feature : " - + packageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)); - report.append("\nUSB Host Feature : " - + packageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)); - report.append("\nUSB Accessory Feature: " - + packageManager.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)); - return report.toString(); - } - - public static String getAudioManagerReport(AudioManager audioManager) { - StringBuffer report = new StringBuffer(); - String unprocessedSupport = audioManager.getParameters(AudioManager.PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED); - report.append("\nSUPPORT_UNPROCESSED : " + ((unprocessedSupport == null) ? "null" : "yes")); - return report.toString(); - } - - private static String getSystemPropertyLine(String key) { - int numSpaces = Math.max(1, 21 - key.length()); - String spaces = String.format("%0" + numSpaces + "d", 0).replace("0", " "); - return "\n" + key + spaces + ": " + getSystemProperty(key); - } - - public static String getAudioPropertyReport() { - StringBuffer report = new StringBuffer(); - report.append(getSystemPropertyLine("aaudio.mmap_policy")); - report.append(getSystemPropertyLine("aaudio.mmap_exclusive_policy")); - report.append(getSystemPropertyLine("aaudio.mixer_bursts")); - report.append(getSystemPropertyLine("aaudio.wakeup_delay_usec")); - report.append(getSystemPropertyLine("aaudio.minimum_sleep_usec")); - report.append(getSystemPropertyLine("aaudio.hw_burst_min_usec")); - report.append(getSystemPropertyLine("aaudio.in_mmap_offset_usec")); - report.append(getSystemPropertyLine("aaudio.out_mmap_offset_usec")); - report.append(getSystemPropertyLine("ro.product.manufacturer")); - report.append(getSystemPropertyLine("ro.product.brand")); - report.append(getSystemPropertyLine("ro.product.model")); - report.append(getSystemPropertyLine("ro.product.name")); - report.append(getSystemPropertyLine("ro.product.device")); - report.append(getSystemPropertyLine("ro.product.cpu.abi")); - report.append(getSystemPropertyLine("ro.soc.manufacturer")); - report.append(getSystemPropertyLine("ro.soc.model")); - report.append(getSystemPropertyLine("ro.arch")); - report.append(getSystemPropertyLine("ro.hardware")); - report.append(getSystemPropertyLine("ro.hardware.chipname")); - report.append(getSystemPropertyLine("ro.board.platform")); - report.append(getSystemPropertyLine("ro.build.changelist")); - report.append(getSystemPropertyLine("ro.build.description")); - return report.toString(); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java deleted file mode 100644 index 7b472237..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioRecordThread.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -package com.mobileer.oboetester; - - -import android.media.AudioFormat; -import android.media.AudioRecord; -import android.media.MediaRecorder; - -/** - * Abstract class for recording. - * Call processBuffer(buffer) when data is read. - */ -class AudioRecordThread implements Runnable { - private static final String TAG = "AudioRecordThread"; - - private final int mSampleRate; - private final int mChannelCount; - private Thread mThread; - protected boolean mGo; - private AudioRecord mRecorder; - private CircularCaptureBuffer mCaptureBuffer; - protected float[] mBuffer = new float[256]; - private static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_FLOAT; - private Runnable mTask; - private int mTaskCountdown; - private boolean mCaptureEnabled = true; - - public AudioRecordThread(int frameRate, int channelCount, int maxFrames) { - mSampleRate = frameRate; - mChannelCount = channelCount; - mCaptureBuffer = new CircularCaptureBuffer(maxFrames); - } - - private void createRecorder() { - int channelConfig = (mChannelCount == 1) - ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO; - int audioFormat = AudioFormat.ENCODING_PCM_FLOAT; - int minRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSampleRate, - channelConfig, - audioFormat); - mRecorder = new AudioRecord( - MediaRecorder.AudioSource.VOICE_RECOGNITION, - mSampleRate, - channelConfig, - audioFormat, - 2 * minRecordBuffSizeInBytes); - if (mRecorder.getState() == AudioRecord.STATE_UNINITIALIZED) { - throw new RuntimeException("Could not make the AudioRecord - UNINITIALIZED"); - } - } - - @Override - public void run() { - startAudioRecording(); - - while (mGo) { - int result = handleAudioPeriod(); - if (result < 0) { - mGo = false; - } - } - - stopAudioRecording(); - } - - public void startAudio() { - if (mThread == null) { - mGo = true; - mThread = new Thread(this); - mThread.start(); - } - } - - public void stopAudio() { - mGo = false; - if (mThread != null) { - try { - mThread.join(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - mThread = null; - } - } - - public int getSampleRate() { - return mSampleRate; - } - - /** - * @return number of samples read or negative error - */ - private int handleAudioPeriod() { - int numSamplesRead = mRecorder.read(mBuffer, 0, mBuffer.length, - AudioRecord.READ_BLOCKING); - if (numSamplesRead <= 0) { - return numSamplesRead; - } else { - if (mTaskCountdown > 0) { - mTaskCountdown -= numSamplesRead; - if (mTaskCountdown <= 0) { - mTaskCountdown = 0; - new Thread(mTask).start(); // run asynchronously with audio thread - } - } - if (mCaptureEnabled) { - return mCaptureBuffer.write(mBuffer, 0, numSamplesRead); - } else { - return numSamplesRead; - } - } - } - - private void startAudioRecording() { - stopAudioRecording(); - createRecorder(); - mRecorder.startRecording(); - } - - private void stopAudioRecording() { - if (mRecorder != null) { - mRecorder.stop(); - mRecorder.release(); - mRecorder = null; - } - } - - /** - * Schedule task to be run on its own thread when numSamples more samples have been recorded. - * - * @param numSamples - * @param task - */ - public void scheduleTask(int numSamples, Runnable task) { - mTask = task; - mTaskCountdown = numSamples; - } - - public void setCaptureEnabled(boolean captureEnabled) { - mCaptureEnabled = captureEnabled; - } - - public int readMostRecent(float[] buffer) { - return mCaptureBuffer.readMostRecent(buffer); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java deleted file mode 100644 index 170fb024..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2015 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. - */ - -package com.mobileer.oboetester; - -import java.io.IOException; - -/** - * Base class for any audio input or output. - */ -public abstract class AudioStreamBase { - - private StreamConfiguration mRequestedStreamConfiguration; - private StreamConfiguration mActualStreamConfiguration; - AudioStreamBase.DoubleStatistics mLatencyStatistics; - - private int mBufferSizeInFrames; - - public StreamStatus getStreamStatus() { - StreamStatus status = new StreamStatus(); - status.bufferSize = getBufferSizeInFrames(); - status.xRunCount = getXRunCount(); - status.framesRead = getFramesRead(); - status.framesWritten = getFramesWritten(); - status.callbackCount = getCallbackCount(); - status.latency = getLatency(); - mLatencyStatistics.add(status.latency); - status.cpuLoad = getCpuLoad(); - status.state = getState(); - return status; - } - - public DoubleStatistics getLatencyStatistics() { - return mLatencyStatistics; - } - - public static class DoubleStatistics { - private double sum; - private int count; - private double minimum = Double.MAX_VALUE; - private double maximum = Double.MIN_VALUE; - - void add(double latency) { - if (latency <= 0.0) return; - sum += latency; - count++; - minimum = Math.min(latency, minimum); - maximum = Math.max(latency, maximum); - } - - double getAverage() { - return sum / count; - } - - public String dump() { - if (count == 0) return "?"; - return String.format("%3.1f/%3.1f/%3.1f ms", minimum, getAverage(), maximum); - } - } - - /** - * Changes dynamic at run-time. - */ - public static class StreamStatus { - public int bufferSize; - public int xRunCount; - public long framesWritten; - public long framesRead; - public double latency; // msec - public int state; - public long callbackCount; - public int framesPerCallback; - public double cpuLoad; - - // These are constantly changing. - String dump(int framesPerBurst) { - if (bufferSize < 0 || framesWritten < 0) { - return "idle"; - } - StringBuffer buffer = new StringBuffer(); - - buffer.append("frames written " + framesWritten + " - read " + framesRead - + " = " + (framesWritten - framesRead) + "\n"); - - String cpuLoadText = String.format("%2d%c", (int)(cpuLoad * 100), '%'); - buffer.append( - convertStateToString(state) - + ", #cb=" + callbackCount - + ", f/cb=" + String.format("%3d", framesPerCallback) - + ", " + cpuLoadText + " cpu" - + "\n"); - - buffer.append("buffer size = "); - if (bufferSize < 0) { - buffer.append("?"); - } else { - int numBuffers = bufferSize / framesPerBurst; - int remainder = bufferSize - (numBuffers * framesPerBurst); - buffer.append(bufferSize + " = (" + numBuffers + " * " + framesPerBurst + ") + " + remainder); - } - buffer.append(", xRun# = " + ((xRunCount < 0) ? "?" : xRunCount) + "\n"); - - return buffer.toString(); - } - /** - * Converts ints from Oboe index to human-readable stream state - */ - private String convertStateToString(int stateId) { - final String[] STATE_ARRAY = {"Uninit.", "Unknown", "Open", "Starting", "Started", - "Pausing", "Paused", "Flushing", "Flushed", - "Stopping", "Stopped", "Closing", "Closed", "Disconn."}; - if (stateId < 0 || stateId >= STATE_ARRAY.length) { - return "Invalid - " + stateId; - } - return STATE_ARRAY[stateId]; - } - } - - /** - * - * @param requestedConfiguration - * @param actualConfiguration - * @param bufferSizeInFrames - * @throws IOException - */ - public void open(StreamConfiguration requestedConfiguration, - StreamConfiguration actualConfiguration, - int bufferSizeInFrames) throws IOException { - mRequestedStreamConfiguration = requestedConfiguration; - mActualStreamConfiguration = actualConfiguration; - mBufferSizeInFrames = bufferSizeInFrames; - mLatencyStatistics = new AudioStreamBase.DoubleStatistics(); - } - - public abstract boolean isInput(); - - public void startPlayback() throws IOException {} - - public void stopPlayback() throws IOException {} - - public abstract int write(float[] buffer, int offset, int length); - - public abstract void close(); - - public int getChannelCount() { - return mActualStreamConfiguration.getChannelCount(); - } - - public int getSampleRate() { - return mActualStreamConfiguration.getSampleRate(); - } - - public int getFramesPerBurst() { - return mActualStreamConfiguration.getFramesPerBurst(); - } - - public int getBufferCapacityInFrames() { - return mBufferSizeInFrames; - } - - public int getBufferSizeInFrames() { - return mBufferSizeInFrames; - } - - public int setBufferSizeInFrames(int bufferSize) { - throw new UnsupportedOperationException("bufferSize cannot be changed"); - } - - public long getCallbackCount() { return -1; } - - public int getLastErrorCallbackResult() { return 0; } - - public long getFramesWritten() { return -1; } - - public long getFramesRead() { return -1; } - - public double getLatency() { return -1.0; } - - public double getCpuLoad() { return 0.0; } - - public int getState() { return -1; } - - public boolean isThresholdSupported() { - return false; - } - - public void setWorkload(double workload) {} - - public abstract int getXRunCount(); - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java deleted file mode 100644 index 32bc2ae6..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamTester.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import java.io.IOException; - -class AudioStreamTester { - protected AudioStreamBase mCurrentAudioStream; - StreamConfiguration requestedConfiguration = new StreamConfiguration(); - StreamConfiguration actualConfiguration = new StreamConfiguration(); - - AudioStreamBase getCurrentAudioStream() { - return mCurrentAudioStream; - } - - public void open() throws IOException { - mCurrentAudioStream.open(requestedConfiguration, actualConfiguration, - -1); - } - - public void reset() { - setWorkload(0.0); - requestedConfiguration.reset(); // TODO consider making new ones - actualConfiguration.reset(); - } - - public void close() { - mCurrentAudioStream.close(); - } - - public void startPlayback() throws IOException { - mCurrentAudioStream.startPlayback(); - } - - public void setWorkload(double workload) { - mCurrentAudioStream.setWorkload(workload); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java deleted file mode 100644 index c7b773c4..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedGlitchActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.mobileer.oboetester; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.Spinner; - -public class AutomatedGlitchActivity extends BaseAutoGlitchActivity { - - private Spinner mDurationSpinner; - - // Test with these configurations. - private static final int[] PERFORMANCE_MODES = { - StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY, - StreamConfiguration.PERFORMANCE_MODE_NONE - }; - private static final int[] SAMPLE_RATES = { 48000, 44100, 16000 }; - private static final int MONO = 1; - private static final int STEREO = 2; - private static final int UNSPECIFIED = 0; - - private class DurationSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener { - @Override - public void onItemSelected(AdapterView parent, View view, int pos, long id) { - String text = parent.getItemAtPosition(pos).toString(); - mDurationSeconds = Integer.parseInt(text); - } - - @Override - public void onNothingSelected(AdapterView parent) { - mDurationSeconds = DEFAULT_DURATION_SECONDS; - } - } - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_auto_glitches); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mDurationSpinner = (Spinner) findViewById(R.id.spinner_glitch_duration); - mDurationSpinner.setOnItemSelectedListener(new DurationSpinnerListener()); - } - - @Override - public String getTestName() { - return "AutoGlitch"; - } - - private void testConfiguration(int perfMode, - int sharingMode, - int sampleRate, - int inChannels, - int outChannels) throws InterruptedException { - - // Configure settings - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - - requestedInConfig.reset(); - requestedOutConfig.reset(); - - requestedInConfig.setPerformanceMode(perfMode); - requestedOutConfig.setPerformanceMode(perfMode); - - requestedInConfig.setSharingMode(sharingMode); - requestedOutConfig.setSharingMode(sharingMode); - - requestedInConfig.setSampleRate(sampleRate); - requestedOutConfig.setSampleRate(sampleRate); - - requestedInConfig.setChannelCount(inChannels); - requestedOutConfig.setChannelCount(outChannels); - - setTolerance(0.3f); // FIXME remove - - testConfigurations(); - } - - private void testConfiguration(int performanceMode, - int sharingMode, - int sampleRate) throws InterruptedException { - testConfiguration(performanceMode, - sharingMode, - sampleRate, MONO, STEREO); - testConfiguration(performanceMode, - sharingMode, - sampleRate, STEREO, MONO); - } - - @Override - public void runTest() { - try { - testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY, - StreamConfiguration.SHARING_MODE_EXCLUSIVE, - UNSPECIFIED); - - for (int perfMode : PERFORMANCE_MODES) { - for (int sampleRate : SAMPLE_RATES) { - testConfiguration(perfMode, - StreamConfiguration.SHARING_MODE_SHARED, - sampleRate); - } - } - } catch (InterruptedException e) { - log(e.getMessage()); - showErrorToast(e.getMessage()); - } - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java deleted file mode 100644 index d8f91efd..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AutomatedTestRunner.java +++ /dev/null @@ -1,285 +0,0 @@ -package com.mobileer.oboetester; - -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.text.method.ScrollingMovementMethod; -import android.util.AttributeSet; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; - -/** - * Run an automated test from a UI, gather logs, - * and display a summary. - */ -public class AutomatedTestRunner extends LinearLayout implements Runnable { - - private Button mStartButton; - private Button mStopButton; - private Button mShareButton; - private TextView mAutoTextView; - private TextView mSingleTestIndex; - private StringBuffer mFailedSummary; - private StringBuffer mSummary; - private int mTestCount; - private int mPassCount; - private int mFailCount; - private TestAudioActivity mActivity; - - private Thread mAutoThread; - private volatile boolean mThreadEnabled; - private CachedTextViewLog mCachedTextView; - - public AutomatedTestRunner(Context context) { - super(context); - initializeViews(context); - } - - public AutomatedTestRunner(Context context, AttributeSet attrs) { - super(context, attrs); - initializeViews(context); - } - - public AutomatedTestRunner(Context context, - AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - initializeViews(context); - } - - public TestAudioActivity getActivity() { - return mActivity; - } - - public void setActivity(TestAudioActivity activity) { - this.mActivity = activity; - mCachedTextView = new CachedTextViewLog(activity, mAutoTextView); - } - - /** - * Inflates the views in the layout. - * - * @param context - * the current context for the view. - */ - private void initializeViews(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.auto_test_runner, this); - - mStartButton = (Button) findViewById(R.id.button_start); - mStartButton.setOnClickListener( new OnClickListener() { - @Override - public void onClick(View v) { - startTest(); - } - }); - - mStopButton = (Button) findViewById(R.id.button_stop); - mStopButton.setOnClickListener( new OnClickListener() { - @Override - public void onClick(View v) { - stopTest(); - } - }); - - mShareButton = (Button) findViewById(R.id.button_share); - mShareButton.setOnClickListener( new OnClickListener() { - @Override - public void onClick(View v) { - shareResult(); - mShareButton.setEnabled(true); - } - }); - mShareButton.setEnabled(false); - - mSingleTestIndex = (TextView) findViewById(R.id.single_test_index); - - mAutoTextView = (TextView) findViewById(R.id.text_log); - mAutoTextView.setMovementMethod(new ScrollingMovementMethod()); - } - - private void updateStartStopButtons(boolean running) { - mStartButton.setEnabled(!running); - mStopButton.setEnabled(running); - } - - public int getTestCount() { - return mTestCount; - } - - public boolean isThreadEnabled() { - return mThreadEnabled; - } - - public void appendFailedSummary(String text) { - mFailedSummary.append(text); - } - public void appendSummary(String text) { - mSummary.append(text); - } - - public void incrementFailCount() { - mFailCount++; - } - public void incrementPassCount() { - mPassCount++; - } - public void incrementTestCount() { - mTestCount++; - } - - // Write to scrollable TextView - public void log(final String text) { - if (text == null) return; - Log.d(TestAudioActivity.TAG, "LOG - " + text); - mCachedTextView.append(text + "\n"); - } - - // Flush any logs that are stuck in the cache. - public void flushLog() { - mCachedTextView.flush(); - } - - private void logClear() { - mCachedTextView.clear(); - } - - private void startAutoThread() { - mThreadEnabled = true; - mAutoThread = new Thread(this); - mAutoThread.start(); - } - - private void stopAutoThread() { - try { - if (mAutoThread != null) { - log("Disable background test thread."); - new RuntimeException("Disable background test thread.").printStackTrace(); - mThreadEnabled = false; - mAutoThread.interrupt(); - mAutoThread.join(100); - mAutoThread = null; - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - private void updateTestIndex() { - CharSequence chars = mSingleTestIndex.getText(); - String text = chars.toString(); - int testIndex = -1; - String trimmed = chars.toString().trim(); - if (trimmed.length() > 0) { - try { - testIndex = Integer.parseInt(text); - } catch (NumberFormatException e) { - mActivity.showErrorToast("Badly formated callback size: " + text); - mSingleTestIndex.setText(""); - } - } - mActivity.setSingleTestIndex(testIndex); - } - - protected void startTest() { - updateTestIndex(); - updateStartStopButtons(true); - startAutoThread(); - } - - public void stopTest() { - stopAutoThread(); - } - - // Only call from UI thread. - public void onTestFinished() { - updateStartStopButtons(false); - mShareButton.setEnabled(true); - } - - public static String getTimestampString() { - DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss"); - Date now = Calendar.getInstance().getTime(); - return df.format(now); - } - - // Share text from log via GMail, Drive or other method. - public void shareResult() { - Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); - sharingIntent.setType("text/plain"); - - String subjectText = "OboeTester-" + mActivity.getTestName() - + "-" + Build.MANUFACTURER - + "-" + Build.MODEL - + "-" + getTimestampString(); - subjectText = subjectText.replace(' ', '-'); - sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subjectText); - - String shareBody = mAutoTextView.getText().toString(); - sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody); - - mActivity.startActivity(Intent.createChooser(sharingIntent, "Share using:")); - } - - @Override - public void run() { - logClear(); - log("=== STARTED at " + new Date()); - log(mActivity.getTestName()); - log(MainActivity.getVersiontext()); - log(Build.MANUFACTURER + ", " + Build.MODEL + ", " + Build.PRODUCT); - log(Build.DISPLAY); - mFailedSummary = new StringBuffer(); - mSummary = new StringBuffer(); - appendFailedSummary("Summary\n"); - mTestCount = 0; - mPassCount = 0; - mFailCount = 0; - try { - mActivity.runTest(); - log("Tests finished without exception."); - } catch(Exception e) { - log("EXCEPTION: " + e.getMessage()); - } finally { - mActivity.stopTest(); - if (mThreadEnabled) { - log("\n==== SUMMARY ========"); - log(mSummary.toString()); - if (mFailCount > 0) { - log("These tests FAILED:"); - log(mFailedSummary.toString()); - log("------------"); - } else if (mPassCount > 0) { - log("All " + mPassCount + " tests PASSED."); - } else { - log("No tests were run!"); - } - int skipped = mTestCount - (mPassCount + mFailCount); - log(mPassCount + " passed. " - + mFailCount + " failed. " - + skipped + " skipped. "); - log("== FINISHED at " + new Date()); - } else { - log("== TEST STOPPED =="); - } - flushLog(); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - onTestFinished(); - } - }); - } - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java deleted file mode 100644 index 072e5528..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BaseAutoGlitchActivity.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.os.Bundle; - -import java.io.IOException; - -public class BaseAutoGlitchActivity extends GlitchActivity { - - private static final int SETUP_TIME_SECONDS = 4; // Time for the stream to settle. - protected static final int DEFAULT_DURATION_SECONDS = 8; // Run time for each test. - private static final int DEFAULT_GAP_MILLIS = 400; // Idle time between each test. - private static final String TEXT_SKIP = "SKIP"; - public static final String TEXT_PASS = "PASS"; - public static final String TEXT_FAIL = "FAIL !!!!"; - - protected int mDurationSeconds = DEFAULT_DURATION_SECONDS; - protected int mGapMillis = DEFAULT_GAP_MILLIS; - - protected AutomatedTestRunner mAutomatedTestRunner; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mAutomatedTestRunner = findViewById(R.id.auto_test_runner); - mAutomatedTestRunner.setActivity(this); - } - - protected void log(String text) { - mAutomatedTestRunner.log(text); - } - - protected void appendFailedSummary(String text) { - mAutomatedTestRunner.appendFailedSummary(text); - } - - protected void appendSummary(String text) { - mAutomatedTestRunner.appendSummary(text); - } - - @Override - public void onStopTest() { - mAutomatedTestRunner.stopTest(); - } - - String channelText(int index, int count) { - return index + "/" + count; - } - - protected String getConfigText(StreamConfiguration config) { - int channel = (config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) - ? getOutputChannel() : getInputChannel(); - return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "INP") - + (config.isMMap() ? "-M" : "-L") - + ", ID = " + String.format("%2d", config.getDeviceId()) - + ", SR = " + String.format("%5d", config.getSampleRate()) - + ", Perf = " + StreamConfiguration.convertPerformanceModeToText( - config.getPerformanceMode()) - + ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode()) - + ", ch = " + channelText(channel, config.getChannelCount()); - } - - public final static int TEST_RESULT_FAILED = -2; - public final static int TEST_RESULT_WARNING = -1; - public final static int TEST_RESULT_SKIPPED = 0; - public final static int TEST_RESULT_PASSED = 1; - - // Run test based on the requested input/output configurations. - protected int testConfigurations() throws InterruptedException { - int result = TEST_RESULT_SKIPPED; - mAutomatedTestRunner.incrementTestCount(); - if ((getSingleTestIndex() >= 0) && (mAutomatedTestRunner.getTestCount() != getSingleTestIndex())) { - return result; - } - - log("========================== #" + mAutomatedTestRunner.getTestCount()); - - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - - StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; - StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - - log("Requested:"); - log(" " + getConfigText(requestedInConfig)); - log(" " + getConfigText(requestedOutConfig)); - - String reason = ""; - boolean openFailed = false; - try { - openAudio(); // this will fill in actualConfig - log("Actual:"); - log(" " + getConfigText(actualInConfig)); - log(" " + getConfigText(actualOutConfig)); - // Set output size to a level that will avoid glitches. - AudioStreamBase stream = mAudioOutTester.getCurrentAudioStream(); - int sizeFrames = stream.getBufferCapacityInFrames() / 2; - stream.setBufferSizeInFrames(sizeFrames); - } catch (Exception e) { - openFailed = true; - log(e.getMessage()); - reason = e.getMessage(); - } - - // The test would only be worth running if we got the configuration we requested on input or output. - String skipReason = shouldTestBeSkipped(); - boolean skipped = skipReason.length() > 0; - boolean valid = !openFailed && !skipped; - boolean startFailed = false; - if (valid) { - try { - startAudioTest(); - } catch (IOException e) { - e.printStackTrace(); - valid = false; - startFailed = true; - log(e.getMessage()); - reason = e.getMessage(); - } - } - mAutomatedTestRunner.flushLog(); - - if (valid) { - // Check for early return until we reach full duration. - long now = System.currentTimeMillis(); - long startedAt = now; - long endTime = System.currentTimeMillis() + (mDurationSeconds * 1000); - boolean finishedEarly = false; - while (now < endTime && !finishedEarly) { - Thread.sleep(100); // Let test run. - now = System.currentTimeMillis(); - finishedEarly = isFinishedEarly(); - if (finishedEarly) { - log("Finished early after " + (now - startedAt) + " msec."); - } - } - } - int inXRuns = 0; - int outXRuns = 0; - - if (!openFailed) { - // get xRuns before closing the streams. - inXRuns = mAudioInputTester.getCurrentAudioStream().getXRunCount(); - outXRuns = mAudioOutTester.getCurrentAudioStream().getXRunCount(); - - super.stopAudioTest(); - } - - if (openFailed || startFailed) { - appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n"); - appendFailedSummary(getConfigText(requestedInConfig) + "\n"); - appendFailedSummary(getConfigText(requestedOutConfig) + "\n"); - appendFailedSummary(reason + "\n"); - mAutomatedTestRunner.incrementFailCount(); - } else if (skipped) { - log(TEXT_SKIP + " - " + skipReason); - } else { - log("Result:"); - reason += didTestFail(); - boolean passed = reason.length() == 0; - - String resultText = getShortReport(); - resultText += ", xruns = " + inXRuns + "/" + outXRuns; - resultText += ", " + (passed ? TEXT_PASS : TEXT_FAIL); - resultText += reason; - log(" " + resultText); - if (!passed) { - appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n"); - appendFailedSummary(" " + getConfigText(actualInConfig) + "\n"); - appendFailedSummary(" " + getConfigText(actualOutConfig) + "\n"); - appendFailedSummary(" " + resultText + "\n"); - mAutomatedTestRunner.incrementFailCount(); - result = TEST_RESULT_FAILED; - } else { - mAutomatedTestRunner.incrementPassCount(); - result = TEST_RESULT_PASSED; - } - } - mAutomatedTestRunner.flushLog(); - - // Give hardware time to settle between tests. - Thread.sleep(mGapMillis); - return result; - } - - protected boolean isFinishedEarly() { - return false; - } - - protected String shouldTestBeSkipped() { - String why = ""; - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; - StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - // No point running the test if we don't get the sharing mode we requested. - if (actualInConfig.getSharingMode() != requestedInConfig.getSharingMode() - || actualOutConfig.getSharingMode() != requestedOutConfig.getSharingMode()) { - log("Did not get requested sharing mode."); - why += "share"; - } - // We don't skip based on performance mode because if you request LOW_LATENCY you might - // get a smaller burst than if you request NONE. - return why; - } - - public String didTestFail() { - String why = ""; - if (getMaxSecondsWithNoGlitch() <= (mDurationSeconds - SETUP_TIME_SECONDS)) { - why += ", glitch"; - } - return why; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java deleted file mode 100644 index ce3b7a44..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/BufferSizeView.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; - - -import android.view.View; -import android.widget.RadioButton; -import android.widget.SeekBar; -import android.widget.TextView; -import android.widget.LinearLayout; - -public class BufferSizeView extends LinearLayout { - private OboeAudioStream mStream; - - private static final int FADER_THRESHOLD_MAX = 1000; // must match layout - private static final int USE_FADER = -1; - private static final int DEFAULT_NUM_BURSTS = 2; - private TextView mTextLabel; - private SeekBar mFader; - private ExponentialTaper mTaper; - private RadioButton mBufferSizeRadio1; - private RadioButton mBufferSizeRadio2; - private RadioButton mBufferSizeRadio3; - private int mCachedCapacity; - private int mFramesPerBurst; - private int mNumBursts; - - private SeekBar.OnSeekBarChangeListener mFaderListener = new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - mNumBursts = USE_FADER; - updateRadioButtons(); - setBufferSizeByPosition(progress); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }; - - public BufferSizeView(Context context) { - super(context); - initializeViews(context); - } - - public BufferSizeView(Context context, AttributeSet attrs) { - super(context, attrs); - initializeViews(context); - } - - public BufferSizeView(Context context, - AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - initializeViews(context); - } - - void setFaderNormalizedProgress(double fraction) { - mFader.setProgress((int) (fraction * FADER_THRESHOLD_MAX)); - } - - /** - * Inflates the views in the layout. - * - * @param context the current context for the view. - */ - private void initializeViews(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.buffer_size_view, this); - - mTextLabel = (TextView) findViewById(R.id.textThreshold); - mFader = (SeekBar) findViewById(R.id.faderBufferSize); - mFader.setOnSeekBarChangeListener(mFaderListener); - mTaper = new ExponentialTaper(0.0, 1.0, 10.0); - mFader.setProgress(0); - - mBufferSizeRadio1 = (RadioButton) findViewById(R.id.bufferSize1); - mBufferSizeRadio1.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - onSizeRadioButtonClicked(view, 1); - } - }); - mBufferSizeRadio2 = (RadioButton) findViewById(R.id.bufferSize2); - mBufferSizeRadio2.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - onSizeRadioButtonClicked(view, 2); - } - }); - mBufferSizeRadio3 = (RadioButton) findViewById(R.id.bufferSize3); - mBufferSizeRadio3.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - onSizeRadioButtonClicked(view, 3); - } - }); - mNumBursts = DEFAULT_NUM_BURSTS; - updateRadioButtons(); - updateBufferSize(); - } - - public void updateRadioButtons() { - if (mBufferSizeRadio3 != null) { - mBufferSizeRadio1.setChecked(mNumBursts == 1); - mBufferSizeRadio2.setChecked(mNumBursts == 2); - mBufferSizeRadio3.setChecked(mNumBursts == 3); - } - } - - private void onSizeRadioButtonClicked(View view, int numBursts) { - boolean checked = ((RadioButton) view).isChecked(); - if (!checked) return; - mNumBursts = numBursts; - setBufferSizeByNumBursts(numBursts); - } - - // sets mStream, mCachedCapacity and mFramesPerBurst - public void onStreamOpened(OboeAudioStream stream) { - mStream = stream; - if (mStream != null) { - int capacity = mStream.getBufferCapacityInFrames(); - if (capacity > 0) mCachedCapacity = capacity; - int framesPerBurst = mStream.getFramesPerBurst(); - if (framesPerBurst > 0) mFramesPerBurst = framesPerBurst; - } - updateBufferSize(); - } - - private void setBufferSizeByNumBursts(int numBursts) { - int sizeFrames = -1; - if (mStream != null) { - int framesPerBurst = mStream.getFramesPerBurst(); - if (framesPerBurst > 0) { - sizeFrames = numBursts * framesPerBurst; - } - } - StringBuffer message = new StringBuffer(); - message.append("bufferSize = #" + numBursts); - - setBufferSize(message, sizeFrames); - } - - private void setBufferSizeByPosition(int progress) { - int sizeFrames = -1; - double normalizedThreshold = 0.0; - - StringBuffer message = new StringBuffer(); - - normalizedThreshold = mTaper.linearToExponential( - ((double) progress) / FADER_THRESHOLD_MAX); - if (normalizedThreshold < 0.0) normalizedThreshold = 0.0; - else if (normalizedThreshold > 1.0) normalizedThreshold = 1.0; - int percent = (int) (normalizedThreshold * 100); - message.append("bufferSize = " + percent + "%"); - - if (mCachedCapacity > 0) { - sizeFrames = (int) (normalizedThreshold * mCachedCapacity); - } - setBufferSize(message, sizeFrames); - } - - private void setBufferSize(StringBuffer message, int sizeFrames) { - if (mStream != null) { - message.append(", " + sizeFrames); - if (mStream != null && sizeFrames >= 0) { - mStream.setBufferSizeInFrames(sizeFrames); - } - int bufferSize = mStream.getBufferSizeInFrames(); - if (bufferSize >= 0) { - message.append(" / " + bufferSize); - } - message.append(" / " + mCachedCapacity); - } - mTextLabel.setText(message.toString()); - } - - private void updateBufferSize() { - if (mNumBursts == USE_FADER) { - int progress = mFader.getProgress(); - setBufferSizeByPosition(progress); - } else { - setBufferSizeByNumBursts(mNumBursts); - } - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - mFader.setEnabled(enabled); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java deleted file mode 100644 index 0cc2f8d9..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CachedTextViewLog.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2020 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.widget.TextView; - -/** Wrap a TextView with a buffer and only update it periodically. - */ -public class CachedTextViewLog { - private final Activity mActivity; - private TextView mTextView; - private int mUpdatePeriodMillis = 500; - private long mLastUpdateTime; - private StringBuffer mBuffer = new StringBuffer(); - - public CachedTextViewLog(Activity activity, TextView textView) { - mActivity = activity; - mTextView = textView; - } - - public synchronized void append(String text) { - mBuffer.append(text); - long now = System.currentTimeMillis(); - if ((now - mLastUpdateTime) > mUpdatePeriodMillis) { - flush_l(); - } - } - - public synchronized void flush() { - flush_l(); - } - - // This must be called from a synchronized method. - private void flush_l() { - final String textToAdd = mBuffer.toString(); - mBuffer.setLength(0); - mLastUpdateTime = System.currentTimeMillis(); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mTextView.append(textToAdd); - } - }); - } - - public synchronized void clear() { - mBuffer.setLength(0); - mLastUpdateTime = System.currentTimeMillis(); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mTextView.setText(""); - } - }); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java deleted file mode 100644 index 0e1f39ca..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/CircularCaptureBuffer.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -package com.mobileer.oboetester; - - -/** - * Circular buffer for continuously capturing audio then reading the previous N samples. - * Can hold from zero to max frames. - */ -public class CircularCaptureBuffer { - - private float[] mData; - private int mCursor; - private int mNumValidSamples; - - public CircularCaptureBuffer(int maxSamples) { - mData = new float[maxSamples]; - } - - public int write(float[] buffer) { - return write(buffer, 0, buffer.length); - } - - public int write(float[] buffer, int offset, int numSamples) { - if (numSamples > mData.length) { - throw new IllegalArgumentException("Tried to write more than maxSamples."); - } - if ((mCursor + numSamples) > mData.length) { - // Wraps so write in two parts. - int numWrite1 = mData.length - mCursor; - System.arraycopy(buffer, offset, mData, mCursor, numWrite1); - offset += numWrite1; - int numWrite2 = numSamples - numWrite1; - System.arraycopy(buffer, offset, mData, 0, numWrite2); - mCursor = numWrite2; - } else { - System.arraycopy(buffer, offset, mData, mCursor, numSamples); - mCursor += numSamples; - if (mCursor == mData.length) { - mCursor = 0; - } - } - mNumValidSamples += numSamples; - if (mNumValidSamples > mData.length) { - mNumValidSamples = mData.length; - } - return numSamples; - } - - public int readMostRecent(float[] buffer) { - return readMostRecent(buffer, 0, buffer.length); - } - - /** - * Read the most recently written samples. - * @param buffer - * @param offset - * @param numSamples - * @return number of samples read - */ - public int readMostRecent(float[] buffer, int offset, int numSamples) { - - if (numSamples > mNumValidSamples) { - numSamples = mNumValidSamples; - } - int cursor = mCursor; // read once in case it gets updated by another thread - // Read in two parts. - if ((cursor - numSamples) < 0) { - int numRead1 = numSamples - cursor; - System.arraycopy(mData, mData.length - numRead1, buffer, offset, numRead1); - offset += numRead1; - int numRead2 = cursor; - System.arraycopy(mData, 0, buffer, offset, numRead2); - } else { - System.arraycopy(mData, cursor - numSamples, buffer, offset, numSamples); - } - - return numSamples; - } - - public void erase() { - mNumValidSamples = 0; - mCursor = 0; - } - - public int getSize() { - return mData.length; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java deleted file mode 100644 index 8848c045..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DeviceReportActivity.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.media.AudioDeviceCallback; -import android.media.AudioDeviceInfo; -import android.media.AudioManager; -import android.media.MicrophoneInfo; -import android.os.Build; -import android.os.Bundle; -import android.text.method.ScrollingMovementMethod; -import android.widget.TextView; - -import com.mobileer.audio_device.AudioDeviceInfoConverter; - -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -/** - * Guide the user through a series of tests plugging in and unplugging a headset. - * Print a summary at the end of any failures. - */ -public class DeviceReportActivity extends Activity { - - class MyAudioDeviceCallback extends AudioDeviceCallback { - private HashMap mDevices - = new HashMap(); - - @Override - public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { - for (AudioDeviceInfo info : addedDevices) { - mDevices.put(info.getId(), info); - } - reportDeviceInfo(mDevices.values()); - } - - public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { - for (AudioDeviceInfo info : removedDevices) { - mDevices.remove(info.getId()); - } - reportDeviceInfo(mDevices.values()); - } - } - - MyAudioDeviceCallback mDeviceCallback = new MyAudioDeviceCallback(); - private TextView mAutoTextView; - private AudioManager mAudioManager; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_device_report); - mAutoTextView = (TextView) findViewById(R.id.text_log); - mAutoTextView.setMovementMethod(new ScrollingMovementMethod()); - - mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - } - - @Override - protected void onStart() { - super.onStart(); - addAudioDeviceCallback(); - } - - @Override - protected void onStop() { - removeAudioDeviceCallback(); - super.onStop(); - } - - @TargetApi(23) - private void addAudioDeviceCallback(){ - // Note that we will immediately receive a call to onDevicesAdded with the list of - // devices which are currently connected. - mAudioManager.registerAudioDeviceCallback(mDeviceCallback, null); - } - - @TargetApi(23) - private void removeAudioDeviceCallback(){ - mAudioManager.unregisterAudioDeviceCallback(mDeviceCallback); - } - - private void reportDeviceInfo(Collection devices) { - logClear(); - StringBuffer report = new StringBuffer(); - report.append("Device Report:\n"); - report.append(MainActivity.getVersiontext()); - report.append(Build.MANUFACTURER + ", " + Build.MODEL + ", " + Build.PRODUCT); - - for (AudioDeviceInfo deviceInfo : devices) { - report.append("\n==== Device =================== " + deviceInfo.getId() + "\n"); - String item = AudioDeviceInfoConverter.toString(deviceInfo); - report.append(item); - } - report.append(reportAllMicrophones()); - report.append(reportExtraDeviceInfo()); - log(report.toString()); - } - - public String reportAllMicrophones() { - StringBuffer report = new StringBuffer(); - report.append("\n############################"); - report.append("\nMicrophone Report:\n"); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { - try { - List micList = mAudioManager.getMicrophones(); - for (MicrophoneInfo micInfo : micList) { - String micItem = MicrophoneInfoConverter.reportMicrophoneInfo(micInfo); - report.append(micItem); - } - } catch (IOException e) { - e.printStackTrace(); - return e.getMessage(); - } - } else { - report.append("\nMicrophoneInfo not available on V" + android.os.Build.VERSION.SDK_INT); - } - return report.toString(); - } - - private String reportExtraDeviceInfo() { - StringBuffer report = new StringBuffer(); - report.append("\n\n############################"); - report.append("\nExtras:"); - - report.append(AudioQueryTools.getAudioManagerReport(mAudioManager)); - report.append(AudioQueryTools.getAudioFeatureReport(getPackageManager())); - report.append(AudioQueryTools.getAudioPropertyReport()); - return report.toString(); - } - - // Write to scrollable TextView - private void log(final String text) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mAutoTextView.append(text); - mAutoTextView.append("\n"); - } - }); - } - - private void logClear() { - runOnUiThread(new Runnable() { - @Override - public void run() { - mAutoTextView.setText(""); - } - }); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java deleted file mode 100644 index 57b3aac6..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/EchoActivity.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright 2018 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.SeekBar; -import android.widget.TextView; - -import java.io.IOException; - -/** - * Activity to capture audio and then send a delayed copy to output. - * There is a fader for setting delay time - */ -public class EchoActivity extends TestInputActivity { - - AudioOutputTester mAudioOutTester; - - protected TextView mTextDelayTime; - protected SeekBar mFaderDelayTime; - protected ExponentialTaper mTaperDelayTime; - private static final double MIN_DELAY_TIME_SECONDS = 0.0; - private static final double MAX_DELAY_TIME_SECONDS = 3.0; - private double mDelayTime; - private Button mStartButton; - private Button mStopButton; - private TextView mStatusTextView; - - private ColdStartSniffer mNativeSniffer = new ColdStartSniffer(this); - - protected static final int MAX_DELAY_TIME_PROGRESS = 1000; - - private SeekBar.OnSeekBarChangeListener mDelayListener = new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - setDelayTimeByPosition(progress); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }; - - // Periodically query for cold start latency from the native code until it is ready. - protected class ColdStartSniffer extends NativeSniffer { - - private int stableCallCount = 0; - private static final int STABLE_CALLS_NEEDED = 20; - private int mInputLatency; - private int mOutputLatency; - - public ColdStartSniffer(Activity activity) { - super(activity); - } - - @Override - public void startSniffer() { - stableCallCount = 0; - mInputLatency = -1; - mOutputLatency = -1; - super.startSniffer(); - } - - public void run() { - mInputLatency = getColdStartInputMillis(); - mOutputLatency = getColdStartOutputMillis(); - updateStatusText(); - if (!isComplete()) { - reschedule(); - } - } - - private boolean isComplete() { - if (mInputLatency > 0 && mOutputLatency > 0) { - stableCallCount++; - } - return stableCallCount > STABLE_CALLS_NEEDED; - } - - private String getCurrentStatusReport() { - StringBuffer message = new StringBuffer(); - message.append("cold.start.input.msec = " + - ((mInputLatency > 0) - ? mInputLatency - : "?") - + "\n"); - message.append("cold.start.output.msec = " + - ((mOutputLatency > 0) - ? mOutputLatency - : "?") - + "\n"); - message.append("stable.call.count = " + stableCallCount + "\n"); - return message.toString(); - } - - @Override - public String getShortReport() { - return getCurrentStatusReport(); - } - - @Override - public void updateStatusText() { - String message = getCurrentStatusReport(); - mStatusTextView.setText(message); - } - - } - - private native int getColdStartInputMillis(); - private native int getColdStartOutputMillis(); - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_echo); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - updateEnabledWidgets(); - - mAudioOutTester = addAudioOutputTester(); - - mStartButton = (Button) findViewById(R.id.button_start_echo); - mStopButton = (Button) findViewById(R.id.button_stop_echo); - mStopButton.setEnabled(false); - - mStatusTextView = (TextView) findViewById(R.id.text_status); - - mTextDelayTime = (TextView) findViewById(R.id.text_delay_time); - mFaderDelayTime = (SeekBar) findViewById(R.id.fader_delay_time); - mFaderDelayTime.setOnSeekBarChangeListener(mDelayListener); - mTaperDelayTime = new ExponentialTaper( - MIN_DELAY_TIME_SECONDS, - MAX_DELAY_TIME_SECONDS, - 100.0); - mFaderDelayTime.setProgress(MAX_DELAY_TIME_PROGRESS / 2); - - hideSettingsViews(); - } - - private void setDelayTimeByPosition(int progress) { - mDelayTime = mTaperDelayTime.linearToExponential( - ((double)progress)/MAX_DELAY_TIME_PROGRESS); - setDelayTime(mDelayTime); - mTextDelayTime.setText("DelayLine: " + (int)(mDelayTime * 1000) + " (msec)"); - } - - private native void setDelayTime(double delayTimeSeconds); - - int getActivityType() { - return ACTIVITY_ECHO; - } - - - @Override - protected void resetConfiguration() { - super.resetConfiguration(); - mAudioOutTester.reset(); - } - - public void onStartEcho(View view) { - try { - openAudio(); - startAudio(); - setDelayTime(mDelayTime); - mStartButton.setEnabled(false); - mStopButton.setEnabled(true); - keepScreenOn(true); - mNativeSniffer.startSniffer(); - } catch (IOException e) { - showErrorToast(e.getMessage()); - } - } - - public void onStopEcho(View view) { - mNativeSniffer.stopSniffer(); - stopAudio(); - closeAudio(); - mStartButton.setEnabled(true); - mStopButton.setEnabled(false); - keepScreenOn(false); - } - - @Override - boolean isOutput() { - return false; - } - - @Override - public void setupEffects(int sessionId) { - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java deleted file mode 100644 index a6d44959..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExponentialTaper.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -/** - * Maps integer range info to a double value along an exponential scale. - * - *

- *
- *   x = ival / mResolution
- *   f(x) = a*(root**bx)
- *   f(0.0) = dmin
- *   f(1.0) = dmax
- *
- *   f(0.0) = a * 1.0 => a = dmin
- *   f(1.0) = dmin * root**b = dmax
- *   b = log(dmax / dmin) / log(root)
- *
- * 
- */ - -public class ExponentialTaper { - private double offset = 0.0; - private double a = 1.0; - private double b = 2.0; - private static final double ROOT = 10.0; // because we are using log10 - - public ExponentialTaper(double dmin, double dmax) { - this(dmin, dmax, 10000.0); - } - - public ExponentialTaper(double dmin, double dmax, double maxRatio) { - a = dmax; - double curvature; - if (dmax > dmin * maxRatio) { - offset = dmax / maxRatio; - a = offset; - curvature = (dmax + offset) / offset; - } else { - curvature = dmax / dmin; - a = dmin; - } - b = Math.log10(curvature); - } - - public double linearToExponential(double linear) { - return a * Math.pow(ROOT, b * linear) - offset; - } - - public double exponentialToLinear(double exponential) { - return Math.log((exponential + offset) / a) / (b * Math.log(ROOT)); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java deleted file mode 100644 index 2f6e2563..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExternalTapToToneActivity.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.mobileer.oboetester; - -import android.Manifest; -import android.app.Activity; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.widget.Button; -import android.widget.Toast; - -import java.io.IOException; - -/** - * Measure the tap-to-tone latency for other apps or devices. - */ -public class ExternalTapToToneActivity extends Activity { - private static final String TAG = "OboeTester"; - private static final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 1235; - - protected TapToToneTester mTapToToneTester; - private Button mStopButton; - private Button mStartButton; - private Button mAnalyzeButton; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_external_tap_to_tone); - - mTapToToneTester = new TapToToneTester(this, - getResources().getString(R.string.external_tap_instructions)); - - mStartButton = (Button) findViewById(R.id.button_start); - mStopButton = (Button) findViewById(R.id.button_stop); - mAnalyzeButton = (Button) findViewById(R.id.button_analyze); - updateButtons(false); - } - - private void updateButtons(boolean running) { - mStartButton.setEnabled(!running); - mAnalyzeButton.setEnabled(running); - mStopButton.setEnabled(running); - } - - public void analyseAndShowResults() { - TapToToneTester.TestResult result = mTapToToneTester.analyzeCapturedAudio(); - if (result != null) { - mTapToToneTester.showTestResults(result); - } - } - - public void analyze(View view) { - analyseAndShowResults(); - } - - public void startTest(View view) throws IOException { - if (hasRecordAudioPermission()) { - startAudioPermitted(); - } else { - requestRecordAudioPermission(); - updateButtons(false); - } - } - - private void startAudioPermitted() { - try { - mTapToToneTester.resetLatency(); - mTapToToneTester.start(); - updateButtons(true); - } catch (IOException e) { - e.printStackTrace(); - showErrorToast("Start audio failed! " + e.getMessage()); - return; - } - } - - public void stopTest(View view) { - mTapToToneTester.stop(); - updateButtons(false); - } - - @Override - public void onStop() { - mTapToToneTester.stop(); - super.onStop(); - } - - - protected void showErrorToast(String message) { - showToast("Error: " + message); - } - - protected void showToast(final String message) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(ExternalTapToToneActivity.this, - message, - Toast.LENGTH_SHORT).show(); - } - }); - } - - private boolean hasRecordAudioPermission(){ - boolean hasPermission = (checkSelfPermission( - Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED); - Log.i(TAG, "Has RECORD_AUDIO permission? " + hasPermission); - return hasPermission; - } - - private void requestRecordAudioPermission(){ - - String requiredPermission = Manifest.permission.RECORD_AUDIO; - - // If the user previously denied this permission then show a message explaining why - // this permission is needed - if (shouldShowRequestPermissionRationale(requiredPermission)) { - showErrorToast("This app needs to record audio through the microphone...."); - } - - // request the permission. - requestPermissions(new String[]{requiredPermission}, - MY_PERMISSIONS_REQUEST_RECORD_AUDIO); - } - - @Override - public void onRequestPermissionsResult(int requestCode, - String[] permissions, - int[] grantResults) { - - if (MY_PERMISSIONS_REQUEST_RECORD_AUDIO != requestCode) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - return; - } - - if (grantResults.length != 1 || - grantResults[0] != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(getApplicationContext(), - getString(R.string.need_record_audio_permission), - Toast.LENGTH_SHORT) - .show(); - } else { - startAudioPermitted(); - } - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java deleted file mode 100644 index 156df1e5..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ExtraTestsActivity.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.mobileer.oboetester; - -import android.content.Intent; -import android.app.Activity; -import android.os.Bundle; -import android.view.View; - -public class ExtraTestsActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_extra_tests); - } - - public void onLaunchMainActivity(View view) { - onLaunchTest(MainActivity.class); - } - - public void onLaunchExternalTapTest(View view) { - onLaunchTest(ExternalTapToToneActivity.class); - } - - private void onLaunchTest(Class clazz) { - Intent intent = new Intent(this, clazz); - startActivity(intent); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java deleted file mode 100644 index 5445f179..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/FastButton.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.widget.TextView; - -import java.util.ArrayList; - -/** - * Button-like View that responds quickly to touch events. - */ -public class FastButton extends TextView { - - public FastButton(Context context) { - super(context); - } - - public FastButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public FastButton(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - private ArrayList mListeners = new ArrayList(); - - /** - * Implement this to receive keyboard events. - */ - public interface FastButtonListener { - /** - * This will be called when a key is pressed. - */ - public void onKeyDown(int id); - - /** - * This will be called when a key is pressed. - */ - public void onKeyUp(int id); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - super.onTouchEvent(event); - int action = event.getActionMasked(); - // Track individual fingers. - int pointerIndex = event.getActionIndex(); - int id = event.getPointerId(pointerIndex); - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - fireKeyDown(id); - break; - case MotionEvent.ACTION_MOVE: - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - fireKeyUp(id); - break; - } - // Must return true or we do not get the ACTION_MOVE and - // ACTION_UP events. - return true; - } - - private void fireKeyDown(int id) { - for (FastButtonListener listener : mListeners) { - listener.onKeyDown(id); - } - invalidate(); - } - - private void fireKeyUp(int id) { - for (FastButtonListener listener : mListeners) { - listener.onKeyUp(id); - } - invalidate(); - } - - public void addFastButtonListener(FastButtonListener listener) { - mListeners.add(listener); - } - - public void removeFastButtonListener(FastButtonListener listener) { - mListeners.remove(listener); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java deleted file mode 100644 index 603f8ee7..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/GlitchActivity.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright 2018 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -import java.io.IOException; - -/** - * Activity to measure the number of glitches. - */ -public class GlitchActivity extends AnalyzerActivity { - private TextView mAnalyzerTextView; - private Button mStartButton; - private Button mStopButton; - private Button mShareButton; - - // These must match the values in LatencyAnalyzer.h - final static int STATE_IDLE = 0; - final static int STATE_IMMUNE = 1; - final static int STATE_WAITING_FOR_SIGNAL = 2; - final static int STATE_WAITING_FOR_LOCK = 3; - final static int STATE_LOCKED = 4; - final static int STATE_GLITCHING = 5; - String mLastGlitchReport; - private int mInputChannel; - private int mOutputChannel; - - native int getStateFrameCount(int state); - native int getGlitchCount(); - native double getSignalToNoiseDB(); - native double getPeakAmplitude(); - - private GlitchSniffer mGlitchSniffer; - private NativeSniffer mNativeSniffer = createNativeSniffer(); - - synchronized NativeSniffer createNativeSniffer() { - if (mGlitchSniffer == null) { - mGlitchSniffer = new GlitchSniffer(this); - } - return mGlitchSniffer; - } - - // Note that these strings must match the enum result_code in LatencyAnalyzer.h - String stateToString(int resultCode) { - switch (resultCode) { - case STATE_IDLE: - return "IDLE"; - case STATE_IMMUNE: - return "IMMUNE"; - case STATE_WAITING_FOR_SIGNAL: - return "WAITING_FOR_SIGNAL"; - case STATE_WAITING_FOR_LOCK: - return "WAITING_FOR_LOCK"; - case STATE_LOCKED: - return "LOCKED"; - case STATE_GLITCHING: - return "GLITCHING"; - default: - return "UNKNOWN"; - } - } - - // Periodically query for glitches from the native detector. - protected class GlitchSniffer extends NativeSniffer { - - private long mTimeAtStart; - private long mTimeOfLastGlitch; - private double mSecondsWithoutGlitches; - private double mMaxSecondsWithoutGlitches; - private int mLastGlitchCount; - private int mLastUnlockedFrames; - private int mLastLockedFrames; - private int mLastGlitchFrames; - - private int mStartResetCount; - private int mLastResetCount; - private int mPreviousState; - - private double mSignalToNoiseDB; - private double mPeakAmplitude; - - public GlitchSniffer(Activity activity) { - super(activity); - } - - - @Override - public void startSniffer() { - long now = System.currentTimeMillis(); - mTimeAtStart = now; - mTimeOfLastGlitch = now; - mLastUnlockedFrames = 0; - mLastLockedFrames = 0; - mLastGlitchFrames = 0; - mSecondsWithoutGlitches = 0.0; - mMaxSecondsWithoutGlitches = 0.0; - mLastGlitchCount = 0; - mStartResetCount = mLastResetCount; - super.startSniffer(); - } - - public void run() { - int state = getAnalyzerState(); - mSignalToNoiseDB = getSignalToNoiseDB(); - mPeakAmplitude = getPeakAmplitude(); - mPreviousState = state; - - long now = System.currentTimeMillis(); - int glitchCount = getGlitchCount(); - int resetCount = getResetCount(); - mLastUnlockedFrames = getStateFrameCount(STATE_WAITING_FOR_LOCK); - int lockedFrames = getStateFrameCount(STATE_LOCKED); - int glitchFrames = getStateFrameCount(STATE_GLITCHING); - - if (glitchFrames > mLastGlitchFrames || glitchCount > mLastGlitchCount) { - mTimeOfLastGlitch = now; - mSecondsWithoutGlitches = 0.0; - onGlitchDetected(); - } else if (lockedFrames > mLastLockedFrames) { - mSecondsWithoutGlitches = (now - mTimeOfLastGlitch) / 1000.0; - } - - if (resetCount > mLastResetCount) { - mLastResetCount = resetCount; - } - - if (mSecondsWithoutGlitches > mMaxSecondsWithoutGlitches) { - mMaxSecondsWithoutGlitches = mSecondsWithoutGlitches; - } - - mLastGlitchCount = glitchCount; - mLastGlitchFrames = glitchFrames; - mLastLockedFrames = lockedFrames; - mLastResetCount = resetCount; - - reschedule(); - } - - private String getCurrentStatusReport() { - long now = System.currentTimeMillis(); - double totalSeconds = (now - mTimeAtStart) / 1000.0; - - StringBuffer message = new StringBuffer(); - message.append("state = " + stateToString(mPreviousState) + "\n"); - message.append(String.format("unlocked.frames = %d\n", mLastUnlockedFrames)); - message.append(String.format("locked.frames = %d\n", mLastLockedFrames)); - message.append(String.format("glitch.frames = %d\n", mLastGlitchFrames)); - message.append(String.format("reset.count = %d\n", mLastResetCount - mStartResetCount)); - message.append(String.format("peak.amplitude = %8.6f\n", mPeakAmplitude)); - if (mLastLockedFrames > 0) { - message.append(String.format("signal.noise.ratio.db = %5.1f\n", mSignalToNoiseDB)); - } - message.append(String.format("time.total = %8.2f seconds\n", totalSeconds)); - if (mLastLockedFrames > 0) { - message.append(String.format("time.no.glitches = %8.2f\n", mSecondsWithoutGlitches)); - message.append(String.format("max.time.no.glitches = %8.2f\n", - mMaxSecondsWithoutGlitches)); - message.append(String.format("glitch.count = %d\n", mLastGlitchCount)); - } - return message.toString(); - } - - @Override - public String getShortReport() { - String resultText = "#glitches = " + getLastGlitchCount() - + ", #resets = " + getLastResetCount() - + ", max no glitch = " + getMaxSecondsWithNoGlitch() + " secs\n"; - resultText += String.format("SNR = %5.1f db", mSignalToNoiseDB); - resultText += ", #locked = " + mLastLockedFrames; - return resultText; - } - - @Override - public void updateStatusText() { - mLastGlitchReport = getCurrentStatusReport(); - setAnalyzerText(mLastGlitchReport); - } - - public double getMaxSecondsWithNoGlitch() { - return mMaxSecondsWithoutGlitches; - } - - public int getLastGlitchCount() { - return mLastGlitchCount; - } - public int getLastResetCount() { - return mLastResetCount; - } - } - - // Called on UI thread - protected void onGlitchDetected() { - } - - protected void setAnalyzerText(String s) { - mAnalyzerTextView.setText(s); - } - - /** - * Set tolerance to deviations from expected value. - * The normalized value will be converted in the native code. - * @param tolerance normalized between 0.0 and 1.0 - */ - public native void setTolerance(float tolerance); - - public void setInputChannel(int channel) { - mInputChannel = channel; - setInputChannelNative(channel); - } - - public void setOutputChannel(int channel) { - mOutputChannel = channel; - setOutputChannelNative(channel); - } - - public int getInputChannel() { - return mInputChannel; - } - - public int getOutputChannel() { - return mOutputChannel; - } - - public native void setInputChannelNative(int channel); - - public native void setOutputChannelNative(int channel); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mStartButton = (Button) findViewById(R.id.button_start); - mStopButton = (Button) findViewById(R.id.button_stop); - mStopButton.setEnabled(false); - mShareButton = (Button) findViewById(R.id.button_share); - mShareButton.setEnabled(false); - mAnalyzerTextView = (TextView) findViewById(R.id.text_status); - updateEnabledWidgets(); - hideSettingsViews(); - // TODO hide sample rate menu - StreamContext streamContext = getFirstInputStreamContext(); - if (streamContext != null) { - if (streamContext.configurationView != null) { - streamContext.configurationView.hideSampleRateMenu(); - } - } - } - - @Override - int getActivityType() { - return ACTIVITY_GLITCHES; - } - - @Override - protected void onStart() { - super.onStart(); - } - - @Override - protected void onStop() { - if (!isBackgroundEnabled()) { - stopAudioTest(); - } - super.onStop(); - } - - @Override - protected void onDestroy() { - if (isBackgroundEnabled()) { - stopAudioTest(); - } - super.onDestroy(); - } - - // Called on UI thread - public void onStartAudioTest(View view) throws IOException { - openAudio(); - startAudioTest(); - mStartButton.setEnabled(false); - mStopButton.setEnabled(true); - mShareButton.setEnabled(false); - keepScreenOn(true); - } - - public void startAudioTest() throws IOException { - startAudio(); - mNativeSniffer.startSniffer(); - onTestBegan(); - } - - public void onCancel(View view) { - stopAudioTest(); - onTestFinished(); - } - - // Called on UI thread - public void onStopAudioTest(View view) { - stopAudioTest(); - onTestFinished(); - mStartButton.setEnabled(true); - mStopButton.setEnabled(false); - mShareButton.setEnabled(false); - keepScreenOn(false); - } - - // Must be called on UI thread. - public void onTestBegan() { - } - - // Must be called on UI thread. - public void onTestFinished() { - mStartButton.setEnabled(true); - mStopButton.setEnabled(false); - mShareButton.setEnabled(true); - } - - public void stopAudioTest() { - mNativeSniffer.stopSniffer(); - stopAudio(); - closeAudio(); - } - - public void stopTest() { - stopAudio(); - } - - @Override - boolean isOutput() { - return false; - } - - @Override - public void setupEffects(int sessionId) { - } - - public double getMaxSecondsWithNoGlitch() { - return mGlitchSniffer.getMaxSecondsWithNoGlitch(); - } - - public String getShortReport() { - return mNativeSniffer.getShortReport(); - } - - @Override - String getWaveTag() { - return "glitches"; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java deleted file mode 100644 index 32a8028b..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/InputMarginView.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.widget.LinearLayout; - -/** - * View for editing an input stream margin to avoid glitches. - * - * TODO: Is this class actually needed? - */ - -public class InputMarginView extends LinearLayout { - - public InputMarginView(Context context) { - super(context); - initializeViews(context); - } - - public InputMarginView(Context context, AttributeSet attrs) { - super(context, attrs); - initializeViews(context); - } - - public InputMarginView(Context context, - AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - initializeViews(context); - } - - /** - * Inflates the views in the layout. - * - * @param context - * the current context for the view. - */ - private void initializeViews(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.input_margin_view, this); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java deleted file mode 100644 index b45e3690..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MainActivity.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.Point; -import android.media.AudioManager; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; -import android.view.Display; -import android.view.View; -import android.widget.AdapterView; -import android.widget.CheckBox; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.Toast; - -/** - * Select various Audio tests. - */ - -public class MainActivity extends Activity { - - private static final String KEY_TEST_NAME = "test"; - public static final String VALUE_TEST_NAME_LATENCY = "latency"; - public static final String VALUE_TEST_NAME_GLITCH = "glitch"; - - static { - // Must match name in CMakeLists.txt - System.loadLibrary("oboetester"); - } - - private Spinner mModeSpinner; - private TextView mCallbackSizeEditor; - protected TextView mDeviceView; - private TextView mVersionTextView; - private TextView mBuildTextView; - private TextView mBluetoothScoStatusView; - private Bundle mBundleFromIntent; - private BroadcastReceiver mScoStateReceiver; - private CheckBox mWorkaroundsCheckBox; - private CheckBox mBackgroundCheckBox; - private static String mVersionText; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - logScreenSize(); - - mVersionTextView = (TextView) findViewById(R.id.versionText); - mCallbackSizeEditor = (TextView) findViewById(R.id.callbackSize); - - mDeviceView = (TextView) findViewById(R.id.deviceView); - updateNativeAudioUI(); - - // Set mode, eg. MODE_IN_COMMUNICATION - mModeSpinner = (Spinner) findViewById(R.id.spinnerAudioMode); - // Update AudioManager now in case user is trying to affect a different app. - mModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView adapterView, View view, int i, long l) { - long mode = mModeSpinner.getSelectedItemId(); - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - myAudioMgr.setMode((int)mode); - } - - @Override - public void onNothingSelected(AdapterView adapterView) { - } - }); - - try { - PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0); - int oboeVersion = OboeAudioStream.getOboeVersionNumber(); - int oboeMajor = (oboeVersion >> 24) & 0xFF; - int oboeMinor = (oboeVersion >> 16) & 0xFF; - int oboePatch = oboeVersion & 0xFF; - mVersionText = "OboeTester (" + pinfo.versionCode + ") v " + pinfo.versionName - + ", Oboe v " + oboeMajor + "." + oboeMinor + "." + oboePatch; - mVersionTextView.setText(mVersionText); - } catch (PackageManager.NameNotFoundException e) { - mVersionTextView.setText(e.getMessage()); - } - - mWorkaroundsCheckBox = (CheckBox) findViewById(R.id.boxEnableWorkarounds); - // Turn off workarounds so we can test the underlying API bugs. - mWorkaroundsCheckBox.setChecked(false); - NativeEngine.setWorkaroundsEnabled(false); - - mBackgroundCheckBox = (CheckBox) findViewById(R.id.boxEnableBackground); - - mBuildTextView = (TextView) findViewById(R.id.text_build_info); - mBuildTextView.setText(Build.DISPLAY); - - mBluetoothScoStatusView = (TextView) findViewById(R.id.textBluetoothScoStatus); - mScoStateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1); - if (state == AudioManager.SCO_AUDIO_STATE_CONNECTING) { - mBluetoothScoStatusView.setText("CONNECTING"); - } else if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) { - mBluetoothScoStatusView.setText("CONNECTED"); - } else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) { - mBluetoothScoStatusView.setText("DISCONNECTED"); - } - } - }; - - saveIntentBundleForLaterProcessing(getIntent()); - } - - public static String getVersiontext() { - return mVersionText; - } - - private void registerScoStateReceiver() { - registerReceiver(mScoStateReceiver, - new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)); - } - - private void unregisterScoStateReceiver() { - unregisterReceiver(mScoStateReceiver); - } - - private void logScreenSize() { - Display display = getWindowManager().getDefaultDisplay(); - Point size = new Point(); - display.getSize(size); - int width = size.x; - int height = size.y; - Log.i(TestAudioActivity.TAG, "Screen size = " + size.x + " * " + size.y); - } - - @Override - public void onNewIntent(Intent intent) { - saveIntentBundleForLaterProcessing(intent); - } - - // This will get processed during onResume. - private void saveIntentBundleForLaterProcessing(Intent intent) { - mBundleFromIntent = intent.getExtras(); - } - - private void processBundleFromIntent() { - if (mBundleFromIntent == null) { - return; - } - - if (mBundleFromIntent.containsKey(KEY_TEST_NAME)) { - String testName = mBundleFromIntent.getString(KEY_TEST_NAME); - if (VALUE_TEST_NAME_LATENCY.equals(testName)) { - Intent intent = new Intent(this, RoundTripLatencyActivity.class); - intent.putExtras(mBundleFromIntent); - startActivity(intent); - } else if (VALUE_TEST_NAME_GLITCH.equals(testName)) { - Intent intent = new Intent(this, ManualGlitchActivity.class); - intent.putExtras(mBundleFromIntent); - startActivity(intent); - } - } - mBundleFromIntent = null; - } - - @Override - public void onResume(){ - super.onResume(); - mWorkaroundsCheckBox.setChecked(NativeEngine.areWorkaroundsEnabled()); - processBundleFromIntent(); - registerScoStateReceiver(); - } - - @Override - public void onPause(){ - unregisterScoStateReceiver(); - super.onPause(); - } - - private void updateNativeAudioUI() { - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - String audioManagerSampleRate = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - String audioManagerFramesPerBurst = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); - mDeviceView.setText("Java AudioManager: rate = " + audioManagerSampleRate + - ", burst = " + audioManagerFramesPerBurst); - } - - public void onLaunchTestOutput(View view) { - onLaunchTest(TestOutputActivity.class); - } - - public void onLaunchTestInput(View view) { - onLaunchTest(TestInputActivity.class); - } - - public void onLaunchTapToTone(View view) { - onLaunchTest(TapToToneActivity.class); - } - - public void onLaunchRecorder(View view) { - onLaunchTest(RecorderActivity.class); - } - - public void onLaunchEcho(View view) { - onLaunchTest(EchoActivity.class); - } - - public void onLaunchRoundTripLatency(View view) { - onLaunchTest(RoundTripLatencyActivity.class); - } - - public void onLaunchManualGlitchTest(View view) { - onLaunchTest(ManualGlitchActivity.class); - } - - public void onLaunchAutoGlitchTest(View view) { onLaunchTest(AutomatedGlitchActivity.class); } - - public void onLaunchTestDisconnect(View view) { - onLaunchTest(TestDisconnectActivity.class); - } - - public void onLaunchTestDataPaths(View view) { - onLaunchTest(TestDataPathsActivity.class); - } - - public void onLaunchTestDeviceReport(View view) { - onLaunchTest(DeviceReportActivity.class); - } - - public void onLaunchExtratests(View view) { - onLaunchTest(ExtraTestsActivity.class); - } - - private void applyUserOptions() { - updateCallbackSize(); - - long mode = mModeSpinner.getSelectedItemId(); - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - myAudioMgr.setMode((int) mode); - - NativeEngine.setWorkaroundsEnabled(mWorkaroundsCheckBox.isChecked()); - TestAudioActivity.setBackgroundEnabled(mBackgroundCheckBox.isChecked()); - } - - private void onLaunchTest(Class clazz) { - applyUserOptions(); - Intent intent = new Intent(this, clazz); - startActivity(intent); - } - - public void onUseCallbackClicked(View view) { - CheckBox checkBox = (CheckBox) view; - OboeAudioStream.setUseCallback(checkBox.isChecked()); - } - - protected void showErrorToast(String message) { - showToast("Error: " + message); - } - - protected void showToast(final String message) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(MainActivity.this, - message, - Toast.LENGTH_SHORT).show(); - } - }); - } - - private void updateCallbackSize() { - CharSequence chars = mCallbackSizeEditor.getText(); - String text = chars.toString(); - int callbackSize = 0; - try { - callbackSize = Integer.parseInt(text); - } catch (NumberFormatException e) { - showErrorToast("Badly formated callback size: " + text); - mCallbackSizeEditor.setText("0"); - } - OboeAudioStream.setCallbackSize(callbackSize); - } - - public void onSetSpeakerphoneOn(View view) { - CheckBox checkBox = (CheckBox) view; - boolean enabled = checkBox.isChecked(); - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - myAudioMgr.setSpeakerphoneOn(enabled); - } - - public void onStartStopBluetoothSco(View view) { - CheckBox checkBox = (CheckBox) view; - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - if (checkBox.isChecked()) { - myAudioMgr.startBluetoothSco(); - } else { - myAudioMgr.stopBluetoothSco(); - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java deleted file mode 100644 index 6bbf0a42..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/ManualGlitchActivity.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.widget.SeekBar; -import android.widget.TextView; - -import java.io.IOException; - -public class ManualGlitchActivity extends GlitchActivity { - - public static final String KEY_IN_PRESET = "in_preset"; - - public static final String KEY_DURATION = "duration"; - public static final int VALUE_DEFAULT_DURATION = 10; - - public static final String KEY_BUFFER_BURSTS = "buffer_bursts"; - public static final int VALUE_DEFAULT_BUFFER_BURSTS = 2; - - public static final String KEY_TOLERANCE = "tolerance"; - private static final float DEFAULT_TOLERANCE = 0.1f; - - private TextView mTextTolerance; - private SeekBar mFaderTolerance; - protected ExponentialTaper mTaperTolerance; - private WaveformView mWaveformView; - private float[] mWaveform = new float[256]; - private boolean mTestRunningByIntent; - private Bundle mBundleFromIntent; - - private float mTolerance = DEFAULT_TOLERANCE; - - private SeekBar.OnSeekBarChangeListener mToleranceListener = new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - setToleranceProgress(progress); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }; - - protected void setToleranceProgress(int progress) { - float tolerance = (float) mTaperTolerance.linearToExponential( - ((double)progress) / FADER_PROGRESS_MAX); - setTolerance(tolerance); - mTextTolerance.setText("Tolerance = " + String.format("%5.3f", tolerance)); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mBundleFromIntent = getIntent().getExtras(); - - mTextTolerance = (TextView) findViewById(R.id.textTolerance); - mFaderTolerance = (SeekBar) findViewById(R.id.faderTolerance); - mTaperTolerance = new ExponentialTaper(0.0, 0.5, 100.0); - mFaderTolerance.setOnSeekBarChangeListener(mToleranceListener); - setToleranceFader(DEFAULT_TOLERANCE); - - mWaveformView = (WaveformView) findViewById(R.id.waveview_audio); - } - - private void setToleranceFader(float tolerance) { - int progress = (int) Math.round((mTaperTolerance.exponentialToLinear( - tolerance) * FADER_PROGRESS_MAX)); - mFaderTolerance.setProgress(progress); - } - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_manual_glitches); - } - - @Override - public void onResume(){ - super.onResume(); - processBundleFromIntent(); - } - - @Override - public void onNewIntent(Intent intent) { - mBundleFromIntent = intent.getExtras(); - } - - private void processBundleFromIntent() { - if (mBundleFromIntent == null) { - return; - } - if (mTestRunningByIntent) { - return; - } - - mResultFileName = null; - if (mBundleFromIntent.containsKey(KEY_FILE_NAME)) { - mTestRunningByIntent = true; - mResultFileName = mBundleFromIntent.getString(KEY_FILE_NAME); - - // Delay the test start to avoid race conditions. - Handler handler = new Handler(Looper.getMainLooper()); // UI thread - handler.postDelayed(new Runnable() { - @Override - public void run() { - startAutomaticTest(); - } - }, 500); // TODO where is the race, close->open? - - } - } - - @Override - public boolean isTestConfiguredUsingBundle() { - return mBundleFromIntent != null; - } - - void configureStreamsFromBundle(Bundle bundle) { - // Extract common parameters - super.configureStreamsFromBundle(bundle); - - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - - // Extract custom parameters from the bundle. - float tolerance = bundle.getFloat(KEY_TOLERANCE, DEFAULT_TOLERANCE); - setToleranceFader(tolerance); - setTolerance(tolerance); - mTolerance = tolerance; - - String defaultText = StreamConfiguration.convertInputPresetToText( - StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION); - String text = bundle.getString(KEY_IN_PRESET, defaultText); - int inputPreset = StreamConfiguration.convertTextToInputPreset(text); - requestedInConfig.setInputPreset(inputPreset); - } - - public void startAudioTest() throws IOException { - super.startAudioTest(); - setToleranceProgress(mFaderTolerance.getProgress()); - } - - void startAutomaticTest() { - configureStreamsFromBundle(mBundleFromIntent); - - int durationSeconds = mBundleFromIntent.getInt(KEY_DURATION, VALUE_DEFAULT_DURATION); - int numBursts = mBundleFromIntent.getInt(KEY_BUFFER_BURSTS, VALUE_DEFAULT_BUFFER_BURSTS); - - try { - onStartAudioTest(null); - int sizeFrames = mAudioOutTester.getCurrentAudioStream().getFramesPerBurst() * numBursts; - mAudioOutTester.getCurrentAudioStream().setBufferSizeInFrames(sizeFrames); - - // Schedule the end of the test. - Handler handler = new Handler(Looper.getMainLooper()); // UI thread - handler.postDelayed(new Runnable() { - @Override - public void run() { - stopAutomaticTest(); - } - }, durationSeconds * 1000); - } catch (IOException e) { - String report = "Open failed: " + e.getMessage(); - maybeWriteTestResult(report); - mTestRunningByIntent = false; - } finally { - mBundleFromIntent = null; - } - - } - - void stopAutomaticTest() { - String report = getCommonTestReport() - + String.format("tolerance = %5.3f\n", mTolerance) - + mLastGlitchReport; - onStopAudioTest(null); - maybeWriteTestResult(report); - mTestRunningByIntent = false; - } - - // Only call from UI thread. - @Override - public void onTestFinished() { - super.onTestFinished(); - } - // Only call from UI thread. - @Override - public void onTestBegan() { - mWaveformView.clearSampleData(); - mWaveformView.postInvalidate(); - super.onTestBegan(); - } - - // Called on UI thread - @Override - protected void onGlitchDetected() { - int numSamples = getGlitch(mWaveform); - mWaveformView.setSampleData(mWaveform, 0, numSamples); - mWaveformView.postInvalidate(); - } - - private float[] getGlitchWaveform() { - return mWaveform; - } - - private native int getGlitch(float[] mWaveform); - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java deleted file mode 100644 index 8dbe502b..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MicrophoneInfoConverter.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.mobileer.oboetester; - -import android.media.MicrophoneInfo; -import android.util.Pair; - -import java.util.List; - -public class MicrophoneInfoConverter { - - static String convertDirectionality(int directionality) { - switch(directionality) { - case MicrophoneInfo.DIRECTIONALITY_BI_DIRECTIONAL: - return "Bidirectional"; - case MicrophoneInfo.DIRECTIONALITY_OMNI: - return "Omni"; - case MicrophoneInfo.DIRECTIONALITY_CARDIOID: - return "Cardioid"; - case MicrophoneInfo.DIRECTIONALITY_SUPER_CARDIOID: - return "SuperCardioid"; - case MicrophoneInfo.DIRECTIONALITY_HYPER_CARDIOID: - return "HyperCardioid"; - default: - return "Unknown"; - } - } - - static String convertLocation(int location) { - switch(location) { - case MicrophoneInfo.LOCATION_MAINBODY: - return "Main Body"; - case MicrophoneInfo.LOCATION_MAINBODY_MOVABLE: - return "Main Body Movable"; - case MicrophoneInfo.LOCATION_PERIPHERAL: - return "Peripheral"; - default: - return "Unknown"; - } - } - - static String convertCoordinates(MicrophoneInfo.Coordinate3F coordinates) { - if (coordinates == MicrophoneInfo.POSITION_UNKNOWN) return "Unknown"; - return String.format("{ %6.4g, %5.3g, %5.3g }", - coordinates.x, coordinates.y, coordinates.z); - } - - public static String reportMicrophoneInfo(MicrophoneInfo micInfo) { - StringBuffer sb = new StringBuffer(); - sb.append("\n==== Microphone ========= " + micInfo.getId()); - sb.append("\nAddress : " + micInfo.getAddress()); - sb.append("\nDescription: " + micInfo.getDescription()); - sb.append("\nDirection : " + convertDirectionality(micInfo.getDirectionality())); - sb.append("\nLocation : " + convertLocation(micInfo.getLocation())); - sb.append("\nMinSPL : " + micInfo.getMinSpl()); - sb.append("\nMaxSPL : " + micInfo.getMaxSpl()); - sb.append("\nSensitivity: " + micInfo.getSensitivity()); - sb.append("\nGroup : " + micInfo.getGroup()); - sb.append("\nIndexInTheGroup: " + micInfo.getIndexInTheGroup()); - sb.append("\nOrientation: " + convertCoordinates(micInfo.getOrientation())); - sb.append("\nPosition : " + convertCoordinates(micInfo.getPosition())); - sb.append("\nType : " + micInfo.getType()); - - List> mapping = micInfo.getChannelMapping(); - sb.append("\nChannelMapping: {"); - for (Pair pair : mapping) { - sb.append("[" + pair.first + "," + pair.second + "], "); - } - sb.append("}"); - - sb.append("\n"); - return sb.toString(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java deleted file mode 100644 index c85e59f1..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/MidiTapTester.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 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. - */ -package com.mobileer.oboetester; - - -import android.media.midi.MidiDeviceService; -import android.media.midi.MidiReceiver; -import android.util.Log; - -import com.mobileer.miditools.MidiConstants; -import com.mobileer.miditools.MidiFramer; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * Measure the latency of various output paths by playing a blip. - * Report the results back to the TestListeners. - */ -public class MidiTapTester extends MidiDeviceService { - - // Sometimes the service can be run without the MainActivity being run! - static { - // Must match name in CMakeLists.txt - System.loadLibrary("oboetester"); - } - - private ArrayList mListeners = new ArrayList(); - private MyMidiReceiver mReceiver = new MyMidiReceiver(); - private MidiFramer mMidiFramer = new MidiFramer(mReceiver); - - private static MidiTapTester mInstance; - - - public static interface NoteListener { - public void onNoteOn(int pitch); - } - - /** - * This is a Service so it is only created when a client requests the service. - */ - public MidiTapTester() { - mInstance = this; - } - - public void addTestListener(NoteListener listener) { - mListeners.add(listener); - } - - public void removeTestListener(NoteListener listener) { - mListeners.remove(listener); - } - - @Override - public void onCreate() { - super.onCreate(); - } - - @Override - public void onDestroy() { - // do stuff here - super.onDestroy(); - } - - public static MidiTapTester getInstance() { - return mInstance; - } - - class MyMidiReceiver extends MidiReceiver { - public void onSend(byte[] data, int offset, - int count, long timestamp) throws IOException { - // parse MIDI - byte command = (byte) (data[0] & 0x0F0); - if (command == MidiConstants.STATUS_NOTE_ON) { - if (data[2] == 0) { - noteOff(data[1]); - } else { - noteOn(data[1]); - } - } else if (command == MidiConstants.STATUS_NOTE_OFF) { - noteOff(data[1]); - } - Log.i(TapToToneActivity.TAG, "MIDI command = " + command); - } - } - - private void noteOn(byte b) { - fireNoteOn(b); - } - - private void fireNoteOn(byte pitch) { - for (NoteListener listener : mListeners) { - listener.onNoteOn(pitch); - } - } - - private void noteOff(byte b) {} - - @Override - public MidiReceiver[] onGetInputPortReceivers() { - return new MidiReceiver[]{mMidiFramer}; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java deleted file mode 100644 index 6978bdca..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.mobileer.oboetester; - -public class NativeEngine { - - static native boolean isMMapSupported(); - - static native boolean isMMapExclusiveSupported(); - - static native void setWorkaroundsEnabled(boolean enabled); - - static native boolean areWorkaroundsEnabled(); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java deleted file mode 100644 index 1bc1232c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeSniffer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; - -abstract class NativeSniffer implements Runnable { - public static final int SNIFFER_UPDATE_PERIOD_MSEC = 100; - public static final int SNIFFER_UPDATE_DELAY_MSEC = 200; - private final Activity activity; - protected Handler mHandler = new Handler(Looper.getMainLooper()); // UI thread - protected volatile boolean mEnabled = true; - - public NativeSniffer(Activity activity) { - this.activity = activity; - } - - public void startSniffer() { - long now = System.currentTimeMillis(); - // Start the initial runnable task by posting through the handler - mEnabled = true; - mHandler.postDelayed(this, SNIFFER_UPDATE_DELAY_MSEC); - } - - public void stopSniffer() { - mEnabled = false; - if (mHandler != null) { - mHandler.removeCallbacks(this); - } - - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - updateStatusText(); - } - }); - } - - public void reschedule() { - updateStatusText(); - // Reschedule so this task repeats - if (mEnabled) { - mHandler.postDelayed(this, SNIFFER_UPDATE_PERIOD_MSEC); - } - } - - public abstract void updateStatusText(); - - public String getShortReport() { - return "no-report"; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java deleted file mode 100644 index 92cde485..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioOutputStream.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 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. - */ - -package com.mobileer.oboetester; - -/** - * Native synthesizer and audio output. - */ -public class OboeAudioOutputStream extends OboeAudioStream { - - @Override - public boolean isInput() { - return false; - } - - public native void trigger(); - - public native void setChannelEnabled(int channelIndex, boolean enabled); - - public native void setSignalType(int type); -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java deleted file mode 100644 index 3ecfe17a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import java.io.IOException; - -/** - * Implementation of an AudioStreamBase using Oboe. - */ - -abstract class OboeAudioStream extends AudioStreamBase { - private static final int INVALID_STREAM_INDEX = -1; - int streamIndex = INVALID_STREAM_INDEX; - - @Override - public void stopPlayback() throws IOException { - int result = stopPlaybackNative(); - if (result < 0) { - throw new IOException("Stop Playback failed! result = " + result); - } - } - - public native int stopPlaybackNative(); - - @Override - public void startPlayback() throws IOException { - int result = startPlaybackNative(); - if (result < 0) { - throw new IOException("Start Playback failed! result = " + result); - } - } - - public native int startPlaybackNative(); - - // Write disabled because the synth is in native code. - @Override - public int write(float[] buffer, int offset, int length) { - return 0; - } - - @Override - public void open(StreamConfiguration requestedConfiguration, - StreamConfiguration actualConfiguration, int bufferSizeInFrames) throws IOException { - super.open(requestedConfiguration, actualConfiguration, bufferSizeInFrames); - int result = openNative(requestedConfiguration.getNativeApi(), - requestedConfiguration.getSampleRate(), - requestedConfiguration.getChannelCount(), - requestedConfiguration.getFormat(), - requestedConfiguration.getSharingMode(), - requestedConfiguration.getPerformanceMode(), - requestedConfiguration.getInputPreset(), - requestedConfiguration.getUsage(), - requestedConfiguration.getDeviceId(), - requestedConfiguration.getSessionId(), - requestedConfiguration.getFramesPerBurst(), - requestedConfiguration.getChannelConversionAllowed(), - requestedConfiguration.getFormatConversionAllowed(), - requestedConfiguration.getRateConversionQuality(), - requestedConfiguration.isMMap(), - isInput() - ); - if (result < 0) { - streamIndex = INVALID_STREAM_INDEX; - throw new IOException("Open failed! result = " + result); - } else { - streamIndex = result; - } - actualConfiguration.setNativeApi(getNativeApi()); - actualConfiguration.setSampleRate(getSampleRate()); - actualConfiguration.setSharingMode(getSharingMode()); - actualConfiguration.setPerformanceMode(getPerformanceMode()); - actualConfiguration.setInputPreset(getInputPreset()); - actualConfiguration.setUsage(getUsage()); - actualConfiguration.setFramesPerBurst(getFramesPerBurst()); - actualConfiguration.setBufferCapacityInFrames(getBufferCapacityInFrames()); - actualConfiguration.setChannelCount(getChannelCount()); - actualConfiguration.setDeviceId(getDeviceId()); - actualConfiguration.setSessionId(getSessionId()); - actualConfiguration.setFormat(getFormat()); - actualConfiguration.setMMap(isMMap()); - actualConfiguration.setDirection(isInput() - ? StreamConfiguration.DIRECTION_INPUT - : StreamConfiguration.DIRECTION_OUTPUT); - } - - private native int openNative( - int nativeApi, - int sampleRate, - int channelCount, - int format, - int sharingMode, - int performanceMode, - int inputPreset, - int usage, - int deviceId, - int sessionId, - int framesPerRead, - boolean channelConversionAllowed, - boolean formatConversionAllowed, - int rateConversionQuality, - boolean isMMap, - boolean isInput); - - @Override - public void close() { - if (streamIndex >= 0) { - close(streamIndex); - streamIndex = INVALID_STREAM_INDEX; - } - } - public native void close(int streamIndex); - - @Override - public int getBufferCapacityInFrames() { - return getBufferCapacityInFrames(streamIndex); - } - private native int getBufferCapacityInFrames(int streamIndex); - - @Override - public int getBufferSizeInFrames() { - return getBufferSizeInFrames(streamIndex); - } - private native int getBufferSizeInFrames(int streamIndex); - - @Override - public boolean isThresholdSupported() { - return true; - } - - @Override - public int setBufferSizeInFrames(int thresholdFrames) { - return setBufferSizeInFrames(streamIndex, thresholdFrames); - } - private native int setBufferSizeInFrames(int streamIndex, int thresholdFrames); - - public int getNativeApi() { - return getNativeApi(streamIndex); - } - public native int getNativeApi(int streamIndex); - - @Override - public int getFramesPerBurst() { - return getFramesPerBurst(streamIndex); - } - public native int getFramesPerBurst(int streamIndex); - - public int getSharingMode() { - return getSharingMode(streamIndex); - } - public native int getSharingMode(int streamIndex); - - public int getPerformanceMode() { - return getPerformanceMode(streamIndex); - } - public native int getPerformanceMode(int streamIndex); - - public int getInputPreset() { - return getInputPreset(streamIndex); - } - public native int getInputPreset(int streamIndex); - - public int getSampleRate() { - return getSampleRate(streamIndex); - } - public native int getSampleRate(int streamIndex); - - public int getFormat() { - return getFormat(streamIndex); - } - public native int getFormat(int streamIndex); - - public int getUsage() { - return getUsage(streamIndex); - } - public native int getUsage(int streamIndex); - - public int getChannelCount() { - return getChannelCount(streamIndex); - } - public native int getChannelCount(int streamIndex); - - public int getDeviceId() { - return getDeviceId(streamIndex); - } - public native int getDeviceId(int streamIndex); - - public int getSessionId() { - return getSessionId(streamIndex); - } - public native int getSessionId(int streamIndex); - - public boolean isMMap() { - return isMMap(streamIndex); - } - public native boolean isMMap(int streamIndex); - - @Override - public native long getCallbackCount(); // TODO Move to another class? - - @Override - public int getLastErrorCallbackResult() { - return getLastErrorCallbackResult(streamIndex); - } - public native int getLastErrorCallbackResult(int streamIndex); - - @Override - public long getFramesWritten() { - return getFramesWritten(streamIndex); - } - public native long getFramesWritten(int streamIndex); - - @Override - public long getFramesRead() { - return getFramesRead(streamIndex); - } - public native long getFramesRead(int streamIndex); - - @Override - public int getXRunCount() { - return getXRunCount(streamIndex); - } - public native int getXRunCount(int streamIndex); - - @Override - public double getLatency() { - return getTimestampLatency(streamIndex); - } - public native double getTimestampLatency(int streamIndex); - - @Override - public double getCpuLoad() { - return getCpuLoad(streamIndex); - } - public native double getCpuLoad(int streamIndex); - - @Override - public native void setWorkload(double workload); - - @Override - public int getState() { - return getState(streamIndex); - } - public native int getState(int streamIndex); - - public static native void setCallbackReturnStop(boolean b); - - public static native void setUseCallback(boolean checked); - - public static native void setCallbackSize(int callbackSize); - - public static native int getOboeVersionNumber(); - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java deleted file mode 100644 index 48df2185..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RecorderActivity.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2018 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. - */ - -package com.mobileer.oboetester; - -import android.os.Bundle; -import android.view.View; -import android.widget.Button; - -import java.io.IOException; - -/** - * Activity to record and play back audio. - */ -public class RecorderActivity extends TestInputActivity { - - private static final int STATE_RECORDING = 5; - private static final int STATE_PLAYING = 6; - private int mRecorderState = AUDIO_STATE_STOPPED; - private Button mRecordButton; - private Button mStopButton; - private Button mPlayButton; - private Button mShareButton; - private boolean mGotRecording; - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_recorder); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mRecordButton = (Button) findViewById(R.id.button_start_recording); - mStopButton = (Button) findViewById(R.id.button_stop_record_play); - mPlayButton = (Button) findViewById(R.id.button_start_playback); - mShareButton = (Button) findViewById(R.id.button_share); - mRecorderState = AUDIO_STATE_STOPPED; - mGotRecording = false; - updateButtons(); - } - - int getActivityType() { - return ACTIVITY_RECORD_PLAY; - } - - public void onStartRecording(View view) { - try { - openAudio(); - startAudio(); - mRecorderState = STATE_RECORDING; - mGotRecording = true; - updateButtons(); - } catch (IOException e) { - showErrorToast(e.getMessage()); - } - } - - public void onStopRecordPlay(View view) { - stopAudio(); - closeAudio(); - mRecorderState = AUDIO_STATE_STOPPED; - updateButtons(); - } - - public void onStartPlayback(View view) { - startPlayback(); - mRecorderState = STATE_PLAYING; - updateButtons(); - } - - private void updateButtons() { - mRecordButton.setEnabled(mRecorderState == AUDIO_STATE_STOPPED); - mStopButton.setEnabled(mRecorderState != AUDIO_STATE_STOPPED); - mPlayButton.setEnabled(mRecorderState == AUDIO_STATE_STOPPED && mGotRecording); - mShareButton.setEnabled(mRecorderState == AUDIO_STATE_STOPPED && mGotRecording); - } - - public void startPlayback() { - try { - mAudioInputTester.startPlayback(); - updateStreamConfigurationViews(); - updateEnabledWidgets(); - } catch (Exception e) { - e.printStackTrace(); - showErrorToast(e.getMessage()); - } - } - - @Override - String getWaveTag() { - return "recording"; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java deleted file mode 100644 index 6a9102cb..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/RoundTripLatencyActivity.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright 2018 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. - */ - -package com.mobileer.oboetester; - -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.text.method.ScrollingMovementMethod; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * Activity to measure latency on a full duplex stream. - */ -public class RoundTripLatencyActivity extends AnalyzerActivity { - - // STATEs defined in LatencyAnalyzer.h - private static final int STATE_MEASURE_BACKGROUND = 0; - private static final int STATE_IN_PULSE = 1; - private static final int STATE_GOT_DATA = 2; - private final static String LATENCY_FORMAT = "%4.2f"; - // When I use 5.3g I only get one digit after the decimal point! - private final static String CONFIDENCE_FORMAT = "%5.3f"; - - private TextView mAnalyzerView; - private Button mMeasureButton; - private Button mAverageButton; - private Button mCancelButton; - private Button mShareButton; - private boolean mHasRecording = false; - - private boolean mTestRunningByIntent; - private Bundle mBundleFromIntent; - private int mBufferBursts = -1; - private Handler mHandler = new Handler(Looper.getMainLooper()); // UI thread - - // Run the test several times and report the acverage latency. - protected class LatencyAverager { - private final static int AVERAGE_TEST_DELAY_MSEC = 1000; // arbitrary - private static final int GOOD_RUNS_REQUIRED = 5; // arbitrary - private static final int MAX_BAD_RUNS_ALLOWED = 5; // arbitrary - private int mBadCount = 0; // number of bad measurements - private int mGoodCount = 0; // number of good measurements - - ArrayList mLatencies = new ArrayList(GOOD_RUNS_REQUIRED); - ArrayList mConfidences = new ArrayList(GOOD_RUNS_REQUIRED); - private double mLatencyMin; - private double mLatencyMax; - private double mConfidenceSum; - private boolean mActive; - private String mLastReport = ""; - - // Called on UI thread. - String onAnalyserDone() { - String message; - boolean reschedule = false; - if (!mActive) { - message = ""; - } else if (getMeasuredResult() != 0) { - mBadCount++; - if (mBadCount > MAX_BAD_RUNS_ALLOWED) { - cancel(); - updateButtons(false); - message = "averaging cancelled due to error\n"; - } else { - message = "skipping this bad run, " - + mBadCount + " of " + MAX_BAD_RUNS_ALLOWED + " max\n"; - reschedule = true; - } - } else { - mGoodCount++; - double latency = getMeasuredLatencyMillis(); - double confidence = getMeasuredConfidence(); - mLatencies.add(latency); - mConfidences.add(confidence); - mConfidenceSum += confidence; - mLatencyMin = Math.min(mLatencyMin, latency); - mLatencyMax = Math.max(mLatencyMax, latency); - if (mGoodCount < GOOD_RUNS_REQUIRED) { - reschedule = true; - } else { - mActive = false; - updateButtons(false); - } - message = reportAverage(); - } - if (reschedule) { - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - measureSingleLatency(); - } - }, AVERAGE_TEST_DELAY_MSEC); - } - return message; - } - - private String reportAverage() { - String message; - if (mGoodCount == 0 || mConfidenceSum == 0.0) { - message = "num.iterations = " + mGoodCount + "\n"; - } else { - final double mAverageConfidence = mConfidenceSum / mGoodCount; - double meanLatency = calculateMeanLatency(); - double meanAbsoluteDeviation = calculateMeanAbsoluteDeviation(meanLatency); - message = "average.latency.msec = " + String.format(LATENCY_FORMAT, meanLatency) + "\n" - + "mean.absolute.deviation = " + String.format(LATENCY_FORMAT, meanAbsoluteDeviation) + "\n" - + "average.confidence = " + String.format(CONFIDENCE_FORMAT, mAverageConfidence) + "\n" - + "min.latency.msec = " + String.format(LATENCY_FORMAT, mLatencyMin) + "\n" - + "max.latency.msec = " + String.format(LATENCY_FORMAT, mLatencyMax) + "\n" - + "num.iterations = " + mGoodCount + "\n"; - } - message += "num.failed = " + mBadCount + "\n"; - mLastReport = message; - return message; - } - - private double calculateMeanAbsoluteDeviation(double meanLatency) { - double deviationSum = 0.0; - for (double latency : mLatencies) { - deviationSum += Math.abs(latency - meanLatency); - } - return deviationSum / mLatencies.size(); - } - - private double calculateMeanLatency() { - double latencySum = 0.0; - for (double latency : mLatencies) { - latencySum += latency; - } - return latencySum / mLatencies.size(); - } - - // Called on UI thread. - public void start() { - mLatencies.clear(); - mConfidences.clear(); - mConfidenceSum = 0.0; - mLatencyMax = Double.MIN_VALUE; - mLatencyMin = Double.MAX_VALUE; - mBadCount = 0; - mGoodCount = 0; - mActive = true; - mLastReport = ""; - measureSingleLatency(); - } - - public void clear() { - mActive = false; - mLastReport = ""; - } - - public void cancel() { - mActive = false; - } - - public boolean isActive() { - return mActive; - } - - public String getLastReport() { - return mLastReport; - } - } - LatencyAverager mLatencyAverager = new LatencyAverager(); - - // Periodically query the status of the stream. - protected class LatencySniffer { - private int counter = 0; - public static final int SNIFFER_UPDATE_PERIOD_MSEC = 150; - public static final int SNIFFER_UPDATE_DELAY_MSEC = 300; - - // Display status info for the stream. - private Runnable runnableCode = new Runnable() { - @Override - public void run() { - String message; - - if (isAnalyzerDone()) { - message = mLatencyAverager.onAnalyserDone(); - message += onAnalyzerDone(); - } else { - message = getProgressText(); - message += "please wait... " + counter + "\n"; - message += convertStateToString(getAnalyzerState()); - - // Repeat this runnable code block again. - mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_PERIOD_MSEC); - } - setAnalyzerText(message); - counter++; - } - }; - - private void startSniffer() { - counter = 0; - // Start the initial runnable task by posting through the handler - mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_DELAY_MSEC); - } - - private void stopSniffer() { - if (mHandler != null) { - mHandler.removeCallbacks(runnableCode); - } - } - } - - static String convertStateToString(int state) { - switch (state) { - case STATE_MEASURE_BACKGROUND: return "BACKGROUND"; - case STATE_IN_PULSE: return "RECORDING"; - case STATE_GOT_DATA: return "ANALYZING"; - default: return "DONE"; - } - } - - private String getProgressText() { - int progress = getAnalyzerProgress(); - int state = getAnalyzerState(); - int resetCount = getResetCount(); - String message = String.format("progress = %d\nstate = %d\n#resets = %d\n", - progress, state, resetCount); - message += mLatencyAverager.getLastReport(); - return message; - } - - private String onAnalyzerDone() { - String message = getResultString(); - if (mTestRunningByIntent) { - String report = getCommonTestReport(); - report += message; - maybeWriteTestResult(report); - } - mTestRunningByIntent = false; - mHasRecording = true; - stopAudioTest(); - return message; - } - - @NonNull - private String getResultString() { - int result = getMeasuredResult(); - int resetCount = getResetCount(); - double confidence = getMeasuredConfidence(); - String message = ""; - - message += String.format("confidence = " + CONFIDENCE_FORMAT + "\n", confidence); - message += String.format("result.text = %s\n", resultCodeToString(result)); - - // Only report valid latencies. - if (result == 0) { - int latencyFrames = getMeasuredLatency(); - double latencyMillis = getMeasuredLatencyMillis(); - int bufferSize = mAudioOutTester.getCurrentAudioStream().getBufferSizeInFrames(); - int latencyEmptyFrames = latencyFrames - bufferSize; - double latencyEmptyMillis = latencyEmptyFrames * 1000.0 / getSampleRate(); - message += String.format("latency.msec = " + LATENCY_FORMAT + "\n", latencyMillis); - message += String.format("latency.frames = %d\n", latencyFrames); - message += String.format("latency.empty.msec = " + LATENCY_FORMAT + "\n", latencyEmptyMillis); - message += String.format("latency.empty.frames = %d\n", latencyEmptyFrames); - } - - message += String.format("rms.signal = %7.5f\n", getSignalRMS()); - message += String.format("rms.noise = %7.5f\n", getBackgroundRMS()); - message += String.format("reset.count = %d\n", resetCount); - message += String.format("result = %d\n", result); - - return message; - } - - private LatencySniffer mLatencySniffer = new LatencySniffer(); - - native int getAnalyzerProgress(); - native int getMeasuredLatency(); - double getMeasuredLatencyMillis() { - return getMeasuredLatency() * 1000.0 / getSampleRate(); - } - native double getMeasuredConfidence(); - native double getBackgroundRMS(); - native double getSignalRMS(); - - private void setAnalyzerText(String s) { - mAnalyzerView.setText(s); - } - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_rt_latency); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mMeasureButton = (Button) findViewById(R.id.button_measure); - mAverageButton = (Button) findViewById(R.id.button_average); - mCancelButton = (Button) findViewById(R.id.button_cancel); - mShareButton = (Button) findViewById(R.id.button_share); - mShareButton.setEnabled(false); - mAnalyzerView = (TextView) findViewById(R.id.text_status); - mAnalyzerView.setMovementMethod(new ScrollingMovementMethod()); - updateEnabledWidgets(); - - hideSettingsViews(); - - mBufferSizeView.setFaderNormalizedProgress(0.0); // for lowest latency - - mBundleFromIntent = getIntent().getExtras(); - } - - @Override - public void onNewIntent(Intent intent) { - mBundleFromIntent = intent.getExtras(); - } - - @Override - int getActivityType() { - return ACTIVITY_RT_LATENCY; - } - - @Override - protected void onStart() { - super.onStart(); - mHasRecording = false; - updateButtons(false); - } - - private void processBundleFromIntent() { - if (mBundleFromIntent == null) { - return; - } - if (mTestRunningByIntent) { - return; - } - - mResultFileName = null; - if (mBundleFromIntent.containsKey(KEY_FILE_NAME)) { - mTestRunningByIntent = true; - mResultFileName = mBundleFromIntent.getString(KEY_FILE_NAME); - getFirstInputStreamContext().configurationView.setExclusiveMode(true); - getFirstOutputStreamContext().configurationView.setExclusiveMode(true); - mBufferBursts = mBundleFromIntent.getInt(KEY_BUFFER_BURSTS, mBufferBursts); - - // Delay the test start to avoid race conditions. - Handler handler = new Handler(Looper.getMainLooper()); // UI thread - handler.postDelayed(new Runnable() { - @Override - public void run() { - startAutomaticTest(); - } - }, 500); // TODO where is the race, close->open? - } - } - - @Override - public boolean isTestConfiguredUsingBundle() { - return mBundleFromIntent != null; - } - - void startAutomaticTest() { - try { - configureStreamsFromBundle(mBundleFromIntent); - onMeasure(null); - } finally { - mBundleFromIntent = null; - } - } - - @Override - public void onResume(){ - super.onResume(); - processBundleFromIntent(); - } - - @Override - protected void onStop() { - mLatencySniffer.stopSniffer(); - super.onStop(); - } - - public void onMeasure(View view) { - mLatencyAverager.clear(); - measureSingleLatency(); - } - - void updateButtons(boolean running) { - boolean busy = running || mLatencyAverager.isActive(); - mMeasureButton.setEnabled(!busy); - mAverageButton.setEnabled(!busy); - mCancelButton.setEnabled(running); - mShareButton.setEnabled(!busy && mHasRecording); - } - - private void measureSingleLatency() { - try { - openAudio(); - if (mBufferBursts >= 0) { - AudioStreamBase stream = mAudioOutTester.getCurrentAudioStream(); - int framesPerBurst = stream.getFramesPerBurst(); - stream.setBufferSizeInFrames(framesPerBurst * mBufferBursts); - // override buffer size fader - mBufferSizeView.setEnabled(false); - mBufferBursts = -1; - } - startAudio(); - mLatencySniffer.startSniffer(); - updateButtons(true); - } catch (IOException e) { - showErrorToast(e.getMessage()); - } - } - - public void onAverage(View view) { - mLatencyAverager.start(); - } - - public void onCancel(View view) { - mLatencyAverager.cancel(); - stopAudioTest(); - } - - // Call on UI thread - public void stopAudioTest() { - mLatencySniffer.stopSniffer(); - stopAudio(); - closeAudio(); - updateButtons(false); - } - - @Override - String getWaveTag() { - return "rtlatency"; - } - - @Override - boolean isOutput() { - return false; - } - - @Override - public void setupEffects(int sessionId) { - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java deleted file mode 100644 index cffc2249..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.content.res.Resources; - -import java.util.HashMap; - -/** - * Container for the properties of a Stream. - * - * This can be used to build a stream, or as a base class for a Stream, - * or as a way to report the properties of a Stream. - */ - -public class StreamConfiguration { - public static final int UNSPECIFIED = 0; - - // These must match order in Spinner and in native code and in AAudio.h - public static final int NATIVE_API_UNSPECIFIED = 0; - public static final int NATIVE_API_OPENSLES = 1; - public static final int NATIVE_API_AAUDIO = 2; - - public static final int SHARING_MODE_EXCLUSIVE = 0; // must match AAUDIO - public static final int SHARING_MODE_SHARED = 1; // must match AAUDIO - - public static final int AUDIO_FORMAT_PCM_16 = 1; // must match AAUDIO - public static final int AUDIO_FORMAT_PCM_FLOAT = 2; // must match AAUDIO - public static final int AUDIO_FORMAT_PCM_24 = 3; // must match AAUDIO - public static final int AUDIO_FORMAT_PCM_32 = 4; // must match AAUDIO - - public static final int DIRECTION_OUTPUT = 0; // must match AAUDIO - public static final int DIRECTION_INPUT = 1; // must match AAUDIO - - public static final int SESSION_ID_NONE = -1; // must match AAUDIO - public static final int SESSION_ID_ALLOCATE = 0; // must match AAUDIO - - public static final int PERFORMANCE_MODE_NONE = 10; // must match AAUDIO - public static final int PERFORMANCE_MODE_POWER_SAVING = 11; // must match AAUDIO - public static final int PERFORMANCE_MODE_LOW_LATENCY = 12; // must match AAUDIO - - public static final int RATE_CONVERSION_QUALITY_NONE = 0; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_FASTEST = 1; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_LOW = 2; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_MEDIUM = 3; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_HIGH = 4; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_BEST = 5; // must match Oboe - - public static final int STREAM_STATE_STARTING = 3; // must match Oboe - public static final int STREAM_STATE_STARTED = 4; // must match Oboe - - public static final int INPUT_PRESET_GENERIC = 1; // must match Oboe - public static final int INPUT_PRESET_CAMCORDER = 5; // must match Oboe - public static final int INPUT_PRESET_VOICE_RECOGNITION = 6; // must match Oboe - public static final int INPUT_PRESET_VOICE_COMMUNICATION = 7; // must match Oboe - public static final int INPUT_PRESET_UNPROCESSED = 9; // must match Oboe - public static final int INPUT_PRESET_VOICE_PERFORMANCE = 10; // must match Oboe - - public static final int ERROR_DISCONNECTED = -899; // must match Oboe - - public static final int USAGE_MEDIA = 1; - public static final int USAGE_VOICE_COMMUNICATION = 2; - public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; - public static final int USAGE_ALARM = 4; - public static final int USAGE_NOTIFICATION = 5; - public static final int USAGE_NOTIFICATION_RINGTONE = 6; - public static final int USAGE_NOTIFICATION_EVENT = 10; - public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; - public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; - public static final int USAGE_ASSISTANCE_SONIFICATION = 13; - public static final int USAGE_GAME = 14; - public static final int USAGE_ASSISTANT = 16; - - public static final int[] usages = { - USAGE_MEDIA, - USAGE_VOICE_COMMUNICATION, - USAGE_VOICE_COMMUNICATION_SIGNALLING, - USAGE_ALARM, - USAGE_NOTIFICATION, - USAGE_NOTIFICATION_RINGTONE, - USAGE_NOTIFICATION_EVENT, - USAGE_ASSISTANCE_ACCESSIBILITY, - USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, - USAGE_ASSISTANCE_SONIFICATION, - USAGE_GAME, - USAGE_ASSISTANT}; - - private int mNativeApi; - private int mBufferCapacityInFrames; - private int mChannelCount; - private int mDeviceId; - private int mSessionId; - private int mDirection; // does not get reset - private int mFormat; - private int mSampleRate; - private int mSharingMode; - private int mPerformanceMode; - private boolean mFormatConversionAllowed; - private boolean mChannelConversionAllowed; - private int mRateConversionQuality; - private int mInputPreset; - private int mUsage; - private static HashMap mUsageStringToIntegerMap; - - private int mFramesPerBurst = 0; - - private boolean mMMap = false; - - public StreamConfiguration() { - reset(); - } - - static { - // Build map for Usage string-to-int conversion. - mUsageStringToIntegerMap = new HashMap(); - for (int usage : usages) { - mUsageStringToIntegerMap.put(convertUsageToText(usage), usage); - } - } - - public void reset() { - mNativeApi = NATIVE_API_UNSPECIFIED; - mBufferCapacityInFrames = UNSPECIFIED; - mChannelCount = UNSPECIFIED; - mDeviceId = UNSPECIFIED; - mSessionId = -1; - mFormat = AUDIO_FORMAT_PCM_FLOAT; - mSampleRate = UNSPECIFIED; - mSharingMode = SHARING_MODE_EXCLUSIVE; - mPerformanceMode = PERFORMANCE_MODE_LOW_LATENCY; - mInputPreset = INPUT_PRESET_VOICE_RECOGNITION; - mUsage = 0; // FIXME add USAGE_* - mFormatConversionAllowed = false; - mChannelConversionAllowed = false; - mRateConversionQuality = RATE_CONVERSION_QUALITY_NONE; - mMMap = NativeEngine.isMMapSupported(); - } - - public int getFramesPerBurst() { - return mFramesPerBurst; - } - - public void setFramesPerBurst(int framesPerBurst) { - this.mFramesPerBurst = framesPerBurst; - } - - public int getBufferCapacityInFrames() { - return mBufferCapacityInFrames; - } - - public void setBufferCapacityInFrames(int bufferCapacityInFrames) { - this.mBufferCapacityInFrames = bufferCapacityInFrames; - } - - public int getFormat() { - return mFormat; - } - - public void setFormat(int format) { - this.mFormat = format; - } - - public int getDirection() { - return mDirection; - } - - public void setDirection(int direction) { - this.mDirection = direction; - } - - public int getPerformanceMode() { - return mPerformanceMode; - } - - public void setPerformanceMode(int performanceMode) { - this.mPerformanceMode = performanceMode; - } - - static String convertPerformanceModeToText(int performanceMode) { - switch(performanceMode) { - case PERFORMANCE_MODE_NONE: - return "NO"; - case PERFORMANCE_MODE_POWER_SAVING: - return "PS"; - case PERFORMANCE_MODE_LOW_LATENCY: - return "LL"; - default: - return "??"; - } - } - - public int getInputPreset() { return mInputPreset; } - public void setInputPreset(int inputPreset) { - this.mInputPreset = inputPreset; - } - - public int getUsage() { return mUsage; } - public void setUsage(int Usage) { - this.mUsage = Usage; - } - - static String convertUsageToText(int usage) { - switch(usage) { - case USAGE_MEDIA: - return "Media"; - case USAGE_VOICE_COMMUNICATION: - return "VoiceComm"; - case USAGE_VOICE_COMMUNICATION_SIGNALLING: - return "VoiceCommSig"; - case USAGE_ALARM: - return "Alarm"; - case USAGE_NOTIFICATION: - return "Notification"; - case USAGE_NOTIFICATION_RINGTONE: - return "Ringtone"; - case USAGE_NOTIFICATION_EVENT: - return "Event"; - case USAGE_ASSISTANCE_ACCESSIBILITY: - return "Accessability"; - case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: - return "Navigation"; - case USAGE_ASSISTANCE_SONIFICATION: - return "Sonification"; - case USAGE_GAME: - return "Game"; - case USAGE_ASSISTANT: - return "Assistant"; - default: - return "?=" + usage; - } - } - - public static int convertTextToUsage(String text) { - return mUsageStringToIntegerMap.get(text); - } - - public int getSharingMode() { - return mSharingMode; - } - - public void setSharingMode(int sharingMode) { - this.mSharingMode = sharingMode; - } - - static String convertSharingModeToText(int sharingMode) { - switch(sharingMode) { - case SHARING_MODE_SHARED: - return "SH"; - case SHARING_MODE_EXCLUSIVE: - return "EX"; - default: - return "??"; - } - } - - public static String convertFormatToText(int format) { - switch(format) { - case UNSPECIFIED: - return "Unspecified"; - case AUDIO_FORMAT_PCM_16: - return "I16"; - case AUDIO_FORMAT_PCM_24: - return "I24"; - case AUDIO_FORMAT_PCM_32: - return "I32"; - case AUDIO_FORMAT_PCM_FLOAT: - return "Float"; - default: - return "Invalid"; - } - } - - public static String convertNativeApiToText(int api) { - switch(api) { - case NATIVE_API_UNSPECIFIED: - return "Unspec"; - case NATIVE_API_AAUDIO: - return "AAudio"; - case NATIVE_API_OPENSLES: - return "OpenSL"; - default: - return "Invalid"; - } - } - - - public String dump() { - String prefix = (getDirection() == DIRECTION_INPUT) ? "in" : "out"; - StringBuffer message = new StringBuffer(); - message.append(String.format("%s.channels = %d\n", prefix, mChannelCount)); - message.append(String.format("%s.perf = %s\n", prefix, - convertPerformanceModeToText(mPerformanceMode).toLowerCase())); - if (getDirection() == DIRECTION_INPUT) { - message.append(String.format("%s.preset = %s\n", prefix, - convertInputPresetToText(mInputPreset).toLowerCase())); - } else { - message.append(String.format("%s.preset = %s\n", prefix, - convertUsageToText(mUsage).toLowerCase())); - } - message.append(String.format("%s.sharing = %s\n", prefix, - convertSharingModeToText(mSharingMode).toLowerCase())); - message.append(String.format("%s.api = %s\n", prefix, - convertNativeApiToText(getNativeApi()).toLowerCase())); - message.append(String.format("%s.rate = %d\n", prefix, mSampleRate)); - message.append(String.format("%s.device = %d\n", prefix, mDeviceId)); - message.append(String.format("%s.mmap = %s\n", prefix, isMMap() ? "yes" : "no")); - message.append(String.format("%s.rate.conversion.quality = %d\n", prefix, mRateConversionQuality)); - return message.toString(); - } - - // text must match menu values - public static final String NAME_INPUT_PRESET_GENERIC = "Generic"; - public static final String NAME_INPUT_PRESET_CAMCORDER = "Camcorder"; - public static final String NAME_INPUT_PRESET_VOICE_RECOGNITION = "VoiceRec"; - public static final String NAME_INPUT_PRESET_VOICE_COMMUNICATION = "VoiceComm"; - public static final String NAME_INPUT_PRESET_UNPROCESSED = "Unprocessed"; - public static final String NAME_INPUT_PRESET_VOICE_PERFORMANCE = "Performance"; - - public static String convertInputPresetToText(int inputPreset) { - switch(inputPreset) { - case INPUT_PRESET_GENERIC: - return NAME_INPUT_PRESET_GENERIC; - case INPUT_PRESET_CAMCORDER: - return NAME_INPUT_PRESET_CAMCORDER; - case INPUT_PRESET_VOICE_RECOGNITION: - return NAME_INPUT_PRESET_VOICE_RECOGNITION; - case INPUT_PRESET_VOICE_COMMUNICATION: - return NAME_INPUT_PRESET_VOICE_COMMUNICATION; - case INPUT_PRESET_UNPROCESSED: - return NAME_INPUT_PRESET_UNPROCESSED; - case INPUT_PRESET_VOICE_PERFORMANCE: - return NAME_INPUT_PRESET_VOICE_PERFORMANCE; - default: - return "Invalid"; - } - } - - private static boolean matchInputPreset(String text, int preset) { - return convertInputPresetToText(preset).toLowerCase().equals(text); - } - - /** - * Case insensitive. - * @param text - * @return inputPreset, eg. INPUT_PRESET_CAMCORDER - */ - public static int convertTextToInputPreset(String text) { - text = text.toLowerCase(); - if (matchInputPreset(text, INPUT_PRESET_GENERIC)) { - return INPUT_PRESET_GENERIC; - } else if (matchInputPreset(text, INPUT_PRESET_CAMCORDER)) { - return INPUT_PRESET_CAMCORDER; - } else if (matchInputPreset(text, INPUT_PRESET_VOICE_RECOGNITION)) { - return INPUT_PRESET_VOICE_RECOGNITION; - } else if (matchInputPreset(text, INPUT_PRESET_VOICE_COMMUNICATION)) { - return INPUT_PRESET_VOICE_COMMUNICATION; - } else if (matchInputPreset(text, INPUT_PRESET_UNPROCESSED)) { - return INPUT_PRESET_UNPROCESSED; - } else if (matchInputPreset(text, INPUT_PRESET_VOICE_PERFORMANCE)) { - return INPUT_PRESET_VOICE_PERFORMANCE; - } - return -1; - } - - public int getChannelCount() { - return mChannelCount; - } - - public void setChannelCount(int channelCount) { - this.mChannelCount = channelCount; - } - - public int getSampleRate() { - return mSampleRate; - } - - public void setSampleRate(int sampleRate) { - this.mSampleRate = sampleRate; - } - - public int getDeviceId() { - return mDeviceId; - } - - public void setDeviceId(int deviceId) { - this.mDeviceId = deviceId; - } - - public int getSessionId() { - return mSessionId; - } - - public void setSessionId(int sessionId) { - mSessionId = sessionId; - } - - public boolean isMMap() { - return mMMap; - } - - public void setMMap(boolean b) { mMMap = b; } - - public int getNativeApi() { - return mNativeApi; - } - - public void setNativeApi(int nativeApi) { - mNativeApi = nativeApi; - } - - public void setChannelConversionAllowed(boolean b) { mChannelConversionAllowed = b; } - - public boolean getChannelConversionAllowed() { - return mChannelConversionAllowed; - } - - public void setFormatConversionAllowed(boolean b) { - mFormatConversionAllowed = b; - } - - public boolean getFormatConversionAllowed() { - return mFormatConversionAllowed; - } - - public void setRateConversionQuality(int quality) { mRateConversionQuality = quality; } - - public int getRateConversionQuality() { - return mRateConversionQuality; - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java deleted file mode 100644 index d71c0a40..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.media.AudioManager; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.AdapterView; -import android.widget.CheckBox; -import android.widget.Spinner; -import android.widget.TableRow; -import android.widget.TextView; -import android.widget.LinearLayout; - -import com.mobileer.audio_device.AudioDeviceListEntry; -import com.mobileer.audio_device.AudioDeviceSpinner; - -/** - * View for Editing a requested StreamConfiguration - * and displaying the actual StreamConfiguration. - */ - -public class StreamConfigurationView extends LinearLayout { - protected Spinner mNativeApiSpinner; - private TextView mActualNativeApiView; - - private TextView mActualMMapView; - private CheckBox mRequestedMMapView; - private TextView mActualExclusiveView; - private TextView mActualPerformanceView; - private Spinner mPerformanceSpinner; - private CheckBox mRequestedExclusiveView; - private CheckBox mChannelConversionBox; - private CheckBox mFormatConversionBox; - private Spinner mChannelCountSpinner; - private TextView mActualChannelCountView; - private TextView mActualFormatView; - - private TableRow mInputPresetTableRow; - private Spinner mInputPresetSpinner; - private TextView mActualInputPresetView; - - private TableRow mUsageTableRow; - private Spinner mUsageSpinner; - private TextView mActualUsageView; - - private Spinner mFormatSpinner; - private Spinner mSampleRateSpinner; - private Spinner mRateConversionQualitySpinner; - private TextView mActualSampleRateView; - private LinearLayout mHideableView; - - private AudioDeviceSpinner mDeviceSpinner; - private TextView mActualSessionIdView; - private CheckBox mRequestAudioEffect; - - private TextView mStreamInfoView; - private TextView mStreamStatusView; - private TextView mOptionExpander; - private String mHideSettingsText; - private String mShowSettingsText; - - // Create an anonymous implementation of OnClickListener - private View.OnClickListener mToggleListener = new View.OnClickListener() { - public void onClick(View v) { - if (mHideableView.isShown()) { - hideSettingsView(); - } else { - showSettingsView(); - } - } - }; - - public static String yesOrNo(boolean b) { - return b ? "YES" : "NO"; - } - - private void updateSettingsViewText() { - if (mHideableView.isShown()) { - mOptionExpander.setText(mHideSettingsText); - } else { - mOptionExpander.setText(mShowSettingsText); - } - } - - public void showSettingsView() { - mHideableView.setVisibility(View.VISIBLE); - updateSettingsViewText(); - } - - public void hideSampleRateMenu() { - if (mSampleRateSpinner != null) { - mSampleRateSpinner.setVisibility(View.GONE); - } - } - - public void hideSettingsView() { - mHideableView.setVisibility(View.GONE); - updateSettingsViewText(); - } - - public StreamConfigurationView(Context context) { - super(context); - initializeViews(context); - } - - public StreamConfigurationView(Context context, AttributeSet attrs) { - super(context, attrs); - initializeViews(context); - } - - public StreamConfigurationView(Context context, - AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - initializeViews(context); - } - - /** - * Inflates the views in the layout. - * - * @param context - * the current context for the view. - */ - private void initializeViews(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.stream_config, this); - - mHideSettingsText = getResources().getString(R.string.hint_hide_settings); - mShowSettingsText = getResources().getString(R.string.hint_show_settings); - - mHideableView = (LinearLayout) findViewById(R.id.hideableView); - - mOptionExpander = (TextView) findViewById(R.id.toggle_stream_config); - mOptionExpander.setOnClickListener(mToggleListener); - - mNativeApiSpinner = (Spinner) findViewById(R.id.spinnerNativeApi); - mNativeApiSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED); - - mActualNativeApiView = (TextView) findViewById(R.id.actualNativeApi); - - mChannelConversionBox = (CheckBox) findViewById(R.id.checkChannelConversion); - - mFormatConversionBox = (CheckBox) findViewById(R.id.checkFormatConversion); - - mActualMMapView = (TextView) findViewById(R.id.actualMMap); - mRequestedMMapView = (CheckBox) findViewById(R.id.requestedMMapEnable); - boolean mmapSupported = NativeEngine.isMMapSupported(); - mRequestedMMapView.setEnabled(mmapSupported); - mRequestedMMapView.setChecked(mmapSupported); - - mActualExclusiveView = (TextView) findViewById(R.id.actualExclusiveMode); - mRequestedExclusiveView = (CheckBox) findViewById(R.id.requestedExclusiveMode); - - boolean mmapExclusiveSupported = NativeEngine.isMMapExclusiveSupported(); - mRequestedExclusiveView.setEnabled(mmapExclusiveSupported); - mRequestedExclusiveView.setChecked(mmapExclusiveSupported); - - mActualSessionIdView = (TextView) findViewById(R.id.sessionId); - mRequestAudioEffect = (CheckBox) findViewById(R.id.requestAudioEffect); - - mActualSampleRateView = (TextView) findViewById(R.id.actualSampleRate); - mSampleRateSpinner = (Spinner) findViewById(R.id.spinnerSampleRate); - mActualChannelCountView = (TextView) findViewById(R.id.actualChannelCount); - mChannelCountSpinner = (Spinner) findViewById(R.id.spinnerChannelCount); - mActualFormatView = (TextView) findViewById(R.id.actualAudioFormat); - mFormatSpinner = (Spinner) findViewById(R.id.spinnerFormat); - mRateConversionQualitySpinner = (Spinner) findViewById(R.id.spinnerSRCQuality); - - mActualPerformanceView = (TextView) findViewById(R.id.actualPerformanceMode); - mPerformanceSpinner = (Spinner) findViewById(R.id.spinnerPerformanceMode); - mPerformanceSpinner.setSelection(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY - - StreamConfiguration.PERFORMANCE_MODE_NONE); - - mInputPresetTableRow = (TableRow) findViewById(R.id.rowInputPreset); - mActualInputPresetView = (TextView) findViewById(R.id.actualInputPreset); - mInputPresetSpinner = (Spinner) findViewById(R.id.spinnerInputPreset); - mInputPresetSpinner.setSelection(2); // TODO need better way to select voice recording default - - mUsageTableRow = (TableRow) findViewById(R.id.rowUsage); - mActualUsageView = (TextView) findViewById(R.id.actualUsage); - mUsageSpinner = (Spinner) findViewById(R.id.spinnerUsage); - mUsageSpinner.setSelection(0); // TODO need better way to select Media default - - mStreamInfoView = (TextView) findViewById(R.id.streamInfo); - - mStreamStatusView = (TextView) findViewById(R.id.statusView); - - mDeviceSpinner = (AudioDeviceSpinner) findViewById(R.id.devices_spinner); - - showSettingsView(); - } - - public void setOutput(boolean output) { - String ioText; - if (output) { - mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_OUTPUTS); - ioText = "OUTPUT"; - } else { - mDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_INPUTS); - ioText = "INPUT"; - } - mHideSettingsText = getResources().getString(R.string.hint_hide_settings) + " - " + ioText; - mShowSettingsText = getResources().getString(R.string.hint_show_settings) + " - " + ioText; - updateSettingsViewText(); - - // Don't show InputPresets for output streams. - mInputPresetTableRow.setVisibility(output ? View.GONE : View.VISIBLE); - // Don't show Usage for input streams. - mUsageTableRow.setVisibility(output ? View.VISIBLE : View.GONE); - } - - public void applyToModel(StreamConfiguration config) { - // Menu position matches actual enum value for these properties. - config.setNativeApi(mNativeApiSpinner.getSelectedItemPosition()); - config.setChannelCount(mChannelCountSpinner.getSelectedItemPosition()); - config.setFormat(mFormatSpinner.getSelectedItemPosition()); - config.setRateConversionQuality(mRateConversionQualitySpinner.getSelectedItemPosition()); - - int id = ((AudioDeviceListEntry) mDeviceSpinner.getSelectedItem()).getId(); - config.setDeviceId(id); - - String text = mSampleRateSpinner.getSelectedItem().toString(); - int sampleRate = Integer.parseInt(text); - config.setSampleRate(sampleRate); - - text = mInputPresetSpinner.getSelectedItem().toString(); - int inputPreset = StreamConfiguration.convertTextToInputPreset(text); - config.setInputPreset(inputPreset); - - text = mUsageSpinner.getSelectedItem().toString(); - int usage = StreamConfiguration.convertTextToUsage(text); - config.setUsage(usage); - - config.setMMap(mRequestedMMapView.isChecked()); - config.setChannelConversionAllowed(mChannelConversionBox.isChecked()); - config.setFormatConversionAllowed(mFormatConversionBox.isChecked()); - config.setSharingMode(mRequestedExclusiveView.isChecked() - ? StreamConfiguration.SHARING_MODE_EXCLUSIVE - : StreamConfiguration.SHARING_MODE_SHARED); - config.setSessionId(mRequestAudioEffect.isChecked() - ? StreamConfiguration.SESSION_ID_ALLOCATE - : StreamConfiguration.SESSION_ID_NONE); - - config.setPerformanceMode(mPerformanceSpinner.getSelectedItemPosition() - + StreamConfiguration.PERFORMANCE_MODE_NONE); - } - - public void setChildrenEnabled(boolean enabled) { - mNativeApiSpinner.setEnabled(enabled); - mRequestedMMapView.setEnabled(enabled); - mPerformanceSpinner.setEnabled(enabled); - mRequestedExclusiveView.setEnabled(enabled); - mChannelConversionBox.setEnabled(enabled); - mFormatConversionBox.setEnabled(enabled); - mChannelCountSpinner.setEnabled(enabled); - mInputPresetSpinner.setEnabled(enabled); - mUsageSpinner.setEnabled(enabled); - mFormatSpinner.setEnabled(enabled); - mSampleRateSpinner.setEnabled(enabled); - mRateConversionQualitySpinner.setEnabled(enabled); - mDeviceSpinner.setEnabled(enabled); - mRequestAudioEffect.setEnabled(enabled); - } - - // This must be called on the UI thread. - void updateDisplay(StreamConfiguration actualConfiguration) { - int value; - - value = actualConfiguration.getNativeApi(); - mActualNativeApiView.setText(StreamConfiguration.convertNativeApiToText(value)); - - mActualMMapView.setText(yesOrNo(actualConfiguration.isMMap())); - int sharingMode = actualConfiguration.getSharingMode(); - boolean isExclusive = (sharingMode == StreamConfiguration.SHARING_MODE_EXCLUSIVE); - mActualExclusiveView.setText(yesOrNo(isExclusive)); - - value = actualConfiguration.getPerformanceMode(); - mActualPerformanceView.setText(StreamConfiguration.convertPerformanceModeToText(value)); - mActualPerformanceView.requestLayout(); - - value = actualConfiguration.getFormat(); - mActualFormatView.setText(StreamConfiguration.convertFormatToText(value)); - mActualFormatView.requestLayout(); - - value = actualConfiguration.getInputPreset(); - mActualInputPresetView.setText(StreamConfiguration.convertInputPresetToText(value)); - mActualInputPresetView.requestLayout(); - - value = actualConfiguration.getUsage(); - mActualUsageView.setText(StreamConfiguration.convertUsageToText(value)); - mActualUsageView.requestLayout(); - - mActualChannelCountView.setText(actualConfiguration.getChannelCount() + ""); - mActualSampleRateView.setText(actualConfiguration.getSampleRate() + ""); - mActualSessionIdView.setText("S#: " + actualConfiguration.getSessionId()); - - boolean isMMap = actualConfiguration.isMMap(); - mStreamInfoView.setText("burst = " + actualConfiguration.getFramesPerBurst() - + ", capacity = " + actualConfiguration.getBufferCapacityInFrames() - + ", devID = " + actualConfiguration.getDeviceId() - + ", " + (actualConfiguration.isMMap() ? "MMAP" : "Legacy") - + (isMMap ? ", " + StreamConfiguration.convertSharingModeToText(sharingMode) : "") - ); - - mHideableView.requestLayout(); - } - - // This must be called on the UI thread. - public void setStatusText(String msg) { - mStreamStatusView.setText(msg); - } - - public void setExclusiveMode(boolean b) { - mRequestedExclusiveView.setChecked(b); - } - - public void setFormat(int format) { - mFormatSpinner.setSelection(format); // position matches format - } - - public void setFormatConversionAllowed(boolean allowed) { - mFormatConversionBox.setChecked(allowed); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java deleted file mode 100644 index 6b9d4b2a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapLatencyAnalyser.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 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. - */ -package com.mobileer.oboetester; - -import java.util.ArrayList; - -/** - * Analyze a recording and extract edges for latency analysis. - */ -public class TapLatencyAnalyser { - public static final int TYPE_TAP = 0; - float[] mHighPassBuffer; - - private float mDroop = 0.995f; - private static final float EDGE_THRESHOLD = 0.01f; - private static final float LOW_FRACTION = 0.5f; - - public static class TapLatencyEvent { - public int type; - public int sampleIndex; - public TapLatencyEvent(int type, int sampleIndex) { - this.type = type; - this.sampleIndex = sampleIndex; - } - } - - public TapLatencyEvent[] analyze(float[] buffer, int offset, int numSamples) { - // Use high pass filter to remove rumble from air conditioners. - mHighPassBuffer = new float[numSamples]; - highPassFilter(buffer, offset, numSamples, mHighPassBuffer); - // Apply envelope follower. - float[] peakBuffer = new float[numSamples]; - fillPeakBuffer(mHighPassBuffer, 0, numSamples, peakBuffer); - // Look for two attacks. - return scanForEdges(peakBuffer, numSamples); - } - - public float[] getFilteredBuffer() { - return mHighPassBuffer; - } - - // Based on https://en.wikipedia.org/wiki/High-pass_filter - private void highPassFilter(float[] buffer, int offset, int numSamples, float[] highPassBuffer) { - float xn1 = 0.0f; - float yn1 = 0.0f; - final float alpha = 0.8f; - for (int i = 0; i < numSamples; i++) { - float xn = buffer[i + offset]; - float yn = alpha * (yn1 + xn - xn1); - highPassBuffer[i] = yn; - xn1 = xn; - yn1 = yn; - } - } - - private TapLatencyEvent[] scanForEdges(float[] peakBuffer, int numSamples) { - ArrayList events = new ArrayList(); - float slow = 0.0f; - float fast = 0.0f; - final float slowCoefficient = 0.01f; - final float fastCoefficient = 0.10f; - float lowThreshold = EDGE_THRESHOLD; - boolean armed = true; - int sampleIndex = 0; - for (float level : peakBuffer) { - slow = slow + (level - slow) * slowCoefficient; // low pass filter - fast = fast + (level - fast) * fastCoefficient; // low pass filter - if (armed && (fast > EDGE_THRESHOLD) && (fast > (2.0 * slow))) { - //System.out.println("edge at " + sampleIndex + ", slow " + slow + ", fast " + fast); - events.add(new TapLatencyEvent(TYPE_TAP, sampleIndex)); - armed = false; - lowThreshold = fast * LOW_FRACTION; - } - // Use hysteresis when rearming. - if (!armed && (fast < lowThreshold)) { - armed = true; - // slow = fast; // This seems unnecessary. - //events.add(new TapLatencyEvent(TYPE_TAP, sampleIndex)); - } - sampleIndex++; - } - return events.toArray(new TapLatencyEvent[0]); - } - - /** - * Envelope follower that rides along the peaks of the waveforms - * and then decays exponentially. - * - * @param buffer - * @param offset - * @param numSamples - */ - private void fillPeakBuffer(float[] buffer, int offset, int numSamples, float[] peakBuffer) { - float previous = 0.0f; - for (int i = 0; i < numSamples; i++) { - float input = Math.abs(buffer[i + offset]); - float output = previous * mDroop; - if (input > output) { - output = input; - } - previous = output; - peakBuffer[i] = output; - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java deleted file mode 100644 index a69829a6..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneActivity.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright 2015 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. - */ - -package com.mobileer.oboetester; - -import android.Manifest; -import android.content.pm.PackageManager; -import android.media.midi.MidiDevice; -import android.media.midi.MidiDeviceInfo; -import android.media.midi.MidiInputPort; -import android.media.midi.MidiManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.widget.Button; -import android.widget.Toast; - -import com.mobileer.miditools.MidiOutputPortConnectionSelector; -import com.mobileer.miditools.MidiPortConnector; -import com.mobileer.miditools.MidiTools; - -import java.io.IOException; - -import static com.mobileer.oboetester.MidiTapTester.NoteListener; -import static com.mobileer.oboetester.TapToToneTester.TestResult; - -public class TapToToneActivity extends TestOutputActivityBase { - private static final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 1234; - private MidiManager mMidiManager; - private MidiInputPort mInputPort; - - protected MidiTapTester mMidiTapTester; - protected TapToToneTester mTapToToneTester; - - private Button mStopButton; - private Button mStartButton; - - private MidiOutputPortConnectionSelector mPortSelector; - private final MyNoteListener mTestListener = new MyNoteListener(); - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_tap_to_tone); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mAudioOutTester = addAudioOutputTester(); - - mTapToToneTester = new TapToToneTester(this, - getResources().getString(R.string.tap_to_tone_instructions)); - - if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) { - setupMidi(); - } else { - Toast.makeText(TapToToneActivity.this, - "MIDI not supported!", Toast.LENGTH_LONG) - .show(); - } - - - // Start a blip test when the waveform view is tapped. - WaveformView mWaveformView = (WaveformView) findViewById(R.id.waveview_audio); - mWaveformView.setOnTouchListener((view, event) -> { - // Do not call view.performClick() because it may trigger a touch sound! - int action = event.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - trigger(); - break; - case MotionEvent.ACTION_MOVE: - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - break; - } - // Must return true or we do not get the ACTION_MOVE and - // ACTION_UP events. - return true; - }); - - mStartButton = (Button) findViewById(R.id.button_start); - mStopButton = (Button) findViewById(R.id.button_stop); - updateButtons(false); - - updateEnabledWidgets(); - } - - private void updateButtons(boolean running) { - mStartButton.setEnabled(!running); - mStopButton.setEnabled(running); - } - - void trigger() { - if (mTapToToneTester.isArmed()) { - mAudioOutTester.trigger(); - mTapToToneTester.analyzeLater(getString(R.string.please_wait)); - } else { - showToast(getString(R.string.no_double_tap)); - } - } - - @Override - int getActivityType() { - return ACTIVITY_TAP_TO_TONE; - } - - @Override - protected void onDestroy() { - mMidiTapTester.removeTestListener(mTestListener); - closeMidiResources(); - super.onDestroy(); - } - - private void setupMidi() { - // Setup MIDI - mMidiManager = (MidiManager) getSystemService(MIDI_SERVICE); - MidiDeviceInfo[] infos = mMidiManager.getDevices(); - - // Open the port now so that the AudioMidiTester gets created. - for (MidiDeviceInfo info : infos) { - Bundle properties = info.getProperties(); - String product = properties - .getString(MidiDeviceInfo.PROPERTY_PRODUCT); - - Log.i(TAG, "product = " + product); - if ("AudioLatencyTester".equals(product)) { - openPort(info); - break; - } - } - - } - - // These should only be set after mAudioMidiTester is set. - private void setSpinnerListeners() { - MidiDeviceInfo synthInfo = MidiTools.findDevice(mMidiManager, "AndroidTest", - "AudioLatencyTester"); - Log.i(TAG, "found tester virtual device info: " + synthInfo); - int portIndex = 0; - mPortSelector = new MidiOutputPortConnectionSelector(mMidiManager, this, - R.id.spinner_synth_sender, synthInfo, portIndex); - mPortSelector.setConnectedListener(new MyPortsConnectedListener()); - - } - - private class MyNoteListener implements NoteListener { - @Override - public void onNoteOn(final int pitch) { - runOnUiThread(() -> { - trigger(); - mStreamContexts.get(0).configurationView.setStatusText("MIDI pitch = " + pitch); - }); - } - } - - - private void openPort(final MidiDeviceInfo info) { - mMidiManager.openDevice(info, device -> { - if (device == null) { - Log.e(TAG, "could not open device " + info); - } else { - mInputPort = device.openInputPort(0); - Log.i(TAG, "opened MIDI port = " + mInputPort + " on " + info); - mMidiTapTester = MidiTapTester.getInstance(); - - Log.i(TAG, "openPort() mAudioMidiTester = " + mMidiTapTester); - // Now that we have created the AudioMidiTester, close the port so we can - // open it later. - try { - mInputPort.close(); - } catch (IOException e) { - e.printStackTrace(); - } - mMidiTapTester.addTestListener(mTestListener); - - setSpinnerListeners(); - } - }, new Handler(Looper.getMainLooper()) - ); - } - - // TODO Listen to the synth server - // for open/close events and then disable/enable the spinner. - private class MyPortsConnectedListener - implements MidiPortConnector.OnPortsConnectedListener { - @Override - public void onPortsConnected(final MidiDevice.MidiConnection connection) { - Log.i(TAG, "onPortsConnected, connection = " + connection); - runOnUiThread(() -> { - if (connection == null) { - Toast.makeText(TapToToneActivity.this, - R.string.error_port_busy, Toast.LENGTH_LONG) - .show(); - mPortSelector.clearSelection(); - } else { - Toast.makeText(TapToToneActivity.this, - R.string.port_open_ok, Toast.LENGTH_LONG) - .show(); - } - }); - } - } - - private void closeMidiResources() { - if (mPortSelector != null) { - mPortSelector.close(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - - return super.onOptionsItemSelected(item); - } - - private boolean hasRecordAudioPermission(){ - boolean hasPermission = (checkSelfPermission( - Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED); - Log.i(TAG, "Has RECORD_AUDIO permission? " + hasPermission); - return hasPermission; - } - - private void requestRecordAudioPermission(){ - - String requiredPermission = Manifest.permission.RECORD_AUDIO; - - // If the user previously denied this permission then show a message explaining why - // this permission is needed - if (shouldShowRequestPermissionRationale(requiredPermission)) { - showErrorToast("This app needs to record audio through the microphone...."); - } - - // request the permission. - requestPermissions(new String[]{requiredPermission}, - MY_PERMISSIONS_REQUEST_RECORD_AUDIO); - } - - @Override - public void onRequestPermissionsResult(int requestCode, - String[] permissions, - int[] grantResults) { - if (MY_PERMISSIONS_REQUEST_RECORD_AUDIO != requestCode) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - return; - } - - if (grantResults.length != 1 || - grantResults[0] != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(getApplicationContext(), - getString(R.string.need_record_audio_permission), - Toast.LENGTH_SHORT) - .show(); - } else { - startAudioPermitted(); - } - } - - public void startTest(View view) { - try { - openAudio(); - } catch (IOException e) { - e.printStackTrace(); - showErrorToast("Open audio failed!"); - return; - } - if (hasRecordAudioPermission()) { - startAudioPermitted(); - } else { - requestRecordAudioPermission(); - } - } - - private void startAudioPermitted() { - try { - super.startAudio(); - mTapToToneTester.resetLatency(); - mTapToToneTester.start(); - updateButtons(true); - } catch (IOException e) { - e.printStackTrace(); - showErrorToast("Start audio failed! " + e.getMessage()); - return; - } - } - - public void stopTest(View view) { - mTapToToneTester.stop(); - stopAudio(); - closeAudio(); - updateButtons(false); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java deleted file mode 100644 index e4130fa5..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TapToToneTester.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.mobileer.oboetester; - -import android.app.Activity; -import android.widget.TextView; - -import java.io.IOException; - -/** - * Measure tap-to-tone latency by and update the waveform display. - */ -public class TapToToneTester { - - private static final float MAX_TOUCH_LATENCY = 0.200f; - private static final float MAX_OUTPUT_LATENCY = 1.200f; - private static final float ANALYSIS_TIME_MARGIN = 0.500f; - - private static final float ANALYSIS_TIME_DELAY = MAX_OUTPUT_LATENCY; - private static final float ANALYSIS_TIME_TOTAL = MAX_TOUCH_LATENCY + MAX_OUTPUT_LATENCY; - private static final int ANALYSIS_SAMPLE_RATE = 48000; // need not match output rate - - private final boolean mRecordEnabled = true; - private final AudioRecordThread mRecorder; - private final TapLatencyAnalyser mTapLatencyAnalyser; - - private final Activity mActivity; - private final WaveformView mWaveformView; - private final TextView mResultView; - - private final String mTapInstructions; - private float mAnalysisTimeMargin = ANALYSIS_TIME_MARGIN; - - private boolean mArmed = true; - - // Stats for latency - private int mMeasurementCount; - private int mLatencySumSamples; - private int mLatencyMin; - private int mLatencyMax; - - public static class TestResult { - public float[] samples; - public float[] filtered; - public int frameRate; - public TapLatencyAnalyser.TapLatencyEvent[] events; - } - - public TapToToneTester(Activity activity, String tapInstructions) { - mActivity = activity; - mTapInstructions = tapInstructions; - mResultView = (TextView) activity.findViewById(R.id.resultView); - mWaveformView = (WaveformView) activity.findViewById(R.id.waveview_audio); - - if (mRecordEnabled) { - float analysisTimeMax = ANALYSIS_TIME_TOTAL + mAnalysisTimeMargin; - mRecorder = new AudioRecordThread(ANALYSIS_SAMPLE_RATE, - 1, - (int) (analysisTimeMax * ANALYSIS_SAMPLE_RATE)); - } - mTapLatencyAnalyser = new TapLatencyAnalyser(); - } - - public void start() throws IOException { - if (mRecordEnabled) { - mRecorder.startAudio(); - } - } - - public void stop() { - if (mRecordEnabled) { - mRecorder.stopAudio(); - } - } - - /** - * @return true if ready to process a tap, false if already triggered - */ - public boolean isArmed() { - return mArmed; - } - - public void setArmed(boolean armed) { - this.mArmed = armed; - } - - public void analyzeLater(String message) { - showPendingStatus(message); - Runnable task = this::analyseAndShowResults; - scheduleTaskWhenDone(task); - mArmed = false; - } - - private void showPendingStatus(final String message) { - mWaveformView.post(() -> { - mWaveformView.setMessage(message); - mWaveformView.clearSampleData(); - mWaveformView.postInvalidate(); - }); - } - - private void scheduleTaskWhenDone(Runnable task) { - if (mRecordEnabled) { - // schedule an analysis to start in the near future - int numSamples = (int) (mRecorder.getSampleRate() * ANALYSIS_TIME_DELAY); - mRecorder.scheduleTask(numSamples, task); - } - } - - private void analyseAndShowResults() { - TestResult result = analyzeCapturedAudio(); - if (result != null) { - showTestResults(result); - } - } - - public TestResult analyzeCapturedAudio() { - if (!mRecordEnabled) return null; - int numSamples = (int) (mRecorder.getSampleRate() * ANALYSIS_TIME_TOTAL); - float[] buffer = new float[numSamples]; - mRecorder.setCaptureEnabled(false); // TODO wait for it to settle - int numRead = mRecorder.readMostRecent(buffer); - - TestResult result = new TestResult(); - result.samples = buffer; - result.frameRate = mRecorder.getSampleRate(); - result.events = mTapLatencyAnalyser.analyze(buffer, 0, numRead); - result.filtered = mTapLatencyAnalyser.getFilteredBuffer(); - mRecorder.setCaptureEnabled(true); - return result; - } - - public void resetLatency() { - mMeasurementCount = 0; - mLatencySumSamples = 0; - mLatencyMin = Integer.MAX_VALUE; - mLatencyMax = 0; - showTestResults(null); - } - - // Runs on UI thread. - public void showTestResults(TestResult result) { - String text; - mWaveformView.setMessage(null); - if (result == null) { - text = mTapInstructions; - mWaveformView.clearSampleData(); - } else { - // Show edges detected. - if (result.events.length == 0) { - mWaveformView.setCursorData(null); - } else { - int numEdges = Math.min(8, result.events.length); - int[] cursors = new int[numEdges]; - for (int i = 0; i < numEdges; i++) { - cursors[i] = result.events[i].sampleIndex; - } - mWaveformView.setCursorData(cursors); - } - // Did we get a good measurement? - if (result.events.length < 2) { - text = "Not enough edges. Use fingernail.\n"; - } else if (result.events.length > 2) { - text = "Too many edges.\n"; - } else { - int latencySamples = result.events[1].sampleIndex - result.events[0].sampleIndex; - mLatencySumSamples += latencySamples; - mMeasurementCount++; - - int latencyMillis = 1000 * latencySamples / result.frameRate; - if (mLatencyMin > latencyMillis) { - mLatencyMin = latencyMillis; - } - if (mLatencyMax < latencyMillis) { - mLatencyMax = latencyMillis; - } - - text = String.format("tap-to-tone latency = %3d msec\n", latencyMillis); - } - mWaveformView.setSampleData(result.filtered); - } - - if (mMeasurementCount > 0) { - int averageLatencySamples = mLatencySumSamples / mMeasurementCount; - int averageLatencyMillis = 1000 * averageLatencySamples / result.frameRate; - final String plural = (mMeasurementCount == 1) ? "test" : "tests"; - text = text + String.format("min = %3d, avg = %3d, max = %3d, %d %s", - mLatencyMin, averageLatencyMillis, mLatencyMax, mMeasurementCount, plural); - } - final String postText = text; - mWaveformView.post(new Runnable() { - public void run() { - mResultView.setText(postText); - mWaveformView.postInvalidate(); - } - }); - - mArmed = true; - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java deleted file mode 100644 index 9717f48a..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestAudioActivity.java +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.content.Context; -import android.media.AudioDeviceInfo; -import android.media.AudioManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.Toast; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * Base class for other Activities. - */ -abstract class TestAudioActivity extends Activity { - public static final String TAG = "OboeTester"; - - protected static final int FADER_PROGRESS_MAX = 1000; - - public static final int AUDIO_STATE_OPEN = 0; - public static final int AUDIO_STATE_STARTED = 1; - public static final int AUDIO_STATE_PAUSED = 2; - public static final int AUDIO_STATE_STOPPED = 3; - public static final int AUDIO_STATE_CLOSING = 4; - public static final int AUDIO_STATE_CLOSED = 5; - - public static final int COLOR_ACTIVE = 0xFFD0D0A0; - public static final int COLOR_IDLE = 0xFFD0D0D0; - - // Pass the activity index to native so it can know how to respond to the start and stop calls. - // WARNING - must match definitions in NativeAudioContext.h ActivityType - public static final int ACTIVITY_TEST_OUTPUT = 0; - public static final int ACTIVITY_TEST_INPUT = 1; - public static final int ACTIVITY_TAP_TO_TONE = 2; - public static final int ACTIVITY_RECORD_PLAY = 3; - public static final int ACTIVITY_ECHO = 4; - public static final int ACTIVITY_RT_LATENCY = 5; - public static final int ACTIVITY_GLITCHES = 6; - public static final int ACTIVITY_TEST_DISCONNECT = 7; - public static final int ACTIVITY_DATA_PATHS = 8; - - private int mAudioState = AUDIO_STATE_CLOSED; - protected String audioManagerSampleRate; - protected int audioManagerFramesPerBurst; - protected ArrayList mStreamContexts; - private Button mOpenButton; - private Button mStartButton; - private Button mPauseButton; - private Button mStopButton; - private Button mCloseButton; - private MyStreamSniffer mStreamSniffer; - private CheckBox mCallbackReturnStopBox; - private int mSampleRate; - private int mSingleTestIndex = -1; - private static boolean mBackgroundEnabled; - - public String getTestName() { - return "TestAudio"; - } - - public static class StreamContext { - StreamConfigurationView configurationView; - AudioStreamTester tester; - - boolean isInput() { - return tester.getCurrentAudioStream().isInput(); - } - } - - // Periodically query the status of the streams. - protected class MyStreamSniffer { - public static final int SNIFFER_UPDATE_PERIOD_MSEC = 150; - public static final int SNIFFER_UPDATE_DELAY_MSEC = 300; - - private Handler mHandler; - - // Display status info for the stream. - private Runnable runnableCode = new Runnable() { - @Override - public void run() { - boolean streamClosed = false; - boolean gotViews = false; - for (StreamContext streamContext : mStreamContexts) { - AudioStreamBase.StreamStatus status = streamContext.tester.getCurrentAudioStream().getStreamStatus(); - AudioStreamBase.DoubleStatistics latencyStatistics = - streamContext.tester.getCurrentAudioStream().getLatencyStatistics(); - if (streamContext.configurationView != null) { - // Handler runs this on the main UI thread. - int framesPerBurst = streamContext.tester.getCurrentAudioStream().getFramesPerBurst(); - status.framesPerCallback = getFramesPerCallback(); - String msg = ""; - msg += "timestamp.latency = " + latencyStatistics.dump() + "\n"; - msg += status.dump(framesPerBurst); - streamContext.configurationView.setStatusText(msg); - updateStreamDisplay(); - gotViews = true; - } - - streamClosed = streamClosed || (status.state >= 12); - } - - if (streamClosed) { - onStreamClosed(); - } else { - // Repeat this runnable code block again. - if (gotViews) { - mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_PERIOD_MSEC); - } - } - } - }; - - private void startStreamSniffer() { - stopStreamSniffer(); - mHandler = new Handler(Looper.getMainLooper()); - // Start the initial runnable task by posting through the handler - mHandler.postDelayed(runnableCode, SNIFFER_UPDATE_DELAY_MSEC); - } - - private void stopStreamSniffer() { - if (mHandler != null) { - mHandler.removeCallbacks(runnableCode); - } - } - - } - - public static void setBackgroundEnabled(boolean enabled) { - mBackgroundEnabled = enabled; - } - public static boolean isBackgroundEnabled() { - return mBackgroundEnabled; - } - - public void onStreamClosed() { - } - - protected abstract void inflateActivity(); - - void updateStreamDisplay() { - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - inflateActivity(); - findAudioCommon(); - } - - public void hideSettingsViews() { - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.configurationView != null) { - streamContext.configurationView.hideSettingsView(); - } - } - } - - abstract int getActivityType(); - - public void setSingleTestIndex(int testIndex) { - mSingleTestIndex = testIndex; - } - public int getSingleTestIndex() { - return mSingleTestIndex; - } - - @Override - protected void onStart() { - super.onStart(); - resetConfiguration(); - setActivityType(getActivityType()); - } - - protected void resetConfiguration() { - } - - @Override - protected void onStop() { - if (!isBackgroundEnabled()) { - Log.i(TAG, "onStop() called so stop the test ========================="); - onStopTest(); - } - super.onStop(); - } - - @Override - protected void onDestroy() { - if (isBackgroundEnabled()) { - Log.i(TAG, "onDestroy() called so stop the test ========================="); - onStopTest(); - } - mAudioState = AUDIO_STATE_CLOSED; - super.onDestroy(); - } - - protected void updateEnabledWidgets() { - if (mOpenButton != null) { - mOpenButton.setBackgroundColor(mAudioState == AUDIO_STATE_OPEN ? COLOR_ACTIVE : COLOR_IDLE); - mStartButton.setBackgroundColor(mAudioState == AUDIO_STATE_STARTED ? COLOR_ACTIVE : COLOR_IDLE); - mPauseButton.setBackgroundColor(mAudioState == AUDIO_STATE_PAUSED ? COLOR_ACTIVE : COLOR_IDLE); - mStopButton.setBackgroundColor(mAudioState == AUDIO_STATE_STOPPED ? COLOR_ACTIVE : COLOR_IDLE); - mCloseButton.setBackgroundColor(mAudioState == AUDIO_STATE_CLOSED ? COLOR_ACTIVE : COLOR_IDLE); - } - setConfigViewsEnabled(mAudioState == AUDIO_STATE_CLOSED); - } - - private void setConfigViewsEnabled(boolean b) { - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.configurationView != null) { - streamContext.configurationView.setChildrenEnabled(b); - } - } - } - private void applyConfigurationViewsToModels() { - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.configurationView != null) { - streamContext.configurationView.applyToModel(streamContext.tester.requestedConfiguration); - } - } - } - - abstract boolean isOutput(); - - public void clearStreamContexts() { - mStreamContexts.clear(); - } - - public StreamContext addOutputStreamContext() { - StreamContext streamContext = new StreamContext(); - streamContext.tester = AudioOutputTester.getInstance(); - streamContext.configurationView = (StreamConfigurationView) - findViewById(R.id.outputStreamConfiguration); - if (streamContext.configurationView == null) { - streamContext.configurationView = (StreamConfigurationView) - findViewById(R.id.streamConfiguration); - } - if (streamContext.configurationView != null) { - streamContext.configurationView.setOutput(true); - } - mStreamContexts.add(streamContext); - return streamContext; - } - - public AudioOutputTester addAudioOutputTester() { - StreamContext streamContext = addOutputStreamContext(); - return (AudioOutputTester) streamContext.tester; - } - - public StreamContext addInputStreamContext() { - StreamContext streamContext = new StreamContext(); - streamContext.tester = AudioInputTester.getInstance(); - streamContext.configurationView = (StreamConfigurationView) - findViewById(R.id.inputStreamConfiguration); - if (streamContext.configurationView == null) { - streamContext.configurationView = (StreamConfigurationView) - findViewById(R.id.streamConfiguration); - } - if (streamContext.configurationView != null) { - streamContext.configurationView.setOutput(false); - } - streamContext.tester = AudioInputTester.getInstance(); - mStreamContexts.add(streamContext); - return streamContext; - } - - public AudioInputTester addAudioInputTester() { - StreamContext streamContext = addInputStreamContext(); - return (AudioInputTester) streamContext.tester; - } - - void updateStreamConfigurationViews() { - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.configurationView != null) { - streamContext.configurationView.updateDisplay(streamContext.tester.actualConfiguration); - } - } - } - - StreamContext getFirstInputStreamContext() { - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.isInput()) - return streamContext; - } - return null; - } - - StreamContext getFirstOutputStreamContext() { - for (StreamContext streamContext : mStreamContexts) { - if (!streamContext.isInput()) - return streamContext; - } - return null; - } - - protected void findAudioCommon() { - mOpenButton = (Button) findViewById(R.id.button_open); - if (mOpenButton != null) { - mStartButton = (Button) findViewById(R.id.button_start); - mPauseButton = (Button) findViewById(R.id.button_pause); - mStopButton = (Button) findViewById(R.id.button_stop); - mCloseButton = (Button) findViewById(R.id.button_close); - } - mStreamContexts = new ArrayList(); - - queryNativeAudioParameters(); - - mCallbackReturnStopBox = (CheckBox) findViewById(R.id.callbackReturnStop); - if (mCallbackReturnStopBox != null) { - mCallbackReturnStopBox.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - OboeAudioStream.setCallbackReturnStop(mCallbackReturnStopBox.isChecked()); - } - }); - } - OboeAudioStream.setCallbackReturnStop(false); - - mStreamSniffer = new MyStreamSniffer(); - } - - private void queryNativeAudioParameters() { - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - audioManagerSampleRate = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - String audioManagerFramesPerBurstText = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); - audioManagerFramesPerBurst = Integer.parseInt(audioManagerFramesPerBurstText); - } - - abstract public void setupEffects(int sessionId); - - protected void showErrorToast(String message) { - showToast("Error: " + message); - } - - protected void showToast(final String message) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(TestAudioActivity.this, - message, - Toast.LENGTH_SHORT).show(); - } - }); - } - - public void openAudio(View view) { - try { - openAudio(); - } catch (Exception e) { - showErrorToast(e.getMessage()); - } - } - - public void startAudio(View view) { - Log.i(TAG, "startAudio() called ======================================="); - try { - startAudio(); - } catch (Exception e) { - showErrorToast(e.getMessage()); - } - keepScreenOn(true); - } - - protected void keepScreenOn(boolean on) { - if (on) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - } - - public void stopAudio(View view) { - stopAudio(); - keepScreenOn(false); - } - - public void pauseAudio(View view) { - pauseAudio(); - keepScreenOn(false); - } - - public void closeAudio(View view) { - closeAudio(); - } - - public int getSampleRate() { - return mSampleRate; - } - - public boolean isTestConfiguredUsingBundle() { - return false; - } - - public void openAudio() throws IOException { - closeAudio(); - - if (!isTestConfiguredUsingBundle()) { - applyConfigurationViewsToModels(); - } - - int sampleRate = 0; - - // Open output streams then open input streams. - // This is so that the capacity of input stream can be expanded to - // match the burst size of the output for full duplex. - for (StreamContext streamContext : mStreamContexts) { - if (!streamContext.isInput()) { - openStreamContext(streamContext); - int streamSampleRate = streamContext.tester.actualConfiguration.getSampleRate(); - if (sampleRate == 0) { - sampleRate = streamSampleRate; - } - } - } - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.isInput()) { - if (sampleRate != 0) { - streamContext.tester.requestedConfiguration.setSampleRate(sampleRate); - } - openStreamContext(streamContext); - } - } - updateEnabledWidgets(); - mStreamSniffer.startStreamSniffer(); - } - - /** - * @param deviceId - * @return true if the device is TYPE_BLUETOOTH_SCO - */ - boolean isScoDevice(int deviceId) { - if (deviceId == 0) return false; // Unspecified - AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - final AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL); - for (AudioDeviceInfo device : devices) { - if (device.getId() == deviceId) { - return device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO; - } - } - return false; - } - - private void openStreamContext(StreamContext streamContext) throws IOException { - StreamConfiguration requestedConfig = streamContext.tester.requestedConfiguration; - StreamConfiguration actualConfig = streamContext.tester.actualConfiguration; - requestedConfig.setFramesPerBurst(audioManagerFramesPerBurst); - - streamContext.tester.open(); // OPEN the stream - - mSampleRate = actualConfig.getSampleRate(); - mAudioState = AUDIO_STATE_OPEN; - int sessionId = actualConfig.getSessionId(); - if (sessionId > 0) { - setupEffects(sessionId); - } - if (streamContext.configurationView != null) { - streamContext.configurationView.updateDisplay(streamContext.tester.actualConfiguration); - } - } - - // Native methods - private native int startNative(); - private native int pauseNative(); - private native int stopNative(); - protected native void setActivityType(int activityType); - private native int getFramesPerCallback(); - - public void startAudio() throws IOException { - int result = startNative(); - if (result < 0) { - showErrorToast("Start failed with " + result); - throw new IOException("startNative returned " + result); - } else { - for (StreamContext streamContext : mStreamContexts) { - StreamConfigurationView configView = streamContext.configurationView; - if (configView != null) { - configView.updateDisplay(streamContext.tester.actualConfiguration); - } - } - mAudioState = AUDIO_STATE_STARTED; - updateEnabledWidgets(); - } - } - - protected void toastPauseError(int result) { - showErrorToast("Pause failed with " + result); - } - - public void pauseAudio() { - int result = pauseNative(); - if (result < 0) { - toastPauseError(result); - } else { - mAudioState = AUDIO_STATE_PAUSED; - updateEnabledWidgets(); - } - } - - public void stopAudio() { - int result = stopNative(); - if (result < 0) { - showErrorToast("Stop failed with " + result); - } else { - mAudioState = AUDIO_STATE_STOPPED; - updateEnabledWidgets(); - } - } - - public void runTest() {} - - // This should only be called from UI events such as onStop or a button press. - public void onStopTest() { - stopTest(); - } - - public void stopTest() { - stopAudio(); - closeAudio(); - } - - public void stopAudioQuiet() { - stopNative(); - mAudioState = AUDIO_STATE_STOPPED; - updateEnabledWidgets(); - } - - // Make synchronized so we don't close from two streams at the same time. - public synchronized void closeAudio() { - if (mAudioState >= AUDIO_STATE_CLOSING) { - Log.d(TAG, "closeAudio() already closing"); - return; - } - mAudioState = AUDIO_STATE_CLOSING; - - mStreamSniffer.stopStreamSniffer(); - // Close output streams first because legacy callbacks may still be active - // and an output stream may be calling the input stream. - for (StreamContext streamContext : mStreamContexts) { - if (!streamContext.isInput()) { - streamContext.tester.close(); - } - } - for (StreamContext streamContext : mStreamContexts) { - if (streamContext.isInput()) { - streamContext.tester.close(); - } - } - - mAudioState = AUDIO_STATE_CLOSED; - updateEnabledWidgets(); - } - - void startBluetoothSco() { - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - myAudioMgr.startBluetoothSco(); - } - - void stopBluetoothSco() { - AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - myAudioMgr.stopBluetoothSco(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java deleted file mode 100644 index 2c436660..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDataPathsActivity.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright 2020 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. - */ - -package com.mobileer.oboetester; - -import android.app.Activity; -import android.content.Context; -import android.media.AudioDeviceInfo; -import android.media.AudioManager; -import android.os.Bundle; - -import com.mobileer.audio_device.AudioDeviceInfoConverter; - -/** - * Play a recognizable tone on each channel of each speaker device - * and listen for the result through a microphone. - * Also test each microphone channel and device. - * Try each InputPreset. - * - * The analysis is based on a cosine transform of a single - * frequency. The magnitude indicates the level. - * The variations in phase, "jitter" indicate how noisy the - * signal is or whether it is corrupted. A noisy room may have - * energy at the target frequency but the phase will be random. - * - * This test requires a quiet room but no other hardware. - */ -public class TestDataPathsActivity extends BaseAutoGlitchActivity { - - public static final int DURATION_SECONDS = 3; - private final static double MIN_REQUIRED_MAGNITUDE = 0.001; - private final static double MAX_SINE_FREQUENCY = 1000.0; - private final static int TYPICAL_SAMPLE_RATE = 48000; - private final static double FRAMES_PER_CYCLE = TYPICAL_SAMPLE_RATE / MAX_SINE_FREQUENCY; - private final static double PHASE_PER_BIN = 2.0 * Math.PI / FRAMES_PER_CYCLE; - private final static double MAX_ALLOWED_JITTER = 0.5 * PHASE_PER_BIN; - // Start by failing then let good results drive us into a pass value. - private final static double INITIAL_JITTER = 2.0 * MAX_ALLOWED_JITTER; - // A coefficient of 0.0 is no filtering. 0.9999 is extreme low pass. - private final static double JITTER_FILTER_COEFFICIENT = 0.8; - private final static String MAGNITUDE_FORMAT = "%7.5f"; - - final int TYPE_BUILTIN_SPEAKER_SAFE = 0x18; // API 30 - - private double mMagnitude; - private double mMaxMagnitude; - private int mPhaseCount; - private double mPhase; - private double mPhaseJitter; - - AudioManager mAudioManager; - - private static final int[] INPUT_PRESETS = { - // VOICE_RECOGNITION gets tested in testInputs() - // StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION, - StreamConfiguration.INPUT_PRESET_GENERIC, - StreamConfiguration.INPUT_PRESET_CAMCORDER, - // TODO Resolve issue with echo cancellation killing the signal. - // TODO StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, - StreamConfiguration.INPUT_PRESET_UNPROCESSED, - StreamConfiguration.INPUT_PRESET_VOICE_PERFORMANCE, - }; - - // Periodically query for magnitude and phase from the native detector. - protected class DataPathSniffer extends NativeSniffer { - - public DataPathSniffer(Activity activity) { - super(activity); - } - - @Override - public void startSniffer() { - mMagnitude = -1.0; - mMaxMagnitude = -1.0; - mPhaseCount = 0; - mPhase = 0.0; - mPhaseJitter = INITIAL_JITTER; - super.startSniffer(); - } - - @Override - public void run() { - mMagnitude = getMagnitude(); - mMaxMagnitude = getMaxMagnitude(); - // Only look at the phase if we have a signal. - if (mMagnitude >= MIN_REQUIRED_MAGNITUDE) { - double phase = getPhase(); - if (mPhaseCount > 3) { - double diff = Math.abs(phase - mPhase); - // low pass filter - mPhaseJitter = (mPhaseJitter * JITTER_FILTER_COEFFICIENT) - + ((diff * (1.0 - JITTER_FILTER_COEFFICIENT))); - } - mPhase = phase; - mPhaseCount++; - } - reschedule(); - } - - public String getCurrentStatusReport() { - StringBuffer message = new StringBuffer(); - message.append( - "magnitude = " + getMagnitudeText(mMagnitude) - + ", max = " + getMagnitudeText(mMaxMagnitude) - + "\nphase = " + getMagnitudeText(mPhase) - + ", jitter = " + getMagnitudeText(mPhaseJitter) - + "\n"); - return message.toString(); - } - - @Override - public String getShortReport() { - return "maxMag = " + getMagnitudeText(mMaxMagnitude) - + ", jitter = " + getMagnitudeText(mPhaseJitter); - } - - @Override - public void updateStatusText() { - mLastGlitchReport = getCurrentStatusReport(); - setAnalyzerText(mLastGlitchReport); - } - - } - - @Override - NativeSniffer createNativeSniffer() { - return new TestDataPathsActivity.DataPathSniffer(this); - } - - native double getMagnitude(); - native double getMaxMagnitude(); - native double getPhase(); - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_data_paths); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - } - - @Override - public String getTestName() { - return "DataPaths"; - } - - @Override - int getActivityType() { - return ACTIVITY_DATA_PATHS; - } - - String getMagnitudeText(double value) { - return String.format(MAGNITUDE_FORMAT, value); - } - - protected String getConfigText(StreamConfiguration config) { - String text = super.getConfigText(config); - if (config.getDirection() == StreamConfiguration.DIRECTION_INPUT) { - text += ", inPre = " + StreamConfiguration.convertInputPresetToText(config.getInputPreset()); - } - return text; - } - - @Override - protected String shouldTestBeSkipped() { - String why = ""; - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; - StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - // No point running the test if we don't get the sharing mode we requested. - if (actualInConfig.isMMap() != requestedInConfig.isMMap() - || actualOutConfig.isMMap() != requestedOutConfig.isMMap()) { - log("Did not get requested MMap stream"); - why += "mmap"; - } // Did we request a device and not get that device? - if (requestedInConfig.getDeviceId() != 0 - && (requestedInConfig.getDeviceId() != actualInConfig.getDeviceId())) { - why += ", inDev(" + requestedInConfig.getDeviceId() - + "!=" + actualInConfig.getDeviceId() + ")"; - } - if (requestedOutConfig.getDeviceId() != 0 - && (requestedOutConfig.getDeviceId() != actualOutConfig.getDeviceId())) { - why += ", outDev(" + requestedOutConfig.getDeviceId() - + "!=" + actualOutConfig.getDeviceId() + ")"; - } - if ((requestedInConfig.getInputPreset() != actualInConfig.getInputPreset())) { - why += ", inPre(" + requestedInConfig.getInputPreset() - + "!=" + actualInConfig.getInputPreset() + ")"; - } - return why; - } - - @Override - protected boolean isFinishedEarly() { - return (mMaxMagnitude > MIN_REQUIRED_MAGNITUDE) && (mPhaseJitter < MAX_ALLOWED_JITTER); - } - - // @return reasons for failure of empty string - @Override - public String didTestFail() { - String why = ""; - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; - StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - boolean passed = true; - if (mMaxMagnitude <= MIN_REQUIRED_MAGNITUDE) { - why += ", mag"; - } - if (mPhaseJitter > MAX_ALLOWED_JITTER) { - why += ", jitter"; - } - return why; - } - - String getOneLineSummary() { - StreamConfiguration actualInConfig = mAudioInputTester.actualConfiguration; - StreamConfiguration actualOutConfig = mAudioOutTester.actualConfiguration; - return "#" + mAutomatedTestRunner.getTestCount() - + ", IN" + (actualInConfig.isMMap() ? "-M" : "-L") - + " D=" + actualInConfig.getDeviceId() - + ", ch=" + channelText(getInputChannel(), actualInConfig.getChannelCount()) - + ", OUT" + (actualOutConfig.isMMap() ? "-M" : "-L") - + " D=" + actualOutConfig.getDeviceId() - + ", ch=" + channelText(getOutputChannel(), actualOutConfig.getChannelCount()) - + ", mag = " + getMagnitudeText(mMaxMagnitude); - } - - void setupDeviceCombo(int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel) throws InterruptedException { - // Configure settings - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - - requestedInConfig.reset(); - requestedOutConfig.reset(); - - requestedInConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY); - requestedOutConfig.setPerformanceMode(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY); - - requestedInConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); - requestedOutConfig.setSharingMode(StreamConfiguration.SHARING_MODE_SHARED); - - requestedInConfig.setChannelCount(numInputChannels); - requestedOutConfig.setChannelCount(numOutputChannels); - - requestedInConfig.setMMap(false); - requestedOutConfig.setMMap(false); - - setInputChannel(inputChannel); - setOutputChannel(outputChannel); - } - - void testPresetCombo(int inputPreset, - int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel, - boolean mmapEnabled - ) throws InterruptedException { - - setupDeviceCombo(numInputChannels, inputChannel, numOutputChannels, outputChannel); - - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - requestedInConfig.setInputPreset(inputPreset); - requestedInConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - int result = testConfigurations(); - if (result != TEST_RESULT_SKIPPED) { - String summary = getOneLineSummary() - + ", inPre = " - + StreamConfiguration.convertInputPresetToText(inputPreset) - + "\n"; - appendSummary(summary); - if (result == TEST_RESULT_FAILED) { - if (inputPreset == StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION) { - logFailed("Maybe sine wave blocked by Echo Cancellation!"); - } - } - } - } - - void testPresetCombo(int inputPreset, - int numInputChannels, - int inputChannel, - int numOutputChannels, - int outputChannel - ) throws InterruptedException { - if (NativeEngine.isMMapSupported()) { - testPresetCombo(inputPreset, numInputChannels, inputChannel, - numOutputChannels, outputChannel, true); - } - testPresetCombo(inputPreset, numInputChannels, inputChannel, - numOutputChannels, outputChannel, false); - } - - void testPresetCombo(int inputPreset) throws InterruptedException { - testPresetCombo(inputPreset, 1, 0, 1, 0); - } - - private void testInputPresets() throws InterruptedException { - logBoth("\nTest InputPreset -------"); - - for (int inputPreset : INPUT_PRESETS) { - testPresetCombo(inputPreset); - } -// TODO Resolve issue with echo cancellation killing the signal. -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 1, 0, 2, 0); -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 1, 0, 2, 1); -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 2, 0, 2, 0); -// testPresetCombo(StreamConfiguration.INPUT_PRESET_VOICE_COMMUNICATION, -// 2, 0, 2, 1); - } - - void testInputDeviceCombo(int deviceId, - int numInputChannels, - int inputChannel, - boolean mmapEnabled) throws InterruptedException { - final int numOutputChannels = 2; - setupDeviceCombo(numInputChannels, inputChannel, numOutputChannels, 0); - - StreamConfiguration requestedInConfig = mAudioInputTester.requestedConfiguration; - requestedInConfig.setInputPreset(StreamConfiguration.INPUT_PRESET_VOICE_RECOGNITION); - requestedInConfig.setDeviceId(deviceId); - requestedInConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - int result = testConfigurations(); - if (result != TEST_RESULT_SKIPPED) { - appendSummary(getOneLineSummary() + "\n"); - } - } - - void testInputDeviceCombo(int deviceId, - int numInputChannels, - int inputChannel) throws InterruptedException { - if (NativeEngine.isMMapSupported()) { - testInputDeviceCombo(deviceId, numInputChannels, inputChannel, true); - } - testInputDeviceCombo(deviceId, numInputChannels, inputChannel, false); - } - - void testInputDevices() throws InterruptedException { - logBoth("\nTest Input Devices -------"); - - AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS); - int numTested = 0; - for (AudioDeviceInfo deviceInfo : devices) { - log("----\n" - + AudioDeviceInfoConverter.toString(deviceInfo) + "\n"); - if (!deviceInfo.isSource()) continue; // FIXME log as error?! - if (deviceInfo.getType() == AudioDeviceInfo.TYPE_BUILTIN_MIC) { - int id = deviceInfo.getId(); - int[] channelCounts = deviceInfo.getChannelCounts(); - numTested++; - // Always test mono and stereo. - testInputDeviceCombo(id, 1, 0); - testInputDeviceCombo(id, 2, 0); - testInputDeviceCombo(id, 2, 1); - if (channelCounts.length > 0) { - for (int numChannels : channelCounts) { - // Test higher channel counts. - if (numChannels > 2) { - log("numChannels = " + numChannels + "\n"); - for (int channel = 0; channel < numChannels; channel++) { - testInputDeviceCombo(id, numChannels, channel); - } - } - } - } - } else { - log("Device skipped for type."); - } - } - - if (numTested == 0) { - log("NO INPUT DEVICE FOUND!\n"); - } - } - - void testOutputDeviceCombo(int deviceId, - int deviceType, - int numOutputChannels, - int outputChannel, - boolean mmapEnabled) throws InterruptedException { - final int numInputChannels = 2; // TODO review, done because of mono problems on some devices - setupDeviceCombo(numInputChannels, 0, numOutputChannels, outputChannel); - - StreamConfiguration requestedOutConfig = mAudioOutTester.requestedConfiguration; - requestedOutConfig.setDeviceId(deviceId); - requestedOutConfig.setMMap(mmapEnabled); - - mMagnitude = -1.0; - int result = testConfigurations(); - if (result != TEST_RESULT_SKIPPED) { - appendSummary(getOneLineSummary() + "\n"); - if (result == TEST_RESULT_FAILED) { - if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE - && numOutputChannels == 2 - && outputChannel == 1) { - logFailed("Maybe EARPIECE does not mix stereo to mono!"); - } - if (deviceType == TYPE_BUILTIN_SPEAKER_SAFE - && numOutputChannels == 2 - && outputChannel == 0) { - logFailed("Maybe SPEAKER_SAFE blocked channel 0!"); - } - } - } - } - - void testOutputDeviceCombo(int deviceId, - int deviceType, - int numOutputChannels, - int outputChannel) throws InterruptedException { - if (NativeEngine.isMMapSupported()) { - testOutputDeviceCombo(deviceId, deviceType, numOutputChannels, outputChannel, true); - } - testOutputDeviceCombo(deviceId, deviceType, numOutputChannels, outputChannel, false); - } - - void logBoth(String text) { - log(text); - appendSummary(text + "\n"); - } - void logFailed(String text) { - log(text); - appendFailedSummary(text + "\n"); - } - - void testOutputDevices() throws InterruptedException { - logBoth("\nTest Output Devices -------"); - - AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); - int numTested = 0; - for (AudioDeviceInfo deviceInfo : devices) { - log("----\n" - + AudioDeviceInfoConverter.toString(deviceInfo) + "\n"); - if (!deviceInfo.isSink()) continue; - int deviceType = deviceInfo.getType(); - if (deviceType == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER - || deviceType == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE - || deviceType == TYPE_BUILTIN_SPEAKER_SAFE) { - int id = deviceInfo.getId(); - int[] channelCounts = deviceInfo.getChannelCounts(); - numTested++; - // Always test mono and stereo. - testOutputDeviceCombo(id, deviceType, 1, 0); - testOutputDeviceCombo(id, deviceType, 2, 0); - testOutputDeviceCombo(id, deviceType, 2, 1); - if (channelCounts.length > 0) { - for (int numChannels : channelCounts) { - // Test higher channel counts. - if (numChannels > 2) { - log("numChannels = " + numChannels + "\n"); - for (int channel = 0; channel < numChannels; channel++) { - testOutputDeviceCombo(id, deviceType, numChannels, channel); - } - } - } - } - } else { - log("Device skipped for type."); - } - } - if (numTested == 0) { - log("NO OUTPUT DEVICE FOUND!\n"); - } - } - - void logExtraInfo() { - log("\n############################"); - log("\nDevice Info:"); - log(AudioQueryTools.getAudioManagerReport(mAudioManager)); - log(AudioQueryTools.getAudioFeatureReport(getPackageManager())); - log(AudioQueryTools.getAudioPropertyReport()); - log("\n############################"); - } - - @Override - public void runTest() { - try { - mDurationSeconds = DURATION_SECONDS; - - logExtraInfo(); - - log("min.required.magnitude = " + MIN_REQUIRED_MAGNITUDE); - log("max.allowed.jitter = " + MAX_ALLOWED_JITTER); - log("test.gap.msec = " + mGapMillis); - - testInputPresets(); - testInputDevices(); - testOutputDevices(); - - } catch (Exception e) { - log(e.getMessage()); - showErrorToast(e.getMessage()); - } - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java deleted file mode 100644 index 9c730563..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestDisconnectActivity.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -import java.io.IOException; - -/** - * Guide the user through a series of tests plugging in and unplugging a headset. - * Print a summary at the end of any failures. - */ -public class TestDisconnectActivity extends TestAudioActivity { - - private static final String TEXT_SKIP = "SKIP"; - private static final String TEXT_PASS = "PASS"; - private static final String TEXT_FAIL = "FAIL !!!!"; - public static final int POLL_DURATION_MILLIS = 50; - public static final int SETTLING_TIME_MILLIS = 600; - public static final int TIME_TO_FAILURE_MILLIS = 3000; - - private TextView mInstructionsTextView; - private TextView mStatusTextView; - private TextView mPlugTextView; - - private volatile boolean mTestFailed; - private volatile boolean mSkipTest; - private volatile int mPlugCount; - private BroadcastReceiver mPluginReceiver = new PluginBroadcastReceiver(); - private Button mFailButton; - private Button mSkipButton; - - protected AutomatedTestRunner mAutomatedTestRunner; - - // Receive a broadcast Intent when a headset is plugged in or unplugged. - // Display a count on screen. - public class PluginBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - mPlugCount++; - runOnUiThread(new Runnable() { - @Override - public void run() { - String message = "Intent.HEADSET_PLUG #" + mPlugCount; - mPlugTextView.setText(message); - } - }); - } - } - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_test_disconnect); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mAutomatedTestRunner = findViewById(R.id.auto_test_runner); - mAutomatedTestRunner.setActivity(this); - - mInstructionsTextView = (TextView) findViewById(R.id.text_instructions); - mStatusTextView = (TextView) findViewById(R.id.text_status); - mPlugTextView = (TextView) findViewById(R.id.text_plug_events); - - mFailButton = (Button) findViewById(R.id.button_fail); - mSkipButton = (Button) findViewById(R.id.button_skip); - updateFailSkipButton(false); - } - - @Override - public String getTestName() { - return "Disconnect"; - } - - int getActivityType() { - return ACTIVITY_TEST_DISCONNECT; - } - - @Override - boolean isOutput() { - return true; - } - - @Override - public void setupEffects(int sessionId) { - } - - private void updateFailSkipButton(final boolean running) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mFailButton.setEnabled(running); - mSkipButton.setEnabled(running); - } - }); - } - - // Write to status and command view - private void setInstructionsText(final String text) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mInstructionsTextView.setText(text); - } - }); - } - - // Write to status and command view - private void setStatusText(final String text) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mStatusTextView.setText(text); - } - }); - } - - @Override - public void onResume() { - super.onResume(); - IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); - this.registerReceiver(mPluginReceiver, filter); - } - - @Override - public void onPause() { - this.unregisterReceiver(mPluginReceiver); - super.onPause(); - } - - // This should only be called from UI events such as onStop or a button press. - @Override - public void onStopTest() { - mAutomatedTestRunner.stopTest(); - } - - public void startAudioTest() throws IOException { - startAudio(); - } - - public void stopAudioTest() { - stopAudioQuiet(); - closeAudio(); - } - - public void onCancel(View view) { - stopAudioTest(); - mAutomatedTestRunner.onTestFinished(); - } - - // Called on UI thread - public void onStopAudioTest(View view) { - stopAudioTest(); - mAutomatedTestRunner.onTestFinished(); - keepScreenOn(false); - } - - public void onFailTest(View view) { - mTestFailed = true; - } - - public void onSkipTest(View view) { - mSkipTest = true; - } - - private String getConfigText(StreamConfiguration config) { - return ((config.getDirection() == StreamConfiguration.DIRECTION_OUTPUT) ? "OUT" : "IN") - + ", Perf = " + StreamConfiguration.convertPerformanceModeToText( - config.getPerformanceMode()) - + ", " + StreamConfiguration.convertSharingModeToText(config.getSharingMode()) - + ", " + config.getSampleRate(); - } - - private void log(String text) { - mAutomatedTestRunner.log(text); - } - - private void appendFailedSummary(String text) { - mAutomatedTestRunner.appendFailedSummary(text); - } - - private void testConfiguration(boolean isInput, - int perfMode, - int sharingMode, - int sampleRate, - boolean requestPlugin) throws InterruptedException { - String actualConfigText = "none"; - mSkipTest = false; - - AudioInputTester mAudioInTester = null; - AudioOutputTester mAudioOutTester = null; - - clearStreamContexts(); - - if (isInput) { - mAudioInTester = addAudioInputTester(); - } else { - mAudioOutTester = addAudioOutputTester(); - } - - // Configure settings - StreamConfiguration requestedConfig = (isInput) - ? mAudioInTester.requestedConfiguration - : mAudioOutTester.requestedConfiguration; - StreamConfiguration actualConfig = (isInput) - ? mAudioInTester.actualConfiguration - : mAudioOutTester.actualConfiguration; - - requestedConfig.reset(); - requestedConfig.setPerformanceMode(perfMode); - requestedConfig.setSharingMode(sharingMode); - requestedConfig.setSampleRate(sampleRate); - if (sampleRate != 0) { - requestedConfig.setRateConversionQuality(StreamConfiguration.RATE_CONVERSION_QUALITY_MEDIUM); - } - - log("========================== #" + mAutomatedTestRunner.getTestCount()); - log("Requested:"); - log(getConfigText(requestedConfig)); - - // Give previous stream time to close and release resources. Avoid race conditions. - Thread.sleep(SETTLING_TIME_MILLIS); - if (!mAutomatedTestRunner.isThreadEnabled()) return; - boolean openFailed = false; - AudioStreamBase stream = null; - try { - openAudio(); - log("Actual:"); - actualConfigText = getConfigText(actualConfig) - + ", " + (actualConfig.isMMap() ? "MMAP" : "Legacy"); - log(actualConfigText); - - stream = (isInput) - ? mAudioInTester.getCurrentAudioStream() - : mAudioOutTester.getCurrentAudioStream(); - } catch (IOException e) { - openFailed = true; - log(e.getMessage()); - } - - // The test is only worth running if we got the configuration we requested. - boolean valid = true; - if (!openFailed) { - if(actualConfig.getSharingMode() != sharingMode) { - log("did not get requested sharing mode"); - valid = false; - } - if (actualConfig.getPerformanceMode() != perfMode) { - log("did not get requested performance mode"); - valid = false; - } - if (actualConfig.getNativeApi() == StreamConfiguration.NATIVE_API_OPENSLES) { - log("OpenSL ES does not support automatic disconnect"); - valid = false; - } - } - - if (!openFailed && valid) { - try { - startAudioTest(); - } catch (IOException e) { - e.printStackTrace(); - valid = false; - log(e.getMessage()); - } - } - - int oldPlugCount = mPlugCount; - if (!openFailed && valid) { - mTestFailed = false; - updateFailSkipButton(true); - // poll until stream started - while (!mTestFailed && mAutomatedTestRunner.isThreadEnabled() && !mSkipTest && - stream.getState() == StreamConfiguration.STREAM_STATE_STARTING) { - Thread.sleep(POLL_DURATION_MILLIS); - } - String message = (requestPlugin ? "Plug IN" : "UNplug") + " headset now!"; - setStatusText("Testing:\n" + actualConfigText); - setInstructionsText(message); - int timeoutCount = 0; - // Wait for Java plug count to change or stream to disconnect. - while (!mTestFailed && mAutomatedTestRunner.isThreadEnabled() && !mSkipTest && - stream.getState() == StreamConfiguration.STREAM_STATE_STARTED) { - Thread.sleep(POLL_DURATION_MILLIS); - if (mPlugCount > oldPlugCount) { - timeoutCount = TIME_TO_FAILURE_MILLIS / POLL_DURATION_MILLIS; - break; - } - } - // Wait for timeout or stream to disconnect. - while (!mTestFailed && mAutomatedTestRunner.isThreadEnabled() && !mSkipTest && (timeoutCount > 0) && - stream.getState() == StreamConfiguration.STREAM_STATE_STARTED) { - Thread.sleep(POLL_DURATION_MILLIS); - timeoutCount--; - if (timeoutCount == 0) { - mTestFailed = true; - } else { - setStatusText("Plug detected by Java.\nCounting down to Oboe failure: " + timeoutCount); - } - } - if (!mTestFailed) { - int error = stream.getLastErrorCallbackResult(); - if (error != StreamConfiguration.ERROR_DISCONNECTED) { - log("onEerrorCallback error = " + error - + ", expected " + StreamConfiguration.ERROR_DISCONNECTED); - mTestFailed = true; - } - } - setStatusText(mTestFailed ? "Failed" : "Passed - detected"); - } - updateFailSkipButton(false); - setInstructionsText("Wait..."); - - if (!openFailed) { - stopAudioTest(); - } - - if (mSkipTest) valid = false; - - if (valid) { - if (openFailed) { - appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n"); - appendFailedSummary(getConfigText(requestedConfig) + "\n"); - appendFailedSummary("Open failed!\n"); - mAutomatedTestRunner.incrementFailCount(); - } else { - log("Result:"); - boolean passed = !mTestFailed; - String resultText = requestPlugin ? "plugIN" : "UNplug"; - resultText += ", " + (passed ? TEXT_PASS : TEXT_FAIL); - log(resultText); - if (!passed) { - appendFailedSummary("------ #" + mAutomatedTestRunner.getTestCount() + "\n"); - appendFailedSummary(" " + actualConfigText + "\n"); - appendFailedSummary(" " + resultText + "\n"); - mAutomatedTestRunner.incrementFailCount(); - } else { - mAutomatedTestRunner.incrementPassCount(); - } - } - } else { - log(TEXT_SKIP); - } - // Give hardware time to settle between tests. - Thread.sleep(1000); - mAutomatedTestRunner.incrementTestCount(); - } - - private void testConfiguration(boolean isInput, int performanceMode, - int sharingMode, int sampleRate) throws InterruptedException { - boolean requestPlugin = true; // plug IN - testConfiguration(isInput, performanceMode, sharingMode, sampleRate, requestPlugin); - requestPlugin = false; // UNplug - testConfiguration(isInput, performanceMode, sharingMode, sampleRate, requestPlugin); - } - - private void testConfiguration(boolean isInput, int performanceMode, - int sharingMode) throws InterruptedException { - final int sampleRate = 0; - testConfiguration(isInput, performanceMode, sharingMode, sampleRate); - } - - private void testConfiguration(int performanceMode, - int sharingMode) throws InterruptedException { - testConfiguration(false, performanceMode, sharingMode); - testConfiguration(true, performanceMode, sharingMode); - } - - @Override - public void runTest() { - mPlugCount = 0; - // Try several different configurations. - try { - testConfiguration(false, StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY, - StreamConfiguration.SHARING_MODE_EXCLUSIVE, 44100); - testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY, - StreamConfiguration.SHARING_MODE_EXCLUSIVE); - testConfiguration(StreamConfiguration.PERFORMANCE_MODE_LOW_LATENCY, - StreamConfiguration.SHARING_MODE_SHARED); - testConfiguration(StreamConfiguration.PERFORMANCE_MODE_NONE, - StreamConfiguration.SHARING_MODE_SHARED); - } catch (InterruptedException e) { - log(e.getMessage()); - showErrorToast(e.getMessage()); - } finally { - setInstructionsText("Test completed."); - updateFailSkipButton(false); - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java deleted file mode 100644 index 3a2aea1c..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestInputActivity.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.Manifest; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.media.audiofx.AcousticEchoCanceler; -import android.media.audiofx.AutomaticGainControl; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.support.annotation.NonNull; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.FileProvider; -import android.view.View; -import android.widget.RadioButton; -import android.widget.Toast; - -import java.io.File; -import java.io.IOException; - -/** - * Test Oboe Capture - */ - -public class TestInputActivity extends TestAudioActivity - implements ActivityCompat.OnRequestPermissionsResultCallback { - - private static final int MY_PERMISSIONS_REQUEST_RECORD_AUDIO = 9371; - protected AudioInputTester mAudioInputTester; - private static final int NUM_VOLUME_BARS = 4; - private VolumeBarView[] mVolumeBars = new VolumeBarView[NUM_VOLUME_BARS]; - private InputMarginView mInputMarginView; - private int mInputMarginBursts = 0; - private WorkloadView mWorkloadView; - - public native void setMinimumFramesBeforeRead(int frames); - public native int saveWaveFile(String absolutePath); - - @Override boolean isOutput() { return false; } - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_test_input); - - BufferSizeView bufferSizeView = findViewById(R.id.buffer_size_view); - bufferSizeView.setVisibility(View.GONE); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mVolumeBars[0] = (VolumeBarView) findViewById(R.id.volumeBar0); - mVolumeBars[1] = (VolumeBarView) findViewById(R.id.volumeBar1); - mVolumeBars[2] = (VolumeBarView) findViewById(R.id.volumeBar2); - mVolumeBars[3] = (VolumeBarView) findViewById(R.id.volumeBar3); - - mInputMarginView = (InputMarginView) findViewById(R.id.input_margin_view); - - updateEnabledWidgets(); - - mAudioInputTester = addAudioInputTester(); - - mWorkloadView = (WorkloadView) findViewById(R.id.workload_view); - if (mWorkloadView != null) { - mWorkloadView.setAudioStreamTester(mAudioInputTester); - } - } - - @Override - int getActivityType() { - return ACTIVITY_TEST_INPUT; - } - - @Override - protected void resetConfiguration() { - super.resetConfiguration(); - mAudioInputTester.reset(); - } - - @Override - void updateStreamDisplay() { - int numChannels = mAudioInputTester.getCurrentAudioStream().getChannelCount(); - if (numChannels > NUM_VOLUME_BARS) { - numChannels = NUM_VOLUME_BARS; - } - for (int i = 0; i < numChannels; i++) { - if (mVolumeBars[i] == null) break; - double level = mAudioInputTester.getPeakLevel(i); - mVolumeBars[i].setVolume((float) level); - } - } - - void resetVolumeBars() { - for (int i = 0; i < mVolumeBars.length; i++) { - if (mVolumeBars[i] == null) break; - mVolumeBars[i].setVolume((float) 0.0); - } - } - - void setMinimumBurstsBeforeRead(int numBursts) { - int framesPerBurst = mAudioInputTester.getCurrentAudioStream().getFramesPerBurst(); - if (framesPerBurst > 0) { - setMinimumFramesBeforeRead(numBursts * framesPerBurst); - } - } - - @Override - public void openAudio() throws IOException { - if (!isRecordPermissionGranted()){ - requestRecordPermission(); - return; - } - super.openAudio(); - setMinimumBurstsBeforeRead(mInputMarginBursts); - resetVolumeBars(); - } - - @Override - public void stopAudio() { - super.stopAudio(); - resetVolumeBars(); - } - - @Override - protected void toastPauseError(int result) { - showToast("Pause not implemented. Returned " + result); - } - - private boolean isRecordPermissionGranted() { - return (ActivityCompat.checkSelfPermission(this, - Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED); - } - - private void requestRecordPermission(){ - ActivityCompat.requestPermissions( - this, - new String[]{Manifest.permission.RECORD_AUDIO}, - MY_PERMISSIONS_REQUEST_RECORD_AUDIO); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { - - if (MY_PERMISSIONS_REQUEST_RECORD_AUDIO != requestCode) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - return; - } - - if (grantResults.length != 1 || - grantResults[0] != PackageManager.PERMISSION_GRANTED) { - - Toast.makeText(getApplicationContext(), - getString(R.string.need_record_audio_permission), - Toast.LENGTH_SHORT) - .show(); - } else { - // Permission was granted - try { - super.openAudio(); - } catch (IOException e) { - showErrorToast(e.getMessage()); - } - } - } - - public void setupAGC(int sessionId) { - AutomaticGainControl effect = AutomaticGainControl.create(sessionId); - } - - public void setupAEC(int sessionId) { - AcousticEchoCanceler effect = AcousticEchoCanceler.create(sessionId); - } - - @Override - public void setupEffects(int sessionId) { - setupAEC(sessionId); - } - - protected int saveWaveFile(File file) { - // Pass filename to native to write WAV file - int result = saveWaveFile(file.getAbsolutePath()); - if (result < 0) { - showErrorToast("Save returned " + result); - } else { - showToast("Saved " + result + " bytes."); - } - return result; - } - - String getWaveTag() { - return "input"; - } - - @NonNull - private File createFileName() { - // Get directory and filename - File dir = getExternalFilesDir(Environment.DIRECTORY_MUSIC); - return new File(dir, "oboe_" + getWaveTag() + "_" + AutomatedTestRunner.getTimestampString() + ".wav"); - } - - public void shareWaveFile() { - // Share WAVE file via GMail, Drive or other method. - File file = createFileName(); - int result = saveWaveFile(file); - if (result > 0) { - Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); - sharingIntent.setType("audio/wav"); - String subjectText = file.getName(); - sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subjectText); - Uri uri = FileProvider.getUriForFile(this, - BuildConfig.APPLICATION_ID + ".provider", - file); - sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); - sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(Intent.createChooser(sharingIntent, "Share WAV using:")); - } - } - - public void onShareFile(View view) { - shareWaveFile(); - } - - public void onMarginBoxClicked(View view) { - RadioButton radioButton = (RadioButton) view; - String text = (String) radioButton.getText(); - mInputMarginBursts = Integer.parseInt(text); - setMinimumBurstsBeforeRead(mInputMarginBursts); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java deleted file mode 100644 index 586443e1..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivity.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.CheckBox; -import android.widget.Spinner; - -import java.io.IOException; - -/** - * Test basic output. - */ -public final class TestOutputActivity extends TestOutputActivityBase { - - public static final int MAX_CHANNEL_BOXES = 8; - private CheckBox[] mChannelBoxes; - private Spinner mNativeApiSpinner; - - private class NativeApiSpinnerListener implements android.widget.AdapterView.OnItemSelectedListener { - @Override - public void onItemSelected(AdapterView parent, View view, int pos, long id) { - mAudioOutTester.setSignalType(pos); - } - - @Override - public void onNothingSelected(AdapterView parent) { - mAudioOutTester.setSignalType(0); - } - } - - @Override - protected void inflateActivity() { - setContentView(R.layout.activity_test_output); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - updateEnabledWidgets(); - - mAudioOutTester = addAudioOutputTester(); - - mChannelBoxes = new CheckBox[MAX_CHANNEL_BOXES]; - int ic = 0; - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox0); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox1); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox2); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox3); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox4); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox5); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox6); - mChannelBoxes[ic++] = (CheckBox) findViewById(R.id.channelBox7); - configureChannelBoxes(0); - - mNativeApiSpinner = (Spinner) findViewById(R.id.spinnerOutputSignal); - mNativeApiSpinner.setOnItemSelectedListener(new NativeApiSpinnerListener()); - mNativeApiSpinner.setSelection(StreamConfiguration.NATIVE_API_UNSPECIFIED); - } - - @Override - int getActivityType() { - return ACTIVITY_TEST_OUTPUT; - } - - public void openAudio() throws IOException { - super.openAudio(); - int channelCount = mAudioOutTester.getCurrentAudioStream().getChannelCount(); - configureChannelBoxes(channelCount); - } - - private void configureChannelBoxes(int channelCount) { - for (int i = 0; i < mChannelBoxes.length; i++) { - mChannelBoxes[i].setChecked(i < channelCount); - mChannelBoxes[i].setEnabled(i < channelCount); - } - } - - public void closeAudio() { - configureChannelBoxes(0); - super.closeAudio(); - } - - public void onChannelBoxClicked(View view) { - CheckBox checkBox = (CheckBox) view; - String text = (String) checkBox.getText(); - int channelIndex = Integer.parseInt(text); - mAudioOutTester.setChannelEnabled(channelIndex, checkBox.isChecked()); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java deleted file mode 100644 index 73a0cc92..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/TestOutputActivityBase.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2017 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. - */ - -package com.mobileer.oboetester; - -import android.media.audiofx.Equalizer; -import android.media.audiofx.PresetReverb; -import android.util.Log; - -import java.io.IOException; - - -abstract class TestOutputActivityBase extends TestAudioActivity { - AudioOutputTester mAudioOutTester; - - private BufferSizeView mBufferSizeView; - private WorkloadView mWorkloadView; - - @Override boolean isOutput() { return true; } - - @Override - protected void resetConfiguration() { - super.resetConfiguration(); - mAudioOutTester.reset(); - } - - protected void findAudioCommon() { - super.findAudioCommon(); - mBufferSizeView = (BufferSizeView) findViewById(R.id.buffer_size_view); - mWorkloadView = (WorkloadView) findViewById(R.id.workload_view); - } - - @Override - public AudioOutputTester addAudioOutputTester() { - AudioOutputTester audioOutTester = super.addAudioOutputTester(); - mWorkloadView.setAudioStreamTester(audioOutTester); - return audioOutTester; - } - - @Override - public void openAudio() throws IOException { - super.openAudio(); - if (mBufferSizeView != null) { - mBufferSizeView.onStreamOpened((OboeAudioStream) mAudioOutTester.getCurrentAudioStream()); - } - } - - // TODO Add editor - public void setupEqualizer(int sessionId) { - Equalizer equalizer = new Equalizer(0, sessionId); - int numBands = equalizer.getNumberOfBands(); - Log.d(TAG, "numBands " + numBands); - for (short band = 0; band < numBands; band++) { - String msg = "band " + band - + ", center = " + equalizer.getCenterFreq(band) - + ", level = " + equalizer.getBandLevel(band); - Log.d(TAG, msg); - equalizer.setBandLevel(band, (short)40); - } - - equalizer.setBandLevel((short) 1, (short) 300); - } - - public void setupReverb(int sessionId) { - PresetReverb effect = new PresetReverb(0, sessionId); - } - - @Override - public void setupEffects(int sessionId) { - // setupEqualizer(sessionId); - // setupReverb(sessionId); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java deleted file mode 100644 index 3a08de21..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/VolumeBarView.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.View; - -public class VolumeBarView extends View { - - private Paint mBarPaint; - private int mCurrentWidth; - private int mCurrentHeight; - private Paint mBackgroundPaint; - private float mVolume; - - public VolumeBarView(Context context, AttributeSet attrs) { - super(context, attrs); -// TypedArray a = context.getTheme().obtainStyledAttributes(attrs, -// R.styleable.VolumeBarView, 0, 0); - init(); - } - - private void init() { - mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBarPaint.setColor(Color.RED); - mBarPaint.setStyle(Paint.Style.FILL); - - mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBackgroundPaint.setColor(Color.LTGRAY); - mBackgroundPaint.setStyle(Paint.Style.FILL); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mCurrentWidth = w; - mCurrentHeight = h; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.drawRect(0.0f, 0.0f, mCurrentWidth, - mCurrentHeight, mBackgroundPaint); - float scaledVolume = mVolume * mCurrentWidth; - canvas.drawRect(0.0f, 0.0f, scaledVolume, - mCurrentHeight, mBarPaint); - } - - /** - * Set volume between 0.0 and 1.0 - */ - public void setVolume(float volume) { - mVolume = volume; - postInvalidate(); - } - -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java deleted file mode 100644 index 04c11598..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WaveformView.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.View; - -/** - * Display an audio waveform in a custom View. - */ -public class WaveformView extends View { - private static final float MESSAGE_TEXT_SIZE = 80; - private Paint mWavePaint; - private Paint mBackgroundPaint; - private Paint mMessagePaint; - private int mCurrentWidth; - private int mCurrentHeight; - private float[] mData; - private int mSampleCount; - private int mSampleOffset; - private float mOffsetY; - private float mScaleY; - private int[] mCursors; - private String mMessage; - private Paint mCursorPaint; - - public WaveformView(Context context, AttributeSet attrs) { - super(context, attrs); - TypedArray a = context.getTheme().obtainStyledAttributes(attrs, - R.styleable.WaveformView, 0, 0); - init(); - } - @SuppressWarnings("deprecation") - private void init() { - Resources res = getResources(); - - mWavePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mWavePaint.setColor(res.getColor(R.color.waveform_line)); - float strokeWidth = res.getDimension(R.dimen.waveform_stroke_width); - mWavePaint.setStrokeWidth(strokeWidth); - - mCursorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mCursorPaint.setColor(Color.RED); - mCursorPaint.setStrokeWidth(3.0f); - - mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBackgroundPaint.setColor(res.getColor(R.color.waveform_background)); - mBackgroundPaint.setStyle(Paint.Style.FILL); - - mMessagePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mMessagePaint.setColor(res.getColor(R.color.waveform_line)); - mMessagePaint.setTextSize(MESSAGE_TEXT_SIZE); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mCurrentWidth = w; - mCurrentHeight = h; - mOffsetY = 0.5f * h; - mScaleY = 0.0f - mOffsetY; - } - - public String getMessage() { - return mMessage; - } - - public void setMessage(String mMessage) { - this.mMessage = mMessage; - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - float [] localData = mData; - canvas.drawRect(0.0f, 0.0f, mCurrentWidth, - mCurrentHeight, mBackgroundPaint); - if (mMessage != null) { - canvas.drawText(mMessage, 20, mCurrentHeight - 20, mMessagePaint); - } - if (localData == null || mSampleCount == 0) { - return; - } - float xScale = ((float) mCurrentWidth) / (mSampleCount - 1); - float x0 = 0.0f; - if (xScale < 1.0) { - // Draw a vertical bar for multiple samples. - float ymin = mOffsetY; - float ymax = mOffsetY; - for (int i = 0; i < mSampleCount; i++) { - float x1 = i * xScale; - if ((int) x0 != (int) x1) { - // draw old data - canvas.drawLine(x0, ymin, x0, ymax, mWavePaint); - x0 = x1; - ymin = mOffsetY; - ymax = mOffsetY; - } - float y1 = (localData[i] * mScaleY) + mOffsetY; - ymin = Math.min(ymin, y1); - ymax = Math.max(ymax, y1); - } - } else { - // Draw line between samples. - float y0 = (localData[0] * mScaleY) + mOffsetY; - for (int i = 1; i < mSampleCount; i++) { - float x1 = i * xScale; - float y1 = (localData[i] * mScaleY) + mOffsetY; - canvas.drawLine(x0, y0, x1, y1, mWavePaint); - x0 = x1; - y0 = y1; - } - } - if (mCursors != null) { - for (int i = 0; i < mCursors.length; i++) { - float x = mCursors[i] * xScale; - canvas.drawLine(x, 0, x, mCurrentHeight, mCursorPaint); - } - } - } - - /** - * Copy data into internal buffer then repaint. - */ - public void setSampleData(float[] samples) { - setSampleData(samples, 0, samples.length); - } - - public void setSampleData(float[] samples, int offset, int count) { - if ((offset+count) > samples.length) { - throw new IllegalArgumentException("Exceed array bounds. (" - + offset + " + " + count + ") > " + samples.length); - } - if (mData == null || count > mData.length) { - mData = new float[count]; - } - System.arraycopy(samples, offset, mData, 0, count); - mSampleCount = count; - mSampleOffset = offset; - } - - public void clearSampleData() { - mData = null; - mSampleCount = 0; - mSampleOffset = 0; - } - - /** - * Copy cursor positions into internal buffer then repaint. - */ - public void setCursorData(int[] cursors) { - if (cursors == null) { - mCursors = null; - } else { - if (mCursors == null || cursors.length != mCursors.length) { - mCursors = new int[cursors.length]; - } - System.arraycopy(cursors, 0, mCursors, 0, mCursors.length); - } - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java b/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java deleted file mode 100644 index 78d78df7..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/WorkloadView.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2019 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. - */ - -package com.mobileer.oboetester; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.widget.LinearLayout; -import android.widget.SeekBar; -import android.widget.TextView; - -public class WorkloadView extends LinearLayout { - - private AudioStreamTester mAudioStreamTester; - - protected static final int FADER_PROGRESS_MAX = 1000; // must match layout - protected TextView mTextView; - protected SeekBar mSeekBar; - protected ExponentialTaper mExponentialTaper; - - private SeekBar.OnSeekBarChangeListener mChangeListener = new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - setValueByPosition(progress); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }; - - public WorkloadView(Context context) { - super(context); - initializeViews(context); - } - - public WorkloadView(Context context, AttributeSet attrs) { - super(context, attrs); - initializeViews(context); - } - - public WorkloadView(Context context, - AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - initializeViews(context); - } - - public AudioStreamTester getAudioStreamTester() { - return mAudioStreamTester; - } - - public void setAudioStreamTester(AudioStreamTester audioStreamTester) { - mAudioStreamTester = audioStreamTester; - } - - void setFaderNormalizedProgress(double fraction) { - mSeekBar.setProgress((int)(fraction * FADER_PROGRESS_MAX)); - } - - /** - * Inflates the views in the layout. - * - * @param context - * the current context for the view. - */ - private void initializeViews(Context context) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.workload_view, this); - - mTextView = (TextView) findViewById(R.id.textWorkload); - mSeekBar = (SeekBar) findViewById(R.id.faderWorkload); - mSeekBar.setOnSeekBarChangeListener(mChangeListener); - mExponentialTaper = new ExponentialTaper(0.0, 100.0, 10.0); - //mSeekBar.setProgress(0); - } - - private void setValueByPosition(int progress) { - double workload = mExponentialTaper.linearToExponential( - ((double)progress) / FADER_PROGRESS_MAX); - mAudioStreamTester.setWorkload(workload); - mTextView.setText("Workload = " + String.format("%6.2f", workload)); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - mSeekBar.setEnabled(enabled); - } -} diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/button_shape.xml b/src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/button_shape.xml deleted file mode 100644 index 03e76906..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/button_shape.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml b/src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index c6b72859..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml b/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml deleted file mode 100644 index 6d251efc..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_auto_glitches.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml b/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml deleted file mode 100644 index c3f29b57..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_data_paths.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml b/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml deleted file mode 100644 index 0748b276..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_device_report.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_echo.xml b/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_echo.xml deleted file mode 100644 index 03ad1a84..00000000 --- a/src/libs/oboe/apps/OboeTester/app/src/main/res/layout/activity_echo.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - -