mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-21 06:25:46 +00:00
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
parent
c0cceff365
commit
6c655321e6
4081 changed files with 1185566 additions and 45 deletions
19
externals/oboe/samples/hello-oboe/README.md
vendored
Normal file
19
externals/oboe/samples/hello-oboe/README.md
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Hello Oboe
|
||||
==========
|
||||
Creates an output (playback) stream and plays a sine wave when you tap the screen.
|
||||
|
||||
Here's an overview of the UI:
|
||||
|
||||
**Audio API:** Leave as "Unspecified" to select the best audio API for the current API level, or select AAudio or OpenSL ES to force the use of that API. AAudio is only available on Android API 26 and above.
|
||||
|
||||
**Audio device:** Choose the audio device, or leave as "Automatic" to use the default device. The list of audio devices is automatically updated when devices (e.g. headphones, USB audio devices) are added or removed.
|
||||
|
||||
**Channel count:** Choose the number of audio channels to output. A different pitched sine wave will be played through each of the channels.
|
||||
|
||||
**Buffer size:** Choose the buffer size in bursts. A burst is an array of audio frames read by the audio device in a single operation and typically represents the minimum possible buffer size.
|
||||
|
||||
**Latency:** Shows the average latency of the audio stream between data entering the stream and it being presented to the audio device. This latency figure is only as accurate as the timestamps being reported by the audio device to the Android audio framework. It does not include any latency introduced *after* the audio device (e.g. echo cancellation for the built-in speaker). Only available on API 26+.
|
||||
|
||||
Screenshots
|
||||
-----------
|
||||

