Author Topic: Audio glitches after a week  (Read 2485 times)

Chris Oakley

  • Posts: 96
Audio glitches after a week
« on: 7 Aug '18 - 09:53 »
Hi, got an odd one here, not sure if there's a solution to it. Our app streams audio and at the same time logs the audio (records) to disk. This all works fine. It closes off the audio in hourly chunks so you end up with 24 files for one day for example.

This all works fine for around a week of running. However, after this time, when it stops one file and starts another, it creates this audio glitch which lasts for around 10 seconds. I can only liken it the main background worker thread that is pulling the data is not getting the data fast enough and the audio slows until it stops, at which point it jumps, around 5 seconds of audio is lost and it all goes back to normal.

We hear this on the streamed output and also on the recorded audio.

What's strange is if we turn off the recording facility then the problem goes away. When it starts doing it, it does it every hour until we restart the app. If we tell it to not record a specific hour then when it comes to that hour it closes off the one it's recording and the glitching starts but doesn't stop. It's like starting it up again stops it. If I turn off the recording in the app it closes off the file, doesn't start a new one, but it doesn't glitch.

I have a main worker thread which is pulling the audio data, but then I split off when needed so I can plug the main stream into other submixers to adjust the sample rate the user has selected, be it recording or streaming.

Some other notes, we have the app running on a virtual machine under Hyper-V.

I used this to stop the recording:

Code: [Select]
BassEnc.BASS_Encode_StopEx(EncoderLog, False)
I have also tried True - and that made no difference. It doesn't matter if it's WASAPI, DirectSound or ASIO.

I used the
Code: [Select]
BassEnc.BASS_Encode_Start to start the encoding, using LAME.

This is the worker thread to get the data:

Code: [Select]

        Dim LastMS As Integer = Environment.TickCount - 10

        Dim i As Integer = 0
        Do Until bkgLoggingMixer Is Nothing OrElse bkgLoggingMixer.CancellationPending

            Dim TimeNowMS As Integer = Environment.TickCount

            Dim Levels(2) As Single
            Bass.BASS_ChannelGetLevel(LoggingMixer, Levels, (TimeNowMS - LastMS + 1) / 1000, BASSLevel.BASS_LEVEL_STEREO)

            LastMS = Environment.TickCount

            Threading.Thread.Sleep(10)

        Loop


There are no apparent memory leaks.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #1 on: 7 Aug '18 - 15:20 »
Please show how you are creating the "LoggingMixer" stream and also the BASS_Encode_Start call parameters.

I would also suggest changing this line:

Code: [Select]
            LastMS = Environment.TickCount

To this:

Code: [Select]
            LastMS = TimeNowMS

Otherwise you could be processing too slowly if the BASS_ChannelGetLevel call takes more than 1ms.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #2 on: 7 Aug '18 - 15:37 »
So this bunch of code deals with the creation of the mixer:

Code: [Select]
            'Make a split stream off the main mixer
            LoggingSplitStream = BassMix.BASS_Split_StreamCreate(MixerChan, BASSFlag.BASS_STREAM_DECODE, Nothing)

            'Now make the mixer to resample the split stream
            LoggingMixer = BassMix.BASS_Mixer_StreamCreate(LogFrequency, Channels, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_MIXER_NONSTOP)
            Dim AddEncMix As Boolean = BassMix.BASS_Mixer_StreamAddChannel(LoggingMixer, LoggingSplitStream, BASSFlag.BASS_MIXER_BUFFER Or BASSFlag.BASS_MIXER_LIMIT)

These are the parameters for the encode start:

Code: [Select]
                    EncoderLog = BassEnc.BASS_Encode_Start(LoggingMixer, "lame.exe -r -s " & log & " -b " & LogBitrate & " -a -m " & IIf(LogChannels = 1, "m", "s") & " - """ & FName & ".mp3""", BASSEncode.BASS_ENCODE_NOHEAD Or BASSEncode.BASS_ENCODE_FP_16BIT Or BASSEncode.BASS_ENCODE_LIMIT, Nothing, IntPtr.Zero) 'Or BASSEncode.BASS_ENCODE_AUTOFREE


Obviously is string is built up of various variables, but that's not the problem as it works fine.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #3 on: 7 Aug '18 - 18:06 »
OK. If I understand correctly, you have 2 splitters on a main mixer (MixerChan), one of which is playing and the other (LoggingSplitStream) is being encoded/written to file? If so, you could try adding the BASS_SPLIT_SLAVE flag to the LoggingSplitStream stream's BASS_Split_StreamCreate call and then remove the BASS_ENCODE_LIMIT flag from the BASS_Encode_Start call, so that the encoder's data rate is effectively controlled by the local playback. I'm not sure you need the BASS_MIXER_NONSTOP and BASS_MIXER_LIMIT flags in the code above, so you could also remove those.

With the data rate controlled by the playback, you could simply process as much data as possible each time in the worker thread loop. For example:

