21 May '13 - 23:18 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: Spliter lag  (Read 670 times)
Cristian1980
Posts: 36


« on: 19 Oct '11 - 13:14 »
Reply with quoteQuote

Hello,

I am using bass with the following scenario:

(3 source streams) -> mixer -> spliter -> mixer1
                                      -> spliter -> mixer2

The mixer1 and mixer2 can be on different sound cards or the same and the issue still occurs.

Under a heavy CPU usage scenario I am getting some lag between mixer1 output and mixer2 output.
BASS_Split_StreamGetAvailable seems to return values that account for this delay.

The some source streams are created  with BASS_StreamCreate() which uses a callback, that callback in some situations(eg. seeking) will take a small time to return. The issue is more easy to reproduce if I do a lot of seeks when high CPU usage.
What I don't understand is why I don't get the same amount of lag in both mixers?

I installed a sync proc on both mixers:
HSYNC s = BASS_ChannelSetSync(mixer, BASS_SYNC_STALL, 0, StallSyncProc,&_element);
But it never gets called.

I am using 5ms update period but still I get the lag.
BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 5)

Any ideas how I can prevent this lag and what causes it?

Regards,
Cristian
Logged
Ian @ un4seen
Administrator
Posts: 15259


« Reply #1 on: 19 Oct '11 - 15:38 »
Reply with quoteQuote

To get an idea of what's happening, I have a few questions...

Is your diagram above the entire thing, ie. there's nothing else plugged into any of the mixers? Are the splitters/mixers left alone once started, eg. you're not resetting the splitters via BASS_Split_StreamReset?

What sort of time difference are you seeing/hearing in the splitters, and what is BASS_Split_StreamGetAvailable reporting?

What BASS_CONFIG_BUFFER setting are you using? How long might the STREAMPROC take, eg. when seeking?

Do you hear the sound repeating and/or stalling?

The BASS_SYNC_STALL sync will be triggered if the mixer doesn't provide sufficient data to sustain playback, but it won't be triggered (on Windows) if the mixer takes so long that a buffer underrun occurs in the meantime. In that scenario, you will hear the sound repeating rather than stalling. For that reason, it is better for a STREAMPROC to provide no data rather than wait for more. Can you move your seeking outside of the STREAMPROC, and have the STREAMPROC return 0 in the meantime?
Logged
Cristian1980
Posts: 36


« Reply #2 on: 19 Oct '11 - 18:20 »
Reply with quoteQuote

You are right, it seems it was BASS_ChannelSetDSP() with priority -1000 on the first mixer, removed it and now it is a lot better.
It seems to be ok if I have the mixer on the same sound card but there is still a small delay if there are different sound cards.
BASS_Split_StreamGetAvailable  reports 45680 bytes for 32 bit stereo stream that means around 129ms. My BASS_CONFIG_BUFFER buffer is 96ms.
I will come back with more details if I can't figure it out.

I am not resetting them with BASS_Split_StreamReset because I fear for sound artifacts.
mixer1 and mixer2 are sound card mixers created like this:
BASS_SetDevice(id1);
BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 5);
bStatus = BASS_SetConfig(BASS_CONFIG_BUFFER, 96*4); // set the buffer length
mixer1 = BASS_Mixer_StreamCreate(44100, 2, BASS_MIXER_NONSTOP | BASS_SAMPLE_FLOAT | BASS_SAMPLE_SOFTWARE );
s = BASS_ChannelSetSync(mixer1, BASS_SYNC_STALL, 0, StallSyncProc,&_element);
BASS_ChannelPlay(mixer1,FALSE);

BASS_SetDevice(id2);
BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 5);
bStatus = BASS_SetConfig(BASS_CONFIG_BUFFER, 96*4); // set the buffer length
mixer2 = BASS_Mixer_StreamCreate(44100, 2, BASS_MIXER_NONSTOP | BASS_SAMPLE_FLOAT | BASS_SAMPLE_SOFTWARE );
s = BASS_ChannelSetSync(mixer2, BASS_SYNC_STALL, 0, StallSyncProc,&_element);
BASS_ChannelPlay(mixer2,FALSE);

BASS_SetDevice(0);
//create spliter
HSTREAM splitter1 = BASS_Split_StreamCreate(mixer, BASS_STREAM_DECODE, NULL);
//connect spliter
BASS_Mixer_StreamAddChannel(mixer1 , splitter1 , BASS_MIXER_BUFFER|BASS_MIXER_PAUSE|BASS_MIXER_MATRIX|BASS_SAMPLE_SOFTWARE);

//create spliter
HSTREAM splitter2 = BASS_Split_StreamCreate(mixer, BASS_STREAM_DECODE, NULL);
//connect spliter
BASS_Mixer_StreamAddChannel(mixer2 , splitter2 , BASS_MIXER_BUFFER|BASS_MIXER_PAUSE|BASS_MIXER_MATRIX|BASS_SAMPLE_SOFTWARE);
           

BASS_Mixer_ChannelFlags(splitter1 , 0, BASS_MIXER_PAUSE); 
BASS_Mixer_ChannelFlags(splitter2 , 0, BASS_MIXER_PAUSE);

My goal is to have a nonstop playing BASS pipeline and do all the stuff in the sources, which may be destroyed played or stopped.

>>Can you move your seeking outside of the STREAMPROC, and have the STREAMPROC return 0 in the meantime?

The seek is done in another thread already I was just waiting for the thread to finish. I will try your idea and return 0 in the callback until the thread finishes.

In the mentioned callback besides the seek there is a lot of audio processing done.
Is there a way I can increase the priority for the thread that calls the callback and what priority does it normally have?

Best regards,
Constantin Cristian
Logged
Ian @ un4seen
Administrator
Posts: 15259


« Reply #3 on: 20 Oct '11 - 17:40 »
Reply with quoteQuote

With the source stopping/starting, the problem may be that the mixers' processing is at different positions each time that happens. For example, there might be no data available when the 1st mixer does its processing and then there is data when the 2nd mixer does its processing; the 1st mixer wouldn't receive that data until the next update cycle. You could try removing the BASS_MIXER_NONSTOP flag from the mixers, and see if that helps (it would prevent the 1st mixer filling in with silence when the source has no data in the previous scenario).

Regarding thread priority, the STREAMPROC will be called from BASS's update thread, which runs at time critical priority. So it isn't possible to raise it any higher.
Logged
Cristian1980
Posts: 36


« Reply #4 on: 10 Nov '11 - 10:39 »
Reply with quoteQuote

Hello,

I was finally able to reproduce this issue in "BASSmix multiple output example" delivered with bassmix.
However I did some changes to it(see attached file), basically I only use one sound card output and I connect 2 mixers to the same sound card. This way you can clearly hear the echo even if the delay is not very big, however I also have very big delays(BASS_Split_StreamGetAvailable returns 81120 as you can see from the log file).

The flag BASS_MIXER_NONSTOP does not influence this issue however in the BASS_CONFIG_BUFFER seems to be a factor, in the code bellow if I replace the 20 with 80 the issue still occurs however once the file is loaded I get a delay(BASS_Split_StreamGetAvailable ) between 3000 and 10000 and that delay remains constant while the song is playing and does not vary until another song is loaded.

BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 5);
int config_buf = 500;
BASS_INFO info;
if ( BASS_GetInfo(&info) )
  config_buf = info.minbuf;
// get update period
DWORD len = BASS_GetConfig(BASS_CONFIG_UPDATEPERIOD);
// default buffer size = update period + 'minbuf' + 1ms extra margin (20ms to be safe...)
config_buf = len + config_buf + 20;
// set the buffer length
BASS_SetConfig(BASS_CONFIG_BUFFER, config_buf);

The issue as I said is easier to reproduce while there is high CPU usage but also happens when it's not(there are probably some CPU usage spikes produced by other apps).
You don't have to do anything like seeking in the attached app it just happens.

Also when closing the demo app I noticed that a lot of threads are exiting is this normal?
Can you please tell me what am I doing wrong it is essential for me to have BASS_CONFIG_BUFFER as small as possible.

PS: I also attached a log file "log_normal_cpu_usage.txt" you can see that everything goes OK for a while just ~3000 delay and at some point it just jumps to 127608

Best regards,
Cristian

* Documents.zip (7.99 KB - downloaded 1 times.)
Logged
Ian @ un4seen
Administrator
Posts: 15259


« Reply #5 on: 10 Nov '11 - 17:46 »
Reply with quoteQuote

Firstly, I see a few issues in the code... The BASS_SAMPLE_SOFTWARE flag has no effect on BASS_Mixer_StreamAddChannel; all BASSmix mixing is performed in software (by BASSmix). BASS_ChannelSetLink has no effect on mixer-played channels; it only applies to normal playback channels, ie. those that are played via BASS_ChannelPlay. The BASS_DEVICE_LATENCY flag is needed in the BASS_Init call to get a valid BASS_INFO "minbuf" value (on Windows). Another important thing to note about the "minbuf" (and "latency") value is that it applies to hardware-mixed channels (when available), so it may not be appropriate when using the BASS_SAMPLE_SOFTWARE flag on pre-Vista systems (there is no hardware mixing post-Vista). I don't think any of this is causing the lag, but still worth mentioning Smiley

Regarding the lag, it appears to be caused by a delay between the 1st and 2nd mixers resuming once the sources are unpaused, ie. they aren't resumed simultaneously. The length of the delay will be system-dependent. I think the answer is to put back the BASS_MIXER_NONSTOP flag on the mixers so that they are constantly playing, and wait for the mixers' buffers to be filled before playing any sources that need to be in sync on both mixers. You would also lock the mixers to get the sources to start in sync with each other. The unpausing part of your code could look something like this...

QWORD preplay=BASS_ChannelSeconds2Bytes(m2, config_buf/1000.f); // the buffer length in bytes
while (BASS_ChannelGetPosition(m2, BASS_POS_BYTE)<preplay) Sleep(10); // wait for the 2nd mixer to reach it (could also check 1st mixer to be sure)

BASS_ChannelLock(m1, TRUE); // lock the 1st mixer
BASS_ChannelLock(m2, TRUE); // and the 2nd
BASS_Mixer_ChannelFlags(ochan[0], 0, BASS_MIXER_PAUSE); // resume the 1st source
BASS_Mixer_ChannelFlags(ochan[1], 0, BASS_MIXER_PAUSE); // and the 2nd
BASS_ChannelLock(m1, FALSE); // unlock the 1st mixer
BASS_ChannelLock(m2, FALSE); // and the 2nd
Logged
Cristian1980
Posts: 36


« Reply #6 on: 11 Nov '11 - 10:43 »
Reply with quoteQuote

Hello,

Thank you for the reply.
My biggest problem is not that the streams don not start exactly at the same moment. My problem is that they seem to drift apart while they are playing and the drift becomes so big that is noticeable.
I implemented your changes and the 2 splitters seem to drift appart more slowly but they still do(I attached the modified code).
As you can see from the log file attached the seem to drift by ~11111 bytes each time(as reported by BASS_Split_StreamGetAvailable).
My buffer is 5 + 38 + 20  milliseconds which equals 22226.4 bytes (0.063*44100(sample per second) * 8(float stereo for output)).
So I modified the line:
chan=BASS_StreamCreateFile(FALSE,file,0,0,BASS_STREAM_DECODE|BASS_SAMPLE_LOOP)
and added BASS_SAMPLE_FLOAT.
The effect was it started to drift apart by ~22226.4 .

The drift seems to favor the second splitter(I would say always with the latest changes).

I am not doing anything to the test app I just let it play. However I started some CPU intensive tasks.

About BASS_CONFIG_SPLIT_BUFFER if I see that I can set it to 100 ms instead of 2000.
In this sentence from bass mix documentation:
Quote
determines how far splitter streams can drift apart before there are buffer overflow issues for those left behind.
What do you mean by
Quote
buffer overflow issues
, what are those issues?

PS: I am using windows 7 64bit(the test app is 32 bit) for my tests and I was able to reproduce this on 2 sound cards from different vendors.

Best regards,
Cristian

* test_bass.zip (15.06 KB - downloaded 2 times.)
Logged
Ian @ un4seen
Administrator
Posts: 15259


« Reply #7 on: 11 Nov '11 - 17:12 »
Reply with quoteQuote

As you can see from the log file attached the seem to drift by ~11111 bytes each time(as reported by BASS_Split_StreamGetAvailable).
My buffer is 5 + 38 + 20  milliseconds which equals 22226.4 bytes (0.063*44100(sample per second) * 8(float stereo for output)).
So I modified the line:
chan=BASS_StreamCreateFile(FALSE,file,0,0,BASS_STREAM_DECODE|BASS_SAMPLE_LOOP)
and added BASS_SAMPLE_FLOAT.
The effect was it started to drift apart by ~22226.4 .

That looks like BASS didn't get enough CPU to keep one of the mixer playback buffers updated, and it suffered an underflow, ie. it ran out of fresh data to play and old data was repeated. Note a DirectSound buffer is circular and plays in a loop; if new data isn't placed in the buffer, then old data gets repeated. Increasing the buffer length (BASS_CONFIG_BUFFER) reduces the chances of that happening, as it gives the buffer updates more time (before old data gets repeated).

About BASS_CONFIG_SPLIT_BUFFER if I see that I can set it to 100 ms instead of 2000.
In this sentence from bass mix documentation:
Quote
determines how far splitter streams can drift apart before there are buffer overflow issues for those left behind.
What do you mean by
Quote
buffer overflow issues
, what are those issues?

A buffer overflow would occur when the distance between the splitters exceeds the splitter buffer length (as determined by the BASS_CONFIG_SPLIT_BUFFER setting). The result of that will be that the splitter that is left behind will miss a whole buffer length's worth of data.

The splitter buffer won't affect latency, so I would suggest leaving it reasonably large.
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines