jasonmc / forked-daapd

A re-write of the firefly media server (mt-daapd). It's released under GPLv2+. Please note that this git repository is a mirror of the official one at git://git.debian.org/~jblache/forked-daapd.git
http://blog.technologeek.org/2009/06/12/217
GNU General Public License v2.0
328 stars 45 forks source link

Announce: Allow playback on non apple Airplay devices #108

Open elwertk opened 11 years ago

elwertk commented 11 years ago

Hi,

forked daapd originaly was build and tested to support playback only for the following devices: apex g, apex N, appletv2. The likes of denon, pioneer, panasonic etc etc. may work but a lot don't.

Here is a simple patch that fixes this and should enable playback on most of the third party devices as well: https://gist.github.com/elwertk/5851432 It applies straight to the non GCD version (GCD to follow if I got time but hey..it is not that hard)

Tested this for a Pioneer and a Panasonic airplay enabled device I had flying arround. In therory others should not be that different.

Here's the trick:

Simple: Any "other" airplay device forked daapd talks to get's probed as airport express type N which is using RSA encrypted audio streams. This fails for the majority of those third party devices as they are using unencrypted audio streams. Hence a generic device type with no encryption was coded in.

Longer: Look at the bonjour announced txt record for your airplay device

avahi-browse -all -r

