more android progress

This commit is contained in:
Stefano D'Angelo 2023-07-27 16:48:03 +02:00
parent 9e31fb8058
commit b719737eda
5 changed files with 163 additions and 23 deletions

View File

@ -12,6 +12,15 @@ import android.content.pm.PackageManager;
import androidx.core.app.ActivityCompat;
public class MainActivity extends Activity {
static {
System.loadLibrary("@NAME@");
}
public native boolean nativeAudioStart();
public native void nativeAudioStop();
public native float nativeGetParameter(int i);
public native void nativeSetParameter(int i, float v);
private WebView webView;
public class WebAppInterface {
@ -21,9 +30,28 @@ public class MainActivity extends Activity {
}
@JavascriptInterface
public boolean requestAudioPermission() {
public void requestAudioPermission() {
ActivityCompat.requestPermissions(MainActivity.this, new String[] { android.Manifest.permission.RECORD_AUDIO }, 0);
return false;
}
@JavascriptInterface
public boolean audioStart() {
return nativeAudioStart();
}
@JavascriptInterface
public void audioStop() {
nativeAudioStop();
}
@JavascriptInterface
public float getParameter(int i) {
return nativeGetParameter(i);
}
@JavascriptInterface
public void setParameter(int i, float v) {
nativeSetParameter(i, v);
}
}

View File

@ -1,6 +1,7 @@
COMMON_DIR := ${ROOT_DIR}/../../common/android
BUILD_TOOLS_DIR := ${HOME}/Android/Sdk/build-tools/34.0.0
ANDROIDX_DIR := ${HOME}/Android/androidx
MINIAUDIO_DIR := ${ROOT_DIR}/../../../../miniaudio
JAR_FILE := ${HOME}/Android/Sdk/platforms/android-34/android.jar
ANDROIDX_CORE_FILE := ${ANDROIDX_DIR}/core-1.10.1.jar
@ -26,6 +27,7 @@ CXXFLAGS := \
-I${ROOT_DIR}/../src \
-I${COMMON_DIR} \
-I${ROOT_DIR}/../../../include \
-I${MINIAUDIO_DIR} \
-O3 \
-Wall \
-Wextra \
@ -39,7 +41,7 @@ LDFLAGS := \
-landroid
SOURCES_COMMON := \
${COMMON_DIR}/jni.cpp
build/gen/jni.cpp
JARS := \
${JAR_FILE} \
@ -50,6 +52,8 @@ JARS := \
${KOTLINX_COROUTINES_CORE_FILE} \
${KOTLINX_COROUTINES_CORE_JVM_FILE}
JNI_NAME := $(shell echo ${NAME} | sed 's:_:_1:g')
all: build/${NAME}.apk
build/${NAME}.apk: build/gen/${NAME}.aligned.apk build/apk/lib/armeabi-v7a/lib${NAME}.so build/gen/keystore.jks
@ -61,7 +65,7 @@ build/gen/keystore.jks: | build/gen
build/gen/${NAME}.aligned.apk: build/gen/${NAME}.unsigned.apk
${ZIPALIGN} -f -p 4 $^ $@
build/gen/${NAME}.unsigned.apk: build/apk/classes.dex build/gen/AndroidManifest.xml build/assets/index.html build/assets/config.js | build/gen
build/gen/${NAME}.unsigned.apk: build/apk/classes.dex build/gen/AndroidManifest.xml build/assets/index.html build/assets/config.js build/apk/lib/armeabi-v7a/lib${NAME}.so| build/gen
${AAPT} package -f -M build/gen/AndroidManifest.xml -A build/assets -I ${JAR_FILE} -I ${ANDROIDX_CORE_FILE} -I ${ANDROIDX_LIFECYCLE_COMMON_FILE} -I ${ANDROIDX_VERSIONEDPARCELABLE_FILE} -I ${KOTLIN_STDLIB_FILE} -I ${KOTLINX_COROUTINES_CORE_FILE} -I ${KOTLINX_COROUTINES_CORE_JVM_FILE} -F $@ build/apk
build/apk/classes.dex: build/apk/my_classes.jar
@ -73,6 +77,9 @@ build/apk/my_classes.jar: build/obj/com/orastron/${NAME}/MainActivity.class buil
build/apk/lib/armeabi-v7a/lib${NAME}.so: ${SOURCES} | build/apk/lib/armeabi-v7a
${CXX} $^ ${CXXFLAGS} ${LDFLAGS} -o $@
build/gen/jni.cpp: ${COMMON_DIR}/jni.cpp | build/gen
cat $^ | sed s:@JNI_NAME@:${JNI_NAME}:g > $@
build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class: build/obj/com/orastron/${NAME}/MainActivity.class
build/obj/com/orastron/${NAME}/MainActivity.class: build/gen/com/orastron/${NAME}/MainActivity.java | build/obj

View File

@ -2,35 +2,72 @@
<head>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript">
var hasAudioPermission = Android.hasAudioPermission();
var hasAudioPermission = true;
for (var i = 0; i < buses.length; i++)
if (!buses[i].output) {
hasAudioPermission = Android.hasAudioPermission();
break;
}
var audioStarted = false;
var topButtonElem;
var outParamInterval;
window.onload = function () {
topButtonElem = document.getElementById("topButton");
var paramsElem = document.getElementById("params");
topButtonElem.value = hasAudioPermission ? "START" : "INIT";
topButtonElem.addEventListener("click", function () {
if (hasAudioPermission) {
for (var i = 0; i < parameters.length; i++) {
var div = document.createElement("div");
document.body.appendChild(div);
if (audioStarted) {
clearInterval(outParamInterval);
Android.audioStop();
var label = document.createElement("label");
label.innerText = parameters[i].name;
div.appendChild(label);
paramsElem.innerHTML = "";
div.appendChild(document.createElement("br"));
topButtonElem.value = "START";
audioStarted = false;
} else {
if (Android.audioStart()) {
for (var i = 0; i < parameters.length; i++) {
var div = document.createElement("div");
paramsElem.appendChild(div);
var range = document.createElement("input");
range.classList.add("range");
range.setAttribute("type", "range");
range.setAttribute("id", "p" + i);
range.setAttribute("min", 0);
range.setAttribute("max", 1);
range.setAttribute("step", parameters[i].step ? 1 / parameters[i].step : "any");
range.value = parameters[i].defaultValue;
if (parameters[i].output)
range.setAttribute("readonly", true);
div.appendChild(range);
var label = document.createElement("label");
label.innerText = parameters[i].name;
div.appendChild(label);
div.appendChild(document.createElement("br"));
var range = document.createElement("input");
range.classList.add("range");
range.setAttribute("type", "range");
range.setAttribute("id", "p" + i);
range.setAttribute("min", 0);
range.setAttribute("max", 1);
range.setAttribute("step", parameters[i].step ? 1 / parameters[i].step : "any");
range.value = parameters[i].defaultValue;
if (parameters[i].output)
range.setAttribute("readonly", "readonly");
else
range.addEventListener("input",
function (ev) {
Android.setParameter(i, e.target.value);
});
div.appendChild(range);
}
outParamInterval = setInterval(
function () {
for (var i = 0; i < parameters.length; i++)
if (parameters[i].output)
document.getElementById("p" + i).value = Android.getParameter(i);
}, 50);
topButtonElem.value = "STOP";
audioStarted = true;
} else
alert("Could not start audio");
}
}
else
@ -59,5 +96,6 @@ function gotAudioPermission() {
</head>
<body>
<input id="topButton" type="button">
<div id="params"></div>
</body>
</html>

View File

@ -0,0 +1,61 @@
#include <jni.h>
#define MINIAUDIO_IMPLEMENTATION
#include <miniaudio.h>
#include "config.h"
extern "C" {
ma_device device;
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
}
JNIEXPORT jboolean JNICALL
Java_com_orastron_@JNI_NAME@_MainActivity_nativeAudioStart(JNIEnv* env, jobject thiz) {
#if NUM_CHANNELS_IN == 0
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback);
#else
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_duplex);
#endif
deviceConfig.sampleRate = 0;
deviceConfig.periodSizeInFrames = 64;
deviceConfig.periods = 1;
deviceConfig.noPreSilencedOutputBuffer = 1;
deviceConfig.noDisableDenormals = 0;
deviceConfig.performanceProfile = ma_performance_profile_low_latency;
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = NUM_CHANNELS_IN;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = NUM_CHANNELS_OUT;
deviceConfig.dataCallback = data_callback;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS)
return false;
if (ma_device_start(&device) != MA_SUCCESS) {
ma_device_uninit(&device);
return false;
}
return true;
}
JNIEXPORT void JNICALL
Java_com_orastron_@JNI_NAME@_MainActivity_nativeAudioStop(JNIEnv* env, jobject thiz) {
ma_device_stop(&device);
ma_device_uninit(&device);
}
JNIEXPORT jfloat JNICALL
Java_com_orastron_@JNI_NAME@_MainActivity_nativeGetParameter(JNIEnv* env, jobject thiz, jint i) {
return 0.3f;
}
JNIEXPORT void JNICALL
Java_com_orastron_@JNI_NAME@_MainActivity_nativeSetParameter(JNIEnv* env, jobject thiz, jint i, jfloat v) {
}
}

View File

@ -0,0 +1,6 @@
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME := bw_example_synth_simple
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_synth_simple.c
include ${ROOT_DIR}/../../common/android/android.mk