B4J Question Can I use AsyncStreams with udpsocket?

bjfhs

Active Member
Licensed User
I am looking for a way to record the sound from microphone with Android device(use B4A) and play with a PC realtime(Use B4J)

When I use UDPSocket + UDPPacket,I can't hear anything.
 
Last edited:

OliverA

Expert
Licensed User
Longtime User
Others here have used UDP to transmit audio without issues. No AsyncStream required. You may need to post some sending/receiving code and or post a minimal app(s) that reproduce your issue.
 
Upvote 0

bjfhs

Active Member
Licensed User
Others here have used UDP to transmit audio without issues. No AsyncStream required. You may need to post some sending/receiving code and or post a minimal app(s) that reproduce your issue.
Thank you!The attached file is I use UDPSocket + UDPPacket,I can't hear anything.
 

Attachments

  • B4A.zip
    8 KB · Views: 178
  • B4J.zip
    17.1 KB · Views: 204
Upvote 0

OliverA

Expert
Licensed User
Longtime User
First thing I notice is that your sample rate is inconsistent. You have 22050 in you B4A app and 44100 in your B4J app.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
How did you come up with the receive buffer size for you B4J application? It may be too small for some Android phones' recording buffer size.
 
Upvote 0

bjfhs

Active Member
Licensed User
First thing I notice is that your sample rate is inconsistent. You have 22050 in you B4A app and 44100 in your B4J app.
Thank you very much! I changed to 22050 all, I can't hear anything.
when I use log(data.length),I get 1792 every time.
When I make it large enough ,I still can't hear anything.
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Is your phone on the same wifi? Are you sure the IP address used in your B4A app is correct? How about adding a log statement to your udpsock_PacketArrived sub to see if it is fired (that you are receiving data on the B4J side). You could also add a log statement in AudioStream_RecordBuffer of your B4A app
B4X:
Sub AudioStream_RecordBuffer (Data() As Byte)
    If sendingAudio Then
        'astream.Write(Data)
        Log("Recording audio. Length of Data(): " & Data.Length)
        sendM(Data)
    End If
End Sub
just to ensure you are actually sending and receiving data. Run both in Debug mode for logging (or, for B4A, turn #BridgeLogger on if your running the B4A app in Release mode).
 
Upvote 0

bjfhs

Active Member
Licensed User
Is your phone on the same wifi? Are you sure the IP address used in your B4A app is correct? How about adding a log statement to your udpsock_PacketArrived sub to see if it is fired (that you are receiving data on the B4J side). You could also add a log statement in AudioStream_RecordBuffer of your B4A app
B4X:
Sub AudioStream_RecordBuffer (Data() As Byte)
    If sendingAudio Then
        'astream.Write(Data)
        Log("Recording audio. Length of Data(): " & Data.Length)
        sendM(Data)
    End If
End Sub
just to ensure you are actually sending and receiving data. Run both in Debug mode for logging (or, for B4A, turn #BridgeLogger on if your running the B4A app in Release mode).
I can get data from the socket(B4J),but can't play it(hear nothing).
In B4A I get Recording audio. Length of Data(): 1792
In B4J I get Receiving audio. Length of Data(): 1792
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Here we go:
1) The first problem you are having is that you are not using the same encoding / decoding setup for the audio. In your B4A app you have
B4X:
audioStream.Initialize("AudioStream", 22050, True, 16, audioStream.VOLUME_MUSIC)
and in B4J you originally had
B4X:
AT.Initialize(44100,16,AT.Ch_Conf_Stereo)
There are actually two issues in the B4J statement. The first I mentioned above, the second is that in B4A you are recording in Mono (that's the True portion of the audioStream.Initialize), yet you are setting up B4J for stereo playback. So the correct line in B4J should be
B4X:
AT.Initialize(22050,16,AT.Ch_Conf_Mono)

2)
In B4J I get Receiving audio. Length of Data(): 1792
Actually, what you are displaying on the B4J side is the size of the UDP buffer. That will always be the size that you set up with (as in your B4J code)
B4X:
udpsock.Initialize("udpsock", port, 1792)
If instead you would have written
B4X:
udpsock.Initialize("udpsock", port, 2000)
Then your Data() length would have always been 2000. And here is the other issue. The buffer size needs to be large enough to handle other recording buffer sizes. Just because your phone does 1792, does not mean others user more (or less). My 1st generation Moto-X has a recording buffer size of 2048. Would you use my phone with your setup, you would chop off over 250 bytes of audio. Just go ahead and make the buffer big enough to handle other phones. Most examples in this forum seem to use 8000
B4X:
udpsock.Initialize("udpsock", port, 2000)
Note: From work I've done for someone else, it seems that the less powerful a phone's CPU is, the bigger the recording buffer is.

3)
The reason that you have no playback in your B4J application is that you did not use AT.Start (and AT.Stop). Now, this seems to get a little trickier. If you put AT.Start right after AT.Initialize (and AT.Stop in you MainForm_Closed sub), playback occurs, but at times you experience a endless loop after the B4A app finished sending data. I've developed one workaround, but please note, I'm not an expert on the jAudioTrack library, nor audio in general.
Workaround steps:
a) In your B4A app
1) Add a variable to your Process_Globals
B4X:
Private sendFlagPacket(10) As Byte
2) In your SendAudio sub, add
B4X:
    sendM(sendFlagPacket)
3) In your StopSendingAudio sub add
B4X:
    sendM(sendFlagPacket)
This will signal you B4J app when to start and stop playback
b) In your B4J app, change udpsock_PacketArrived's Try block to to
B4X:
    Try
        If(Packet.Length = 10) Then
            If playbackFlag = False Then
                playbackFlag = True
                Log("Start playing")
                AT.Start
            Else
                playbackFlag = False
                Log("Stop playing")
                AT.Drain
                AT.Stop
            End If
        End If
        If playbackFlag = True Then AT.Write(Packet.Data,Packet.Offset,Packet.Length)
    Catch
        Log(LastException)
    End Try
Note: This may not be 100% robust, since UDP can have packet loss and the start/stop flags may be one of the packets that get lost. Nor does this handle multiple playback devices. But this at least should get you up and running.
 
Upvote 0

bjfhs

Active Member
Licensed User
You are right.Now I can work with it ,but with a long delay about one second.Do you know how to reduce it?
You are so kind,thank you very much.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
You can try changing the size of the buffer that AudioStreamer uses for recording. In your B4A app, after
B4X:
audioStream.Initialize("AudioStream", 22050, True, 16, audioStream.VOLUME_MUSIC)
do
B4X:
Dim r As Reflector
r.Target = audioStream
Dim newBuffer(512) As Byte
r.SetField2("recordBuffer", newBuffer)
Note: This requires the Reflection library (make sure it's checked under the Libraries Manager).
Note2: Use the like feature of the forum for posts you like. Thanks.
 
Upvote 0

bjfhs

Active Member
Licensed User
You can try changing the size of the buffer that AudioStreamer uses for recording. In your B4A app, after
B4X:
audioStream.Initialize("AudioStream", 22050, True, 16, audioStream.VOLUME_MUSIC)
do
B4X:
Dim r As Reflector
r.Target = audioStream
Dim newBuffer(512) As Byte
r.SetField2("recordBuffer", newBuffer)
Note: This requires the Reflection library (make sure it's checked under the Libraries Manager).
Note2: Use the like feature of the forum for posts you like. Thanks.
Thank you very much.You're really good.Now It work well.
 
Upvote 0
Top