Code: [Select]
        Do Until bkgLoggingMixer Is Nothing OrElse bkgLoggingMixer.CancellationPending
            Dim Levels(2) As Single
            Bass.BASS_ChannelGetLevel(LoggingMixer, Levels, 1, BASSLevel.BASS_LEVEL_STEREO)
            Threading.Thread.Sleep(100)
        Loop

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #4 on: 8 Aug '18 - 10:06 »
Wow excellent. I'll try this Ian, thanks. It'll be hillarious if it's down to something as simple as a few flag settings. I've got a few other splits too, I create a split for each casting encoder too so the main mixer is just tapped off, so I'll try these mods on the other splits too. Fingers crossed, I'll let you know how it goes.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #5 on: 12 Aug '18 - 20:36 »
Ian, could I just double check something with you. You wrote this code:

Code: [Select]
Bass.BASS_ChannelGetLevel(LoggingMixer, Levels, 1, BASSLevel.BASS_LEVEL_STEREO)
Threading.Thread.Sleep(100)

As the get level is set to 1 second in the first line, shouldn't the sleep be 1000?

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #6 on: 13 Aug '18 - 16:26 »
Waiting 1000ms is likely to mean the stream isn't processed quickly enough. For example, if the BASS_ChannelGetLevel call takes 1ms, then 1001ms will have passed between calls but you only processed 1000ms. So the wait should be shorter than the BASS_ChannelGetLevel processing length. I chose 100ms to avoid delaying a cancellation too much.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #7 on: 13 Aug '18 - 16:35 »
Okay, we just found that using this loop technique twinned with the other suggestions we got the attached audio in the zip. However, going back to the original loop with the TimeNowMS in it, it recorded fine and it also was fine if I changed the sleep to 1000.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #8 on: 13 Aug '18 - 17:47 »
Is that the mixer output, and the mixer is outputting silence rather than stalling? If so, did you definitely remove the BASS_MIXER_NONSTOP flag from it? That flag will make the mixer output silence when the source(s) have insufficient data available.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #9 on: 14 Aug '18 - 10:12 »
Ah - I missed the BASS_MIXER_NONSTOP

Done that and now that works great. There is another loop where I'm getting the level data just for display purposes. I suppose I should do this there too, just to be on the safe side.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #10 on: 14 Aug '18 - 14:33 »
Ah - all this has screwed up the emergency file playing:

Code: [Select]
            EmergencyChan = Bass.BASS_StreamCreateFile(EmergencyFile, 0, 0, BASSFlag.BASS_STREAM_DECODE Or BASSFlag.BASS_SAMPLE_LOOP Or BASSFlag.BASS_SAMPLE_FLOAT)
            BassMix.BASS_Mixer_StreamAddChannel(MixerChan, EmergencyChan, BASSFlag.BASS_MIXER_PAUSE Or BASSFlag.BASS_MIXER_LIMIT Or BASSFlag.BASS_MIXER_DOWNMIX)
            BassMix.BASS_Mixer_ChannelPlay(EmergencyChan)

Basically this is being plugged into the main mixer so it gets processed by everything which is split off the main mixer.

What's now happening is you get short bursts of the file. I'm sure it's data related.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #11 on: 14 Aug '18 - 15:44 »
Are you getting short bursts of the EmergencyChan file in the mixer output while the mixer's other source(s) continue as normal? If so, that is strange. As it's a local file, there shouldn't be a lack of data, unless the file is being written at the same time? How long are the bursts and are they evenly spaced? For example, a 100ms burst every 500ms.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #12 on: 14 Aug '18 - 15:48 »
Not really. It's like it plays at the right rate, but it skips chunks every 500ms or so.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #13 on: 14 Aug '18 - 15:58 »
Oh, so is the mixer skipping parts of the file rather than inserting gaps? If so, check that you aren't calling BASS_ChannelGetLevel/Data on the EmergencyChan handle anywhere.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #14 on: 14 Aug '18 - 16:42 »
No I'm not doing that. I think I've created a bit of a rats nest of issues.

I've got the main source I want to stream. I then create a mixer to resample it and then use that as the main mixer to stream and to log from. From that point I split off that main mixer as slaves when I need to log and stream.

When I play the audio I add it to the main mixer, so in turn it gets streamed.

My understanding is if I used the SPLIT_SLAVE flag I just need to process the main mixer in a worker thread. Is that correct?

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #15 on: 14 Aug '18 - 17:32 »
When the BASS_SPLIT_SLAVE flag is set on a splitter, that splitter will only receive data that has already been received by a non-slave splitter (of the same source), which means it can never get ahead of the other splitters. It shouldn't be set on all splitters because otherwise no data will ever get processed.

Are you playing a splitter, eg. calling BASS_ChannelPlay on it? If so, you could set the BASS_SPLIT_SLAVE flag on all except that one, to have the playback control the data rate.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #16 on: 14 Aug '18 - 18:09 »
No I'm not calling Bass_ChannelPlay on it or anything else, only the mixer which has the emergency file in it.

