BASS_Encode_ServerInit delay

Started by Chris Oakley,

Ian @ un4seen

What server/software are the BASS_StreamCreateURL calls connecting to, and is it the same URL in all instances? Please also confirm what flags you're using in those calls (the call above doesn't look right because I guess there's at least BASS_STREAM_DECODE?) and what BASS_CONFIG_NET_BUFFER setting.

What you describe sounds like one or more of the streams are stalling at some point. Are you absolutely certain that no BASS_SYNC_STALL syncs are being triggered? Remember those syncs should be set on the sources via BASS_Mixer_ChannelSetSync (not BASS_ChannelSetSync), after they've been plugged into the mixer (check the return value to confirm success).

Chris Oakley

It's the same URL in all instances and it's a URL which is being streamed by BASS itself using the ServerInit which is where this thread started.

The calls are correct. As I said, I'm playing the stream on the No Sound device. This is both for the stream and the local file test. I then do a DSP_StreamCopy from the stream and set the TargetMixer to be the mixer I want to plug into. I'm doing this because originally doing it as a DECODE doesn't make any difference and I wanted to rule this out.

The BASS_CONFIG_NET_BUFFER is being set to the buffer returned by BASS_CONFIG_BUFFER which is 500. Any less than that and it breaks up.

I'm pretty certain non of the streams are stalling, unless there is something wrong with this:
m_VirtualCableStall = New SYNCPROC(AddressOf VirtualCableStall)
m_VirtualCableStallId = BassMix.BASS_Mixer_ChannelSetSync(_VirtualCableId, BASSSync.BASS_SYNC_STALL Or BASSSync.BASS_SYNC_MIXTIME, 0, m_VirtualCableStall, IntPtr.Zero)

Private Sub VirtualCableStall(ByVal handle As Integer, ByVal channel As Integer, ByVal data As Integer, ByVal user As IntPtr)
    Try
        LogEvent("Virtual Cable Stalled: handle = " & handle.ToString & " : channel = " & channel.ToString, "stalllog", True, False)
    Catch ex As Exception
    End Try
End Sub

LogEvents is our own routine and it's thread safe.

Let's assume the streams are stalling - surely if one stalls then they should all stall? The consumption of the data should be the same across each stream shouldn't it?

Ian @ un4seen

Quote from: Chris OakleyIt's the same URL in all instances and it's a URL which is being streamed by BASS itself using the ServerInit which is where this thread started.

Just to be clear... separate from the BASS_StreamCreateURL app instances, there's another app hosting a BASS_Encode_ServerInit server which the former all connect to. Is that correct?

Quote from: Chris OakleyThe calls are correct. As I said, I'm playing the stream on the No Sound device. This is both for the stream and the local file test. I then do a DSP_StreamCopy from the stream and set the TargetMixer to be the mixer I want to plug into. I'm doing this because originally doing it as a DECODE doesn't make any difference and I wanted to rule this out.

That's another variable in the mix. It's best to minimize the number of variables when trying to find a problem, so please set the BASS_STREAM_DECODE flag on the stream and plug it directly into the mixer for now.

Quote from: Chris OakleyThe BASS_CONFIG_NET_BUFFER is being set to the buffer returned by BASS_CONFIG_BUFFER which is 500. Any less than that and it breaks up.

That could potentially cause problems/stalls. Perhaps they are less obvious but still present with BASS_CONFIG_NET_BUFFER=500? Please try leaving it at the default (5000).

Quote from: Chris OakleyI'm pretty certain non of the streams are stalling, unless there is something wrong with this:
m_VirtualCableStall = New SYNCPROC(AddressOf VirtualCableStall)
m_VirtualCableStallId = BassMix.BASS_Mixer_ChannelSetSync(_VirtualCableId, BASSSync.BASS_SYNC_STALL Or BASSSync.BASS_SYNC_MIXTIME, 0, m_VirtualCableStall, IntPtr.Zero)

Is "_VirtualCableId" the URL stream or the DSP_StreamCopy stream? Removing DSP_StreamCopy will at least avoid this confusion if nothing else :)

Quote from: Chris OakleyLet's assume the streams are stalling - surely if one stalls then they should all stall? The consumption of the data should be the same across each stream shouldn't it?

There may be timing differences in when each stream requests/receives their copy of the data from the server, and if the buffers (eg. BASS_CONFIG_NET_BUFFER) are small then that could have a significant effect, ie. stalls in some cases.

Chris Oakley

