Author Topic: Tell me reasons why I might have a gap in playback while freeing an audio file  (Read 807 times)

Christos

  • Posts: 21
Hi there,
so I have my playlist going on and on the "tail" of of song1 I start the next song2. So at about 3-4 seconds while song2 is playing, song1 must be unloaded. I do not have AUTOFREE flag on because under some circumstances I might need the song again, so I have a timer that checks the the file has finished (with BASS_ChannelIsActive) and frees the file when it has come to an end. This is where the weird thing happens. In random intervals, but not frequently (almost every 12-15 hours) song2 will stop playing for 200-300ms while song1 is being freed. Its like bass halts for those 200-300ms and I cannot find the reason. It is also difficult to reproduce as I need to wait hours and listen all the time till this happens.

The songs plug into a nonstop mixer channel, that connects to a split stream that will playback directly to the soundcard. I do this so I can get the output of the mixed content and add split streams whenever I want so I can redirect the audio to other stuff too simultaneously (like encoders, or secondary soundcards etc).

I am using vb.net with bass.net of course. I tried freeing the file from a different thread (not the STA) that minimized the problem but did not vanish.

Any ideas what I might be doing wrong?

Ian @ un4seen

  • Administrator
  • Posts: 21861
To perhaps help identify what's causing the problem, can you try logging how long the BASS_StreamFree call takes and see if it's taking longer than usual when the problem happens? Also confirm whether the stream is plugged into a mixer at that time. If you're unsure, you can use BASS_Mixer_ChannelGetMixer to check. If it is plugged into a mixer, you could also try calling BASS_Mixer_ChannelRemove first and see if that helps.

Btw, rather than polling BASS_ChannelIsActive, you could set a BASS_SYNC_END sync (via BASS_ChannelSetSync) to get notified when the end is reached.

Christos

  • Posts: 21
Hi again,
Its more than a year that this issue basically started and I tried all the stuff you suggested but I never had a cure, so I continued ignoring it until I am close to release when I will dedicate time only for this issue. The problem never dissapeared. I used the BASS_SYNC_END to unload when needed the files, I also logged that either freeing the files or unplugging them from the mixer would not take more than 1ms, but I noticed something very wrong previously. The gaps do not happen when the previous file is freed, rather when the new file starts playing, with a 1-2 second delay. The whole mixer stalls. I hooked up a sync to the playable channel - that is a mixer with NONSTOP and it will fire up one or two times the stall and resume event when this happens.

And here comes the very strange part:
Simultaneously there is another mixer running, outputing to another soundcard (mostly for PFL/Monitoring purposes) that is usually dormant at the time (the mixer was running nonstop but nothing was playing) and this fired up a stall event too!! This gave me the impression that the whole BASS system halted for these 400ms, as the second soundcard and mixer had nothing to do with the main playable mixer and sources.

I am attaching an audio file where I have recorded these events several times the last week.

This problem might appear 2 times in an hour, or 1 time a day. You dont know!! I have not found a way to reproduce it. Is there a way to get a debugging BASS dll to log what is going on so you can see what could be the cause?

The strange thing is that I basically use the same playback methodology in my very old VB6 application with no problems, but in VB.NET I have this problem. The difference is that the files are loaded on a different thread (Stream_CreateFile) so it wont halt the UI thread while loading & scanning.

This is a huge problem that has gotten me sooo frustrated, and I tried everything before continuing this post again.

Thanks in advance!

Ian @ un4seen

  • Administrator
  • Posts: 21861
Its more than a year that this issue basically started and I tried all the stuff you suggested but I never had a cure, so I continued ignoring it until I am close to release when I will dedicate time only for this issue. The problem never dissapeared. I used the BASS_SYNC_END to unload when needed the files, I also logged that either freeing the files or unplugging them from the mixer would not take more than 1ms, but I noticed something very wrong previously. The gaps do not happen when the previous file is freed, rather when the new file starts playing, with a 1-2 second delay. The whole mixer stalls. I hooked up a sync to the playable channel - that is a mixer with NONSTOP and it will fire up one or two times the stall and resume event when this happens.

Are you calling BASS_StreamCreateFile in a "mixtime" SYNCPROC callback on the mixer? If so, that would block the mixer processing while the file's stream is created. If the drive has gone to sleep in the meantime that could introduce a significant delay. If that is what's happening, you could try creating the new file's stream in a different thread some time in advance of adding it to the mixer (so the SYNCPROC can simply call BASS_Mixer_StreamAddChannel).

And here comes the very strange part:
Simultaneously there is another mixer running, outputing to another soundcard (mostly for PFL/Monitoring purposes) that is usually dormant at the time (the mixer was running nonstop but nothing was playing) and this fired up a stall event too!! This gave me the impression that the whole BASS system halted for these 400ms, as the second soundcard and mixer had nothing to do with the main playable mixer and sources.

By default, BASS uses a single thread to update playback buffers, which means that any delays in one stream's processing will also delay the processing of other streams. You can avoid that by enabling additional update threads via the BASS_CONFIG_UPDATETHREADS option.

The strange thing is that I basically use the same playback methodology in my very old VB6 application with no problems, but in VB.NET I have this problem. The difference is that the files are loaded on a different thread (Stream_CreateFile) so it wont halt the UI thread while loading & scanning.

If the problem began when you started using .Net, the delay may be related to garbage collection, which blocks all .Net code (including your mixtime SYNCPROCs). I'm not a .Net user myself but this stuff looks like it could be useful in that regard:

   https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/latency

Christos

  • Posts: 21
Are you calling BASS_StreamCreateFile in a "mixtime" SYNCPROC callback on the mixer? If so, that would block the mixer processing while the file's stream is created. If the drive has gone to sleep in the meantime that could introduce a significant delay. If that is what's happening, you could try creating the new file's stream in a different thread some time in advance of adding it to the mixer (so the SYNCPROC can simply call BASS_Mixer_StreamAddChannel).

No, a timer is watching the "mixtime" of the currently playing file, so it will unpause the next one that is already created and plugged into the mixer with the pause flag, waiting to play - many minutes before its airing time, so it can be ready to roll in case the user wants to play it earlier. I use absolutely no syncs and callbacks of bass exactly for the reason of that there is a chance that they might be blocked by .net. For this reason I always have timers checking asking bass what is the state and position of a file, instaid of relying on callbacks.

The only callback I have created for debugging purposes is the STALL one on the mixers/output playable streams. The decoding streams never raise a stall event.

By default, BASS uses a single thread to update playback buffers, which means that any delays in one stream's processing will also delay the processing of other streams. You can avoid that by enabling additional update threads via the BASS_CONFIG_UPDATETHREADS option.

Yes, just by increasing the threads, the stall event stopped on the second sound card. But it continued to raise on the main one.

If the problem began when you started using .Net, the delay may be related to garbage collection, which blocks all .Net code (including your mixtime SYNCPROCs). I'm not a .Net user myself but this stuff looks like it could be useful in that regard:

   https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/latency

For debugging purposes I have made a button where I call manually the garbage collector, or call it by code to see if there is any blocking, although I do not have any callbacks as I told you. I also have tried loading the audio files into memory and playing them from there, and also with BASS_ASYNCFILE, but I have the same effect. Hard disks never turn off and the computer is in high performance power state with nothing turning off. This is very strange!! I even plugged the audio file into the mixer the time it is to play, without waiting for several minutes in pause state. Nothing. Anything else I could try?

The only thing I am going to test and try now, is to call BASS_StreamCreateFile on my main thread and not on a different one, as my VB6 app used to, other than that I cannot find any differences. This is called several minutes before the file is going to be played as I told you, so there will be no delay when time comes to play.

