Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio handler improvements #19

Merged
merged 4 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading