B4J Question Inline Java class with sub return question

Douglas Farias

Expert
Licensed User
Longtime User
Hello everybody.
I have a question about inline java and classes.


In summary.
I need to make an app in B4J that listens to the microphone so I can use it with the VOSK right after.

The objective is to listen to the microphone with inline java and pass the stream to b4j.

However, I am experiencing some errors when trying.


B4X:
Sub Inicia_Java
    Dim thisClass As String = (Me).As(JavaObject).RunMethod("getClass",Null)
    jo.InitializeNewInstance(thisClass.Replace("class ","") & "$" & "AudioCapture",Null)
    StartRecording
End Sub


Sub StartRecording
    jo.RunMethod("startRecording", Null)
End Sub

Sub StopRecording
    jo.RunMethod("stopRecording", Null)
End Sub



#if java
import javax.sound.sampled.*;
import java.io.ByteArrayOutputStream;

public class AudioCapture {

    public AudioCapture() {
        // inicialização necessária
    }
   
    private TargetDataLine line;
    private boolean running = false;

    public void startRecording() {
        try {
            AudioFormat format = new AudioFormat(16000, 16, 1, true, false);
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
            if (!AudioSystem.isLineSupported(info)) {
                subQvEvent("logs", "Line not supported");
                return;
            }

            line = (TargetDataLine) AudioSystem.getLine(info);
            line.open(format);
            line.start();
            running = true;

            new Thread(() -> {
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                while (running) {
                    int numRead = line.read(buffer, 0, buffer.length);
                    if (numRead > 0) {
                        out.write(buffer, 0, numRead);
                    }
                }
                line.drain();
                line.close();
                subQvEvent("audio_data", out.toByteArray());
            }).start();
        } catch (LineUnavailableException e) {
            subQvEvent("logs", "Line unavailable: " + e.getMessage());
        }
    }

    public void stopRecording() {
        running = false;
    }

    private void subQvEvent(String eventName, Object data) {
        getBA().raiseEventFromDifferentThread(null, null, 0, eventName.toLowerCase() + "_qv", true, new Object[]{data});
    }
}
#end if


Sub audio_data(data() As Byte)
    Log("Received audio data of length: " & data.Length)
End Sub

Sub logs(message As String)
    Log(message)
End Sub


Error

WARNING: package com.sun.javafx.embed.swing.oldimpl not in javafx.swing
Waiting for debugger to connect...
Program started.
Error occurred on line: 58 (B4XMainPage)
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.keywords.Common.CallSubDebug2(Common.java:486)
at teste.app.b4xpagesmanager._createpageifneeded(b4xpagesmanager.java:872)
at teste.app.b4xpagesmanager._showpage(b4xpagesmanager.java:351)
at teste.app.b4xpagesmanager._addpage(b4xpagesmanager.java:172)
at teste.app.b4xpagesmanager._addpageandcreate(b4xpagesmanager.java:186)
at teste.app.b4xpagesmanager._initialize(b4xpagesmanager.java:122)
at teste.app.main._appstart(main.java:80)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at teste.app.main.start(main.java:38)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at anywheresoftware.b4a.debug.Debug.CallSub4(Debug.java:134)
at anywheresoftware.b4a.debug.Debug.CallSubNew2(Debug.java:81)
... 35 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at anywheresoftware.b4a.debug.Debug.CallSub4(Debug.java:115)
... 36 more
Caused by: java.lang.InstantiationException: teste.app.b4xmainpage$AudioCapture
at java.base/java.lang.Class.newInstance(Class.java:598)
at anywheresoftware.b4j.object.JavaObject.InitializeNewInstance(JavaObject.java:86)
at teste.app.b4xmainpage._inicia_java(b4xmainpage.java:86)
at teste.app.b4xmainpage._b4xpage_created(b4xmainpage.java:68)
... 41 more
Caused by: java.lang.NoSuchMethodException: teste.app.b4xmainpage$AudioCapture.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3427)
at java.base/java.lang.Class.newInstance(Class.java:585)
... 44 more


if I try to use static.


B4J Version: 10.00
Parsing code. (0.01s)
Java Version: 14
Building folders structure. (0.01s)
Running custom action. (0.02s)
Compiling code. (0.04s)
Compiling layouts code. (0.00s)
Organizing libraries. (0.00s)
Compiling generated Java code. Error
src\teste\app\b4xmainpage.java:249: error: non-static method getBA() cannot be referenced from a static context
getBA().raiseEventFromDifferentThread(null, null, 0, eventName.toLowerCase() + "_qv", true, new Object[]{data});
^
1 error

javac 14.0.1

How can I use inline java, have classes in java and at the same time be able to return values to subs in b4j

Obs: I know that there are already recording libraries in b4j, but this question is about inline java/class and subs.


Thx
 

aeric

Expert
Licensed User
Longtime User
I am not expert in Java but I understand that if you want the Java function to return value to B4J, you need to add the data type before the function name instead of using void.

For eg.
Java:
public byte[] getAudioData() {
    byte[] data = new byte[1024];
    // some Java code
    return data;
}
 
Upvote 0

jkhazraji

Active Member
Licensed User
Longtime User
raiseEventFromDifferentThread doesn't return a value as it happens asynchronously.
Try BA.raiseEvent()
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
threads don't return anything, but callables do. try things this way.
 

Attachments

  • farias.zip
    2.8 KB · Views: 146
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
by the way, what you originally posted can work. with a few modifications. i can initialize your class and get raiseevent to work. go over it carefully if you still want to use the original approach.
 

Attachments

  • farias2.zip
    2.7 KB · Views: 164
Upvote 0

Douglas Farias

Expert
Licensed User
Longtime User
by the way, what you originally posted can work. with a few modifications. i can initialize your class and get raiseevent to work. go over it carefully if you still want to use the original approach.
Thank you very much, you gave me a way.

posted here

thx
 
Upvote 0
Top