I've removed the slaves now but still got the same issues. It's really confusing. Let me get back to you on it as my head is totally frazzled with this today, but thanks for your assistance so far Ian. I'm sure we'll crack it :)

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #17 on: 14 Aug '18 - 22:07 »
I've spent all evening on this and I reckon it's down to the data rate when the file is playing. I don't know how to get the files data to be pulled at the correct rate. Am I missing a trick with this?

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #18 on: 14 Aug '18 - 22:38 »
I'm almost there now. It's playing the file okay but after about 60 seconds it jumps, like it's missed a bit. Then it carries on and after another period, around 30 seconds it will jump again.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #19 on: 15 Aug '18 - 12:50 »
If you aren't playing any of the mixer's splitters, can you show how you are controlling the mixer's processing rate? I think that is a likely place of the problem.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #20 on: 15 Aug '18 - 13:09 »
It's a bit puzzling this because I use this code:

Code: [Select]
        Dim LastMS As Integer = Environment.TickCount - 10

        Dim i As Integer = 0
        Do Until bkgLevel Is Nothing OrElse bkgLevel.CancellationPending

            Dim TimeNowMS As Integer
            Dim Levels(2) As Single

            TimeNowMS = Environment.TickCount

            Bass.BASS_ChannelGetLevel(LevelMixer, Levels, (TimeNowMS - LastMS + 1) / 1000, BASSLevel.BASS_LEVEL_STEREO)

            Dim el As New ELevels
            el.LeftLevel = Levels(0) * 32767
            el.RightLevel = Levels(1) * 32767
            bkgLevel.ReportProgress(10, el)

            Dim RChanLevel = BassMix.BASS_Mixer_ChannelGetLevel(RChan)
            If Bass.BASS_ChannelIsActive(RChan) = 0 Then
                RChanLevel = 0
            End If
            Dim LeftLevel As Integer = Math.Abs(Un4seen.Bass.Utils.HighWord32(RChanLevel))
            Dim RightLevel As Integer = Math.Abs(Un4seen.Bass.Utils.LowWord32(RChanLevel))
            OverallLevel = Math.Max(LeftLevel, RightLevel)

            Threading.Thread.Sleep(10)

            LastMS = TimeNowMS

        Loop


Note I'm using LevelMixer not MixerChan. MixerChan is the main mixer handle, but if I try and process MixerChan instead of LevelMixer (which is a split off the main mixer, but not a slave) the stream encoder keeps stalling, I presume as there is no data being processed for it.

The encoder use MixerChan as its main source, so why I have to pull the data from LevelMixer and not MixerChan is beyond me, and why when I do try and process from MixerChan it doesn't do anything is another mystery.

If I make the LevelMixer a slave split it still doesn't work properly and the levels then don't get processed even if I try and process MixerChan.

The reason for this code is I have to process the levels, but I have to reflect the overall mix, but monitor just the main input channel which is plugged into the main mixer MixerChan. This is so I can detect when the main input audio goes silent and trigger the emergency file.

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #21 on: 15 Aug '18 - 13:31 »
Code: [Select]
            Bass.BASS_ChannelGetLevel(LevelMixer, Levels, (TimeNowMS - LastMS + 1) / 1000, BASSLevel.BASS_LEVEL_STEREO)

Try changing that to this:

Code: [Select]
            Bass.BASS_ChannelGetLevel(LevelMixer, Levels, (TimeNowMS - LastMS) / 1000, BASSLevel.BASS_LEVEL_STEREO)

Note I'm using LevelMixer not MixerChan. MixerChan is the main mixer handle, but if I try and process MixerChan instead of LevelMixer (which is a split off the main mixer, but not a slave) the stream encoder keeps stalling, I presume as there is no data being processed for it.

Yeah, when using splitters, you should not process any data directly from the source (eg. call BASS_ChannelGetData/Level on it) because that data will then not be available to the splitters.

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #22 on: 15 Aug '18 - 14:21 »
OH MY GOD!!!! That seems to have sorted it. All the way through the audio file without a blip.

Why would such a small thing cause the audio to jump?

Ian @ un4seen

  • Administrator
  • Posts: 21363
Re: Audio glitches after a week
« Reply #23 on: 15 Aug '18 - 14:56 »
OH MY GOD!!!! That seems to have sorted it. All the way through the audio file without a blip.

Excellent!

Why would such a small thing cause the audio to jump?

The loop was processing 1ms too much data every time, eg. 11ms instead of 10ms. The result of that would be that other splitters that are processing at the correct rate would eventually suffer a buffer overflow, ie. too much buffered data (which gets lost/skipped).

Chris Oakley

  • Posts: 96
Re: Audio glitches after a week
« Reply #24 on: 15 Aug '18 - 15:20 »
This is fantastic. Thanks Ian. Just one more question - why, when I use the BASSFlag.BASS_SPLIT_SLAVE on the LevelMixer split it all stops processing data? All the other splits are BASSFlag.BASS_SPLIT_SLAVE and they all work okay.

Is it just that one of them needs to not be so the data can be processed?