Example: appleTv txt = ["sf=0x4" "am=AppleTV2,1" "vs=130.14" "vn=65537" "tp=UDP" "ss=16" "sr=4 4100" "sv=false" "pw=false" "md=0,1,2" "et=0,3,5" "da=true" "cn=0,1,2,3" "ch=2"

The apple TV supports encryption types et=0,3,5 which is essentialy no encryption(0), fairplay(3) and some enhanced version of fairplay(5). The airport express devices would show et=1 here (don't have one at hand at present)

Example: Other txt = ["fv=95.8947" "am=JB2 Gen" "vs=103.2" "tp=UDP" "vn=65537" "pw=false" "s s=16" "sr=44100" "da=true" "sv=false" "et=0,4" "cn=0,1" "ch=2" "txtvers=1"]

The other device does supports no encryption (0) and a third party encryption (4) which usualy is not enabled.

Now we simply teach forked daapd about an "other" device type - essentialy anything that is not apex or atv - that requires no encryption and does not want metadata (for cover art; song name). I leave it to others with suitable devices at hand to play with this and test if metadata can/need to be re-enabled.

Note: This has not been widely tested and I haven't looked at the code for years. Just wanted to get the kitchen radio play what I want. Have fun.

ejurgensen commented 11 years ago

Thank you for this patch, I've included it in my fork of forked-daapd. Also good to see that you are still contributing (some of the original sources - like jasons git here - seem to have become inactive).

StephenAtty commented 11 years ago

I've also included it in my fork of forked-daapd which is the GCD version - it all compiled OK.

DeepFriedTwinkie commented 11 years ago

Question: Does anyone here have experience with the newest Airport Expresses? I just did an avahi-browse and the two that I have reported "et=0,4". And older one I have reported "et=0,1" as discussed above. Am I to assume that the above fix may work for the new APE? Or, is it likely that Apple has yet another encryption scheme for the newer APEs?

Thanks for doing this @elwertk! This is exciting. I was about to abandon forked-daapd for an old PC running iTunes!

elwertk commented 11 years ago

Likely they've dropped encryption for newer apex devices like they did for the atvs. And yes this should work for your newer one - can't see a reason why it should not. Why not just try it?

DeepFriedTwinkie commented 10 years ago

Yup it works! Added your gist to my local version and can now stream to newest APEs.

Now, I just have to get it to do a better job scanning my library. Still missing lots of songs. I've seen some stuff out there about open files, etc. So maybe I will dig into it at some point.

Thanks again @elwertk!

DeepFriedTwinkie commented 10 years ago

I spoke too soon. It almost works. The single else overrides prior devtype setup for other devices. (In essence, there are some old APEs that require encryption and report an am value in avahi-browse. I added a comment to @elwertk 's gist: https://gist.github.com/elwertk/5851432#comment-868053.

But, in short, I suggest updating the else' in player.c to: else if (strncmp(p, "AirPort4", strlen("AirPort4")) != 0)`

StephenAtty commented 10 years ago

I'll look at adding it this even when I get home from work

ejurgensen commented 10 years ago

I've included DeepFriedTwinkie's update in my fork, which I use to package forked-daapd for the Raspberry Pi. I wanted to let you know that a user confirmed that the update made his APE work again, so that's really great. He had an AirPort4. I have an old APE which doesn't report an am-field, and this works too (but it always did). Thank you very much for your update!

Right now eltwerks patch with DeepFriedTwinkies update means that AirPort10-devices get labeled as Other. This works fine, but perhaps it would be better to give them a specific, new label? (since these devices can apparently be identified).

@StephenAtty I see you have some artwork changes in your fork. In my fork I've done some more extensive changes in that regard, so you might be interested in looking at that.

StephenAtty commented 10 years ago

@ejurgensen - I'll check those out, mine was someone elses with a little more added to it. Most of my work has been round allowing you to restart the service without it rebuilding the DB which is important when you've over 20,000 in the library.

sprevrha commented 10 years ago

@ejurgensen - I cloned your fork to compile for my Pi with raspbmc, but can't get it to compile. autoreconf -i throws some errors like "possibly undefined macro: AM_ICONV". I'd love to get your comments, and thanks for the work being done here.

ejurgensen commented 10 years ago

@sprevrha If you just want to compile, you don't really need to fork. About getting it to compile on raspmc I suppose it would be better if you asked here: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=66&t=49928&p=394935

sprevrha commented 10 years ago

That's awesome. Does your package already include the patch for non-Apple non-encrypted Airplay devices as described on Jason's page?

Sven

On Wed, Aug 7, 2013 at 10:56 PM, ejurgensen notifications@github.comwrote:

@sprevrha https://github.com/sprevrha If you just want to compile, you don't really need to fork. About getting it to compile on raspmc I suppose it would be better if you asked here: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=66&t=49928&p=394935

— Reply to this email directly or view it on GitHubhttps://github.com/jasonmc/forked-daapd/issues/108#issuecomment-22283384 .

sprevrha commented 10 years ago

Dummy me. I was too excited and didn't read on. Forget the question.

On Wed, Aug 7, 2013 at 11:00 PM, Sven Prevrhal sprevrha@gmail.com wrote:

That's awesome. Does your package already include the patch for non-Apple non-encrypted Airplay devices as described on Jason's page?

Sven

On Wed, Aug 7, 2013 at 10:56 PM, ejurgensen notifications@github.comwrote:

@sprevrha https://github.com/sprevrha If you just want to compile, you don't really need to fork. About getting it to compile on raspmc I suppose it would be better if you asked here: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=66&t=49928&p=394935

— Reply to this email directly or view it on GitHubhttps://github.com/jasonmc/forked-daapd/issues/108#issuecomment-22283384 .

Sven

sprevrha commented 10 years ago

I downloaded your deb package and tried to install it but:

pi@raspbmc:~$ sudo dpkg -i forked-daapd_0.19.9.gitb52bd94-1_armhf.deb (Reading database ... 35120 files and directories currently installed.) Preparing to replace forked-daapd 0.19.9.gitb52bd94-1 (using forked-daapd_0.19.9.gitb52bd94-1_armhf.deb) ... Unpacking replacement forked-daapd ... Setting up forked-daapd (0.19.9.gitb52bd94-1) ... insserv: Service avahi has to be enabled to start service forked-daapd insserv: exiting now! update-rc.d: error: insserv rejected the script header dpkg: error processing forked-daapd (--install): subprocess installed post-installation script returned error exit status 1 Errors were encountered while processing: forked-daapd pi@raspbmc:~$ which forked-daapd /usr/sbin/forked-daapd pi@raspbmc:~$ sudo forked-daapd -v Forked Media Server: Version 0.19 Copyright (C) 2009-2011 Julien BLACHE jb@jblache.org Based on mt-daapd, Copyright (C) 2003-2007 Ron Pedde ron@pedde.com Released under the GNU General Public License version 2 or later pi@raspbmc:~$ sudo service avahi-daemon start start: Job is already running: avahi-daemon

On Wed, Aug 7, 2013 at 11:01 PM, Sven Prevrhal sprevrha@gmail.com wrote:

Dummy me. I was too excited and didn't read on. Forget the question.

On Wed, Aug 7, 2013 at 11:00 PM, Sven Prevrhal sprevrha@gmail.com wrote:

That's awesome. Does your package already include the patch for non-Apple non-encrypted Airplay devices as described on Jason's page?

Sven

On Wed, Aug 7, 2013 at 10:56 PM, ejurgensen notifications@github.comwrote:

@sprevrha https://github.com/sprevrha If you just want to compile, you don't really need to fork. About getting it to compile on raspmc I suppose it would be better if you asked here: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=66&t=49928&p=394935

— Reply to this email directly or view it on GitHubhttps://github.com/jasonmc/forked-daapd/issues/108#issuecomment-22283384 .

Sven

Sven

ejurgensen commented 10 years ago

@sprevrha Since your issue is about the build for Rasperry Pi/raspmbc I would again suggest that you make your inquiry in the Rasperry Pi forum. That way more people with a similar problem will be able to find help.

ejurgensen commented 10 years ago

I found out that forked-daapd cannot stream to AirFoil Speakers, because the AirFoil emulation does not completely match an AirPort Express. AirFoil does not return CSeq (control sequence numbers?) when it communicates with forked-daapd, and the server checks for these. However, it seems the server doesn't actually use these for anything, so I think it's safe to turn of the check when CSeq is missing. I did that like this: https://github.com/ejurgensen/forked-daapd/commit/3215d32b57182d404bd647a63fda5a9e83213884

elwertk commented 10 years ago

Nice investigative work yet I would not recommend using forked daapd against airfoil stuff in a multi speaker setup as I'm dead certain you'll loose the ability of all your speakers playing nicely in sync.

ejurgensen commented 10 years ago

Yes, that's what I thought too, but according to the user who reported the problem with AirFoil, sync is actually between his Pioneer Airplay Speaker and his Airport Express. So maybe it's ok with AirFoil too? I don't use it myself, so I haven't tested it. You can read about it here: http://www.raspberrypi.org/phpBB3/viewtopic.php?p=403365#p403365

By the way, I found and fixed a bug in raop.c, which sometimes made forked-daapd crash after stopping music. It's been annoying me for a long time, and it wasn't until I tried Valgrind that I finally found it. I use the non-GCD version, but I think it's in the GCD version too, though I'm not sure. Here is the patch (the player.c stuff is less important but keeps Valgrind happy): https://github.com/ejurgensen/forked-daapd/commit/b6df68b75b41a7f836652982c3faae57914ecdab

StephenAtty commented 10 years ago

Wow, is that the fix for the crash when stopping? don't mind Pause sometimes flipping back to the start of the track but the random crashes were very annoying. I'll roll those into my code base and test it over the coming weekend

ejurgensen commented 10 years ago

Yes, that's it. I haven't had any crashes since, so I hope the problem is solved.

StephenAtty commented 10 years ago

The code looks a little different for raop.c in the GCD version:

static void
raop_pktbuf_free_task(void *arg)
{
  struct raop_v2_packet *pkt;

  pkt = (struct raop_v2_packet *)arg;

  for (; pkt; pkt = pkt->next)
    free(pkt);
}

static void
raop_session_cleanup(struct raop_session *rs)
{
  struct raop_session *s;
  dispatch_queue_t global_q;

  if (rs == sessions)
    sessions = sessions->next;
  else
    {
      for (s = sessions; s && (s->next != rs); s = s->next)
    ; /* EMPTY */

      if (!s)
    DPRINTF(E_WARN, L_RAOP, "WARNING: struct raop_session not found in list; BUG!\n");
      else
    s->next = rs->next;
    }

  /* free_cb takes care of rs */
  http_client_free(rs->ctrl);

  /* No more active sessions, free retransmit buffer */
  if (!sessions)
    {
      global_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      dispatch_async_f(global_q, pktbuf_head, raop_pktbuf_free_task);

      pktbuf_head = NULL;
      pktbuf_tail = NULL;
      pktbuf_size = 0;
    }
}
ejurgensen commented 10 years ago

I think this part is bad, it is trying to address pkt->next after pkt has been free'd.

for (; pkt; pkt = pkt->next) free(pkt);

The pointer to the next packet should be set before freeing pkt, that's why I added the next_pkt pointer in my patch. I also changed it to a while loop, because then it is easier to understand what is going on.

StephenAtty commented 10 years ago

I've changed it to:

static void
raop_pktbuf_free_task(void *arg)
{
  struct raop_v2_packet *pkt;
 struct raop_v2_packet *next_pkt;

/*
pkt = (struct raop_v2_packet *)arg;
  for (; pkt; pkt = pkt->next)
    free(pkt);
 */
     pkt = pktbuf_head;
     while (pkt)
 {
    next_pkt = pkt->next;
    free(pkt);
    pkt = next_pkt;
  }
}

And it seems a lot more stable but I still seem to get the following from time to time if I'm impatient with iTunes and keep skipping tracks:

[2013-08-24 17:18:09]    httpd: Read 65536 bytes; streaming file id 8202
[2013-08-24 17:18:10]    httpd: Connection failed (fd 23)
[2013-08-24 17:18:10]    httpd: Write error (fd 23)

What I need to do is work out why the Write Error terminates the whole server process...

ejurgensen commented 10 years ago

Strange, I haven't seen that error. If you haven't already tried, I can recommend Valgrind. It helped me a lot finding the above culprit.

StephenAtty commented 10 years ago

I might look into it - C coding is not my natural habitat ;-)

attunicity commented 10 years ago

Would one of the posters in this thread help me get on board with the best fork/package that rolls up all the post Julian Bache fixes into v19 GCD based code (that I'm running on Ubuntu 12.04 LTS) ? I've been working around most of the issues but now with two devices (Denon Ceol Piccolo & latest 802.11n Gen APX) that won't accept output & the likelihood of a new iOS Remote app coming I need to adopt the most recent code and updates. Thanks.

jkiddo commented 10 years ago

Hey Applehacker lovers - just wanna inform you of the following hack-Apple projects that might be of interest for you guys: https://github.com/jkiddo/jolivia and https://github.com/mattstevens/dmap-parser

couteau commented 10 years ago

On the original topic of this thread, I submitted a patch to Julien Blache about a year and a half ago to support airplay on non-apple devices. It takes a slightly different approach than @elwertk, reading from the mDNS record to determine whether the device supports encryption and/or metadata, rather than assuming no support for either. This has the advantage that if the device supports it, you will see the artist/title on the device's vfd. It works on my Marantz m-cr603. I haven't tested any other devices.

Patches:

for GCD: https://gist.github.com/couteau/7532496

for libevent: https://gist.github.com/couteau/7532531

ejurgensen commented 10 years ago

Thank you for providing this patch, I've committed part of it in my fork: https://github.com/ejurgensen/forked-daapd/commit/1199a459acc3bb91c0ace2a08c6e764e2290a261

I only used the metadata part, because I'm afraid changing the encryption part might break something.