Author Topic: Slow buffering, pops, and crackles with BASS_StreamCreateFileUser on Android  (Read 6594 times)

mcooper

  • Posts: 53
Hello,

We are using Bass.NET on iOS and Android to play online audio streams.  I want to be able to retry / resume http connections on errors, so I'm using Bass.BASS_StreamCreateFileUser(BASSStreamSystem.STREAMFILE_BUFFER, BASSFlag.BASS_STREAM_AUTOFREE, _fileProcs, IntPtr.Zero) to create the stream handle.

Its working correctly, and the FILEREADPROC basically just reads from an HTTP response stream.  This will be improved later to add the error handling.

On iOS, the playback starts quickly (similar to as it was with BASS_StreamCreateURL), but its much slower on Android.  It looks like the FILEREADPROC is making many more requests with a very small length (4).  The settings and config is the same on both platform.  Is there any way to increase this length, or reduce the number of calls?

Thank you,

Matt
      
« Last Edit: 11 Jun '15 - 13:13 by mcooper »

Ian @ un4seen

  • Administrator
  • Posts: 26223
I guess the small read requests only happen within the BASS_StreamCreateFileUser call, not after it has returned? Within the BASS_StreamCreateFileUser call, the read requests will be coming directly from the decoder, and some of them may be small. After the call returns, BASS will request larger blocks to fill the download buffer, and the decoder will then get the data from there. Generally, smaller reads shouldn't be much slower as the OS will still be receiving normal sized packets from the server, eg. it won't be receiving 4 byte packets in your case. I guess the .Net managed stuff will increase the overhead of each request though, making smaller requests less efficient. The same could apply to Java too. To help with that, a BASS update is now up in the Android thread that will request at least 512 bytes each time. Let me know if it still seems slower in your case.

   www.un4seen.com/forum/?topic=13225

mcooper

  • Posts: 53
Thank you for the very quick response.  It seems better so far, but the network is very unreliable right now, so I need to do some more testing.

mcooper

  • Posts: 53
It's definitely faster, but unstable. I'll need to debug to see what is going on, perhaps adjust the buffer settings. Do they still apply in this case?

Ian @ un4seen

  • Administrator
  • Posts: 26223
Please clarify what you mean by "unstable", eg. is the app crashing or the sound stuttering, or something else? Also, do you get the same thing on Windows (with the same URL and internet connection) or is it only happening on Android?

The BASS_CONFIG_NET_BUFFER/etc options do also apply to "buffered" user file streams, but I think it's unlikely they would be causing the problem. To check whether those settings could be causing the problem, you could try playing the same URL with BASS_StreamCreateURL instead of BASS_StreamCreateFileUser and your file routines, with the same BASS_CONFIG_NET_BUFFER/etc settings.

mcooper

  • Posts: 53
Hello Ian,

Sorry about the confusion. I had been trying different config and flags to see if they helped with the small reads.  When I reverted all of those changes, everything appears to be working as it should.  So, the Bass Android update does seem to have fixed my issue, and performance is now similar to as it was when using BASS_StreamCreateURL.

Thanks again,

Matt

mcooper

  • Posts: 53
I am hearing little blips during playback on android though, which aren't noticeable on iOS (with the same settings, code, uri, connection, etc).  I didn't hear these when using BASS_StreamCreateURL.

Ian @ un4seen

  • Administrator
  • Posts: 26223
To help locate where the "blips" are coming from, please try writing the stream's data to a WAV file and then see if the blips are also present in that. You can use the BASSenc add-on to do the WAV writing, like this:

Code: [Select]
BASS_Encode_Start(handle, "/sdcard/output.wav", BASS_ENCODE_PCM|BASS_ENCODE_AUTOFREE, NULL, 0);

mcooper

  • Posts: 53
Hello Ian,

Thank you for the suggestion, and sorry about the late reply. The problem is intermittent, and I was trying to see if I could identify a pattern.  I can't see though, so suspect it might be related to network connection speed.

It may be hardware dependant - I can consistently repro this on an HTC One, but not on a Sony Z1.

