Author Topic: StreamCopy DSP and Casting  (Read 1179 times)

Chris Oakley

  • Posts: 304
StreamCopy DSP and Casting
« on: 7 Jun '23 - 09:20 »
If I make a stream copy using the StreamCopy DSP like this:
Code: [Select]
                m_DspClone = New DSP_StreamCopy()
                Dim _info As BASS_INFO = Bass.BASS_GetInfo
                With m_DspClone
                    .OutputLatency = _info.latency
                    .StreamCopyFlags = .ChannelInfo.flags
                    .ChannelHandle = _NodeID 'Mixer node to clone
                    .DSPPriority = -1000
                    .StreamCopyDevice = 0 'Send to nosound
                    .Start() 'Start
                End With
                m_EncoderCloneStreamId = m_DspClone.StreamCopy

Then I encode it like this:
Code: [Select]
                _Encoder = BassEnc.BASS_Encode_Start(m_EncoderCloneStreamId, _EncoderString, BASSEncode.BASS_ENCODE_NOHEAD Or BASSEncode.BASS_ENCODE_FP_16BIT, Nothing, IntPtr.Zero)

If I then cast it to a stream like this:
Code: [Select]
                BassEnc.BASS_Encode_CastInit(_Encoder, .FullStreamURL, .Password, _EncoderContent, .Title, .URL, .Genre, .Description, Nothing, CInt(.EncodingBitrate), .Public)

After a while the cast stream starts to pause and then after a few seconds it continues.

What I'm wondering is does this copy create a completely independent stream from the source? Also how can I stop the stream from stopping and then continuing? Is there some sort of flag that needs setting or should I create a separate decode mixer for this process then instead of sending the copy to the No Sound device, send it to the mixer instead and set the frequency of the mixer to 45000 instead of 44100?

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #1 on: 7 Jun '23 - 12:44 »
Are you sure the DSP_StreamCopy stuff is actually needed? It seems like you could simply call BASS_Encode_Start directly on the source, ie. use the "_NodeID" handle in that call. Is there a reason not to do that?

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #2 on: 7 Jun '23 - 13:14 »
Well I was doing that but we kept getting issues where it was almost like any delay or issue on the cast stream would have a knock on effect to the source mixer and it's sources. You may recall the recent chat about the recording which was getting delayed compared to other recordings that weren't being cast. Well I made the suggested changes and we had no problem with drift, however, it then introduced this streaming issue.

This seemed to be the only way I could be sure of what I believed to be an independent data stream.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #3 on: 7 Jun '23 - 13:36 »
Please try adding the BASS_ENCODE_QUEUE flag to the BASS_Encode_Start call (with handle=_NodeID) and see if that helps. If the problem persists then also confirm how the source (_NodeID) is being processed, eg. is it being played via BASS_ChannelPlay or is it a decoding channel? If it's a decoding channel then how/where is it being decoded?

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #4 on: 7 Jun '23 - 13:39 »
Hi Ian, I did have the QUEUE flag set, and whilst that helped prevent the drift, it then introduced this stream pausing issue.

Are you suggesting I shouldn't do what I'm doing with the streamcopy? Would you be able to confirm if doing a dsp streamcopy would create an independent stream?

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #5 on: 7 Jun '23 - 14:24 »
Yes, with the DSP_StreamCopy stuff it seems like you're basically recreating what the BASS_ENCODE_QUEUE option does (ie. feeding the encoder asynchronously) but less efficiently :)

Is the "stream pausing issue" on the client side, ie. playback stalls? If so, it may be that the encoder/caster's source is running slower than specified. What is the source? And how often does playback stall? If the source is a recording device then for comparison you could try running the pre-compiled CAST.EXE example from the BASSenc package (C\BIN folder) on the same system and feed the same Icecast/Shoutcast server with it, and then see if playback of the stream still stalls then.

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #6 on: 7 Jun '23 - 14:39 »
It's a bit involved to be honest. I couldn't give a simple example because I've had to create a flexible routing system so code wise it's very lengthy and all configurations would be unique to a users requirements.

There are 16 outputs / mixers. Each mixer can take a variety of inputs. So it might be a stream playing a file. It might be an input from a physical device. It might be both. That mixer / output then is sent to its destination. This could be a physical device or it could be casting to a stream.

The streaming was going fine yesterday for hours,  then it started to pause, then continue, then pause, then continue ad nasuem, until we restarted the app, when it went okay again. It reminded me of this thread https://www.un4seen.com/forum/?topic=19037.0 so as of today I've made a decode mixer and I've applied the stream copy to that mixer. I then process that mixer in a loop:
Code: [Select]
        Do Until m_EncoderCloneStreamId = 0
            Dim length As Integer = CInt(Bass.BASS_ChannelSeconds2Bytes(m_EncoderCloneStreamId, 0.03))
            Dim data(length - 1) As Byte
            length = Bass.BASS_ChannelGetData(m_EncoderCloneStreamId, data, length) 'Get the data
            Threading.Thread.Sleep(10)
        Loop

My thinking here is if I aim to get 30ms of data from the mixer buffer then sleep for 10ms, I shouldn't ever get a build up of buffer data. Of course please tell me if I'm way off with this. It's been running for a good few hours now and it's fine. However, we need to get through 24 hours really to call it a win.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #7 on: 7 Jun '23 - 15:40 »
There are 16 outputs / mixers. Each mixer can take a variety of inputs. So it might be a stream playing a file. It might be an input from a physical device. It might be both. That mixer / output then is sent to its destination. This could be a physical device or it could be casting to a stream.

How is the mixer processed when it's being casted, ie. when the problem happens? If it isn't being played by BASS then you could try adding the BASS_ENCODE_CAST_NOLIMIT flag to the BASS_Encode_Start call to disable the encoder's realtime rate limiting (it's automatically disabled when BASSenc detects that the source is already being processed at realtime speed, eg. it's a standed playback/recording channel). It could be possible for the rate limiting to cause problems like yours if the system's clock isn't running at the correct speed.

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #8 on: 7 Jun '23 - 15:49 »
Sorry Ian, what do you mean by "if it isn't being played by BASS"? It's all being played / dealt with by BASS, or is that not what you meant? I've tried the NOLIMIT as well, but that didn't help.

This is why I wanted to almost draw a line between the overall mixers, which are working and doing their job, so I don't want to mess about with them. By separating with the StreamCopy I can then have another mixer which I can apply flags too as much as I need and not worry that it's going to affect something else.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #9 on: 7 Jun '23 - 16:04 »
Sorry Ian, what do you mean by "if it isn't being played by BASS"? It's all being played / dealt with by BASS, or is that not what you meant?

I meant that you're calling BASS_ChannelPlay to play it, or it's plugged into another mixer that's being played that way. As opposed to being a decoding channel processed with BASS_ChannelGetData (like your m_EncoderCloneStreamId example above).

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #10 on: 7 Jun '23 - 16:20 »
Ah okay, in that case the original mixer is being played by BASS. Does that mean it could be affected by the system clock?

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #11 on: 7 Jun '23 - 16:33 »
No, it shouldn't be, at least not in relation to BASSenc's rate limiting. But you could include the BASS_ENCODE_CAST_NOLIMIT flag anyway just to be sure.

Btw, are you using the latest versions of BASS/BASSmix/BASSenc? If any are old, you could try upgrading and see if that makes any difference.

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #12 on: 7 Jun '23 - 17:01 »
Just before any of that, what's interesting is the method I'm using with the StreamCopy and separate mixer, hasn't worked either. It's been almost 8 hours and it's now just started pausing. It's really confusing. I have another app which is used as a streamer only which takes the specified input device as its feed but that doesn't suffer from these pauses.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #13 on: 7 Jun '23 - 17:49 »
Yeah, it did seem unlikely that would fix the problem if the BASS_ENCODE_QUEUE option didn't. To confirm, when you say "pausing", you mean playback is stalling/rebuffering, eg. BASS_SYNC_STALL syncs are triggered when BASS plays it? Does the problem continue after reconnecting the client?

To see if it may be something system-specific (eg. a slow device/clock), can you try running the software on a different system for comparison? Or is the other unaffected app that you mention running on the same system, and are both using the same input device?

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #14 on: 7 Jun '23 - 17:54 »
The playback pauses for a second, then continues from where the audio paused. This is on the stream. It's not stalling. If I stop the stream and reconnect then it's all okay again.

We're not seeing this behaviour on another system, which is why we're a bit puzzled. With my very limited knowledge I'm trying to come up with ideas, figure out potential places where there could be errors etc. Not easy when you don't understand what's happening under the bonnet so to speak.

If it was a slow device clock, surely it wouldn't take 8 hours before having the issue?

Yes, the unaffected app runs on the same system no problem.

I did notice when it was acting up before the app usage went to 20% CPU, when it's normally between 1% and 5%. Restarting the stream brought it back down. However, I'm not sure what caused this.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #15 on: 8 Jun '23 - 12:23 »
If the server is going only slightly slower than the client then it could well take hours for the problem to appear; the client starts with a full buffer that gets drained slightly more quickly than it gets filled, until it it's totally empty and playback has to stall (while the buffer refills). When you say it's not stalling, are you sure about that? If reconnecting stops the problem then that suggests it is stalling, as reconnecting lets it restart with a full buffer. If the client is using BASS then you can set a BASS_SYNC_STALL sync to confirm whether it is stalling. You can also monitor the download buffer level with BASS_StreamGetFilePosition (BASS_FILEPOS_BUFFER).

Besides a clock difference, another possibility is skipped update cycles on the server, perhaps related to the higher CPU usage that you've noted. To find the cause of that higher CPU usage, you can try monitoring the BASS_ATTRIB_CPU value of each mixer and source, ie. see which (if any) has risen when the higher CPU usage happens. If you find one (or more) with raised CPU usage, check for any DSP/FX/VST/encoders set on it and see if disabling that stops the problem.

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #16 on: 8 Jun '23 - 13:41 »
It may be stalling somewhere actually. If I remove the NONSTOP flags from the mixers then if there is no data flowing through them they stall and become useless, because they then cease to function and would need to be re-created.

However, with that flag in place I believe silent data will still be generated by the mixer if the sources aren't supplying. On this basis, if the sources are somehow, after hours, not supplying enough data, then of course you would get bursts of silence while the buffer is filled - which may account for the pauses I'm hearing.

Now, the BASS_MIXER_LIMIT flag seems like a perfect candidate for when adding a source to a mixer, but as the documentation says:

Quote
This flag can only be applied to one source per mixer, so it will automatically be removed from any other source of the same mixer.

Which seems useless because I would have a number of sources plugged into the mixer. Unless of course I'm missing something?

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #17 on: 8 Jun '23 - 16:25 »
In addition to the above info I've drawn up a diagram which hopefully will illustrate the layout a bit better. It should be attached.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #18 on: 8 Jun '23 - 16:46 »
It may be stalling somewhere actually. If I remove the NONSTOP flags from the mixers then if there is no data flowing through them they stall and become useless, because they then cease to function and would need to be re-created.

However, with that flag in place I believe silent data will still be generated by the mixer if the sources aren't supplying. On this basis, if the sources are somehow, after hours, not supplying enough data, then of course you would get bursts of silence while the buffer is filled - which may account for the pauses I'm hearing.

Are you using BASS to play the stream, ie. BASS_StreamCreateURL? If so, please try setting a BASS_SYNC_STALL sync to confirm whether it is stalling. You can also check whether the silence is in the data by writing it to a file (using a DOWNLOADPROC callback) and then play that back afterwards, ie. check if the written file contains silence where you heard it.

In addition to the above info I've drawn up a diagram which hopefully will illustrate the layout a bit better. It should be attached.

Are the sources all files (as in that diagram) or may there be recording channels too? To check if it's in any way related, can you try removing the BASS_FX_TempoCreate calls and see if the problem still happens then? Whenever there's a mysterious problem, removing/disabling things can be helpful in finding the cause of it.

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #19 on: 8 Jun '23 - 18:29 »
Quote
Are you using BASS to play the stream, ie. BASS_StreamCreateURL?
Sorry, where did you see that? I'm not playing URLs, I'm playing files using BASS_StreamCreateFile.

Quote
Are the sources all files (as in that diagram) or may there be recording channels too? To check if it's in any way related, can you try removing the BASS_FX_TempoCreate calls and see if the problem still happens then? Whenever there's a mysterious problem, removing/disabling things can be helpful in finding the cause of it.
There could be recording channels too. I can try removing the Tempo, but I'm currently in the process of listening to a current setup and it's not paused yet. The more I'm dealing with this, the more I'm thinking that the files BASS_StreamCreateFile playing via the are the cause of the problem. By that, I don't mean the actual files, I mean the data buffer from those files. As I'm dealing with splits, would the SPLIT_SLAVE flag be relevant here?

What I'm doing with the current setup test is I am casting an input / recording channel to one ShoutCast stream and playing files to another ShoutCast stream. The aim with this is to see if / when the files stream has audible pauses, to see if the stream with the recording channel is pausing too.

I've noticed that when the pauses did happen, the players playing the audio, that have DSP PeakLevels on them, graphically didn't stop responding. Sadly I couldn't hear them because the setup wasn't configured to route to a physical device. It was going to the no sound device. It was as though the items in question didn't pause, but somewhere the data was strangled.

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #20 on: 9 Jun '23 - 10:53 »
Further to the above, here's an example of what it's doing when it goes wrong. It was all running fine until I turned on the streaming to Live365 and very soon CPU usage went up and it started freaking out. Turn off the Live365 stream its CPU drops and streaming returns to normal.

This recorded sample was the input / recording channel being cast back out. This is a recording of that stream.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #21 on: 9 Jun '23 - 14:35 »
Quote
Are you using BASS to play the stream, ie. BASS_StreamCreateURL?
Sorry, where did you see that? I'm not playing URLs, I'm playing files using BASS_StreamCreateFile.

On the client-side, playing the casted stream? I'm starting to think I may have misunderstand what the problem is, and the silence is actually heard locally in the mixing/casting app rather than just in the casted stream?

It was all running fine until I turned on the streaming to Live365 and very soon CPU usage went up and it started freaking out. Turn off the Live365 stream its CPU drops and streaming returns to normal.

What exactly does the Live365 streaming involve, ie. what calls? Please also confirm how you are measuring the CPU usage, eg. something like Task Manager or BASS_GetCPU?

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #22 on: 10 Jun '23 - 10:29 »
Quote
the silence is actually heard locally in the mixing/casting app rather than just in the casted stream?
Yes this is correct. Imagine loading and playing files in the app and then sending them to a mixer which is casting out. This is it put simply. The pauses / skipping is coming from inside the app somewhere.

Quote
What exactly does the Live365 streaming involve, ie. what calls? Please also confirm how you are measuring the CPU usage, eg. something like Task Manager or BASS_GetCPU?
On the CPU, both to be honest. I monitor via Task Manager and then when the CPU spikes I call the BASS_GetCPU which returns values like 0.10%. I'm not clear, and it's not clear in the BASS.NET documentation if this means 10% or 1% due to the floating point nature.

I've definately narrowed down the area I need to be looking in. It's definately something regarding Live365 but I need to do a little more testing. I'm going to run the app on another machine and stream to Live365 and see what happens.

Ian @ un4seen

  • Administrator
  • Posts: 26047
Re: StreamCopy DSP and Casting
« Reply #23 on: 12 Jun '23 - 12:20 »
BASS_GetCPU returns a percentage, so 0.10 would be 0.1% rather than 10%. Is that the value you're seeing when Task Manager shows high CPU usage? Note that BASS_GetCPU includes the time to decode/process/mix the data for playback by BASS. It doesn't include the time taken by decoding channels, unless they're plugged into a mixer that's being played by BASS. To check the timeliness of individual BASS channels (including decoding channels), you can check their BASS_ATTRIB_CPU value (via BASS_ChannelGetAttibute).

Chris Oakley

  • Posts: 304
Re: StreamCopy DSP and Casting
« Reply #24 on: 12 Jun '23 - 12:52 »
Hi Ian, that's good info to know and is what I suspected about the CPU.

We appear to have had a breakthrough but unfortunately I was looking in the wrong area. I did mention this is a complex little app and because of this I was looking at streaming increasing the CPU usage but should have been looking at a BASS_StreamPutData elsewhere which was being triggered, but because it was putting the data on a stream whose mixer consuming it, it was building up memory and cpu usage.

We proved this by commenting out the line and the problem went away. We've now put a flag in place because it doesn't need to be putting data from a clone buffer all the time, it just needs to when a certain part of the app is functioning.

So far all seems well, but we're going to fully benchtest this a little later today. I will let you know fully of the results.

So sorry to have taken this down a road we didn't need to go down.