owntone / owntone-server

Linux/FreeBSD DAAP (iTunes) and MPD audio server with support for AirPlay 1 and 2 speakers (multiroom), Apple Remote (and compatibles), Chromecast, Spotify and internet radio.
https://owntone.github.io/owntone-server
GNU General Public License v2.0
2.09k stars 237 forks source link

kqueue timer is too inaccurate for FreeBSD RAOP streaming #46

Closed pipian closed 10 years ago

pipian commented 10 years ago

When using FreeBSD 10, RAOP streaming falls out of sync after about 30 seconds when streaming to a Denon AVR-X2000 receiver with Airplay support. A cursory check of timing in player.c finds that FreeBSD uses kqueue timers, which have only millisecond accuracy. Furthermore, there is anecdotal evidence that EVFILT_TIMER is generally inaccurate for real-time use.

Suggested fix is to replace kevent with POSIX-compliant signal-based timers (timer_create/timer_settime) which should still be compatible with libevent using the signal_set() macro. A cursory implementation using this appears to stay in sync for upwards of 12 minutes. Another advantage of this conversion is that it may be possible to directly refactor most of the Linux-specific timerfd API calls (except clock_gettime_with_res) to use the POSIX timer API calls as well, reducing the amount of OS-specific code in the codebase.

freultwah commented 10 years ago

How does the 30 second issue manifest itself in your case? In my case (also FreeBSD 10) playback stops for approximately two seconds every 32 seconds or so.

Also: have you got local audio working meaningfully? I've been having trouble with it, I've tinkered somewhat with the code without really knowing what I was doing, and I got something to work while breaking other stuff. In my case, local audio starts stuttering about six seconds in. The two issues could be related.

Oh, I built the software against system soundcard.h, not OSS4 provided in the ports. There was no difference either way, though.

pipian commented 10 years ago

I didn't leave it long enough to see if sound would restart after a period, but after about 30 seconds, audio would become increasingly choppy over about a second or two before cutting out entirely. I tried tweaking the value of AIRTUNES_V2_STREAM_PERIOD, but the best performance I could get was about 60 seconds before cutting out when it was set to 7ms.

I haven't tested local audio except in so far as I've installed the OSS4 port to make sure forked-daapd compiles. My configure-line is as follows (bash/zsh-specific, owing to the variables):

LDFLAGS=-L/usr/local/lib CPPFLAGS="-I/usr/local/include" ZLIB_CFLAGS=-I/usr/local \
ZLIB_LIBS=-lz GPERF=/usr/local/bin/gperf ./configure \
--with-oss4=/usr/local/lib/oss/include/sys --localstatedir=/var
pipian commented 10 years ago

The only other thing I needed to do was patch around #45 as that was causing a segfault and do some finicky hacking around to get ANTLR working. I'd been working with libantlr3c-3.4-beta4 on the GCD branch a while back, but that was giving me a segfault in the call to toStringTree() at daap_query.c:107 when passed

char *daap_query = "('daap.songartist!:'+('com.apple.itunes.extended-media-kind:1','com.apple.itunes.extended-media-kind:32'))";

I switched to ANTLR 3.5.2, but apparently this broke the nested use of strop, intop, dateop, dateref and dateintval in RSP.g (in addition to spitting out a bunch of warning messages), so I had to refactor strcrit, intcrit, and datecrit to not use those definitions.

I haven't filed a bug about that because it's possible that I made a mistake in jumping to 3.5.x.

ejurgensen commented 10 years ago

I probably won’t be able to do much about these FreeBSD issues, as I’m a bit of a rookie in this area. It seems you have made some improvements/fixes, and have a good understanding of these issues in general. Would you be willing to contribute with some pull requests?

pipian commented 10 years ago

I probably won’t be able to do much about these FreeBSD issues, as I’m a bit of a rookie in this area. It seems you have made some improvements/fixes, and have a good understanding of these issues in general. Would you be willing to contribute with some pull requests?

Unfortunately, due to the terms of employment at my day job, accepting any pull requests that I might submit would open forked-daapd and myself up to certain legal liabilities, so I am unable to do so. :disappointed:

ejurgensen commented 10 years ago

@pipian, I made an attempt at changing the timers, following your suggestion. It seems to work in Linux, but it still doesn’t work in FreeBSD. With local audio the sound is slow and crackling, and with AirPlay it just breaks quickly.

Since you had it working, when you tried, I am hoping you are willing to take a look at the change. Perhaps you can spot the problem? You can see my full change here:

https://github.com/ejurgensen/forked-daapd/compare/ejurgensen:master...laudio?expand=1

ejurgensen commented 10 years ago

I found out why it wasn't working, it turned out that even with timer_create() the FreeBSD timer did not have sufficient resolution. However, using timer_create had the advantage that it was easy to extend a low-resolution patch originally made by @AntDok to also work in FreeBSD. So now it seems to be working (here: https://github.com/ejurgensen/forked-daapd/tree/freebsd)

AntDok commented 10 years ago

@ejurgensen, This was a nice surprise to see in my Inbox this morning. I'm glad to see that work is still being done on forked-daapd.

ejurgensen commented 10 years ago

Yes, forked-daapd is good fun and sometimes quite challenging. I think it was originally a guy from Netgear that sent me your patch, so your work 3 years back is still being valued.

I'm closing this since I think the timing issue is now solved (however, it seems there may still be a bunch of FreeBSD issues).