B4J Library jAudioRecord

There is a newer version of this library with more functionality (not a direct plugin replacement) jAudioRecord2

This is an Audio Recording Library based on javax.sound.sampled that I have tried to make as simple to use as possible. It will record from the default device as selected in the Control Panel or Mixer (on Windows Machines).

I haven't been able to test it on Linux and Mac, but as it only uses the default devices, I hope it should be OK. I may be able to test it on Linux soon. If you run it on any system, please let me know how it runs.

The Java Audio system is a great deal more complicated than the Android equivalent, I may look at implementing more features such as input / output selection and accessing Volume and Pan controls if there is a demand for it.

My sound card doesn't support 8bit recording so I would be grateful if someone could test that. I get a lot of noise and was about to investigate when I thought I should check if the Realtek HD actually did 8bit, and apparently it doesn't so I was getting a 0 byte for every valid data byte, hence the noise.

The library:

JAudioRecord
Author:
Steve Laming
Version: 1.0

  • Methods:
    • AddLineListener(EventName As String)
      Adds a listener to this line.
      Callback to sub {EventName}_Event will be called when one of the following events has been raised:
      OPEN, CLOSE, START or STOP


      Available As Int
      Obtains the number of bytes of data currently available
      to the application for processing in the data line's internal buffer.


      Buffersize As Int
      Get the buffer size of the TargetDataLine

      Drain
      Drains queued data from the line by continuing data I/O until the data line's internal buffer has been emptied.

      Flush
      Flushes queued data from the line.

      Initialize(SampleRateHZ As Float, SampleSizeInBits As Int, ChannelConfig As Int) As Boolean


      IsActive As Boolean
      Indicates whether the line is engaging in active I/O (such as playback or capture). When an inactive line becomes active, it sends a START event to its listeners.
      Similarly, when an active line becomes inactive, it sends a STOP event.


      IsInitialized As Boolean


      IsRunning As Boolean
      Indicates whether the line is running. The default is false. An open line begins running when the first data is presented in response to an invocation of the start method,
      and continues until presentation ceases in response to a call to stop or because playback completes.


      LastException As String
      If an error occurred get the last exception

      Read(Data As Byte(), Off As Int, Len As Int) As Int
      Reads data from the TargetDataLine, it requests len bytes which are stored in data
      off = offset into array data
      Returns the actual number of bytes read


      Release
      Closes the line and

      Start
      Start capturing data

      Stop
      Stop capturing data

There are no external dependencies for the Library.

The Demo is a modified version of the Android one and depends on libraries:

jMsgBoxes
jRandomAccessFile
Threading

The threading library is necessary so we can control the processing of data as it arrives within B4j. The data capture is blocking, so if you run it on the GUI thread, the app will lock.

It captures PCM Signed linear data. No Mp3 or other formats, although access to the samples is available if you have an encoder library. The demo captures the input stream and saves it to a wav file and plays it back through MediaPlayer.

You cannot debug an application that uses the threading library, so if you are just testing and don't need a Gui, run the record subroutine in the Gui thread.

Unzip jAudioRecord and copy the xml and jar files to your addl Libraries folder.
 

Attachments

  • jAudioRecord.zip
    4.3 KB · Views: 1,141
  • ARTest.zip
    2.4 KB · Views: 963
Last edited:

BPak

Active Member
Licensed User
Longtime User
I receive a message in the Logs
B4X:
Program started.
Getting line from Audiosystem
true
Pos 40
Thread Rec EndedOK false Exception : wrong number of arguments
DataSize 0
 

stevel05

Expert
Licensed User
Longtime User
It is not possible to run an app that contains a thread in debug mode.
 

BPak

Active Member
Licensed User
Longtime User
It is not possible to run an app that contains a thread in debug mode.

Runs as expected in Release compile....

Have a Mac OS X Lion and ran the Test Record program on it.
Works as expected...
Attach some screenshots of Mac which may interest you.
Thanks for great Library.
 

Attachments

  • MacRecord.zip
    52.1 KB · Views: 555

stevel05

Expert
Licensed User
Longtime User
Yes, looks good.

Thanks for the pics.

If you want to test it in debug mode, remove the thread start line and call the sub directly, it will run on the gui thread, but you won't be able to interact with any Gui you may add.
 

rdkartono

Member
Licensed User
Longtime User
Hi Stevel05,

Supposedly if i have multiple audio adapters, all of them capable of doing recording.
1. is this library able to select which adapter to use ?
2. is this library able to work on different threads ?
 

stevel05

Expert
Licensed User
Longtime User
I haven't looked at it for a while but as far as I remember it records the default audio input.

Threading is controlled by the B4j code, so yes.
 

Magma

Expert
Licensed User
Longtime User
@stevel05 Hi there....

jAudioRecord or jAudioTrack recording from default/selected audio-in - is there a way to select different audio-in with code, java etc ? and more complicated is there a way to enumerate the avaliable sources of audio-in...

here found a way (using third party tool)

What am I asking :)... thanks in advance ! - hope it is possible...
 

stevel05

Expert
Licensed User
Longtime User
This sub and InlineJava will enumerate the mixers available, you can then get the lines you need from the mixer objects. You can also filter for a specific device if required.

B4X:
'Required global constants
Public Const DEVICETYPE_INPUT As String = "input"
Public Const DEVICETYPE_OUTPUT As String = "output"

B4X:
Public Sub GetDevices(DType As String,Filter As String) As List
 
    Dim CallJava As JavaObject = Me
 
    Dim Result As List
    Result.Initialize
 
    Dim ClassName As String
    If DType.ToLowerCase = DEVICETYPE_INPUT Then
        ClassName = "TargetDataLine"
    Else If DType.ToLowerCase = DEVICETYPE_OUTPUT Then
        ClassName = "SourceDataLine"
    Else
        Log("Invalid device " & DType)
        Return Result
    End If
 
    Dim Class As JavaObject
    Class.InitializeStatic("java.lang.Class")
    Dim ThisLineClass As Object = Class.RunMethod("forName",Array($"javax.sound.sampled.${ClassName}"$))
 
    Dim LineInfo1 As JavaObject
    LineInfo1.InitializeNewInstance("javax.sound.sampled.Line.Info",Array(ThisLineClass))
 
    Dim AudioSystem As JavaObject
    AudioSystem.InitializeStatic("javax.sound.sampled.AudioSystem")

    Dim MixerInfoList() As Object = AudioSystem.RunMethod("getMixerInfo",Null)
 
    For Each MI As JavaObject In MixerInfoList
        If MI.RunMethod("getName",Null).As(String).ToLowerCase.Contains(Filter.ToLowerCase) Then
            Dim M As JavaObject = AudioSystem.RunMethod("getMixer",Array(MI))
            If CallJava.RunMethod("isLineSupported",Array(M,LineInfo1)) Then
                Result.Add(MI)
            End If
        End If
    Next
 
    Return Result
End Sub

#If java
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.LineUnavailableException;

public static boolean isLineSupported(Mixer m, Line.Info targetLineInfo) throws LineUnavailableException{
     Boolean found;
     m.open();
     found = m.isLineSupported(targetLineInfo);
     m.close();
     return found;
}
#End If

Usage:
B4X:
Dim MixerInfos As List = GetDevices(DEVICETYPE_INPUT,"")
 
For Each MI As JavaObject In MixerInfos
    Log(MI.RunMethod("getName",Null))
Next

There is no guarantee that you mixer devices support an 'all output' line, you'll need to try it.

The m.open & m.close in java is required as some lines are not available unless the mixer is open, this may not be the case for your devices (it makes no difference for mine), you can try it without if it causes issues, such as calling the method when you have already opened a device.
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
and how to select different audio-in with code, java etc ?
That depends on how you are currently selecting the device to use.

You will need to populate a B4xCombobox, then change the output once selected. (or have you not got that far?)

If you have problems, post an example project and I will try to help. I don't have a similar project I can use.
 

Magma

Expert
Licensed User
Longtime User
That depends on how you are currently selecting the device to use.

You will need to populate a B4xCombobox, then change the output once selected. (or have you not got that far?)

If you have problems, post an example project and I will try to help. I don't have a similar project I can use.
For my project... I am thinking using the loop... and check with (ofcourse into a language loop):
B4X:
if MI.RunMethod("getName",Null).As(String).Contains("Stereo Mix") then selectit
 

stevel05

Expert
Licensed User
Longtime User
Before you go too far, I would suggest running the code and checking that there is a suitable input. on my system I get:
Waiting for debugger to connect...
Program started.
Primary Sound Capture Driver
Line (ZOOM U-44 Audio)
Microphone (Realtek(R) Audio)

Have you run the code? does Stereo Mix exist?. My Primary Sound Capture doesn't appear to work.
 

Magma

Expert
Licensed User
Longtime User
at my system...
B4X:
Βασικό πρόγραμμα οδήγησης ηχογράφησης
Μικρόφωνο (GENERAL - AUDIO)
Στερεοφωνική μείξη (Realtek High Definition Audio)

Where "Στερεοφωνική μείξη" is Stereo Mix in Greek Windows...

I know that every time, different system and language this will change so i will create an array with different supported languages strings with Stereo Mix possible inputs...

ps: At your system may be driver not having stereo-mix... or default windows driver from update... also some laptop model (if laptop) have copyrights... so may be need to run the .reg i have at link with my tip and restart your pc... may be... not sure...

ps2: from the other hand your card - is a pro as i understand u-44 - so not possible not installed drivers... but actually is a different thing !!!
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
This is an example of recording from a selected input source. it is similar to the jAudioRecord library (but does not require the threading library).

It is slightly more complex to use by necessity, but will do what you want.

I may release it as a general library if it works OK for you. Please try it and let me know.

For more functionality see jAudioRecord2
 

Attachments

  • jAudioRecord2.zip
    7.2 KB · Views: 215
Last edited:

Magma

Expert
Licensed User
Longtime User
it works...
recording to wav file...

ps: only a strange thing - ...stereomix was disabled (may be before running) - and needed to reenable from sound control panel...

but it works!!! BRAVO!!!

pic-jaudio1.jpg
 

Magma

Expert
Licensed User
Longtime User
@stevel05 hmmm..

- Is there a way to know what user/system had by default selected before we change the line-in ?

- Is there a way to know if the microphone is the microphone of soundcard or the microphone of a webcam ? (Or if the jaudiorecord shows all avaliable sound devices or from default audio-card... and not showing all)... May be a user had an extra usb-audio or a second pcie-soundcard...

Ofcourse you can answer me... that this going to very complex setups... sorry for asking too much... are just questions to fill some gaps...
 
  • Like
Reactions: omo

stevel05

Expert
Licensed User
Longtime User
- Is there a way to know what user/system had by default selected before we change the line-in ?
I can't see a way to do this. Using Audiosystem.getTargetDataLine AudioSystem matches the audioformat to a device that supports it. If there is more than one it could be any, so it appears not.

Is there a way to know if the microphone is the microphone of soundcard or the microphone of a webcam ?
Only by the name returned in the Mixer.Info object. I don't think it can be automated. For instance my system has:

1659611442199.png

The USB audio device is on my webcam, Realtek is the soundcard.

I think it's a manual selection.

I've had a quick look on the internet and couldn't find anything, If you can find some java code I will help you port it.
 
Top