Android Question MediaPlayer Load causing program lag

Greg Conely

Member
Licensed User
Longtime User
I have been trying on and off for the last month or more on ways to get the MediaPlayer to load and play a song and not delay the rest of the execution of my game. It seems like the delay occurs when the .Load() function is called, and nothing I can do seems to get me around this. Tried using CallSubDelayed and even have the entire procedure that loads and plays a song on a separate dedicated timer that is separate from my main timer that I use for everything else.

I looked into the MediaPlayerStream but could not find a way to load from a local location. Tried for a while working with using "file:///android_asset/" URI, but just kept getting a generic error in the StreamError procedure. My guess is I can't use use this method.

The delay is not very long, maybe 1/2 to 1 and 1/2 seconds, but is something I would really like to eliminate. The audio files are OGG format, added to the Files tab, anywhere between 200kb and 2.7mb (it doesn't seem like it really matters which one I call to cause the delay).

I am using a little bit older version (3.20), so have wondered if this may have been resolved with a newer version. (I did try looking through any release notes I could find). I have also tried looking at maybe calling a JavaObject to do this?

Thanks.
 

Greg Conely

Member
Licensed User
Longtime User
Attached is one of the files. This one is one of the smaller ones. Some get upwards to 2-4 Mbytes. However any load call, no matter the size of file, causes a lag. I have even tried to copy the files out of the Assests folder and loading it from the SD card or internal storage, yet it still causes the delay.

It would be hard to post my code, but essentially I do the following:

B4X:
Sub Activity_Create(FirstTime As Boolean)
  ...
  myMediaPlayer.Initialize2("myMedia")
  ....
end sub

Private Sub LoadAGameSong()
        tmpId = Rnd(0,13)
        Select Case tmpId
            Case 0 : SongName="_346455.ogg"
            Case 1 : SongName="_210737.ogg"
            ....
        End Select


        myMediaPlayer.Load(File.DirAssets,SongName )
        myMediaPlayer.Looping=False
        myMediaPlayer.SetVolume(MusicVolume,MusicVolume)
        myMediaPlayer.Play
        ShouldPlayASong=False

End Sub



Sub Timer2_Tick()
    If ShouldPlayASong AND LoadingSong=False Then CallSubDelayed(Me,"LoadAGameSong")
End Sub
 

Attachments

  • _210737.zip
    382.4 KB · Views: 221
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Switch to MediaPlayerStream. It will allow you to load the file asynchronously:
B4X:
Sub Process_Globals
   Private mps As MediaPlayerStream
End Sub


Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     mps.Initialize("mps")
     Dim f As String = "_210737.ogg"
     If File.Exists(File.DirDefaultExternal, f) = False Then
       File.Copy(File.DirAssets, f, File.DirDefaultExternal, f)
     End If
     mps.Load($"file://${File.Combine(File.DirDefaultExternal,f)}"$)
   End If
End Sub

Sub mps_StreamReady
   Log("ready")
   mps.Play
End Sub
 
Upvote 0

Greg Conely

Member
Licensed User
Longtime User
I had to change the Load call for syntax.

myMediaPlayer.Load("file://"&File.Combine(File.DirDefaultExternal,SongName))

Tried to keep the brackets and $, but not sure what those are for. I changed it to the following syntax. It does load and play, however it still causes a lag. Not sure if it is during the load or play call.
 
Upvote 0

Greg Conely

Member
Licensed User
Longtime User
Below is what I changed my code to. I have a primary 'Timer1' that runs my main game thread. I was calling the PlaySong within this loop, but tried to change it to a secondary timer to troubleshoot the issue. In this first timer, it does all the game logic and screen refresh. When the song switches (either when the last song was done or the user presses the [next song] button) there is a delay where no logic or screen refresh occurs (I am guessing timer 1 doesn't get fired). Also, I use the TouchGestures to control pinch zooming, dragging, etc... If the user is in the middle of dragging when the song switches, it stops any refresh from the user touch events until the song starts playing. You may notice I also use a soundpool. I have been testing recently and making sure the SoundPool.Play event wasn't being called at the same time.

B4X:
Sub Process_Globals
   Private timer1 As Timer
   Private timer2 As Timer

   Dim MusicVolume As Double
   Dim SoundVolume As Double
   Dim SoundNames(128) As String
   Dim SoundIds(128) As String
   Dim Sounds As SoundPool
   Dim myMediaPlayer As MediaPlayerStream
   Dim SoundCount As Int = 0
   Dim CurrentSong As String
   Dim PlayingSong As Boolean = False
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("1")
   cvs.Initialize(Activity)
   myMediaPlayer.Initialize("myMedia")

  If FirstTime Then
     timer1.Initialize("Timer1",  10)
     timer2.Initialize("Timer2",  1000)   
   End If

End Sub


Sub myMedia_StreamReady()
    Log ("Media stream has ben loaded.")
    myMediaPlayer.Play
End Sub

Sub myMedia_StreamError(ErrorCode As String, ExtraData As Int  )
    Log ("Media load had an error. Code = '" & ErrorCode & "', Data=" & NumberFormat(ExtraData,1,0))
    myMediaPlayer.Stop
    PlayingSong=False
    CurrentSong = ""
End Sub

Sub PlaySong(SongName As String )
    If Muted Then Return
    If CurrentSong = SongName AND myMediaPlayer.IsPlaying Then Return
   
    If PlayingSong Then myMediaPlayer.Stop ' Sounds.Stop(CurrentSongId)
    PlayingSong=True
    CurrentSong = SongName
    myMediaPlayer.Looping=True
    myMediaPlayer.SetVolume(MusicVolume,MusicVolume)
    myMediaPlayer.Load("file://"&File.Combine(File.DirDefaultExternal,SongName))
End Sub

Sub PlaySongOnce(SongName As String)
    If Muted Then Return
    If PlayingSong Then myMediaPlayer.Stop ' Sounds.Stop(CurrentSongId)
    PlayingSong=False
    CurrentSong=""
    myMediaPlayer.Looping=False
    myMediaPlayer.Load("file://"&File.Combine(File.DirDefaultExternal,SongName))
End Sub


Sub StopSong()
    If myMediaPlayer.IsPlaying Then myMediaPlayer.Stop
    PlayingSong=False
    CurrentSong=""
End Sub

Sub Timer2_Tick()
   If ShouldPlayASong AND LoadingSong=False Then CallSubDelayed(Me,"LoadAGameSong")
End Sub

Thanks again greatly for all of your time and assistance in this - Greg
 
Upvote 0

Greg Conely

Member
Licensed User
Longtime User
I added some logging with timestamps and then noticed I was checking to see if the file existed in the assets folder before trying to load it. This check is what was slowing it down. Once I fixed this to look for the file in the external storage, it worked great. Any way of getting the MediaPlayerStream to load from the applications Assets folder instead of the external directory? Just trying to see if I could limit the storage usage by not needing this second copy of the files.

Again, very much thanks for your assistance and patience.
 
Upvote 0
Top