Android Question Audio Library v1.63 - IsInitialized ?

Jmu5667

Well-Known Member
Licensed User
Longtime User
Hi

I have noticed that there is no IsInitialized method in the lib, how can we test if it is initialized ?

Regards

John.
 

Jmu5667

Well-Known Member
Licensed User
Longtime User
I don't know this specific case; but, generally, I would use a Try-Catch block, setting a property.
Yeah, put that in this morning, I was just wondering is there was a more formal way, maybe a generic piece of Java or something ....
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
I took a look; it does not seem to me that it should be initialized, only "imported" (checked) and used.

Mmm.. I had an issue after it was initialized2 when I called audiostream.startplaying I got :
error - java.lang.IllegalStateException: play() called on uninitialized AudioTrack

The init stream was :
09/02/2018 04:40:11.751 - svc_data(3), init_stream, Sample Rate 8000, Encoding 16
The error occurred at:
2018 10:00:56.464 - svc_data(), TextMessageReceived, error - java.lang.IllegalStateException: play() called on uninitialized AudioTrack.

notice the time difference, I wounder does it die after a time.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Posting your code would help.

What were the parameters you used? Not all devices support all possible parameters.

What do you get if you try logging your audiostream object when it fails?
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Posting your code would help.

What were the parameters you used? Not all devices support all possible parameters.

What do you get if you try logging your audiostream object when it fails?

Hi Steve

This is the init code:

B4X:
Sub init_stream

   Dim p As Phone
   Dim mono As Boolean = True
   
   mod_functions.writelog("svc_data(" & Main.APPSET.currentChannel.channel_id & "), init_stream, Sample Rate " & _
                   Main.APPSET.currentChannel.pcm_samplerate & ", Encoding " & _
                   Main.APPSET.currentChannel.pcm_endcoding  )

   ' // https://developer.android.com/reference/android/media/MediaRecorder.AudioSource
   Try
       If p.SdkVersion = 21 Or p.SdkVersion = 22 Then
           ' // VOICE_COMMUNICATION
           If Main.APPSET.ptt_device.connected Then
               audioStream.Initialize2(7,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_VOICE_CALL)
           Else
               audioStream.Initialize2(7,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_MUSIC)
           End If
       Else
           ' // MIC
           audioStream.Initialize2(1,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_MUSIC)
           
       End If
   Catch
       mod_functions.writeLog("connector:init_stream() error - " & LastException.Message)
   End Try
   
End Sub

This the start playing code:

B4X:
Sub register_listen

   Dim failedToPlay As Boolean

   Try
       audioStream.StartPlaying
   Catch
       mod_functions.writelog("svc_data(), register_listen(), error -  " & LastException.Message)
       failedToPlay = True
       init_stream
   End Try
   
   Try
       If failedToPlay Then
           audioStream.StartPlaying
       End If
       listeningForAudio = True
       QualityCheck = 0
       udpSck.Initialize("udpSocket",0,2048)
       
       Dim data() As Byte
       data = Main.APPSET.imei.GetBytes("UTF8")

       Dim p As UDPPacket
       p.Initialize(data,Main.APPSET.currentChannel.host,Main.APPSET.currentChannel.udp_listener)
       udpSck.Send(p)
       tmrQualityCheck.Enabled = True
       mod_functions.writelog("svc_data(), register_listen() " & Main.APPSET.currentChannel.host & ":" & Main.APPSET.currentChannel.udp_listener)
   Catch
       mod_functions.writelog("svc_data(), register_listen(), error -  " & LastException.Message)
   End Try   
   
   
End Sub

This is the stop play code:

B4X:
Sub unregister_listen
   
   Try
       ' // call Quality
       tmrQualityCheck.Enabled = False
       IsRemoteSpeaker = False
       listeningForAudio = False
       QualityCheck = 0
       udpSck.close
       audioStream.StopPlaying
   Catch
       mod_functions.writeLog("svc_data(), unregister_listen(),  error - " & LastException.Message)
   End Try
       
End Sub


This is part of a PTT app the connect to out B4J PTT server. The error occurs when I call register_listen. This is a freak occurrence and cannot make it happen.

Regards

