feat: audio resources
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
#include "PlaybackEngine.h"
|
#include "PlaybackEngine.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
PlaybackEngine::PlaybackEngine() {
|
PlaybackEngine::PlaybackEngine(std::string filesDir): mFilesDir(filesDir) {
|
||||||
LOGI("PlaybackEngine()");
|
LOGI("PlaybackEngine()");
|
||||||
LOGI("NDK LOG_LEVEL=%d", LOG_LEVEL);
|
LOGI("NDK LOG_LEVEL=%d", LOG_LEVEL);
|
||||||
// NDK LOG_LEVEL=3 (DEBUG)
|
// NDK LOG_LEVEL=3 (DEBUG)
|
||||||
|
|||||||
@@ -6,13 +6,15 @@
|
|||||||
#define LOCKSTEP_PLAYBACKENGINE_H
|
#define LOCKSTEP_PLAYBACKENGINE_H
|
||||||
|
|
||||||
#include "OboeSinePlayer.h"
|
#include "OboeSinePlayer.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class PlaybackEngine {
|
class PlaybackEngine {
|
||||||
public:
|
public:
|
||||||
PlaybackEngine();
|
PlaybackEngine(std::string filesDir);
|
||||||
virtual ~PlaybackEngine();
|
virtual ~PlaybackEngine();
|
||||||
private:
|
private:
|
||||||
OboeSinePlayer *mPlayer;
|
OboeSinePlayer *mPlayer;
|
||||||
|
std::string mFilesDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //LOCKSTEP_PLAYBACKENGINE_H
|
#endif //LOCKSTEP_PLAYBACKENGINE_H
|
||||||
|
|||||||
@@ -4,9 +4,12 @@
|
|||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include "mpg123.h"
|
#include "mpg123.h"
|
||||||
|
#include <oboe/Oboe.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
// nice-to: merge with lockstep.cpp
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_at_lockstep_pb_PlaybackEngine_native_1mpg123_1init
|
Java_at_lockstep_pb_PlaybackEngine_native_1mpg123_1init
|
||||||
(JNIEnv *env, jclass) {
|
(JNIEnv *env, jclass) {
|
||||||
|
|||||||
@@ -30,15 +30,13 @@ extern "C" {
|
|||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_at_lockstep_pb_PlaybackEngine_native_1createEngine(
|
Java_at_lockstep_pb_PlaybackEngine_native_1createEngine(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jclass /*unused*/) {
|
jclass /*unused*/, jstring filesDir) {
|
||||||
/*
|
|
||||||
const char* filesDirTemp = env->GetStringUTFChars(filesDir, NULL);
|
const char* filesDirTemp = env->GetStringUTFChars(filesDir, NULL);
|
||||||
std::string filesDirString(filesDirTemp);
|
std::string filesDirString(filesDirTemp);
|
||||||
env->ReleaseStringUTFChars(filesDir, filesDirTemp);
|
env->ReleaseStringUTFChars(filesDir, filesDirTemp);
|
||||||
*/
|
|
||||||
|
|
||||||
// We use std::nothrow so `new` returns a nullptr if the engine creation fails
|
// 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);
|
return reinterpret_cast<jlong>(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,4 +49,13 @@ jlong engineHandle) {
|
|||||||
delete reinterpret_cast<PlaybackEngine *>(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"
|
} // extern "C"
|
||||||
|
|||||||
60
app/src/main/java/at/lockstep/pb/AudioResources.java
Normal file
60
app/src/main/java/at/lockstep/pb/AudioResources.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,16 @@
|
|||||||
package at.lockstep.pb;
|
package at.lockstep.pb;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class PlaybackEngine {
|
public class PlaybackEngine {
|
||||||
static long mEngineHandle = 0;
|
static long mEngineHandle = 0;
|
||||||
static final int MPG123_OK = 0;
|
static final int MPG123_OK = 0;
|
||||||
|
static boolean mFilesystemInitialized = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("lockstep-native");
|
System.loadLibrary("lockstep-native");
|
||||||
@@ -15,14 +20,36 @@ public class PlaybackEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean create(Context context) {
|
public static boolean create(Context context) {
|
||||||
|
try {
|
||||||
|
if(!mFilesystemInitialized) {
|
||||||
|
AudioResources.copyRawTracksToFilesystem(context);
|
||||||
|
mFilesystemInitialized = true;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (mEngineHandle == 0) {
|
if (mEngineHandle == 0) {
|
||||||
//setDefaultStreamValues(context); // TODO
|
setDefaultStreamValues(context);
|
||||||
Log.i("PlaybackEngine", "Hello PlaybackEngine");
|
Log.i("PlaybackEngine", "Hello PlaybackEngine");
|
||||||
mEngineHandle = native_createEngine();
|
mEngineHandle = native_createEngine(context.getFilesDir().toString());
|
||||||
}
|
}
|
||||||
return (mEngineHandle != 0);
|
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() {
|
public static void delete() {
|
||||||
if (mEngineHandle != 0){
|
if (mEngineHandle != 0){
|
||||||
native_deleteEngine(mEngineHandle);
|
native_deleteEngine(mEngineHandle);
|
||||||
@@ -30,8 +57,9 @@ public class PlaybackEngine {
|
|||||||
mEngineHandle = 0;
|
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_deleteEngine(long engineHandle);
|
||||||
|
private static native void native_setDefaultStreamValues(int sampleRate, int framesPerBurst);
|
||||||
|
|
||||||
private static native int native_mpg123_init();
|
private static native int native_mpg123_init();
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
app/src/main/res/raw/track_beat.mp3
Normal file
BIN
app/src/main/res/raw/track_beat.mp3
Normal file
Binary file not shown.
Reference in New Issue
Block a user