Java Question BA.raiseEvent and bass library

wbtcpip

Member
Licensed User
Longtime User
Hello,
having this java code:
B4X:
/ Record callback
    @Events(values={"RecordProc(int handle, ByteBuffer buffer, int length, Object user)"})
    @ShortName("BASS_RecordProc")
    public static class RecordProcedure {
        private BA ba;
        private String eventName;
        private boolean ret;
        public void Initialize(BA ba, String EventName) {
             this.ba = ba;
             this.eventName = EventName.toLowerCase(BA.cul);
        }
        public BASS.RECORDPROC recordproc = new BASS.RECORDPROC() {    
                 public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
                         ba.raiseEvent(null, eventName + "_recordproc", handle, buffer, length, user);            
                }
       };
    }

i get error: missing return statement

i don't know how to return the value from the sub

Java:
B4X:
public interface RECORDPROC
   {
     boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user);
 
     /*RETURN : true = continue recording, false = stop */
   }

B4A:
B4X:
Sub myrec_recordproc(handle As Int, buffer() As Byte, length As Int, User As Object) As Boolean

How i get the return value of the sub?
 
Last edited:

wbtcpip

Member
Licensed User
Longtime User
a second question, the same code cause the following exception:

B4X:
java.lang.IllegalArgumentException: argument 2 should have type byte[], got java.nio.ReadWriteDirectByteBuffer

my sub is
B4X:
Sub myrec_recordproc(handle As Int, buffer() As Byte, length As Int, User As Object) As Boolean

how to pass the type java.nio.ByteBuffer to b4a?
Is buffer() as Byte correct?
 

wbtcpip

Member
Licensed User
Longtime User
No.

bb.array() will return the base array (if there is one).

I changed like this:

B4X:
// Record callback
  @Events(values={"RecordProc(int handle, ByteBuffer buffer, int length, Object user)"})
   @ShortName("BASS_RecordProc")
   public static class RecordProcedure {
     public boolean IsRec = true;
     private BA ba;
     private String eventName;
     public void Initialize(BA ba, String EventName) {
         this.ba = ba;
       this.eventName = EventName.toLowerCase(BA.cul);
     }
     public BASS.RECORDPROC recordproc = new BASS.RECORDPROC() {   
  public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
  ba.raiseEvent(null, eventName + "_recproc", handle, buffer.array(), length, user);   
  return IsRec;   
  }
  };
  }

but now ba do not raise the event anymore
 

wbtcpip

Member
Licensed User
Longtime User
It seems i solved converting ByteBuffer to Byte Array like this:

B4X:
public BASS.RECORDPROC recordproc = new BASS.RECORDPROC() {  
  public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
       byte[] b = new byte[length];
                   buffer.get(b);
                   ba.raiseEvent(null, eventName + "_recproc", handle, b, length, user);  
       return IsRec;  
  }
  };

One more question please:

my sub has a boolean return value

B4X:
Sub myrec_recordproc(handle As Int, buffer() As Byte, length As Int, User As Object) As Boolean

In Java ba.raiseEvent return an object ... how i can return the boolean value from sub to java?

B4X:
ba.raiseEvent(null, eventName + "_recproc", handle, buffer.array(), length, user);
return ??? <--------------- how i return the boolean from my B4A sub?
 
Last edited:

wbtcpip

Member
Licensed User
Longtime User
you are raising an event. Add a parameter in the event to give a boolean too

ok

Java:
B4X:
ba.raiseEvent(null, eventName + "_recproc", handle, b, length, user, IsRec);
ba.Log(IsRec);   <------------------- it's still false ...me i set True in the B4A Sub

B4A:
B4X:
Sub myrec_recproc(handle As Int, mybuffer() As Byte, length As Int, User As Object, IsRec As Boolean)
  IsRec = True  <------------------- i set True my boolean
End Sub

dont' work .... so ....

How to pass a sub return value from B4A -> to java?
 

DonManfred

Expert
Licensed User
Longtime User
I´ve difficulties to understand the problem without knowing what exactly you want archieve. And especially without knowing the libs code you want to wrap it ishard for me to answer.

What is the lib you want to wrap? github-url, upload the lib, whatever
 

wbtcpip

Member
Licensed User
Longtime User

again thank you for the help.

I will give you all the details about the library at the bottom of this message but my question is not related to a specific library, it is a generale question about the ba.raisevent and a sub of Basic4Android.

Imagine to have a sub in Basic4Android like this:

B4X:
sub myadd_myproc(a as int, b as int) as Int
       return a+b
end sub

and now imagine that a java library wants to use that sub passing 2 values and getting a result:

B4X:
a=4;
b=6;
ba.raiseEvent(null, eventName + "_myproc", a, b);

In java code how i get the result 10?

I'm wrapping this library: http://www.un4seen.com/forum/?topic=13225.0 anyway as you can see my question is not related to the library.
 

DonManfred

Expert
Licensed User
Longtime User
This is how i would write it i guess.

B4X:
package de.donmanfred;