|
46
externals/oboe/samples/hello-oboe/build.gradle
vendored
Normal file
46
externals/oboe/samples/hello-oboe/build.gradle
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 35
|
||||
defaultConfig {
|
||||
applicationId 'com.google.oboe.samples.hellooboe'
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
compileSdkVersion 35
|
||||
versionCode 1
|
||||
versionName '1.0'
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++17"
|
||||
arguments '-DANDROID_STL=c++_static'
|
||||
// armeabi and mips are deprecated in NDK r16 so we don't want to build for them
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||
'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_18
|
||||
targetCompatibility JavaVersion.VERSION_18
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'src/main/cpp/CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
namespace 'com.google.oboe.samples.hellooboe'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation project(':audio-device')
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
||||
}
|
BIN
externals/oboe/samples/hello-oboe/hello-oboe-screenshot.png
vendored
Normal file
BIN
externals/oboe/samples/hello-oboe/hello-oboe-screenshot.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
17
externals/oboe/samples/hello-oboe/proguard-rules.pro
vendored
Normal file
17
externals/oboe/samples/hello-oboe/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
# 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 *;
|
||||
#}
|
24
externals/oboe/samples/hello-oboe/src/main/AndroidManifest.xml
vendored
Normal file
24
externals/oboe/samples/hello-oboe/src/main/AndroidManifest.xml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-feature android:name="android.hardware.audio.output" android:required="true" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:supportsRtl="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.google.oboe.samples.hellooboe.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
60
externals/oboe/samples/hello-oboe/src/main/cpp/CMakeLists.txt
vendored
Normal file
60
externals/oboe/samples/hello-oboe/src/main/cpp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
### INCLUDE OBOE LIBRARY ###
|
||||
|
||||
# Set the path to the Oboe library directory
|
||||
set (OBOE_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)
|
||||
|
||||
# Include the Oboe headers and shared sample code
|
||||
include_directories(${OBOE_DIR}/include ${OBOE_DIR}/samples/shared)
|
||||
|
||||
# Debug utilities
|
||||
set (DEBUG_UTILS_PATH "${OBOE_DIR}/samples/debug-utils")
|
||||
set (DEBUG_UTILS_SOURCES ${DEBUG_UTILS_PATH}/trace.cpp)
|
||||
include_directories(${DEBUG_UTILS_PATH})
|
||||
|
||||
|
||||
### END OBOE INCLUDE SECTION ###
|
||||
|
||||
|
||||
# App specific sources
|
||||
set (APP_SOURCES
|
||||
jni_bridge.cpp
|
||||
HelloOboeEngine.cpp
|
||||
SoundGenerator.cpp
|
||||
LatencyTuningCallback.cpp
|
||||
)
|
||||
|
||||
# Build the libhello-oboe library
|
||||
add_library(hello-oboe SHARED
|
||||
${DEBUG_UTILS_SOURCES}
|
||||
${APP_SOURCES}
|
||||
)
|
||||
|
||||
# Specify the libraries needed for hello-oboe
|
||||
target_link_libraries(hello-oboe android log oboe)
|
||||
target_link_options(hello-oboe PRIVATE "-Wl,-z,max-page-size=16384")
|
||||
|
||||
# Enable optimization flags: if having problems with source level debugging,
|
||||
# disable -Ofast ( and debug ), re-enable after done debugging.
|
||||
target_compile_options(hello-oboe PRIVATE -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
|
175
externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
vendored
Normal file
175
externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
/**
|
||||
* 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 <inttypes.h>
|
||||
#include <memory>
|
||||
|
||||
#include <Oscillator.h>
|
||||
|
||||
#include "HelloOboeEngine.h"
|
||||
#include "SoundGenerator.h"
|
||||
|
||||
|
||||
/**
|
||||
* Main audio engine for the HelloOboe sample. It is responsible for:
|
||||
*
|
||||
* - Creating a callback object which is supplied when constructing the audio stream, and will be
|
||||
* called when the stream starts
|
||||
* - Restarting the stream when user-controllable properties (Audio API, channel count etc) are
|
||||
* changed, and when the stream is disconnected (e.g. when headphones are attached)
|
||||
* - Calculating the audio latency of the stream
|
||||
*
|
||||
*/
|
||||
HelloOboeEngine::HelloOboeEngine()
|
||||
: mLatencyCallback(std::make_shared<LatencyTuningCallback>()),
|
||||
mErrorCallback(std::make_shared<DefaultErrorCallback>(*this)) {
|
||||
}
|
||||
|
||||
double HelloOboeEngine::getCurrentOutputLatencyMillis() {
|
||||
if (!mIsLatencyDetectionSupported) return -1.0;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
if (!mStream) return -1.0;
|
||||
|
||||
oboe::ResultWithValue<double> latencyResult = mStream->calculateLatencyMillis();
|
||||
if (latencyResult) {
|
||||
return latencyResult.value();
|
||||
} else {
|
||||
LOGE("Error calculating latency: %s", oboe::convertToText(latencyResult.error()));
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void HelloOboeEngine::setBufferSizeInBursts(int32_t numBursts) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
if (!mStream) return;
|
||||
|
||||
mLatencyCallback->setBufferTuneEnabled(numBursts == kBufferSizeAutomatic);
|
||||
auto result = mStream->setBufferSizeInFrames(
|
||||
numBursts * mStream->getFramesPerBurst());
|
||||
if (result) {
|
||||
LOGD("Buffer size successfully changed to %d", result.value());
|
||||
} else {
|
||||
LOGW("Buffer size could not be changed, %d", result.error());
|
||||
}
|
||||
}
|
||||
|
||||
bool HelloOboeEngine::isLatencyDetectionSupported() {
|
||||
return mIsLatencyDetectionSupported;
|
||||
}
|
||||
|
||||
bool HelloOboeEngine::isAAudioRecommended() {
|
||||
return oboe::AudioStreamBuilder::isAAudioRecommended();
|
||||
}
|
||||
|
||||
void HelloOboeEngine::tap(bool isDown) {
|
||||
if (mAudioSource) {
|
||||
mAudioSource->tap(isDown);
|
||||
}
|
||||
}
|
||||
|
||||
oboe::Result HelloOboeEngine::openPlaybackStream() {
|
||||
oboe::AudioStreamBuilder builder;
|
||||
oboe::Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
|
||||
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||
->setFormat(oboe::AudioFormat::Float)
|
||||
->setFormatConversionAllowed(true)
|
||||
->setDataCallback(mLatencyCallback)
|
||||
->setErrorCallback(mErrorCallback)
|
||||
->setAudioApi(mAudioApi)
|
||||
->setChannelCount(mChannelCount)
|
||||
->setDeviceId(mDeviceId)
|
||||
->openStream(mStream);
|
||||
if (result == oboe::Result::OK) {
|
||||
mChannelCount = mStream->getChannelCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HelloOboeEngine::restart() {
|
||||
// The stream will have already been closed by the error callback.
|
||||
mLatencyCallback->reset();
|
||||
start();
|
||||
}
|
||||
|
||||
oboe::Result HelloOboeEngine::start(oboe::AudioApi audioApi, int deviceId, int channelCount) {
|
||||
mAudioApi = audioApi;
|
||||
mDeviceId = deviceId;
|
||||
mChannelCount = channelCount;
|
||||
return start();
|
||||
}
|
||||
|
||||
oboe::Result HelloOboeEngine::start() {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
oboe::Result result = oboe::Result::OK;
|
||||
// It is possible for a stream's device to become disconnected during the open or between
|
||||
// the Open and the Start.
|
||||
// So if it fails to start, close the old stream and try again.
|
||||
int tryCount = 0;
|
||||
do {
|
||||
if (tryCount > 0) {
|
||||
usleep(20 * 1000); // Sleep between tries to give the system time to settle.
|
||||
}
|
||||
mIsLatencyDetectionSupported = false;
|
||||
result = openPlaybackStream();
|
||||
if (result == oboe::Result::OK) {
|
||||
mAudioSource = std::make_shared<SoundGenerator>(mStream->getSampleRate(),
|
||||
mStream->getChannelCount());
|
||||
mLatencyCallback->setSource(
|
||||
std::dynamic_pointer_cast<IRenderableAudio>(mAudioSource));
|
||||
|
||||
LOGD("Stream opened: AudioAPI = %d, channelCount = %d, deviceID = %d",
|
||||
mStream->getAudioApi(),
|
||||
mStream->getChannelCount(),
|
||||
mStream->getDeviceId());
|
||||
|
||||
result = mStream->requestStart();
|
||||
if (result != oboe::Result::OK) {
|
||||
LOGE("Error starting playback stream. Error: %s", oboe::convertToText(result));
|
||||
mStream->close();
|
||||
mStream.reset();
|
||||
} else {
|
||||
mIsLatencyDetectionSupported = (mStream->getTimestamp((CLOCK_MONOTONIC)) !=
|
||||
oboe::Result::ErrorUnimplemented);
|
||||
}
|
||||
} else {
|
||||
LOGE("Error creating playback stream. Error: %s", oboe::convertToText(result));
|
||||
}
|
||||
} while (result != oboe::Result::OK && tryCount++ < 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
oboe::Result HelloOboeEngine::stop() {
|
||||
oboe::Result result = oboe::Result::OK;
|
||||
// Stop, close and delete in case not already closed.
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
if (mStream) {
|
||||
result = mStream->stop();
|
||||
mStream->close();
|
||||
mStream.reset();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
oboe::Result HelloOboeEngine::reopenStream() {
|
||||
if (mStream) {
|
||||
stop();
|
||||
return start();
|
||||
} else {
|
||||
return oboe::Result::OK;
|
||||
}
|
||||
}
|
95
externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
vendored
Normal file
95
externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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 OBOE_HELLO_OBOE_ENGINE_H
|
||||
#define OBOE_HELLO_OBOE_ENGINE_H
|
||||
|
||||
#include <oboe/Oboe.h>
|
||||
|
||||
#include "SoundGenerator.h"
|
||||
#include "LatencyTuningCallback.h"
|
||||
#include "IRestartable.h"
|
||||
#include "DefaultErrorCallback.h"
|
||||
|
||||
constexpr int32_t kBufferSizeAutomatic = 0;
|
||||
|
||||
class HelloOboeEngine : public IRestartable {
|
||||
|
||||
public:
|
||||
HelloOboeEngine();
|
||||
|
||||
virtual ~HelloOboeEngine() = default;
|
||||
|
||||
void tap(bool isDown);
|
||||
|
||||
/**
|
||||
* Open and start a stream.
|
||||
* @param deviceId the audio device id, can be obtained through an {@link AudioDeviceInfo} object
|
||||
* using Java/JNI.
|
||||
* @return error or OK
|
||||
*/
|
||||
oboe::Result start(oboe::AudioApi audioApi, int deviceId, int channelCount);
|
||||
/* Start using current settings. */
|
||||
oboe::Result start();
|
||||
|
||||
/**
|
||||
* Stop and close the stream.
|
||||
*/
|
||||
oboe::Result stop();
|
||||
|
||||
// From IRestartable
|
||||
void restart() override;
|
||||
|
||||
void setBufferSizeInBursts(int32_t numBursts);
|
||||
|
||||
/**
|
||||
* Calculate the current latency between writing a frame to the output stream and
|
||||
* the same frame being presented to the audio hardware.
|
||||
*
|
||||
* Here's how the calculation works:
|
||||
*
|
||||
* 1) Get the time a particular frame was presented to the audio hardware
|
||||
* @see AudioStream::getTimestamp
|
||||
* 2) From this extrapolate the time which the *next* audio frame written to the stream
|
||||
* will be presented
|
||||
* 3) Assume that the next audio frame is written at the current time
|
||||
* 4) currentLatency = nextFramePresentationTime - nextFrameWriteTime
|
||||
*
|
||||
* @return Output Latency in Milliseconds
|
||||
*/
|
||||
double getCurrentOutputLatencyMillis();
|
||||
|
||||
bool isLatencyDetectionSupported();
|
||||
|
||||
bool isAAudioRecommended();
|
||||
|
||||
private:
|
||||
oboe::Result reopenStream();
|
||||
oboe::Result openPlaybackStream();
|
||||
|
||||
std::shared_ptr<oboe::AudioStream> mStream;
|
||||
std::shared_ptr<LatencyTuningCallback> mLatencyCallback;
|
||||
std::shared_ptr<DefaultErrorCallback> mErrorCallback;
|
||||
std::shared_ptr<SoundGenerator> mAudioSource;
|
||||
bool mIsLatencyDetectionSupported = false;
|
||||
|
||||
int32_t mDeviceId = oboe::Unspecified;
|
||||
int32_t mChannelCount = oboe::Unspecified;
|
||||
oboe::AudioApi mAudioApi = oboe::AudioApi::Unspecified;
|
||||
std::mutex mLock;
|
||||
};
|
||||
|
||||
#endif //OBOE_HELLO_OBOE_ENGINE_H
|
45
externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.cpp
vendored
Normal file
45
externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.cpp
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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 "LatencyTuningCallback.h"
|
||||
|
||||
oboe::DataCallbackResult LatencyTuningCallback::onAudioReady(
|
||||
oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) {
|
||||
if (oboeStream != mStream) {
|
||||
mStream = oboeStream;
|
||||
mLatencyTuner = std::make_unique<oboe::LatencyTuner>(*oboeStream);
|
||||
}
|
||||
if (mBufferTuneEnabled
|
||||
&& mLatencyTuner
|
||||
&& oboeStream->getAudioApi() == oboe::AudioApi::AAudio) {
|
||||
mLatencyTuner->tune();
|
||||
}
|
||||
auto underrunCountResult = oboeStream->getXRunCount();
|
||||
int bufferSize = oboeStream->getBufferSizeInFrames();
|
||||
/**
|
||||
* The following output can be seen by running a systrace. Tracing is preferable to logging
|
||||
* inside the callback since tracing does not block.
|
||||
*
|
||||
* See https://developer.android.com/studio/profile/systrace-commandline.html
|
||||
*/
|
||||
if (Trace::isEnabled()) Trace::beginSection("numFrames %d, Underruns %d, buffer size %d",
|
||||
numFrames, underrunCountResult.value(), bufferSize);
|
||||
auto result = DefaultDataCallback::onAudioReady(oboeStream, audioData, numFrames);
|
||||
if (Trace::isEnabled()) Trace::endSection();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
67
externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.h
vendored
Normal file
67
externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.h
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* 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 SAMPLES_LATENCY_TUNING_CALLBACK_H
|
||||
#define SAMPLES_LATENCY_TUNING_CALLBACK_H
|
||||
|
||||
#include <oboe/Oboe.h>
|
||||
#include <oboe/LatencyTuner.h>
|
||||
|
||||
#include <TappableAudioSource.h>
|
||||
#include <DefaultDataCallback.h>
|
||||
#include <trace.h>
|
||||
|
||||
/**
|
||||
* This callback object extends the functionality of `DefaultDataCallback` by automatically
|
||||
* tuning the latency of the audio stream. @see onAudioReady for more details on this.
|
||||
*
|
||||
* It also demonstrates how to use tracing functions for logging inside the audio callback without
|
||||
* blocking.
|
||||
*/
|
||||
class LatencyTuningCallback: public DefaultDataCallback {
|
||||
public:
|
||||
LatencyTuningCallback() : DefaultDataCallback() {
|
||||
|
||||
// Initialize the trace functions, this enables you to output trace statements without
|
||||
// blocking. See https://developer.android.com/studio/profile/systrace-commandline.html
|
||||
Trace::initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Every time the playback stream requires data this method will be called.
|
||||
*
|
||||
* @param audioStream the audio stream which is requesting data, this is the mPlayStream object
|
||||
* @param audioData an empty buffer into which we can write our audio data
|
||||
* @param numFrames the number of audio frames which are required
|
||||
* @return Either oboe::DataCallbackResult::Continue if the stream should continue requesting data
|
||||
* or oboe::DataCallbackResult::Stop if the stream should stop.
|
||||
*/
|
||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override;
|
||||
|
||||
void setBufferTuneEnabled(bool enabled) {mBufferTuneEnabled = enabled;}
|
||||
|
||||
void useStream(std::shared_ptr<oboe::AudioStream> stream);
|
||||
|
||||
private:
|
||||
bool mBufferTuneEnabled = true;
|
||||
|
||||
// This will be used to automatically tune the buffer size of the stream, obtaining optimal latency
|
||||
std::unique_ptr<oboe::LatencyTuner> mLatencyTuner;
|
||||
oboe::AudioStream *mStream = nullptr;
|
||||
};
|
||||
|
||||
#endif //SAMPLES_LATENCY_TUNING_CALLBACK_H
|
51
externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.cpp
vendored
Normal file
51
externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.cpp
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 "SoundGenerator.h"
|
||||
|
||||
SoundGenerator::SoundGenerator(int32_t sampleRate, int32_t channelCount) :
|
||||
TappableAudioSource(sampleRate, channelCount)
|
||||
, mOscillators(std::make_unique<Oscillator[]>(channelCount)){
|
||||
|
||||
double frequency = 440.0;
|
||||
constexpr double interval = 110.0;
|
||||
constexpr float amplitude = 1.0;
|
||||
|
||||
// Set up the oscillators
|
||||
for (int i = 0; i < mChannelCount; ++i) {
|
||||
mOscillators[i].setFrequency(frequency);
|
||||
mOscillators[i].setSampleRate(mSampleRate);
|
||||
mOscillators[i].setAmplitude(amplitude);
|
||||
frequency += interval;
|
||||
}
|
||||
}
|
||||
|
||||
void SoundGenerator::renderAudio(float *audioData, int32_t numFrames) {
|
||||
// Render each oscillator into its own channel
|
||||
std::fill_n(mBuffer.get(), kSharedBufferSize, 0);
|
||||
for (int i = 0; i < mChannelCount; ++i) {
|
||||
mOscillators[i].renderAudio(mBuffer.get(), numFrames);
|
||||
for (int j = 0; j < numFrames; ++j) {
|
||||
audioData[(j * mChannelCount) + i] = mBuffer[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundGenerator::tap(bool isOn) {
|
||||
for (int i = 0; i < mChannelCount; ++i) {
|
||||
mOscillators[i].setWaveOn(isOn);
|
||||
}
|
||||
}
|
58
externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.h
vendored
Normal file
58
externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.h
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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 SAMPLES_SOUNDGENERATOR_H
|
||||
#define SAMPLES_SOUNDGENERATOR_H
|
||||
|
||||
|
||||
#include <Oscillator.h>
|
||||
#include <TappableAudioSource.h>
|
||||
|
||||
/**
|
||||
* Generates a fixed frequency tone for each channel.
|
||||
* Implements RenderableTap (sound source with toggle) which is required for AudioEngines.
|
||||
*/
|
||||
class SoundGenerator : public TappableAudioSource {
|
||||
static constexpr size_t kSharedBufferSize = 1024;
|
||||
public:
|
||||
/**
|
||||
* Create a new SoundGenerator object.
|
||||
*
|
||||
* @param sampleRate - The output sample rate.
|
||||
* @param maxFrames - The maximum number of audio frames which will be rendered, this is used to
|
||||
* calculate this object's internal buffer size.
|
||||
* @param channelCount - The number of channels in the output, one tone will be created for each
|
||||
* channel, the output will be interlaced.
|
||||
*
|
||||
*/
|
||||
SoundGenerator(int32_t sampleRate, int32_t channelCount);
|
||||
~SoundGenerator() = default;
|
||||
|
||||
SoundGenerator(SoundGenerator&& other) = default;
|
||||
SoundGenerator& operator= (SoundGenerator&& other) = default;
|
||||
|
||||
// Switch the tones on
|
||||
void tap(bool isOn) override;
|
||||
|
||||
void renderAudio(float *audioData, int32_t numFrames) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Oscillator[]> mOscillators;
|
||||
std::unique_ptr<float[]> mBuffer = std::make_unique<float[]>(kSharedBufferSize);
|
||||
};
|
||||
|
||||
|
||||
#endif //SAMPLES_SOUNDGENERATOR_H
|
90
externals/oboe/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
vendored
Normal file
90
externals/oboe/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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 <jni.h>
|
||||
#include <oboe/Oboe.h>
|
||||
#include "HelloOboeEngine.h"
|
||||
#include "logging_macros.h"
|
||||
|
||||
extern "C" {
|
||||
/* We only need one HelloOboeEngine and it is needed for the entire time.
|
||||
* So just allocate one statically. */
|
||||
static HelloOboeEngine sEngine;
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_startEngine(
|
||||
JNIEnv *env,
|
||||
jclass,
|
||||
int audioApi, int deviceId, int channelCount) {
|
||||
return static_cast<jint>(sEngine.start((oboe::AudioApi)audioApi, deviceId, channelCount));
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_stopEngine(
|
||||
JNIEnv *env,
|
||||
jclass) {
|
||||
return static_cast<jint>(sEngine.stop());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setToneOn(
|
||||
JNIEnv *env,
|
||||
jclass,
|
||||
jboolean isToneOn) {
|
||||
|
||||
sEngine.tap(isToneOn);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setBufferSizeInBursts(
|
||||
JNIEnv *env,
|
||||
jclass,
|
||||
jint bufferSizeInBursts) {
|
||||
sEngine.setBufferSizeInBursts(bufferSizeInBursts);
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_getCurrentOutputLatencyMillis(
|
||||
JNIEnv *env,
|
||||
jclass) {
|
||||
return static_cast<jdouble>(sEngine.getCurrentOutputLatencyMillis());
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_isLatencyDetectionSupported(
|
||||
JNIEnv *env,
|
||||
jclass) {
|
||||
return (sEngine.isLatencyDetectionSupported() ? JNI_TRUE : JNI_FALSE);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_isAAudioRecommended(
|
||||
JNIEnv *env,
|
||||
jclass) {
|
||||
return (sEngine.isAAudioRecommended() ? JNI_TRUE : JNI_FALSE);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setDefaultStreamValues(
|
||||
JNIEnv *env,
|
||||
jclass,
|
||||
jint sampleRate,
|
||||
jint framesPerBurst) {
|
||||
oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
|
||||
oboe::DefaultStreamValues::FramesPerBurst = (int32_t) framesPerBurst;
|
||||
}
|
||||
} // extern "C"
|
|
@ -0,0 +1,56 @@
|
|||
package com.google.oboe.samples.hellooboe;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Message;
|
||||
|
||||
/** Run Audio function in a background thread.
|
||||
* This will avoid ANRs that can occur if the AudioServer or HAL crashes
|
||||
* and takes a long time to recover.
|
||||
*
|
||||
* This thread will run for the lifetime of the app so only make one BackgroundRunner
|
||||
* and reuse it.
|
||||
*/
|
||||
public abstract class BackgroundRunner {
|
||||
private Handler mHandler;
|
||||
private HandlerThread mThread = new HandlerThread("BackgroundRunner");
|
||||
|
||||
public BackgroundRunner() {
|
||||
mThread.start();
|
||||
mHandler = new Handler(mThread.getLooper()) {
|
||||
public void handleMessage(Message message) {
|
||||
super.handleMessage(message);
|
||||
handleMessageInBackground(message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @return true if the message was successfully queued
|
||||
*/
|
||||
public boolean sendMessage(Message message) {
|
||||
return mHandler.sendMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param what command code for background operation
|
||||
* @param arg1 optional argument
|
||||
* @return true if the message was successfully queued
|
||||
*/
|
||||
public boolean sendMessage(int what, int arg1) {
|
||||
Message message = mHandler.obtainMessage();
|
||||
message.what = what;
|
||||
message.arg1 = arg1;
|
||||
return sendMessage(message);
|
||||
}
|
||||
|
||||
public boolean sendMessage(int what) {
|
||||
return sendMessage(what, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this in your app.
|
||||
*/
|
||||
abstract void handleMessageInBackground(Message message);
|
||||
}
|
456
externals/oboe/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/MainActivity.java
vendored
Normal file
456
externals/oboe/samples/hello-oboe/src/main/java/com/google/oboe/samples/hellooboe/MainActivity.java
vendored
Normal file
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
* 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.google.oboe.samples.hellooboe;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.SimpleAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.oboe.samples.audio_device.AudioDeviceListEntry;
|
||||
import com.google.oboe.samples.audio_device.AudioDeviceSpinner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
private static final String TAG = "HelloOboe";
|
||||
private static final long UPDATE_LATENCY_EVERY_MILLIS = 1000;
|
||||
private static final Integer[] CHANNEL_COUNT_OPTIONS = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
// Default to Stereo (OPTIONS is zero-based array so index 1 = 2 channels)
|
||||
private static final int CHANNEL_COUNT_DEFAULT_OPTION_INDEX = 1;
|
||||
private static final int[] BUFFER_SIZE_OPTIONS = {0, 1, 2, 4, 8};
|
||||
private static final String[] AUDIO_API_OPTIONS = {"Unspecified", "OpenSL ES", "AAudio"};
|
||||
private static final int OBOE_API_OPENSL_ES = 1;
|
||||
// Default all other spinners to the first option on the list
|
||||
private static final int SPINNER_DEFAULT_OPTION_INDEX = 0;
|
||||
|
||||
private Spinner mAudioApiSpinner;
|
||||
private AudioDeviceSpinner mPlaybackDeviceSpinner;
|
||||
private Spinner mChannelCountSpinner;
|
||||
private Spinner mBufferSizeSpinner;
|
||||
private TextView mLatencyText;
|
||||
private Timer mLatencyUpdater;
|
||||
private boolean mScoStarted = false;
|
||||
|
||||
/** Commands for background thread. */
|
||||
private static final int WHAT_START = 100;
|
||||
private static final int WHAT_STOP = 101;
|
||||
private static final int WHAT_SET_DEVICE_ID = 102;
|
||||
private static final int WHAT_SET_AUDIO_API = 103;
|
||||
private static final int WHAT_SET_CHANNEL_COUNT = 104;
|
||||
private BackgroundRunner mRunner = new MyBackgroundRunner();
|
||||
|
||||
private class MyBackgroundRunner extends BackgroundRunner {
|
||||
// These are initialized to zero by Java.
|
||||
// Zero matches the oboe::Unspecified value.
|
||||
int audioApi;
|
||||
int deviceId;
|
||||
int channelCount;
|
||||
|
||||
@Override
|
||||
/* Execute this in a background thread to avoid ANRs. */
|
||||
void handleMessageInBackground(Message message) {
|
||||
int what = message.what;
|
||||
int arg1 = message.arg1;
|
||||
Log.i(MainActivity.TAG, "got background message, what = " + what + ", arg1 = " + arg1);
|
||||
int result = 0;
|
||||
boolean restart = false;
|
||||
switch (what) {
|
||||
case WHAT_START:
|
||||
result = PlaybackEngine.startEngine(audioApi, deviceId, channelCount);
|
||||
break;
|
||||
case WHAT_STOP:
|
||||
result = PlaybackEngine.stopEngine();
|
||||
break;
|
||||
case WHAT_SET_AUDIO_API:
|
||||
if (audioApi != arg1) {
|
||||
audioApi = arg1;
|
||||
restart = true;
|
||||
}
|
||||
break;
|
||||
case WHAT_SET_DEVICE_ID:
|
||||
if (deviceId != arg1) {
|
||||
deviceId = arg1;
|
||||
restart = true;
|
||||
}
|
||||
break;
|
||||
case WHAT_SET_CHANNEL_COUNT:
|
||||
if (channelCount != arg1) {
|
||||
channelCount = arg1;
|
||||
restart = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (restart) {
|
||||
int result1 = PlaybackEngine.stopEngine();
|
||||
int result2 = PlaybackEngine.startEngine(audioApi, deviceId, channelCount);
|
||||
result = (result2 != 0) ? result2 : result1;
|
||||
}
|
||||
if (result != 0) {
|
||||
Log.e(TAG, "audio error " + result);
|
||||
showToast("Error in audio =" + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook to user control to start / stop audio playback:
|
||||
* touch-down: start, and keeps on playing
|
||||
* touch-up: stop.
|
||||
* simply pass the events to native side.
|
||||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case (MotionEvent.ACTION_DOWN):
|
||||
PlaybackEngine.setToneOn(true);
|
||||
break;
|
||||
case (MotionEvent.ACTION_UP):
|
||||
PlaybackEngine.setToneOn(false);
|
||||
break;
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
mLatencyText = findViewById(R.id.latencyText);
|
||||
setupAudioApiSpinner();
|
||||
setupPlaybackDeviceSpinner();
|
||||
setupChannelCountSpinner();
|
||||
setupBufferSizeSpinner();
|
||||
}
|
||||
|
||||
/*
|
||||
* Creating engine in onResume() and destroying in onPause() so the stream retains exclusive
|
||||
* mode only while in focus. This allows other apps to reclaim exclusive stream mode.
|
||||
*/
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
PlaybackEngine.setDefaultStreamValues(this);
|
||||
setupLatencyUpdater();
|
||||
|
||||
// Return the spinner states to their default value
|
||||
mChannelCountSpinner.setSelection(CHANNEL_COUNT_DEFAULT_OPTION_INDEX);
|
||||
mPlaybackDeviceSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
|
||||
mBufferSizeSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
|
||||
if (PlaybackEngine.isAAudioRecommended()) {
|
||||
mAudioApiSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
|
||||
} else {
|
||||
mAudioApiSpinner.setSelection(OBOE_API_OPENSL_ES);
|
||||
mAudioApiSpinner.setEnabled(false);
|
||||
}
|
||||
|
||||
startAudioAsync();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (mLatencyUpdater != null) mLatencyUpdater.cancel();
|
||||
stopAudioAsync();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
clearCommunicationDevice();
|
||||
} else {
|
||||
if (mScoStarted) {
|
||||
stopBluetoothSco();
|
||||
mScoStarted = false;
|
||||
}
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private void setupChannelCountSpinner() {
|
||||
mChannelCountSpinner = findViewById(R.id.channelCountSpinner);
|
||||
|
||||
ArrayAdapter<Integer> channelCountAdapter = new ArrayAdapter<>(this, R.layout.channel_counts_spinner, CHANNEL_COUNT_OPTIONS);
|
||||
mChannelCountSpinner.setAdapter(channelCountAdapter);
|
||||
mChannelCountSpinner.setSelection(CHANNEL_COUNT_DEFAULT_OPTION_INDEX);
|
||||
|
||||
mChannelCountSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
setChannelCountAsync(CHANNEL_COUNT_OPTIONS[mChannelCountSpinner.getSelectedItemPosition()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupBufferSizeSpinner() {
|
||||
mBufferSizeSpinner = findViewById(R.id.bufferSizeSpinner);
|
||||
mBufferSizeSpinner.setAdapter(new SimpleAdapter(
|
||||
this,
|
||||
createBufferSizeOptionsList(), // list of buffer size options
|
||||
R.layout.buffer_sizes_spinner, // the xml layout
|
||||
new String[]{getString(R.string.buffer_size_description_key)}, // field to display
|
||||
new int[]{R.id.bufferSizeOption} // View to show field in
|
||||
));
|
||||
|
||||
mBufferSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
PlaybackEngine.setBufferSizeInBursts(getBufferSizeInBursts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupPlaybackDeviceSpinner() {
|
||||
mPlaybackDeviceSpinner = findViewById(R.id.playbackDevicesSpinner);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
mPlaybackDeviceSpinner.setDirectionType(AudioManager.GET_DEVICES_OUTPUTS);
|
||||
mPlaybackDeviceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
// To use Bluetooth SCO, setCommunicationDevice() or startBluetoothSco() must
|
||||
// be called. The AudioManager.startBluetoothSco() is deprecated in Android T.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (isScoDevice(getPlaybackDeviceId())){
|
||||
setCommunicationDevice(getPlaybackDeviceId());
|
||||
} else {
|
||||
clearCommunicationDevice();
|
||||
}
|
||||
} else {
|
||||
// Start Bluetooth SCO if needed.
|
||||
if (isScoDevice(getPlaybackDeviceId()) && !mScoStarted) {
|
||||
startBluetoothSco();
|
||||
mScoStarted = true;
|
||||
} else if (!isScoDevice(getPlaybackDeviceId()) && mScoStarted) {
|
||||
stopBluetoothSco();
|
||||
mScoStarted = false;
|
||||
}
|
||||
}
|
||||
setAudioDeviceIdAsync(getPlaybackDeviceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mPlaybackDeviceSpinner.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupAudioApiSpinner() {
|
||||
mAudioApiSpinner = findViewById(R.id.audioApiSpinner);
|
||||
mAudioApiSpinner.setAdapter(new SimpleAdapter(
|
||||
this,
|
||||
createAudioApisOptionsList(),
|
||||
R.layout.audio_apis_spinner, // the xml layout
|
||||
new String[]{getString(R.string.audio_api_description_key)}, // field to display
|
||||
new int[]{R.id.audioApiOption} // View to show field in
|
||||
));
|
||||
|
||||
mAudioApiSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
setAudioApiAsync(i);
|
||||
if (i == OBOE_API_OPENSL_ES) {
|
||||
mPlaybackDeviceSpinner.setSelection(SPINNER_DEFAULT_OPTION_INDEX);
|
||||
mPlaybackDeviceSpinner.setEnabled(false);
|
||||
} else {
|
||||
mPlaybackDeviceSpinner.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int getPlaybackDeviceId() {
|
||||
return ((AudioDeviceListEntry) mPlaybackDeviceSpinner.getSelectedItem()).getId();
|
||||
}
|
||||
|
||||
private int getBufferSizeInBursts() {
|
||||
@SuppressWarnings("unchecked")
|
||||
HashMap<String, String> selectedOption = (HashMap<String, String>)
|
||||
mBufferSizeSpinner.getSelectedItem();
|
||||
|
||||
String valueKey = getString(R.string.buffer_size_value_key);
|
||||
|
||||
// parseInt will throw a NumberFormatException if the string doesn't contain a valid integer
|
||||
// representation. We don't need to worry about this because the values are derived from
|
||||
// the BUFFER_SIZE_OPTIONS int array.
|
||||
return Integer.parseInt(Objects.requireNonNull(selectedOption.get(valueKey)));
|
||||
}
|
||||
|
||||
private void setupLatencyUpdater() {
|
||||
//Update the latency every 1s
|
||||
TimerTask latencyUpdateTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
final String latencyStr;
|
||||
if (PlaybackEngine.isLatencyDetectionSupported()) {
|
||||
double latency = PlaybackEngine.getCurrentOutputLatencyMillis();
|
||||
if (latency >= 0) {
|
||||
latencyStr = String.format(Locale.getDefault(), "%.2fms", latency);
|
||||
} else {
|
||||
latencyStr = "Unknown";
|
||||
}
|
||||
} else {
|
||||
latencyStr = getString(R.string.only_supported_on_api_26);
|
||||
}
|
||||
|
||||
runOnUiThread(() -> mLatencyText.setText(getString(R.string.latency, latencyStr)));
|
||||
}
|
||||
};
|
||||
mLatencyUpdater = new Timer();
|
||||
mLatencyUpdater.schedule(latencyUpdateTask, 0, UPDATE_LATENCY_EVERY_MILLIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of buffer size options which can be used to populate a SimpleAdapter.
|
||||
* Each option has a description and a value. The description is always equal to the value,
|
||||
* except when the value is zero as this indicates that the buffer size should be set
|
||||
* automatically by the audio engine
|
||||
*
|
||||
* @return list of buffer size options
|
||||
*/
|
||||
private List<HashMap<String, String>> createBufferSizeOptionsList() {
|
||||
|
||||
ArrayList<HashMap<String, String>> bufferSizeOptions = new ArrayList<>();
|
||||
|
||||
for (int i : BUFFER_SIZE_OPTIONS) {
|
||||
HashMap<String, String> option = new HashMap<>();
|
||||
String strValue = String.valueOf(i);
|
||||
String description = (i == 0) ? getString(R.string.automatic) : strValue;
|
||||
option.put(getString(R.string.buffer_size_description_key), description);
|
||||
option.put(getString(R.string.buffer_size_value_key), strValue);
|
||||
|
||||
bufferSizeOptions.add(option);
|
||||
}
|
||||
|
||||
return bufferSizeOptions;
|
||||
}
|
||||
|
||||
private List<HashMap<String, String>> createAudioApisOptionsList() {
|
||||
|
||||
ArrayList<HashMap<String, String>> audioApiOptions = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < AUDIO_API_OPTIONS.length; i++) {
|
||||
HashMap<String, String> option = new HashMap<>();
|
||||
option.put(getString(R.string.buffer_size_description_key), AUDIO_API_OPTIONS[i]);
|
||||
option.put(getString(R.string.buffer_size_value_key), String.valueOf(i));
|
||||
audioApiOptions.add(option);
|
||||
}
|
||||
return audioApiOptions;
|
||||
}
|
||||
|
||||
protected void showToast(final String message) {
|
||||
runOnUiThread(() -> Toast.makeText(MainActivity.this,
|
||||
message,
|
||||
Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.S)
|
||||
private void setCommunicationDevice(int deviceId) {
|
||||
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
final AudioDeviceInfo[] devices;
|
||||
devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
|
||||
for (AudioDeviceInfo device : devices) {
|
||||
if (device.getId() == deviceId) {
|
||||
audioManager.setCommunicationDevice(device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.S)
|
||||
private void clearCommunicationDevice() {
|
||||
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.clearCommunicationDevice();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private boolean isScoDevice(int deviceId) {
|
||||
if (deviceId == 0) return false; // Unspecified
|
||||
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
final AudioDeviceInfo[] devices;
|
||||
devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
|
||||
for (AudioDeviceInfo device : devices) {
|
||||
if (device.getId() == deviceId) {
|
||||
return device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startBluetoothSco() {
|
||||
AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
myAudioMgr.startBluetoothSco();
|
||||
}
|
||||
|
||||
private void stopBluetoothSco() {
|
||||
AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
myAudioMgr.stopBluetoothSco();
|
||||
}
|
||||
|
||||
|
||||
void startAudioAsync() {
|
||||
mRunner.sendMessage(WHAT_START);
|
||||
}
|
||||
|
||||
void stopAudioAsync() {
|
||||
mRunner.sendMessage(WHAT_STOP);
|
||||
}
|
||||
|
||||
void setAudioApiAsync(int audioApi){
|
||||
mRunner.sendMessage(WHAT_SET_AUDIO_API, audioApi);
|
||||
}
|
||||
|
||||
void setAudioDeviceIdAsync(int deviceId){
|
||||
mRunner.sendMessage(WHAT_SET_DEVICE_ID, deviceId);
|
||||
}
|
||||
|
||||
void setChannelCountAsync(int channelCount) {
|
||||
mRunner.sendMessage(WHAT_SET_CHANNEL_COUNT, channelCount);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.google.oboe.samples.hellooboe;
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
|
||||
public class PlaybackEngine {
|
||||
// Load native library
|
||||
static {
|
||||
System.loadLibrary("hello-oboe");
|
||||
}
|
||||
|
||||
static void setDefaultStreamValues(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
|
||||
AudioManager myAudioMgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
|
||||
int defaultSampleRate = Integer.parseInt(sampleRateStr);
|
||||
String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
|
||||
int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr);
|
||||
|
||||
setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Native methods that require audioserver calls and might take several seconds.
|
||||
static native int startEngine(int audioApi, int deviceId, int channelCount);
|
||||
static native int stopEngine();
|
||||
|
||||
// Native methods that only talk to the native client code.
|
||||
static native void setToneOn(boolean isToneOn);
|
||||
static native void setBufferSizeInBursts(int bufferSizeInBursts);
|
||||
static native double getCurrentOutputLatencyMillis();
|
||||
static native boolean isLatencyDetectionSupported();
|
||||
static native boolean isAAudioRecommended();
|
||||
static native void setDefaultStreamValues(int sampleRate, int framesPerBurst);
|
||||
}
|
154
externals/oboe/samples/hello-oboe/src/main/res/layout/activity_main.xml
vendored
Normal file
154
externals/oboe/samples/hello-oboe/src/main/res/layout/activity_main.xml
vendored
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<!-- Audio API container -->
|
||||
<LinearLayout
|
||||
android:id="@+id/audioApisContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/audio_api"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:id="@+id/audioApisTitleText"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"
|
||||
/>
|
||||
<Spinner
|
||||
android:id="@+id/audioApiSpinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Playback device container -->
|
||||
<LinearLayout
|
||||
android:id="@+id/playbackDevicesContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toBottomOf="@id/audioApisContainer"
|
||||
app:layout_constraintLeft_toLeftOf="parent">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/playback_device"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:id="@+id/playbackDeviceTitleText"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<com.google.oboe.samples.audio_device.AudioDeviceSpinner
|
||||
android:id="@+id/playbackDevicesSpinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Channel count container -->
|
||||
<LinearLayout
|
||||
android:id="@+id/channelCountContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toBottomOf="@id/playbackDevicesContainer"
|
||||
app:layout_constraintLeft_toLeftOf="parent">
|
||||
<TextView
|
||||
android:id="@+id/channelCountTitleText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:text="Channel count"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
<Spinner
|
||||
android:id="@+id/channelCountSpinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Buffer size container -->
|
||||
<LinearLayout
|
||||
android:id="@+id/bufferSizeContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintTop_toBottomOf="@id/channelCountContainer"
|
||||
app:layout_constraintLeft_toLeftOf="parent">
|
||||
<TextView
|
||||
android:id="@+id/bufferSizeTitleText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:text="@string/buffer_size_title"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/bufferSizeSpinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:layout_gravity="center_vertical"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Audio stream latency -->
|
||||
<TextView
|
||||
android:id="@+id/latencyText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/latency"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bufferSizeContainer"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin" />
|
||||
|
||||
<!-- User instructions -->
|
||||
<TextView
|
||||
android:id="@+id/userInstructionView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||
android:layout_marginTop="20dp"
|
||||
android:lines="3"
|
||||
android:text="@string/init_status"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/latencyText"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
23
externals/oboe/samples/hello-oboe/src/main/res/layout/audio_apis_spinner.xml
vendored
Normal file
23
externals/oboe/samples/hello-oboe/src/main/res/layout/audio_apis_spinner.xml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/audioApiOption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/default_padding"
|
||||
/>
|
23
externals/oboe/samples/hello-oboe/src/main/res/layout/buffer_sizes_spinner.xml
vendored
Normal file
23
externals/oboe/samples/hello-oboe/src/main/res/layout/buffer_sizes_spinner.xml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/bufferSizeOption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/default_padding"
|
||||
/>
|
23
externals/oboe/samples/hello-oboe/src/main/res/layout/channel_counts_spinner.xml
vendored
Normal file
23
externals/oboe/samples/hello-oboe/src/main/res/layout/channel_counts_spinner.xml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 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.
|
||||
-->
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/channelCountOption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/default_padding"
|
||||
/>
|
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-hdpi/ic_launcher.png
vendored
Normal file
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-hdpi/ic_launcher.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-mdpi/ic_launcher.png
vendored
Normal file
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-mdpi/ic_launcher.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-xhdpi/ic_launcher.png
vendored
Normal file
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-xhdpi/ic_launcher.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-xxhdpi/ic_launcher.png
vendored
Normal file
BIN
externals/oboe/samples/hello-oboe/src/main/res/mipmap-xxhdpi/ic_launcher.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.5 KiB |
5
externals/oboe/samples/hello-oboe/src/main/res/values-v21/styles.xml
vendored
Normal file
5
externals/oboe/samples/hello-oboe/src/main/res/values-v21/styles.xml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="android:Theme.Material.Light">
|
||||
</style>
|
||||
</resources>
|
6
externals/oboe/samples/hello-oboe/src/main/res/values-w820dp/dimens.xml
vendored
Normal file
6
externals/oboe/samples/hello-oboe/src/main/res/values-w820dp/dimens.xml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<resources>
|
||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||
(such as screen margins) for screens with more than 820dp of available width. This
|
||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||
</resources>
|
5
externals/oboe/samples/hello-oboe/src/main/res/values/dimens.xml
vendored
Normal file
5
externals/oboe/samples/hello-oboe/src/main/res/values/dimens.xml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
</resources>
|
16
externals/oboe/samples/hello-oboe/src/main/res/values/strings.xml
vendored
Normal file
16
externals/oboe/samples/hello-oboe/src/main/res/values/strings.xml
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<resources>
|
||||
<string name="app_name">Hello Oboe</string>
|
||||
<string name="init_status">Touch anywhere on the screen to play audio</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="need_record_audio_permission">"This sample needs RECORD_AUDIO permission"</string>
|
||||
<string name="playback_device">Playback device</string>
|
||||
<string name="latency">Latency: %s</string>
|
||||
<string name="buffer_size_title">Buffer size</string>
|
||||
<string name="automatic">Automatic</string>
|
||||
<string name="buffer_size_description_key">description</string>
|
||||
<string name="buffer_size_value_key">value</string>
|
||||
<string name="audio_api_description_key">description</string>
|
||||
<string name="audio_api_value_key">value</string>
|
||||
<string name="only_supported_on_api_26">Only supported in AAudio (API 26+)</string>
|
||||
<string name="audio_api">Audio API</string>
|
||||
</resources>
|
8
externals/oboe/samples/hello-oboe/src/main/res/values/styles.xml
vendored
Normal file
8
externals/oboe/samples/hello-oboe/src/main/res/values/styles.xml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue