winearts patch

Jeremy Shaw jeremy.shaw at lindows.com
Mon Jan 5 23:31:46 CST 2004


Hello,
 
> (4d) Removed wodPlayer_DSPWait()
> 
> I just calculate the wait value once in wodOpen() and store it in
> wwo->dwSleepTime.
> 
> Won't this value change as arts becomes filled with data or plays data out?

No. The only function that calls wodPlayer_DSPWait() is the FeedDSP()
-- and it only calls DSPWait() if availInQ == 0 (ie. the arts buffer
is full and can't handle more data).

Looking at the old calculation in DSPWait(), you will see that
arts_stream_get() will always return 0 (since the buffer will always
be full when DSPWait() is called). The rest of the terms will also
remain the same every call since they are only changed it
wodOpen(). Hence, it makes since to do the calculation in wodOpen()
once and be done with it.

int waitvalue = (wwo->dwBufferSize - arts_stream_get(wwo->play_stream,
		ARTS_P_BUFFER_SPACE)) / ((wwo->format.wf.nSamplesPerSec *
		wwo->format.wBitsPerSample * wwo->format.wf.nChannels)
		/1000);

It you look at the waitvalue calculation further, you will start to
wonder what it is trying to calculate anyway?

If you do the calculation with units:

f (bytes) =  (wwo->dwBufferSize - arts_stream_get(wwo->play_stream,ARTS_P_BUFFER_SPACE))
s (samples/sec) = wwo->format.wf.nSamplesPerSecond
n (bits/sample) = wwo->format.wf.wBitsPerSample
c = wwo->format.wf.nChannels.

waitvalue = f bytes / (( s (samples/sec) * n (bits/sample) * c ) * (1 sec / 1000 ms))

you get:

waitvalue = ((1000 * f) / (s * n * c)) ((bytes * ms) / bits)

notice that the units are (bytes * ms) / bits, not ms.

It turns out that it is calculating the amount of time it will take to
play 1/8 of the data in the buffer -- although I don't think this is
what the intention was.

I changed the sleep time to be the number of milliseconds to play one
packet, times the number of packets you want to wait for before
writing again:

wwo->dwSleepTime = ((1 << (wwo->packetSettings & 0xFFFF)) * 1000 * BUFFER_REFILL_THRESHOLD) / wwo->format.wf.nAvgBytesPerSec;

The way arts works, you are always going to see the amount of free
space in the arts buffers as an integer multiple of the packet
size. So I think it makes the most sense to for the sleep time to be
some multiple of the amount of time it takes to play a single packet.

As with the old calculation, the new calculation is only dependant on
things that will not be changing while the stream is playing. So I
think it is safe to calculation the sleep time in wodOpen() and store
it in a structure rather than call DSPWait() all the time.

> ARTS_P_PACKET_SETTINGS
> Can you go over these changes a bit more?  Maybe Tom can add some information 
> to the documentation based on what you have to say about the change.

Internally arts uses packets to move the data around. When you call
arts_writes(), you write to a single buffer, but internally, this is
divided up into packets. Lets say that your buffer size is 16k. If
arts divides this up into two 8k buffers, then you will only be able
to write data in 8k chunks at a time. This can be problematic because
you might spend two much time feeding the dsp instead of doing other
important tasks. So instead you might prefer to have 16 packets that
hold 1k each. Your overall buffer size is the same, but now you can
feed the dsp is smaller chunks allowing your application to be more
responsive. This is important if you are trying to achieve low-latency
real-time operation (something arts is not that great at in the first
place) -- which is exactly what is needed for something like the xten
sipphone client.

With the changes to the code, you can now not only change the buffer
size, but also have finer grain control over how the buffer gets
divided up. I should note that this control is limited to compile
time, not runtime. I did a lot of experimentation, and I believe the
current settings achieve the best balance/performance.

Jeremy Shaw.








More information about the wine-devel mailing list