QuoteJust to be clear... separate from the BASS_StreamCreateURL app instances, there's another app hosting a BASS_Encode_ServerInit server which the former all connect to. Is that correct?
That's correct.

QuoteThat's another variable in the mix. It's best to minimize the number of variables when trying to find a problem, so please set the BASS_STREAM_DECODE flag on the stream and plug it directly into the mixer for now.
Okay I've done that and removed the StreamCopy.

QuoteThat could potentially cause problems/stalls. Perhaps they are less obvious but still present with BASS_CONFIG_NET_BUFFER=500? Please try leaving it at the default (5000).
This is now done too.

QuoteIs "_VirtualCableId" the URL stream or the DSP_StreamCopy stream? Removing DSP_StreamCopy will at least avoid this confusion if nothing else :)
It was the URL stream.

Ian @ un4seen

Quote from: Chris Oakley
QuoteIs "_VirtualCableId" the URL stream or the DSP_StreamCopy stream? Removing DSP_StreamCopy will at least avoid this confusion if nothing else :)
It was the URL stream.

OK, that would explain why the BASS_SYNC_STALL syncs don't/can't get triggered then, as it's the DSP_StreamCopy stream that's in the mixer, and so the BASS_Mixer_ChannelSetSync call above will fail (return 0).

Chris Oakley

Okay. Well I can say now that stalls are 100% being logged because if I kill the app which is host the stream then the receiving app now logs that disconnection and also that it's stalled. Let's see what happens.

Chris Oakley

Update: As of yet I've seen no drifting and no stalls. I'm not sure why, but it normally happens within a day or two.

While I was checking over the documentation though, I checked over the BASS_Init method and just had two questions about it which I can't fathom from the help:
  • On Windows 10 and 11 it seems that the Frequency parameter doesn't do anything. Is this correct? I can set this to whatever I want?
  • Is it required that the Win parameter is set to a windows handle? I'm not doing that at the moment I'm just setting it to nothing. If it's a Windows app and I don't set it, what problems does this cause?

Ian @ un4seen

Quote from: Chris OakleyUpdate: As of yet I've seen no drifting and no stalls. I'm not sure why, but it normally happens within a day or two.

That's good to hear. I suspect it's the raised/default BASS_CONFIG_NET_BUFFER setting making the difference. Perhaps there were occasional stalls with the 500 setting. If you would like to confirm that, you could try putting that setting back in, now that you have the STALL syncs working.

Quote from: Chris OakleyWhile I was checking over the documentation though, I checked over the BASS_Init method and just had two questions about it which I can't fathom from the help:
  • On Windows 10 and 11 it seems that the Frequency parameter doesn't do anything. Is this correct? I can set this to whatever I want?
  • Is it required that the Win parameter is set to a windows handle? I'm not doing that at the moment I'm just setting it to nothing. If it's a Windows app and I don't set it, what problems does this cause?

Yes, the BASS_Init "freq" parameter doesn't affect the output on Windows since Vista (except for the "No Sound" device). The "win" parameter is only used with DirectSound output, and even then 0 will generally work fine (the desktop window handle will be used).

Chris Oakley

I'm still a little perplexed why I can't get each application to start the stream at the same place though. If I start one instance of the app it starts the stream. If I then start another instance there could be something like 500 ms difference in their level meters. Sadly this isn't acceptable for our application. They should all be inline with each other.

Chris Oakley

#69
Okay, so with the BASS_CONFIG_NET_BUFFER left alone, overnight, one of the engines reported a stall. The others didn't. I was expecting them all to report a stall at the same time, but they didn't. In fact all night it's been fine, except one instance of the engine. So that's a little puzzling. Again, everything is on the same PC, even the engine that's doing the streaming.

However, I want to address the RecordStart because that's playing silly beggars too. I did try to combat that problem by doing a RecordStart and using my own RECORDPROC, which was fine, but I couldn't add this into a DECODE mixer. So I did a StreamCopy and added it to the mixer that way. This seemed fine, until yesterday I noticed that there was a difference between the VU meter which was being fed from the RecordStart id and the VU meter on the mixer it was plugged into. So I muted the input device and the RecordStart meter dropped immediately, but the mixer one was at least a second behind it. Same when I unmuted.

I've gone back to taking an actual input device because I can guarantee at least where that audio will be up to, plus I can do the mute test on the input device and watch the vu meters.

So yesterday I've removed the RECORDPROC and the StreamCopy and I've gone back to the original way of adding it into the DECODE mixer. This is of course returned the original problem where the meters are now in sync, the RecordStart meter and the mixer meter, but the whole input audio goes out of sync by at least a second - and there's no reason from what I can see.

