feat: audio resources

This commit is contained in:
2026-03-03 12:04:17 +01:00
parent d2c9a7b2ff
commit bc8002fd59
7 changed files with 109 additions and 9 deletions

View File

@@ -7,7 +7,7 @@
#include "PlaybackEngine.h"
#include "logging.h"
PlaybackEngine::PlaybackEngine() {
PlaybackEngine::PlaybackEngine(std::string filesDir): mFilesDir(filesDir) {
LOGI("PlaybackEngine()");
LOGI("NDK LOG_LEVEL=%d", LOG_LEVEL);
// NDK LOG_LEVEL=3 (DEBUG)

View File

@@ -6,13 +6,15 @@
#define LOCKSTEP_PLAYBACKENGINE_H
#include "OboeSinePlayer.h"
#include <string>
class PlaybackEngine {
public:
PlaybackEngine();
PlaybackEngine(std::string filesDir);
virtual ~PlaybackEngine();
private:
OboeSinePlayer *mPlayer;
std::string mFilesDir;
};
#endif //LOCKSTEP_PLAYBACKENGINE_H

View File

@@ -4,9 +4,12 @@
#include <jni.h>
#include "mpg123.h"
#include <oboe/Oboe.h>
extern "C" {
// nice-to: merge with lockstep.cpp
JNIEXPORT jint JNICALL
Java_at_lockstep_pb_PlaybackEngine_native_1mpg123_1init
(JNIEnv *env, jclass) {

View File

@@ -30,15 +30,13 @@ extern "C" {
JNIEXPORT jlong JNICALL
Java_at_lockstep_pb_PlaybackEngine_native_1createEngine(
JNIEnv *env,
jclass /*unused*/) {
/*
jclass /*unused*/, jstring filesDir) {
const char* filesDirTemp = env->GetStringUTFChars(filesDir, NULL);
std::string filesDirString(filesDirTemp);
env->ReleaseStringUTFChars(filesDir, filesDirTemp);
*/
// We use std::nothrow so `new` returns a nullptr if the engine creation fails
auto *engine = new(std::nothrow) PlaybackEngine();
auto *engine = new(std::nothrow) PlaybackEngine(filesDirString);
return reinterpret_cast<jlong>(engine);
}
@@ -51,4 +49,13 @@ jlong engineHandle) {
delete reinterpret_cast<PlaybackEngine *>(engineHandle);
}
JNIEXPORT void JNICALL
Java_at_lockstep_pb_PlaybackEngine_native_1setDefaultStreamValues(JNIEnv *env,
jclass type,
jint sampleRate,
jint framesPerBurst) {
oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
oboe::DefaultStreamValues::FramesPerBurst = (int32_t) framesPerBurst;
}
} // extern "C"

View File

@@ -0,0 +1,60 @@
package at.lockstep.pb;
import android.content.Context;
import android.os.SystemClock;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import at.lockstep.R;
/**
* Resource helpers.
*
* @author David Madl (git@abanbytes.eu)
* @date 2020-05-16
*/
public class AudioResources {
/**
* Copy raw tracks to filesystem:
* otherwise, packaged resources cannot directly be accessed from C code.
*/
public static void copyRawTracksToFilesystem(Context context) throws IOException {
Field[] fields = R.raw.class.getFields();
long before = SystemClock.uptimeMillis();
try {
for (int i = 0; i < fields.length; i++) {
String assetName = fields[i].getName();
if (assetName.startsWith("track_")) {
int resourceId = fields[i].getInt(null);
copyFileUsingStream(context.getResources().openRawResource(resourceId), new File(context.getFilesDir() + "/" + resourceId + ".mp3"));
}
}
} catch(IllegalAccessException iae) {
// reflection should always work on R.raw
iae.printStackTrace();
}
long after = SystemClock.uptimeMillis();
Log.i("LoadTracks", String.format("copyRawTracksToFilesystem() took %.3f s", ((float)(after-before))/1e3f));
}
private static void copyFileUsingStream(InputStream is, File dest) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
} finally {
is.close();
os.close();
}
}
}

View File

@@ -1,11 +1,16 @@
package at.lockstep.pb;
import android.content.Context;
import android.media.AudioManager;
import android.os.Build;
import android.util.Log;
import java.io.IOException;
public class PlaybackEngine {
static long mEngineHandle = 0;
static final int MPG123_OK = 0;
static boolean mFilesystemInitialized = false;
static {
System.loadLibrary("lockstep-native");
@@ -15,14 +20,36 @@ public class PlaybackEngine {
}
public static boolean create(Context context) {
try {
if(!mFilesystemInitialized) {
AudioResources.copyRawTracksToFilesystem(context);
mFilesystemInitialized = true;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
if (mEngineHandle == 0) {
//setDefaultStreamValues(context); // TODO
setDefaultStreamValues(context);
Log.i("PlaybackEngine", "Hello PlaybackEngine");
mEngineHandle = native_createEngine();
mEngineHandle = native_createEngine(context.getFilesDir().toString());
}
return (mEngineHandle != 0);
}
private 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);
native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst);
}
}
public static void delete() {
if (mEngineHandle != 0){
native_deleteEngine(mEngineHandle);
@@ -30,8 +57,9 @@ public class PlaybackEngine {
mEngineHandle = 0;
}
private static native long native_createEngine();
private static native long native_createEngine(String filesDir);
private static native void native_deleteEngine(long engineHandle);
private static native void native_setDefaultStreamValues(int sampleRate, int framesPerBurst);
private static native int native_mpg123_init();
}

Binary file not shown.