I have written the stream to a wav file, and in cases where I hear the blips, if I reply the wav file, I cannot hear the blips in that.

Matt
« Last Edit: 4 Jun '15 - 14:49 by mcooper »

Ian @ un4seen

  • Administrator
  • Posts: 26223
OK. If the written WAV file sounds fine, then that means the problem isn't in the original file data or the decoder. Another possibility is that the output is briefly stalling, ie. running out of data to play. To check that, you can set a BASS_SYNC_STALL sync and see if it gets triggered, something like this:

Code: [Select]
BASS.SYNCPROC StallSync=new BASS.SYNCPROC() {
public void SYNCPROC(int handle, int channel, int data, Object user) {
// do something here, eg. display/log problem
}
};

BASS.BASS_ChannelSetSync(handle, BASS.BASS_SYNC_STALL, 0, StallSync, 0);

Another possibility is that the app is being starved of CPU time. Does the problem only happen when the app is in the background, and if so, have you implemented a "foreground service"?

mcooper

  • Posts: 53
Hello,

I have added some logging to the BASS_SYNC_STALL method, and it does get called occasionally, but it doesn't seem to correspond to the audio glitches.  I've heard them in songs when the method isn't called, and heard them without seeing the method called.

Our audio playback is in a foreground service, and I can hear the issue when the app is in the foreground, so I don't think its a cpu issue.

Matt

Ian @ un4seen

  • Administrator
  • Posts: 26223
If the BASS_SYNC_STALL sync is getting triggered, then that is likely to be audible as a gap/stutter in playback, which I guess is what the "blips" you're hearing are? Another thing you could try logging is how much data is available in the "download" buffer using BASS_StreamGetFilePosition. For example, you could do this in the BASS_SYNC_STALL sync callback:

Code: [Select]
long buffered=BASS.BASS_StreamGetFilePosition(handle, BASS.BASS_FILEPOS_DOWNLOAD) // download position
-BASS.BASS_StreamGetFilePosition(handle, BASS.BASS_FILEPOS_CURRENT); // decoder position

If that hits 0 (or close to it), then it would indicate that the file data isn't arriving quickly enough to sustain playback, which is resulting in the stalling.

You mentioned that the problem never happens when using BASS_StreamCreateURL. For comparison, if you set a BASS_SYNC_STALL sync on that, does it ever get triggered?

mcooper

  • Posts: 53
BASS_SYNC_STALL is called very rarely, only on a very poor network connection and this results in a noticeable pause in the audio. The blips are noticeable on average every 15 seconds, regardless of network connection, and these don't coincide wth calls to BASS_SYNC_STALL.    I can listen for hours, hear multiple blips per track without BASS_SYNC_STALL being called, so I'm convinced they are unrelated.

I've gone back to an earlier version of the app that used BASS_StreamCreateURL and can also hear the blips.  I didn't notice them at the time, but its the sort of thing that is quite subtle until you're aware of it, and then quite annoying after that.

I am also now sure this is hardware specific.  It seems to be reproducible on an HTC one, but not on a Sony Z1.  My colleague also noticed this on an HTC, but we have since released a test version to more users on a range of devices, so we'll see if anyone else notices it.

Ian @ un4seen

  • Administrator
  • Posts: 26223
Another thing you could try is increasing the size of the device buffer via the BASS_CONFIG_DEV_BUFFER option. It needs to be set prior to calling BASS_Init, ie. you will need to call BASS_Free and BASS_Init again if you want to change an already initialized output. The default on Android is currently 30ms, so you could try 40ms and see if that makes a difference.

mcooper

  • Posts: 53
Thanks. I'll try that.  I've also heard reports of crackling during playback on other devices.  I assume this could fix that too?

Ian @ un4seen

  • Administrator
  • Posts: 26223
It's a possibility. Let me know what you find.

mcooper

  • Posts: 53
I've tried increasing BASS_CONFIG_DEV_BUFFER to different values (all the way up to 1000) without any noticeable improvements. 

Once again noticed popping sounds when playback starts and stops on Sony phones, but I think I can workaround that by setting the volume to 0 and restoring it.

The crackling seems specific to Samsung, and the blips I originally noticed were only on HTC and I can't hear them anymore. I'm not sure if that is good or bad :(

Ian @ un4seen

  • Administrator
  • Posts: 26223
OK. To help narrow down what the problem is, does it affect playback of local files too, ie. when using BASS_StreamCreateFile rather than BASS_StreamCreateURL? Can you also reproduce it with the examples included in the BASS package, eg. the NETRADIO example?

Regarding the pops when starting/stopping playback, that could be caused by the device starting/stopping output, in which case enabling the BASS_CONFIG_DEV_NONSTOP option (which tells BASS to continue producing output when nothing is playing) may help.

Code: [Select]
BASS.BASS_SetConfig(BASS.BASS_CONFIG_DEV_NONSTOP, 1); // don't stop output when nothing is playing

mcooper

  • Posts: 53
Hello Ian,

Yes, we've had all of these issues reported on local files too.  I'll try some of the sample files (but its not easy to reproduce when I try).

We already have BASS_CONFIG_DEV_NONSTOP enabled, and it doesn't seem to prevent the start / stop noises.

Is there any way to get more logging out of bass android? If so, would that help identify any of these issues?

Matt

Ian @ un4seen

  • Administrator
  • Posts: 26223
OK. I'll try to think of some things to check for clues, and then send you a debug BASS version that logs those things. To help identify what to check, is the problem happening when you play any file format (including WAV) or only a particular file format?

As well as trying to reproduce the problem on the affected devices with the BASS examples, please also check whether it happens with other (non-BASS) software.

mcooper

  • Posts: 53
All of our music files are either eaac+ or aac so its only been noticed on those.  Most users have said this issue is unique to our app, although one user admitted that he has also heard crackling on another music app (google play music), but much less frequently.

Valdi

  • Posts: 8
Hello Ian!

We've added BASS_CONFIG_DEV_NONSTOP to our code for android to avoid pops and crackling between tracks.
The problem we have now is that it consumes a lot of power while the music is in paused state.
One of wake locks audiomix is not released until I remove that option from our code.

Is there any way to fix that issue?
Thanks in advance for your help.

Ian @ un4seen

  • Administrator
  • Posts: 26223
I'm not sure whether it will be as effective as enabling BASS_CONFIG_DEV_NONSTOP, but one thing you could try is just delaying the stopping of the output for a short time. You could do that by using a sample of the wanted delay length. For example, something like this:

Code: [Select]
// initialization
BASS.BASS_SetConfig(BASS_CONFIG_DEV_NONSTOP, 0); // disable nonstop output
sample=BASS.BASS_SampleCreate(30*2, 1000, 1, 1, 0); // create a 30ms sample

...

// pausing playback
int samchan=BASS.BASS_SampleGetChannel(sample, false); // get a sample channel
BASS.BASS_ChannelSetAttribute(samchan, BASS.BASS_ATTRIB_VOL, 0); // mute it (saves CPU)
BASS.BASS_ChannelPlay(samchan, false); // start it
BASS.BASS_ChannelPause(music); // pause playback of the music

You can try adjusting the length of the sample to find the smallest (if any) delay that works. If that avoids the "pops" when stopping playback, but you're also getting them when starting, then you could also try playing the sample just before starting playback of the main channel.

Ian @ un4seen

  • Administrator
  • Posts: 26223
If delaying the output stopping doesn't help (eg. it just delays the "pop" sound), then another thing you could try is the BASS_CONFIG_DEV_PERIOD option. That was added quite recently and is currently undocumented, but it controls how often BASS sends data to the output device and how much each time. The default setting is 10ms, which means it sends 10ms of data to the output device 100 times per second. Perhaps raising that (eg. to 15ms) will reduce the power usage when BASS_CONFIG_DEV_NONSTOP is enabled. Note that it needs to be set prior to calling BASS_Init, like the BASS_CONFIG_DEV_BUFFER option.