I think it may be best to explain what I'm trying to do because there doesn't seem to be a way to do what I want to do in BASS properly due to limitations surrounding Splits and Decode channels / mixers etc.

I have 16 output buses A to P. Each of these are independent from each other and can either go to a physical device output or they stream out to shoutcast or are sent to a file for recording or they create a 0.0.0.0 stream. There is a 17th output bus (BUS X) which doesn't go anywhere except to No Sound. The use of this will be explained shortly.

I have 8 input buses. Each of these are independent from each other and can either take a physical device input or a stream from 0.0.0.0.

So you set Input 1 up to take a physical input and you can map Input 1 to Output Bus A. You can map it to any output bus. If you choose not to map it to an output bus then it is assigned bus 17. This is the No Sound bus (BUS X) mentioned before.

In this case though, we will map it to bus A. Input 1 is now feeding into Bus A and this bus is outputting to an internet stream or output device. One or the other.

This is all I want to do. I don't think this should be as difficult as it has become.

I've attached a diagram that shows how it is laid out.

Ian @ un4seen

Quote from: Chris OakleyOkay, so with the BASS_CONFIG_NET_BUFFER left alone, overnight, one of the engines reported a stall. The others didn't. I was expecting them all to report a stall at the same time, but they didn't. In fact all night it's been fine, except one instance of the engine. So that's a little puzzling. Again, everything is on the same PC, even the engine that's doing the streaming.

Even when it appears that all instances are doing the same thing, they won't actually be doing so, ie. they won't all be running the same code on the same data at exactly the same time - there will be timing differences. It seems like one of them was delayed long enough to stall at one point. Larger buffers reduce the chances of timing irregularities causing stalls (because there's still data to decode/play from the buffers in the meantime).

Quote from: Chris OakleySo yesterday I've removed the RECORDPROC and the StreamCopy and I've gone back to the original way of adding it into the DECODE mixer. This is of course returned the original problem where the meters are now in sync, the RecordStart meter and the mixer meter, but the whole input audio goes out of sync by at least a second - and there's no reason from what I can see.

Are the inputs going out of sync with each other in the same instance or only with the other instances? If in the same instance, at what level in your diagram is that starting, eg. at level 1 or 3?

Please also clarify how you're getting the levels for each of your meters. To eliminate them causing the problem, does the audio still go out of sync without them, ie. if you don't try to get the levels?

Chris Oakley

Before I address the above, I've been doing some exploration and found what I think could be the contributing factor. I'm just running a test on this to see if it helps so I don't have anything solid just yet.

I noticed in the documentation for the DSP_StreamCopy that the parameter IsOutputBuffered is on by default. The test I'm running is making this False.

My reasoning is that everything that is having issues where it goes out of sync is when there is a DSP_StreamCopy in the mix. For example I was taking the input from the RecordStart with my own RECORDPROC, but was doing a stream copy on this and setting the TargetMixer to the input mixer.

I had a DSP_PeakLevelMeter on the RecordStart and one on the TargetMixer and I would notice the one on the RecordStart was always bang on, but the one on the TargetMixer would always get more and more delayed.

It's taken a while to spot this because a lot of the music on the test machine is 120 BPM so that's around 2 beats per second so when a buffer goes out by a second, you wouldn't really notice.

Is it possible that this flag could be having this undesired effect? I ask because we have a further issue where the overall output mixer on each BUS is suffering from a similair delay build up and this has a stream copy on it too? Just seems a little suspect.

Ian @ un4seen

I'm not very familiar with BASS.Net's DSP_StreamCopy class, so can't comment on it definitively, but it seems to be primarily intended for cloning a stream playing on one device to other devices by creating "push" streams, much like the clone option in the MULTI.C example included in the BASS package. From your diagram, it doesn't appear to be needed as you're already using splitters to achieve the same?

Chris Oakley

I'm just trying to understand why there is a sync delay between when I use a RECORDPROC and when I don't.

When I don't use the RECORDPROC I can plug the recording channel into the mixer at Level 5. That's when you see a gradual drifting between the DSP_PeakLevelMeter on the recording channel and the DSP_PeakLevelMeter on the mixer at Level 5. The mixer level gets behind. The recording channel meter is always spot on. You can tell when you mute the input device.

When I use the RECORDPROC I have to use a DSP_StreamCopy to be able to plug the record channel into the mixer at Level 5. When I do it this way I don't see a drift between the peak level meters. They stay in sync.

What has alerted me to this option is that I use a DSP_StreamCopy at Level 2 to send a synchronized copy of the mixer at Level 3, which is No Sound. On a client setup using AOIP, they are getting a delay building up on the output which makes no sense at all. I'm not sure at this stage if the AOIP is part of the equation. I did try this IsOutputBuffered as false but it's made no difference.

I was setting up another mixer at Level 1 which was set to the desired physical device, but I've now changed this to get the DSP_StreamCopy to target the device instead of setting up a mixer and sending to that. This seems a step which isn't required. I'm just waiting to see if that has helped. It's not clear what the stream copy is doing under the bonnet though in this scenario.

Ian @ un4seen

Quote from: Chris OakleyWhen I don't use the RECORDPROC I can plug the recording channel into the mixer at Level 5. That's when you see a gradual drifting between the DSP_PeakLevelMeter on the recording channel and the DSP_PeakLevelMeter on the mixer at Level 5. The mixer level gets behind. The recording channel meter is always spot on. You can tell when you mute the input device.

I believe BASS.Net's DSP_PeakLevelMeter class simply measures the sample data as it is produced by the channel, with no buffering. Mixers also don't buffer data from their sources (except for a small resampling buffer). So it seems like DSP_PeakLevelMeters set on a recording channel and a mixer that the recording is plugged into should be pretty much in sync. How far off are they drifting? The DSP_PeakLevelMeter documentation states it measures levels in 100ms blocks by default, so if the drift is within that amount (or a custom "UpdateTime" that you've set) then perhaps that could explain it.

Chris Oakley

No, it's more than 100ms. It can be at least 1000ms, maybe more.

I do appear to have solved this problem by the look of it by using the RECORDPROC and having to settle for the DSP_StreamCopy to copy the RecordStart stream and assign it to the mixer. I'm continuing to monitor this carefully and I'm not getting too excited.

Once I'm happy it's sorted than I can go back to looking at the stream because this problem has been clouded so much by all these moving parts and elements that just weren't obvious.

Ian @ un4seen

Quote from: Chris OakleyNo, it's more than 100ms. It can be at least 1000ms, maybe more.

Strange. I'm not sure how that's possible if the mixer is the only thing taking data from the recording channel, as the mixer will be driving both meters (they get updated when the mixer is processed). Is there definitely nothing else taking data, eg. via splitters? Maybe the reason DSP_StreamCopy seems to help is because there is in fact something else feeding on the recording, and the copy allows you to do so without affecting the mixer? To get to the bottom of it, please search your code for any calls where the recording channel handle is used.

You could perhaps also try adding another level meter based on BASS_Mixer_ChannelGetLevelEx and see how that compares to the 2 DSP_PeakLevelMeter meters. I would expect it to look the same as the recording channel's DSP_PeakLevelMeter meter.

Chris Oakley

It's been a while but I just wanted to say I did resolve this issue after countless hours of trial, error, debugging out values etc. I discovered that the problem wasn't solved, it would still drift, especially after I moved everything up from being 44100Hz to 48000Hz.

I debugged out the DSP_StreamCopy's buffer, as I had done with the other issue where I had an increasing delay on the output of audio, and found that, at what seems to be random points, the buffer would increase. This lead to the audio being delayed. I would start a recording with RecordStart and process it using my own RECORDPROC (without the Record Proc the recording would get delayed - possibly due to this problem, but I'm not changing it back). I then do a DSP_StreamCopy of the RecordStart and set the target mixer to be a No Sound mixer at 48000Hz. This is the mixer that would display the delayed recording while the recording itself was bang on. I know this from the VU's I had attached to the record and the mixer.

I implemented my own buffer marshal and it is now keeping the buffer down. For this testing period I'm still debugging out when it adjusts the sample rate of the mixer receiving the stream copy and I can see it just randomly increased at 00:06:03 in the morning, then at 07:18:09 and at 09:43:49 at time of writing this.

I have no idea why this would happen, but it does happen and it's a royal pain in the backside, so I'm hoping my findings here will help others get to the bottom of similiar issues after they've changed just about every flag they can and tried every option including not having a stream copy and just doing the record without a proc and plugging it into the mixer direct - which has the same drifting problem. Using a stream copy appeared to be the only way I could monitor and adjust the buffer. Also, No, the mixer that gets delayed doesn't report any stalls.

I'm just keeping my fingers cross that there are no other gotchas.