I would also like to remind you that the mixer has the NONSTOP flag. This means that even if the new stream started playing, the old stream was still fading out, but BOTH stopped. Why would the old stream stop playing too? Basically why would the mixer stop processing even if one of the two sources stalled? I have not used any BASS_MIXER_LIMIT to any sources or generally anywhere in my app, so the mixer would stall if data from a source becomes unavailable.  :-[

UPDATE: Loading the file on the UI thread had no effect in the problem. It continues. I had the stall event again...
« Last Edit: 14 May '19 - 11:05 by Christos »

Ian @ un4seen

  • Administrator
  • Posts: 21861
No, a timer is watching the "mixtime" of the currently playing file, so it will unpause the next one that is already created and plugged into the mixer with the pause flag, waiting to play - many minutes before its airing time, so it can be ready to roll in case the user wants to play it earlier. I use absolutely no syncs and callbacks of bass exactly for the reason of that there is a chance that they might be blocked by .net. For this reason I always have timers checking asking bass what is the state and position of a file, instaid of relying on callbacks.

If the stream was created a long time in advance, perhaps the drive may have gone to sleep in the meantime? To eliminate that as a possibility, you could try running this to keep the drive alive:

   https://github.com/stsrki/keepalivehd

The drive going to sleep has been the source of problems like yours for other users, so this would be the first thing to check.

By default, BASS uses a single thread to update playback buffers, which means that any delays in one stream's processing will also delay the processing of other streams. You can avoid that by enabling additional update threads via the BASS_CONFIG_UPDATETHREADS option.

Yes, just by increasing the threads, the stall event stopped on the second sound card. But it continued to raise on the main one.

This confirms that the delay is occuring somewhere in the mixer's update cycle. First check if the drive is going to sleep. If that isn't it, another thing to check is if you're using BASS_ChannelLock at all?

I would also like to remind you that the mixer has the NONSTOP flag. This means that even if the new stream started playing, the old stream was still fading out, but BOTH stopped. Why would the old stream stop playing too? Basically why would the mixer stop processing even if one of the two sources stalled? I have not used any BASS_MIXER_LIMIT to any sources or generally anywhere in my app, so the mixer would stall if data from a source becomes unavailable.  :-[

I'm not very familiar with .Net's garbage collection but perhaps it can suspend threads at any point? If so, perhaps it happens to be suspending your timer's thread in the middle of a BASS_Mixer_StreamAddChannel call, resulting in the mixer's update cycle being blocked. You could try enabling the "low latency" GC mode (in the link I posted earlier) in the timer.

Christos

  • Posts: 21
Well, here are my experiment results from the last 48 hours:
First of all, although I was pretty sure of it, playing around with the hard disks had absolutely no difference. I compiled and run KeepAliveHD as you mentioned but had no effect. Why would it, as the hard disk would not sleep because it has all the audio, so bass is reading all the time from it. Just for fun, I also disabled KeepAliveHD and put on windows power options the disk to sleep at one minute so I can see what happens. Nothing again. The problem would be there, and show up once in some hours. I even put an SSD disk, copied all audio there and have the same effect!!

I also put the BASS_SAMPLE_SOFTWARE wherever I could to see if there would be any difference. Again nothing

.net cannot suspend an outside native thread by itself. And by the time the gaps were happening, there is no streamcreatefile - as this happens earlier, just the   BASS_Mixer_ChannelFlags(PlayerFileHandle, 0, BASSFlag.BASS_MIXER_PAUSE)

Runtime.GCSettings.LatencyMode = Runtime.GCLatencyMode.LowLatency had no effect, the same thing, the app just took much more memory.

I also tried two instances of the app playing on different soundcards. One onboard and one USB with the same result, with a few hours difference. This is my log:

*09:42:01.605 MTA(16) WINDOWS: Speakers (M-Audio M-Track 2X2) PlaybackChannel BASS STALL EVENT: HANDLE:-2147483597 CHANNEL:-2147483603 DATA:STALLED
*09:42:01.605 MTA(16) WINDOWS: Speakers (M-Audio M-Track 2X2) PlaybackChannel BASS STALL EVENT: HANDLE:-2147483597 CHANNEL:-2147483603 DATA:RESUMED FROM STALLING

*05:30:06.353 MTA(14) WINDOWS: Speakers (Realtek High Definition Audio) PlaybackChannel BASS STALL EVENT: HANDLE:-2147483630 CHANNEL:-2147483636 DATA:STALLED
*05:30:06.359 MTA(14) WINDOWS: Speakers (Realtek High Definition Audio) PlaybackChannel BASS STALL EVENT: HANDLE:-2147483630 CHANNEL:-2147483636 DATA:RESUMED FROM STALLING

Still do not know what else to do...

Ian @ un4seen

  • Administrator
  • Posts: 21861
.net cannot suspend an outside native thread by itself. And by the time the gaps were happening, there is no streamcreatefile - as this happens earlier, just the   BASS_Mixer_ChannelFlags(PlayerFileHandle, 0, BASSFlag.BASS_MIXER_PAUSE)

Although GC won't directly suspend native threads, perhaps it can suspend a .Net thread that's in native code? For example, BASS_Mixer_ChannelFlags will lock the mixer while it applies the flag changes, so if the thread gets suspended in the middle of that, it will block the mixer processing, possibly resulting in stalled playback (depending on how long it's blocked).

I will send you a debug BASSmix version to get more info on what's happening. Please confirm all of the BASS and BASSmix functions that you are using (to see what needs checking).

Christos

  • Posts: 21
(usually when preloading the file)
Code: [Select]
BASS_StreamCreateFile
BASS_Mixer_StreamAddChannel
BASS_ChannelSetPosition

(when it is ready to play)
Code: [Select]
BASS_ChannelGetPosition
BASS_Mixer_ChannelFlags //(FOR PLAY)
BASS_ChannelGetAttribute(PlayerFileHandle, BASSAttribute.BASS_ATTRIB_VOL, CurrentPlayerVolume)
BASS_Mixer_ChannelRemove(PlayerFileHandle)
BASS_StreamFree(PlayerFileHandle)
BASS_Mixer_ChannelFlags(PlayerFileHandle, BASSFlag.BASS_MIXER_PAUSE, 0) //to see if it is paused
BASS_ChannelIsActive(PlayerFileHandle)

these are the functions mostly that run during the time of the problem. some of them are in timers (like the BASS_ChannelGetPosition), some of them execute once in each file.

I am very concerned with what you said about .net because if its not only the callbacks (that I have managed to put them in my mixed assembly so they are not blocked anymore), i will also need to make basically my own version of bass.net in the mixed assembly where I could call the BASS functions in its own c++ unmanaged threads without getting blocked by the managed platform and finding a way asyncly to return any result
« Last Edit: 17 May '19 - 16:01 by Christos »

Ian @ un4seen

  • Administrator
  • Posts: 21861
I am very concerned with what you said about .net because if its not only the callbacks (that I have managed to put them in my mixed assembly so they are not blocked anymore), i will also need to make basically my own version of bass.net in the mixed assembly where I could call the BASS functions in its own c++ unmanaged threads without getting blocked by the managed platform and finding a way asyncly to return any result

I'm not sure if .Net will actually suspend a thread in a native call, I was just pondering the possibility of that. The debug BASSmix version (sent just now) will hopefully reveal if that's happening.