Skip to content

Commit

Permalink
Audio handler improvements (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
GiantLuigi4 authored Oct 23, 2024
1 parent c877637 commit eaeb3d4
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 19 deletions.
7 changes: 2 additions & 5 deletions java/org/cef/CefClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
import org.cef.callback.CefPrintDialogCallback;
import org.cef.callback.CefPrintJobCallback;
import org.cef.handler.*;
import org.cef.misc.BoolRef;
import org.cef.misc.CefAudioParameters;
import org.cef.misc.CefPrintSettings;
import org.cef.misc.StringRef;
import org.cef.misc.*;
import org.cef.network.CefRequest;
import org.cef.network.CefRequest.TransitionType;
import org.cef.network.CefResponse;
Expand Down Expand Up @@ -815,7 +812,7 @@ public void onAudioStreamStarted(CefBrowser browser, CefAudioParameters params,
}

@Override
public void onAudioStreamPacket(CefBrowser browser, float[] data, int frames, long pts) {
public void onAudioStreamPacket(CefBrowser browser, DataPointer data, int frames, long pts) {
if (audioHandler_ != null) audioHandler_.onAudioStreamPacket(browser, data, frames, pts);
}

Expand Down
3 changes: 2 additions & 1 deletion java/org/cef/handler/CefAudioHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import org.cef.browser.CefBrowser;
import org.cef.misc.CefAudioParameters;
import org.cef.misc.DataPointer;

/**
* Implement this interface to handle events related to audio playing.
Expand All @@ -16,7 +17,7 @@ public interface CefAudioHandler {

void onAudioStreamStarted(CefBrowser browser, CefAudioParameters params, int channels);

void onAudioStreamPacket(CefBrowser browser, float[] data, int frames, long pts);
void onAudioStreamPacket(CefBrowser browser, DataPointer data, int frames, long pts);

void onAudioStreamStopped(CefBrowser browser);

Expand Down
3 changes: 2 additions & 1 deletion java/org/cef/handler/CefAudioHandlerAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import org.cef.browser.CefBrowser;
import org.cef.misc.CefAudioParameters;
import org.cef.misc.DataPointer;

/**
* Implement this interface to handle events related to audio playing.
Expand All @@ -19,7 +20,7 @@ public boolean getAudioParameters(CefBrowser browser, CefAudioParameters params)
public void onAudioStreamStarted(CefBrowser browser, CefAudioParameters params, int channels) {
}

public void onAudioStreamPacket(CefBrowser browser, float[] data, int frames, long pts) {
public void onAudioStreamPacket(CefBrowser browser, DataPointer data, int frames, long pts) {
}

public void onAudioStreamStopped(CefBrowser browser) {
Expand Down
85 changes: 85 additions & 0 deletions java/org/cef/misc/DataPointer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.cef.misc;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.ByteBuffer;

public class DataPointer {
private final long address;
private ByteBuffer dataBuffer;
boolean initialized = false;
int alignment = 3;

public DataPointer(long address) {
this.address = address;
}

public DataPointer forCapacity(int capacity) {
try {
dataBuffer = (ByteBuffer) memByteBuffer.invoke(address, capacity);
initialized = true;
return this;
} catch (Throwable err) {
throw new RuntimeException("Failed to invoke memByteBuffer?", err);
}
}

public DataPointer withAlignment(int alignment) {
this.alignment = alignment;
return this;
}

public long getAddress() {
return address;
}

public DataPointer getData(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return new DataPointer(dataBuffer.getLong(offset << alignment));
}

public long getLong(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return dataBuffer.getLong(offset << alignment);
}

public int getInt(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return dataBuffer.getInt(offset << alignment);
}

public short getShort(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return dataBuffer.getShort(offset << alignment);
}

public byte getByte(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return dataBuffer.get(offset << alignment);
}

public double getDouble(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return dataBuffer.getDouble(offset << alignment);
}

public float getFloat(int offset) {
if (!initialized) throw new RuntimeException("DataPoint#forCapacity must be called before the data can be accessed.");
return dataBuffer.getFloat(offset << alignment);
}

// TODO: ideally we'd just directly depend on lwjgl, since we require it for GLFW anyway
private static final MethodHandle memByteBuffer;

static {
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
Class<?> clz = Class.forName("org.lwjgl.system.MemoryUtil", false, lookup.lookupClass().getClassLoader());
memByteBuffer = lookup.findStatic(clz, "memByteBuffer", MethodType.methodType(ByteBuffer.class, new Class[]{Long.TYPE, Integer.TYPE}));
} catch (Throwable err) {
System.err.println("Could not find LWJGL MemoryUtil's memByteBuffer method.\nAre you using LWJGL 3.x?");
throw new RuntimeException(err);
}
}
}
26 changes: 14 additions & 12 deletions native/audio_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
AudioHandler::AudioHandler(JNIEnv* env, jobject handler)
: handle_(env, handler) {}

jobject jniParams(ScopedJNIEnv env, const CefAudioParameters& params) {
jobject jniParams(ScopedJNIEnv env, jclass clsProps, const CefAudioParameters& params) {
jclass cls = env->FindClass("org/cef/misc/CefChannelLayout");
if (cls == nullptr) {
// std::cout << "Could not find class 0";
Expand All @@ -24,7 +24,7 @@ jobject jniParams(ScopedJNIEnv env, const CefAudioParameters& params) {
}
jobject layout = env->CallStaticObjectMethod(cls, getLayout, (int) params.channel_layout);

cls = env->FindClass("org/cef/misc/CefAudioParameters");
cls = clsProps;
if (cls == nullptr) {
// std::cout << "Could not find class 1";
return nullptr;
Expand All @@ -39,6 +39,11 @@ jobject jniParams(ScopedJNIEnv env, const CefAudioParameters& params) {
return parameters;
}

jobject jniParams(ScopedJNIEnv env, const CefAudioParameters& params) {
jclass cls = env->FindClass("org/cef/misc/CefAudioParameters");
return jniParams(env, cls, params);
}

bool AudioHandler::GetAudioParameters(CefRefPtr<CefBrowser> browser,
CefAudioParameters& params) {
ScopedJNIEnv env;
Expand All @@ -48,10 +53,12 @@ bool AudioHandler::GetAudioParameters(CefRefPtr<CefBrowser> browser,
ScopedJNIBrowser jbrowser(env, browser);

jboolean jreturn = JNI_FALSE;
jclass cls = env->FindClass("org/cef/misc/CefAudioParameters");
jobject paramsJni = jniParams(env, cls, params);

JNI_CALL_METHOD(env, handle_, "getAudioParameters",
"(Lorg/cef/browser/CefBrowser;Lorg/cef/misc/CefAudioParameters;)Z", Boolean,
jreturn, jbrowser.get(), jniParams(env, params));
jreturn, jbrowser.get(), paramsJni);

return (jreturn != JNI_FALSE);
}
Expand All @@ -76,17 +83,12 @@ void AudioHandler::OnAudioStreamPacket(CefRefPtr<CefBrowser> browser, const floa

ScopedJNIBrowser jbrowser(env, browser);

// TODO: this should truthfully be using a float buffer, but I'm not yet sure how to do that from JNI
jfloatArray jArray = env->NewFloatArray(frames);
int size = frames;
jfloat* fill = (jfloat*) malloc(size * sizeof(jfloat));
for (int i = 0; i < size; i++)
fill[i] = data[0][i];
env->SetFloatArrayRegion(jArray, 0, size, fill);
ScopedJNIObjectLocal dataPtr(
env, NewJNIObject(env, "org/cef/misc/DataPointer", "(J)V", (jlong) data));

JNI_CALL_VOID_METHOD(env, handle_, "onAudioStreamPacket",
"(Lorg/cef/browser/CefBrowser;[FIJ)V",
jbrowser.get(), jArray, frames, (long long) pts);
"(Lorg/cef/browser/CefBrowser;Lorg/cef/misc/DataPointer;IJ)V",
jbrowser.get(), dataPtr.get(), frames, (long long) pts);
}

void AudioHandler::OnAudioStreamStopped(CefRefPtr<CefBrowser> browser) {
Expand Down

0 comments on commit eaeb3d4

Please sign in to comment.