-
Notifications
You must be signed in to change notification settings - Fork 227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for crash when using the JACK backend and quickly reconfiguring #529
Conversation
Thanks for your code. I'll put some comments to your new code. |
src/client.cpp
Outdated
return; | ||
} | ||
|
||
// In common audio subsystems, there may be multiple audio sizes in use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting concept. Is this Linux-specific or does this apply to all supported OSs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It applies to all OS'es where Jamulus is not the only client of the sound card subsystem.
Usually sound mixers have a pre-defined and fixed interval for the buffering.
Also further, USB hardware only supports small buffers of size of 2ms 3ms 4ms and so on. When Jamulus specifies 64 samples of buffer, the USB hardware cannot technically program that! So you end up with audio bursts, that in turn affect the timing of the UDP packets, and I found this to be the root cause of all jitter problems during my tests with FreeBSD. Too bad Windows doesn't have a nanosecond clock. I'm not fully sure how this patch will work there. Maybe someone can help testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do it when I am back at home in a week. If Windows does not support it, we should move your code in the Jack Sound.cpp file for now. Actually with my audio devices I tested, I did not have any higher jitter from the audio driver. What audio hardware are you using? And how did you measure the jitter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a X32-RACK audio device configured with 8-channel audio, where I use 2 for Jamulus. I measured the jitter by using wireshark and looking at the time between data packets going on the wire. After this patch I saw a major improvement.
I'm disabling this for Win32, because I think the timer there is not good enough (milliseconds only).
Thank you! |
I added in one more patch. I hope it is not too much :-) |
Switching from int to float wouldn't add much processing time? (usually int arithmetic is way faster than float) |
Well, actually it is. I would prefer smaller pull requests. |
Can you please give some more background information why you did this? |
Yes, the opus codec supports float, and I thought it would be cheap to add support for more than 16-bit sound. Many of the professional audio devices you recommend for use with Jamulus do 24-bit audio. There is a distinct difference between 16-bit audio and 24-bit audio, and this may help if the audio level is low, that you get a clear signal, and simply don't loose bits. On the server side, double is used for mixing today. This is overkill! Using float will give a slight performance gain. |
The server is using "double" today. And using "float" is expected to reduce the processing time a bit. |
@corrados : If some of the commits are good to go, and I can put them in a separate pull request, or maybe you can just push them separately and I'll rebase this pull request. |
Let's do things step-by-step and not all together.
|
Will you merge #1 ? |
Regarding #3, what kind audio cards are these? What interface do they use? What OS? |
Regarding #4 I don't see any noticable increase in CPU usage, its like 10->11 % CPU for both server and client on my machine. |
yes |
I have tried with Soundblaster Audigy on Lubuntu, Behringer UCA 202 on Windows and Mac, Lexicon Omega on Windows and Mac. |
Did you enable the jitter measuring debug code for these setups in the audio callback ? BTW: I changed my patch a bit, to attack the UDP transmission instead of the AudioProcess routine. Because encoding/decoding takes a variable amount of time, so to get that out of the equation, I've moved the delay around a bit. |
@corrados : Something else before I forget it: The first bit in every OPUS frame is unused! This may be possible to use for something like a toggle ..... |
done |
Thank you - just rebased my patches. |
I think we should not test it on a normal desktop CPU but on low end hardware like the Raspberry Pi Zero, see: #483 (comment) |
@corrados : Can you test a USB based audio device? |
Thanks for the plots. That is very interesting. I'll evaluate the jitter of my USB-devices as soon as I am back at home. I'm now very curious how it will look like... Can you please add which operating system you have used for these plots? |
I'm using FreeBSD w/ XHCI USB controller. |
I tested on a RPI3 running FreeBSD: Jamulus running on RPI3: However a new problem arised: ntpdate 0.freebsd.pool.ntp.org The RPI3 produces an effective sample rate of 48060 Hz, when there is no packet loss, compared to my other test computer, meaning the jitter buffer on the client "goes nuts" after a while :-( I think we need some tuning parameter here, or calibration, for this to work better! |
@corrados : I have an idea how we can solve all of this jitter issues once and for all by analyzing the timestamps on all packets received on the client :-) Let me work on it a bit. The main problem I see is that we send 3 packets every 4 milliseconds, for the smallest buffer size or 3 packets every 8 milliseconds. There is a simple statistical remainder trick that can be used here, but we need a bigger (prime) number than 3 I think! The goal is not depend on a high-resolution timer, but that a millisecond timer would suffice, like is available in Windows. Meanwhile I would like you to consider my floating point patch. I can put it first in the commit list to make merging easier! |
Yes, I need a pull request that only contains these changes. Then I can Start reviewing your changes. |
Something like that is expected. It likely means the USB stack in Windows is using a 1ms audio buffer, which is a requirement by the XHCI USB host controller. |
@corrados : I have the plans ready for a cool jitter correction algorithm. All I need is one bit per frame, and I see the first bit of every OPUS frame appears unused, so I'm asking for permission to use that bit for something! |
Can you please give some more info for what reason you need the bit? |
@corrados : I want to implement a "noise-based" (not sure what you would call it) sequence number for every OPUS frame. That means there is for example a 13-bit frame number incrementing one by one, then via a formula only one of the 13-bits is or'ed into every OPUS frame. The reason we need a frame number is because it is very difficult to estimate the packet loss accurately when there is not timing information provided by every UDP packet, from the sender side. Also 48kHz is not 48kHz. Over time the clocks will drift (sender and receiver side), but if we had a sequence number, this clock drift could easily be eliminated by libsamplerate on the client side! Without a sequence number it is impossible to know how many packets were dropped on the wire. --HPS |
This goes in a wrong direction. The idea of Jamulus is to keep it simple. About 10 years back I also had done tests with a resampling but that did not give any improvement. The idea is: if a packet is lost, it is lost. No need to track the packet number. You can read more about this in http://llcon.sourceforge.net/PerformingBandRehearsalsontheInternetWithJamulus.pdf If you want to include a resampler, you have a problem that we are working on blocks of data. If you have a clock difference, you would have to resample and get, e.g., 129 samples out of the resampler instead of 128. But you have to transmit 128. So what to do with the additional sample? You would have to introduce a new buffer. So you will have additional latency. The only meaningful clock correction would be hardware based (maybe GPS-based). But this is out of scope for the Jamulus software.
For what reason do you need the packet loss for improving the sound card jitter? |
I understand that Jamulus doesn't care about: a) reordering of packets Using the OPUS codec to conceal jitter might be more time-clever than using libsamplerate.
When you know the exact clock rate differences, you can then subtract or add that to the sound card jitter, to reduce the size of the jitter buffer needed. Right now in the "perfect" link scenario all clock differences are accounted as jitter. It is like Jamulus needs packet loss to keep the jitter buffer down! You asked about testing a Raspberry PI, and what I found is that the system clock is not that accurate. The RPI for example generates 751 64-sample OPUS packets per second, but the client only consumes 750 per second. Even for 1 second of continous data, we could reduce the latency by 1.33 ms, if we knew some sequence numbers here and there, which is possible by filling the first bit of every OPUS frame with a predictable "noise" pattern. I think it is simply wrong to assume that "the internet connection" will always have packet drops. |
Right, you could do that. But then you have to drop a packet from time to time to correct for the different clock rates. The jitter buffer just does exactly this anyway.
This depends on the selected jitter buffer size. If the jitter buffer size is set so that it corrects 1 packet per second, then you have exactly the same behavior.
Sure, you cannot say that the network always drops packet (do I do that in my paper? ;-) ). It depends on what type of network you have. There are more reliable connections and less reliable connections. E.g. over WLAN you will get packet loss in most cases. Usually Jamulus users will have network issues by other devices overloading the network with updates, video streams, etc. In that case you will not be able to estimate the clock offset reliably. Just for the special case for a near perfect network condition you will have a chance to estimate it and drop some audio blocks at the right time to compensate for the clock offsets. But again, this is what the jitter buffer already does. |
I see. Let me do a proof of concept on an own branch, and see if it makes any difference, hopefully w/o breaking too much of the established concepts. |
Yeah. Been there done that. Does not work, even with expensive ones like from Ubiquity. |
I reduced this pull request to only contain two small fixes. Hopefully increasing the chance of being merged. |
Could you please split the pull request further? That makes the integration and testing easier. One pull request for each "topic" like e.g. "replacing the presice timer for ping" would be great. Thanks. |
@corrados : Yes. |
Need to ensure that JACK callbacks see the running flag as false after being stopped. Use a QMutex for this. Signed-off-by: Hans Petter Selasky <hps@selasky.org>
Found some bugs here and there and managed to improve overall jitter with my audio card.