John.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Is audiostream declared in Process_Globals or Globals?
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
No clue if it is related, but looking at the state diagram of MediaRecorder (https://developer.android.com/reference/android/media/MediaRecorder), there are many situations in which reset() seems to be called that reverts the object back to a pre-setAudioSource state (looks like that method part of the Initialize method of AudioStreamer class). Please note that AudioStreamer is a combo of MediaRecorder and AudioTrack.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
No clue if it is related, but looking at the state diagram of MediaRecorder (https://developer.android.com/reference/android/media/MediaRecorder), there are many situations in which reset() seems to be called that reverts the object back to a pre-setAudioSource state (looks like that method part of the Initialize method of AudioStreamer class). Please note that AudioStreamer is a combo of MediaRecorder and AudioTrack.

That'a very interesting, lots of resets ...
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Just check a phone I left running over night, and it has happened again. the device that is fails on can transmit audio to other phones, but when other keyup it cannot receives the audio as the register_listen function fails.

In the normal course of events the audiostreamer is initialized each time a new channel is selected. Each Channel may have different settings:

upload_2018-9-4_8-21-2.png



Anyways, the init_steam is called to set the streamer.

The Speaker Client

When a client keys down to speak it wait for an ack from the server before is calls the send_audio
B4X:
Sub SendAudio
   
   mod_functions.writelog("svc_data(), SendAudio")
   
   ' // check is we are still ptt key down
   If Main.APPSET.currentChannel.ptt_state <> 2 Then
       Return   
   End If
   
   Try
       udpSckTalk.Initialize("",0,0)
       audioStream.StartRecording
       sendingAudio = True
   Catch
       mod_functions.writelog("svc_data(),SendAudio() error - " & LastException.Message )
   End Try
       
End Sub

The Listener Client
When a client receives notification that someone is about to speaker they call the register_listen:
B4X:
Sub register_listen

   Dim failedToPlay As Boolean

   Try
       audioStream.StopPlaying
       audioStream.StartPlaying
   Catch
       mod_functions.writelog("svc_data(), register_listen(), error -  " & LastException.Message)
       failedToPlay = True
       init_stream
   End Try
   
   Try
       If failedToPlay Then
           audioStream.StopPlaying
           audioStream.StartPlaying
       End If
       listeningForAudio = True
       QualityCheck = 0
       udpSck.Initialize("udpSocket",0,2048)
       
       Dim data() As Byte
       data = Main.APPSET.imei.GetBytes("UTF8")

       Dim p As UDPPacket
       p.Initialize(data,Main.APPSET.currentChannel.host,Main.APPSET.currentChannel.udp_listener)
       udpSck.Send(p)
       tmrQualityCheck.Enabled = True
       mod_functions.writelog("svc_data(), register_listen() " & Main.APPSET.currentChannel.host & ":" & Main.APPSET.currentChannel.udp_listener)
   Catch
       mod_functions.writelog("svc_data(), register_listen(), error -  " & LastException.Message)
   End Try   
   
   
End Sub

When the Speaker is done Talking
The speaker client will send a ptt key up notification the the server to inform all the listeners that he is done talking. He will also call StopSendingAudio:
B4X:
Public Sub StopSendingAudio
   
   mod_functions.writelog("svc_data(), StopSendingAudio")
   Try
       udpSckTalk.Close
       audioStream.StopRecording
       sendingAudio = False
   Catch
       mod_functions.writelog("svc_data(),StopSendingAudio() error - " & LastException.Message )
   End Try


End Sub

The listener when they receive the notification call unregister_listen:

B4X:
Sub unregister_listen
   
   Try
       ' // call Quality
       tmrQualityCheck.Enabled = False
       IsRemoteSpeaker = False
       listeningForAudio = False
       QualityCheck = 0
       udpSck.close
       audioStream.StopPlaying
   Catch
       mod_functions.writeLog("svc_data(), unregister_listen(),  error - " & LastException.Message)
   End Try
       
End Sub


So, in summary, the audiostreamer is only required to play when a user is speaking, and is stopped when a user is not speaking. Based on the info @OliverA (https://developer.android.com/reference/android/media/MediaRecorder), provided they may seem like a bad idea, any thoughts ? @Erel I know your are busy, what is your view on this please.

Regards

John.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
java.lang.IllegalStateException: play() called on uninitialized AudioTrack

Clue from https://stackoverflow.com/a/12380380. It looks like it's something you just have to deal with. You could filter this out in your try catch block and just treat this error as recoverable and not-necessarily an issue to be logged, unless you like to see how often this happens.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Clue from https://stackoverflow.com/a/12380380. It looks like it's something you just have to deal with. You could filter this out in your try catch block and just treat this error as recoverable and not-necessarily an issue to be logged, unless you like to see how often this happens.
I log everything, it is an unrecoverable error, even if you try to re-init the audiosteam is does not work. So, I will kill the service that uses it, and the service will get started again with the app.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
So, I will kill the server that uses it, and the service will get started again with the app.

I've noticed that you are re-using the same audiostream object in your init code. Have you tried dim'ing a new one, initializing it and then assigning it to your global variable?

B4X:
Sub init_stream

   Dim p As Phone
   Dim mono As Boolean = True
   Dim newAudioStream As AudioStreamer

   mod_functions.writelog("svc_data(" & Main.APPSET.currentChannel.channel_id & "), init_stream, Sample Rate " & _
                   Main.APPSET.currentChannel.pcm_samplerate & ", Encoding " & _
                   Main.APPSET.currentChannel.pcm_endcoding  )

   ' // https://developer.android.com/reference/android/media/MediaRecorder.AudioSource
   Try
       If p.SdkVersion = 21 Or p.SdkVersion = 22 Then
           ' // VOICE_COMMUNICATION
           If Main.APPSET.ptt_device.connected Then
               newAudioStream.Initialize2(7,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_VOICE_CALL)
           Else
               newAudioStream.Initialize2(7,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_MUSIC)
           End If
       Else
           ' // MIC
           newAudioStream.Initialize2(1,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_MUSIC)
           
       End If
       audioStream = newAudioStream

   Catch
       mod_functions.writeLog("connector:init_stream() error - " & LastException.Message)
   End Try
   
End Sub
Technically you would also need to know if the previous audioStream was set to recording and maybe try to stop it from recording (this may be futile attempt, since the object is "reset") before initializing a new audioStream object and re-enabling recording with the new audioStream object.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
I've noticed that you are re-using the same audiostream object in your init code. Have you tried dim'ing a new one, initializing it and then assigning it to your global variable?

B4X:
Sub init_stream

   Dim p As Phone
   Dim mono As Boolean = True
   Dim newAudioStream As AudioStreamer

   mod_functions.writelog("svc_data(" & Main.APPSET.currentChannel.channel_id & "), init_stream, Sample Rate " & _
                   Main.APPSET.currentChannel.pcm_samplerate & ", Encoding " & _
                   Main.APPSET.currentChannel.pcm_endcoding  )

   ' // https://developer.android.com/reference/android/media/MediaRecorder.AudioSource
   Try
       If p.SdkVersion = 21 Or p.SdkVersion = 22 Then
           ' // VOICE_COMMUNICATION
           If Main.APPSET.ptt_device.connected Then
               newAudioStream.Initialize2(7,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_VOICE_CALL)
           Else
               newAudioStream.Initialize2(7,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_MUSIC)
           End If
       Else
           ' // MIC
           newAudioStream.Initialize2(1,"AudioStream",  _
                                       Main.APPSET.currentChannel.pcm_samplerate, _
                                       mono, _
                                       Main.APPSET.currentChannel.pcm_endcoding, _
                                         audioStream.VOLUME_MUSIC)
          
       End If
       audioStream = newAudioStream

   Catch
       mod_functions.writeLog("connector:init_stream() error - " & LastException.Message)
   End Try
  
End Sub
Technically you would also need to know if the previous audioStream was set to recording and maybe try to stop it from recording (this may be futile attempt, since the object is "reset") before initializing a new audioStream object and re-enabling recording with the new audioStream object.


Mmmm...dont know, the fact that it reset(), i kind of game over. Anyways I will look again at it :)
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
the fact that it reset(), i kind of game over.

Dim'ing a new object should take care of the reset(), since now the old audioStreamer object is just not used anymore. I do not know if the old audioStreamer object would keep the hardware tied up, but I would guess no, since each reset() seems to require a setAudioSource call to use an audio device again. Of course, this is all just speculation, since I really don't know what is happening under the hood and I'm just going by the state diagram in the link above. The only other item to watch out for is an active record session. Before creating the new audioStreamer object an active recording would need to be stopped (if possible) and then re-established with the newly created audioStreamer object.
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Dim'ing a new object should take care of the reset(), since now the old audioStreamer object is just not used anymore. I do not know if the old audioStreamer object would keep the hardware tied up, but I would guess no, since each reset() seems to require a setAudioSource call to use an audio device again. Of course, this is all just speculation, since I really don't know what is happening under the hood and I'm just going by the state diagram in the link above. The only other item to watch out for is an active record session. Before creating the new audioStreamer object an active recording would need to be stopped (if possible) and then re-established with the newly created audioStreamer object.

I'll have a look at your suggestions on Thursday/Friday, out of office tomorrow :)
 
Upvote 0
Top