import java.nio.ByteBuffer;
import com.un4seen.bass.BASS;
import com.un4seen.bass.BASS.RECORDPROC;
import anywheresoftware.b4a.AbsObjectWrapper;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;

@Version(1.00f)
@ShortName("BASS")
@Author(value = "DonManfred (wrapper)")
//@Permissions(values={"android.permission.INTERNET", "android.permission.ACCESS_NETWORK_STATE"})
@Events(values={"recordproc(handle As int, buffer As byte(), lengh As int, user As Object)"})

public class BASSWrapper extends AbsObjectWrapper<BASS> {
    private BA ba;
    private String eventName;

    public void Initialize(final BA ba, String EventName) {
        this.eventName = EventName.toLowerCase(BA.cul);
        this.ba = ba;

        final BASS _obj = new BASS();
        final String eventName = EventName.toLowerCase(BA.cul);
        setObject(_obj);
    }

    public void RecordStart(int freq, int chans, int flags, Object user){
        getObject();
        BASS.BASS_RecordStart(freq, chans, flags, new RECORDPROC(){

            @Override
            public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
                // TODO Auto-generated method stub
                if (ba.subExists(eventName + "_recordproc")) {
                    BA.Log("lib:Raising.. "+eventName + "_recordproc()");                               
                  //app.raiseEvent(app.context, eventName+"_pagerendered", i, pageCount, filename+"-" + i + ".png");
                  return (boolean) ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_recordproc", true, new Object[] {handle, buffer.array(), length, user});
              }else {
                  BA.Log("lib: NOTFOUND '"+eventName + "_recordproc");
              }
                return false;
            }
        }, user);
    }
       
}

Please note that i onlywrapped one of the methodsof the native .so

Only one of these


In this case it was
public static native int BASS_RecordStart(int freq, int chans, int flags, RECORDPROC proc, Object user);
to demonstrate on how to implement the callbacks.

But honestly i´m not sure if that
B4X:
  return (boolean) ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_recordproc", true, new Object[] {handle, buffer.array(), length, user});
works as epected.
 

wbtcpip

Member
Licensed User
Longtime User
Thank you very much for the sample wrapper. Indeed it's very useful for me to learn how to wrap this BASS library. The only difficult part are the callback.

Unfortunately also in your code ba.raiseEventFromDifferentThread do not return the value of the B4A sub.

It seems the BA.raise family of commands only raise the event but they don't wait for the sub to be executed on B4A side, so they don't get the return value.

They work async, so only Void sub can be used ... in BASS there are some callback that need a return value form the sub ... i don't know how to do
 

DonManfred

Expert
Licensed User
Longtime User
he only difficult part are the callback.
Unfortunately also in your code ba.raiseEventFromDifferentThread do not return the value of the B4A sub.

ba.raiseEvent is not asynchronous and you can use it to return a value from B4A code. However you cannot use it if the event is raised from a different thread.

Based on @Erel answer this should work giving a result back from b4a to the libs event method

B4X:
    public void RecordStart(int freq, int chans, int flags, Object user){
        getObject();
        BASS.BASS_RecordStart(freq, chans, flags, new RECORDPROC(){

            @Override
            public boolean RECORDPROC(int handle, ByteBuffer buffer, int length, Object user) {
                // TODO Auto-generated method stub
                if (ba.subExists(eventName + "_recordproc")) {
                    BA.Log("lib:Raising.. "+eventName + "_recordproc()");                               
                  //app.raiseEvent(app.context, eventName+"_pagerendered", i, pageCount, filename+"-" + i + ".png");
                  return (boolean) ba.raiseEvent(this, eventName + "_recordproc", handle, buffer.array(), length, user);
              }else {
                  BA.Log("lib: NOTFOUND '"+eventName + "_recordproc");
              }
                return false;
            }
        }, user);
    }
 

wbtcpip

Member
Licensed User
Longtime User
Hi Manfred, you was so kind wrapping one function of the bass library. Can i ask you a last help? I need to wrap this part of the library:

Java:
B4X:
public static native int BASS_StreamCreateFileUser(int system, int flags, BASS_FILEPROCS procs, Object user);

public interface BASS_FILEPROCS
   {
     // User file stream callback functions
     void FILECLOSEPROC(Object user);
     long FILELENPROC(Object user);
     int FILEREADPROC(ByteBuffer buffer, int length, Object user);
     boolean FILESEEKPROC(long offset, Object user);
   }

In Basic4Android i will have 4 callback:

B4X:
sub fileclose_myfileuserproc(user as Object)

sub filelen_myfileuserproc(user as Object) as long

sub fileread_myfileuserproc(buffer() as byte, length as int, user as object) as Int

sub fileseek_myfileuserproc(offset as long, user as object) as Boolean

Do i have to create 4 different callbacks like your exemple?

and how i pass the 4 callbacks to the function?
 

wbtcpip

Member
Licensed User
Longtime User

Hi Erel,
your code return this error:

incompatible types: Object cannot be converted to Boolean
Boolean res = ba.raiseEvent(this, eventName + "_recordproc", handle, buffer.array(), length, user);
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…