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 235 forks source link

Airplay2 device (LG OLED TV) is not listed #1010

Closed dmikhalsky closed 3 years ago

dmikhalsky commented 4 years ago

Latest forked-daaps 27.1 installed from souce at Pi4. Only airplay1 devices are listed (one shareport based and one is corelec) My LG TV that natively supports Airplay2 is not listed. ipv6 in config file is ON Avahi-browse output:

pi@Pi4:~ $ avahi-browse -kt _airplay._tcp
+  wlan0 IPv4 LG TV                                         _airplay._tcp        local
avahi-browse -kt _raop._tcp
+  wlan0 IPv6 92736CF1CD65@Pi4                              _raop._tcp           local
+  wlan0 IPv4 0242F72ACB0B@Kodi (CoreELEC)                  _raop._tcp           local
+  wlan0 IPv4 92736CF1CD65@Pi4                              _raop._tcp           local
ejurgensen commented 4 years ago

This is the first Airplay device I hear about that doesn't announce raop, but I suppose it is not an unlikely future development :-(

If so, it means forked-daapd needs to get on board the Airplay 2 train. I have been following some of the work discovering the protocol, but I'm not sure what the current feasibility of it is.

dmikhalsky commented 4 years ago

Thanks. Actually it is not that critical for me so far as both TV and Corelec are connected to the same living room audio system so I can point audio to Corelec. The reason I wanted to send the signal to TV is to achieve syncronization between living room audio and another sound system connected to sharepoint-sync reveiver. Unfortunately Kodi (Corelec) has airplay implmentation that is not based on shareport-sync and thus does npt provide audio syncronization betwen different devices.

if you need any info/logs/whatsoever for airplay 2 development, pls. let me know, I am ready to help

jul1an353 commented 4 years ago

Unfortunately my new Samsung UE-RU7179 TV that natively supports Airplay2 also does not announce raop.

pi@raspberrypi:~ $ avahi-browse -kt _raop._tcp

pi@raspberrypi:~ $ avahi-browse -kt _airplay._tcp

ghost commented 3 years ago

Hope this helps, but the new Roku Airplay2 does the same as the Samsung TV as mentioned by @dmikhalsky and also does not announce via raop._tcp. :-(

Kitchen is an old Bose Airplay 1 device, Basement TV is a AppleTV4K both work fine of course. The Roku Library and Living Room are new Apple Airplay2 for Roku running version 9.4.0 build 4190-50 firmware and only sit on airplay._tcp. Looks like this new listen only on airplay_tcp is a thing in more places now. There are graphical similarities between the Samsung and the Roku code, which makes me think that new licensed bundles from Apple are using similar software kits.

+   eth0 IPv6 C8D083xxxxxx@Basement TV                      _raop._tcp           local
+   eth0 IPv4 000C8Axxxxxx@Kitchen                          _raop._tcp           local

vs Roku:

+   eth0 IPv6 Basement TV                                   _airplay._tcp        local
+   eth0 IPv4 Roku Living Room                              _airplay._tcp        local
+   eth0 IPv4 Roku Library                                  _airplay._tcp        local

Forcing this line was my first idea, but I'm sure that's not going to be the right idea it's going to need a grown up to do an intervention here :-)

  ret = mdns_browse("_raop._tcp", family, raop_device_cb, MDNS_CONNECTION_TEST);

I have the latest master branch of forked-daapd built from source, so happy to checkout any changes and recompile (I'm guessing raop.c and friends) and test if I can help in anyway given I've got one of each of these random new devices.

ejurgensen commented 3 years ago

Yeah, changing the line is unlikely to be enough. I haven't gotten around to looking at this, and I'm not sure when I can, even though I consider it a priority. It's not clear to me what exactly would be required to support Airplay 2, but I expect there is a bunch of work in it.

ghost commented 3 years ago

I hear you @ejurgensen, I did read that a few folks have managed to "reverse" AP2 some. No rush on this, I mostly just wanted to add to the thread that it's now a thing sigh. There's always another thing, and it looks like raop's days may well be numbered. Meh. Thanks ever so much for responding, it's clearly going to be a large lift, I'll have a poke given it's now a challenge question to get this to go and probably more so moving forwards. If I find anything useful I'll report back.

Happy thanksgiving from the US!

ghost commented 3 years ago

Sorry, hadn't really done any research into this before now. I think it's a total non starter. The only thing that someone has been able to do was In May 2019, a third-party developer released a macOS app that can stream audio using AirPlay 2. Their app includes a helper tool called "AirPlay Enabler" that uses code injection to bypass restrictions to the AirPlay 2 private API on macOS. It's DRM all the way down now. Anything that could do it would no doubt be end up with lawyers involved. Great. Current state of the art: https://emanuelecozzi.net/docs/airplay2. I think this is a non starter unless someone is brave enough to put out a library. :-(

ejurgensen commented 3 years ago

@jamesdotcuff I have made a branch with adjustments so that forked-daapd also detects and parses _airplay._tcp, and it actually worked with the two Apple devices I have that announce it (an ATV4 and an Airport Express). I didn't make any adjustments to the session setup, but a bit to my surprise it worked as is. So it would be great if you could try with your Roku.

The branch is this one: https://github.com/ejurgensen/forked-daapd/tree/airplay2_1

ghost commented 3 years ago

Ohhh awesome @ejurgensen! Heading in the right direction! It did find the Roku! We are on to something!

It also did create a password attempt. The protocol is close. The password didn't take. But we are close. Hope this helps.

[DEBUG] player: Callback from AirPlay 2 device Roku Library to device_activate_cb (status -2)

makes me happy... tempImageuypCP3 roku2

[DEBUG]   player: Speaker enable: 'Roku Library' (id=152221340618663)
[DEBUG]   player: Registered callback to device_activate_cb with id 0 (device 0xaaaae79fb820, Roku Library)
[DEBUG]   player: Number of active callbacks: 1
[DEBUG]   player: Subscription request for quality 44100/16/2 (now 1 subscribers)
[DEBUG]     raop: device_start: Sending pair-pin-start to 'Roku Library'
[  LOG]     raop: Starting device verification for 'Roku Library', go to the web interface and enter PIN
[DEBUG]   player: Callback request received, id is 0
[DEBUG]   player: Unsubscription request for quality 44100/16/2 (now 0 subscribers)
[DEBUG]   player: Making deferred callback to device_activate_cb, id was 0
[DEBUG]   player: Callback from AirPlay 2 device Roku Library to device_activate_cb (status -2)
[  LOG]   player: The AirPlay 2 device 'Roku Library' requires a valid PIN or password
[DEBUG]     main: Command has 0 pending events
[DEBUG]   player: Status update - status: 2, events: 12, caller: speaker_generic_bh
[DEBUG]      mpd: Asynchronous listener callback called with event type 12.
[DEBUG]      mpd: Notify clients waiting for idle results: 12
[  LOG]      web: JSON api request failed with error code 500 (/api/outputs/152221340618663)
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff58000b80: fd 82 events 1 -> 5
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff58000b80: fd 82 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff58000b80: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: stopped
[DEBUG]       db: Running query 'BEGIN TRANSACTION;'
[DEBUG]       db: Starting enum 'SELECT * FROM queue f WHERE pos = 0 ORDER BY pos;'
[DEBUG]       db: End of queue enum results
[DEBUG]       db: Running query 'END TRANSACTION;'
[DEBUG]      web: JSON api request: '/api/outputs'
[DEBUG]      web: JSON api request: '/api/outputs/152221340618663'
[DEBUG]   player: Registered callback to device_activate_cb with id 0 (device 0xaaaae79fb820, Roku Library)
[DEBUG]   player: Number of active callbacks: 1
[DEBUG]   player: Subscription request for quality 44100/16/2 (now 1 subscribers)
[ INFO]     raop: Making verification request step 1 to 'Roku Library'
[  LOG]     raop: Verification step 1 to 'Roku Library' failed with error code 403: Forbidden
[DEBUG]   player: Callback request received, id is 0
[DEBUG]   player: Unsubscription request for quality 44100/16/2 (now 0 subscribers)
[DEBUG]   player: Making deferred callback to device_activate_cb, id was 0
[DEBUG]   player: Callback from AirPlay 2 device Roku Library to device_activate_cb (status -2)
[  LOG]   player: The AirPlay 2 device 'Roku Library' requires a valid PIN or password
[DEBUG]     main: Command has 0 pending events
[DEBUG]   player: Status update - status: 2, events: 12, caller: speaker_generic_bh
[DEBUG]      mpd: Asynchronous listener callback called with event type 12.
[DEBUG]      mpd: Notify clients waiting for idle results: 12
[  LOG]      web: JSON api request failed with error code 500 (/api/outputs/152221340618663)
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff58000b80: fd 82 events 1 -> 5
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff58000b80: fd 82 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff58000b80: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: stopped
[DEBUG]       db: Running query 'BEGIN TRANSACTION;'
[DEBUG]       db: Starting enum 'SELECT * FROM queue f WHERE pos = 0 ORDER BY pos;'
[DEBUG]       db: End of queue enum results
[DEBUG]       db: Running query 'END TRANSACTION;'
[DEBUG]      web: JSON api request: '/api/outputs'
ghost commented 3 years ago

Same on Samsung TV and Roku with Airplay2. Every Airplay2 device now gives us a login with your patch, which is GREAT progress.

Then alas now fails. Hope this helps @ejurgensen I do think we are close.

[ INFO]     raop: Making verification request step 1 to 'Samsung Library'
[  LOG]     raop: Verification step 1 to 'Samsung Library' failed with error code 403: Forbidden
[DEBUG]   player: Callback request received, id is 0

detail:

[  LOG]   player: The AirPlay 2 device 'Samsung Library' requires a valid PIN or password
[DEBUG]     main: Command has 0 pending events
[DEBUG]   player: Status update - status: 2, events: 12, caller: speaker_generic_bh
[DEBUG]      mpd: Asynchronous listener callback called with event type 12.
[DEBUG]      mpd: Notify clients waiting for idle results: 12
[  LOG]      web: JSON api request failed with error code 500 (/api/outputs/110074351477472)
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff8c000b80: fd 81 events 1 -> 5
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff8c000b80: fd 81 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff8c000b80: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: stopped
ejurgensen commented 3 years ago

Thanks for the quick test. It's bad news that the pairing doesn't work, but maybe it isn't even required. I have added a commit to the branch that skips it, could you pull and try again with that?

Also please post the output of avahi-browse -r -k _airplay._tcp, I would like to see exactly what your devices announce.

ghost commented 3 years ago

yeah alas no joy, the require code is grayed out on the screen with "Require Code First Time Only" and you can't turn it off either :-( The Samsung has the option to swap “First time only” with a preset passcode. Tried both.


So this didn't manage to hop past it either with or with out the comments Sorry!

//  if (keyval_get(&features, "SupportsSystemPairing")) // Not sure if this is the correct one?
//    rd->requires_auth = 1;

Here’s the error from airplay.c bouncing up against a 403: Forbidden "/pair-setup-pin

", I popped my own debug in there to check it wasn't heading down the old raop code.

[DEBUG]   player: Subscription request for quality 44100/16/2 (now 1 subscribers)
[ INFO]     raop: Making verification request step 1 to 'Samsung Library'
[ INFO]     raop: CUFF: Making verification request step 1 to 'Samsung Library' /pair-setup-pin
[  LOG]     raop: CUFF: Verification step 1 to 'Samsung Library' failed with error code 403: Forbidden

Found https://github.com/openairplay/AirPlayAuth and doing some more reading.



Since tvOS 10.2 AppleTV is enforcing the "Device verification" for AirPlay, which could be manually enabled/disabled before. This library allows to pair with an AppleTV and can be used in any app supporting streaming/casting to an AppleTV.

Also: https://htmlpreview.github.io/?https://github.com/philippe44/RAOP-Player/blob/master/doc/auth_protocol.html 
 But looks like most of that is already in airplay.c

Here's the browse info - I've xxxx out the stuff that looks to be identifiable, hope that's ok.



root@mediasrv:~# avahi-browse -r -k _airplay._tcp
+  wlan0 IPv4 Roku Library                                  _airplay._tcp        local
+  wlan0 IPv4 Samsung Library                               _airplay._tcp        local
+  wlan0 IPv4 Roku Living Room                              _airplay._tcp        local
=  wlan0 IPv6 Basement TV                                   _airplay._tcp        local

   hostname = [Basement-TV.local]
   address = [192.168.1.218]
   port = [7000]
   txt = ["vv=2" "osvers=14.2" "srcvers=525.38.42" "pk=xxxxxxxxxx” "psi=xxxxxxxxx” "pi=xxxxxxxx” "protovers=1.1" "model=AppleTV6,2" "gcgl=1" "igl=1" "gid=xxxxxxxxxxxxxx” "flags=0x644" "features=0x4A7FDFD5,0x3C155FDE" "fex=1d9/St5fFTw" "deviceid=C8:D0:83:xxxxxx” "btaddr=C8:D0:83:xxxxxxx” "acl=0"]

=  wlan0 IPv4 Roku Library                                  _airplay._tcp        local
   hostname = [YH00H94xxxxxx.local]
   address = [192.168.1.159]
   port = [7000]
   txt = ["pk=xxxxxxxxx” "gcgl=0" "gid=xxxxxxx” "psi=xxxxx” "pi=8A:71:CA:EF:xxxx" "srcvers=377.28.01" "protovers=1.1" "serialNumber=xxxxxxx” "manufacturer=Roku" "model=3810X" "flags=0x644" "at=0x3" "fv=p20.9.40.4190" "rsf=0x3" "features=0x7F8AD0,0x10BCF46" "deviceid=8A:71:CA:xxxxx” "acl=0"]

=  wlan0 IPv4 Samsung Library                               _airplay._tcp        local
   hostname = [Samsung.local]
   address = [192.168.1.201]
   port = [57692]
   txt = ["pk=7xxxxxxxxxx” "gcgl=0" "gid=xxxxxxxxxxx” "psi=xxxxxxx” "pi=4C:6F:64:xxxxxxx” "srcvers=377.17.24.6" "protovers=1.1" "serialNumber=xxxxxxx” "manufacturer=Samsung" "model=UNU7090" "flags=0x244" "fv=p20.0.1" "rsf=0x3" "features=0x7F8AD0,0x38BCB46" "deviceid=64:1C:AE:xxxxx” "acl=0"]

=  wlan0 IPv4 Basement TV                                   _airplay._tcp        local
   hostname = [Basement-TV.local]
   address = [192.168.1.218]
   port = [7000]
   txt = ["vv=2" "osvers=14.2" "srcvers=525.38.42" "pk=xxxxxxx” "psi=xxxxxxxxxx” "pi=xxxxxxxx” "protovers=1.1" "model=AppleTV6,2" "gcgl=1" "igl=1" "gid=xxxxxxxxx” "flags=0x644" "features=0x4A7FDFD5,0x3C155FDE" "fex=1d9/St5fFTw" "deviceid=C8:D0:83:xxxxxxxxx” "btaddr=C8:D0:83:xxxxxxx”x "acl=0"]

=  wlan0 IPv4 Roku Living Room                              _airplay._tcp        local
   hostname = [YH00CMxxxxxx.local]
   address = [192.168.1.141]
   port = [7000]
   txt = ["pk=xxxxxxxxx” "gcgl=0" "gid=xxxxxxxxx” "psi=xxxxxxxxx” "pi=35:CC:46:xxxxxxx” "srcvers=377.28.01" "protovers=1.1" "serialNumber=0xxxxxxxxx” "manufacturer=Roku" "model=3810X" "flags=0x244" "at=0x3" "fv=p20.9.40.4190" "rsf=0x3" "features=0x7F8AD0,0x10BCF46" "deviceid=35:CC:46:xxxxxxx” "acl=0"]
ejurgensen commented 3 years ago

Thanks again for testing. I'd like to see the logging from when the device is selected and pairing is disabled - to see what error the device is returning. Can you try to restart forked-daapd, start playback and then select one of the devices? Using the latest branch, so with those lines commented out.

And yes, device verification (pairing) is already supported, but I don't know if Apple changed anything. I see they have multiple methods for pairing.

ghost commented 3 years ago

Here’s the error log you asked for:

[DEBUG]   player: Callback from AirPlay 2 device Samsung Library to device_activate_cb (status -2)
[  LOG]   player: The AirPlay 2 device 'Samsung Library' requires a valid PIN or password
[DEBUG]     main: Command has 0 pending events
[DEBUG]   player: Status update - status: 4, events: 12, caller: speaker_generic_bh
[DEBUG]      mpd: Asynchronous listener callback called with event type 12.
[DEBUG]      mpd: Notify clients waiting for idle results: 12
[  LOG]      web: JSON api request failed with error code 500 (/api/outputs/110074351477472/toggle)
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff8c000b80: fd 86 events 1 -> 5
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff8c000b80: fd 86 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff8c000b80: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[DEBUG]      web: JSON api request: '/api/player'

Also here’s the features supported we can parse


[DEBUG]     mdns: Avahi Browser: NEW service 'Roku Library' type '_airplay._tcp' proto 0
[DEBUG]     mdns: Avahi Resolver: resolved service 'Roku Library' type '_airplay._tcp' proto 0, host YH00H9457333.local, address 192.168.1.159
[DEBUG]     mdns: Connection test to 192.168.1.159:7000 completed successfully
[DEBUG]     raop: Event for AirPlay device 'Roku Library' (port 7000, id 8a71caef4fa7)
[DEBUG]     raop: Speaker 'Roku Library' supports feature 7: 'SupportsAirPlayScreen'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 9: 'SupportsAirPlayAudio'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 11: 'AudioRedunant'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 15: 'MetadataFeatures_0'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 16: 'MetadataFeatures_1'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 17: 'MetadataFeatures_2'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 18: 'AudioFormats_0'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 19: 'AudioFormats_1'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 20: 'AudioFormats_2'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 21: 'AudioFormats_3'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 33: 'SupportsAirPlayVideoPlayQueue'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 34: 'SupportsAirPlayFromCloud'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 38: 'SupportsUnifiedMediaControl'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 40: 'SupportsBufferedAudio'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 41: 'SupportsPTP'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 42: 'SupportsScreenMultiCodec'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 43: 'SupportsSystemPairing'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 46: 'SupportsHKPairingAndAccessControl'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 48: 'SupportsCoreUtilsPairingAndEncryption'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 49: 'SupportsAirPlayVideoV2'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 51: 'SupportsUnifiedPairSetupAndMFi'
[DEBUG]     raop: Speaker 'Roku Library' supports feature 56: 'SupportsWoL'
[ INFO]     raop: Adding AirPlay device 'Roku Library': password: 0, verification: 0, encrypt: 0, authsetup: 0, metadata: 7, type Other, address 192.168.1.159:7000


This is compared tp an appletv below



Note:  [DEBUG]     raop: Speaker 'Basement TV' supports feature 27: 'SupportsLegacyPairing'
[DEBUG]     mdns: Avahi Resolver: resolved service 'C8D083D10F3E@Basement TV' type '_raop._tcp' proto 0, host Basement-TV.local, address fe80::c97:c757:6456:bb1d
[ WARN]     mdns: Connection test to fe80::c97:c757:6456:bb1d:7000 failed with getaddrinfo error: Address family for hostname not supported
[ WARN]     mdns: Ignoring announcement from Basement-TV.local, address fe80::c97:c757:6456:bb1d is not connectable
[DEBUG]     mdns: Avahi Resolver: resolved service 'Basement TV' type '_airplay._tcp' proto 0, host Basement-TV.local, address 192.168.1.218
[DEBUG]     mdns: Connection test to 192.168.1.218:7000 completed successfully
[DEBUG]     raop: Event for AirPlay device 'Basement TV' (port 7000, id c8d083d10f3e)
[DEBUG]     raop: Speaker 'Basement TV' supports feature 0: 'SupportsAirPlayVideoV1'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 7: 'SupportsAirPlayScreen'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 9: 'SupportsAirPlayAudio'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 11: 'AudioRedunant'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 14: 'Authentication_4'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 15: 'MetadataFeatures_0'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 16: 'MetadataFeatures_1'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 17: 'MetadataFeatures_2'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 18: 'AudioFormats_0'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 19: 'AudioFormats_1'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 20: 'AudioFormats_2'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 21: 'AudioFormats_3'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 27: 'SupportsLegacyPairing'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 30: 'HasUnifiedAdvertiserInfo'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 33: 'SupportsAirPlayVideoPlayQueue'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 34: 'SupportsAirPlayFromCloud'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 35: 'SupportsTLS_PSK'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 38: 'SupportsUnifiedMediaControl'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 40: 'SupportsBufferedAudio'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 41: 'SupportsPTP'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 42: 'SupportsScreenMultiCodec'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 43: 'SupportsSystemPairing'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 44: 'IsAPValeriaScreenSender'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 46: 'SupportsHKPairingAndAccessControl'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 48: 'SupportsCoreUtilsPairingAndEncryption'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 50: 'MetadataFeatures_3'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 52: 'SupportsSetPeersExtendedMessage'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 58: 'SupportsHangdogRemoteControl'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 59: 'SupportsAudioStreamConnectionSetup'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 60: 'SupportsAudioMediaDataControl'
[DEBUG]     raop: Speaker 'Basement TV' supports feature 61: 'SupportsRFC2198Redundancy'
[ INFO]     raop: Adding AirPlay device 'Basement TV': password: 0, verification: 0, encrypt: 0, authsetup: 0, metadata: 7, type AppleTV, address 192.168.1.218:7000

Also commented but no good, and hard set requires_auth to 0.



//  if (keyval_get(&features, "Authentication_8"))
//    re->supports_auth_setup = 1;
//  if (keyval_get(&features, "SupportsSystemPairing")) // Not sure if this is the correct one?
//   rd->requires_auth = 1;

Also AppleTV is returning [DEBUG] raop: Speaker 'Basement TV' supports feature 14: 'Authentication_4' although we look for Authentication_8. 

There are no “Authentication” string features in the Roku or Samsung. Need to do some wiresharking here. :-)



Open to any other suggestions! We are super close I feel. I think the bit we are commenting isn’t quite forcing it to carry on w/o auth need to do some more digging.



ejurgensen commented 3 years ago

Actually the log I'm interested in is the part before (and make sure you restart forked-daapd before getting it): player: Callback from AirPlay 2 device Samsung Library to device_activate_cb (status -2)

That's because that is where forked-daapd is trying to start a normal session, and gets some error from the device. It is this error I would like to be sure what is.

ghost commented 3 years ago

Ooops - sorry here you go:

[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing

(clicked Roku here)

[DEBUG]      web: JSON api request: '/api/outputs/152221340618663'
[DEBUG]   player: Speaker enable: 'Roku Library' (id=152221340618663)
[DEBUG]   player: Registered callback to device_activate_cb with id 0 (device 0xaaaad09420f0, Roku Library)
[DEBUG]   player: Number of active callbacks: 1
[DEBUG]   player: Subscription request for quality 44100/16/2 (now 1 subscribers)
[DEBUG]     raop: device_start: Sending OPTIONS to 'Roku Library'
[ SPAM]   ffmpeg: Setting 'time_base' to value '1/48000'
[ SPAM]   ffmpeg: Setting 'sample_rate' to value '48000'
[ SPAM]   ffmpeg: Setting 'sample_fmt' to value 's32'
[ SPAM]   ffmpeg: Setting 'channel_layout' to value '0x3'
[DEBUG]   ffmpeg: tb:1/48000 samplefmt:s32 samplerate:48000 chlayout:0x3
[DEBUG]    xcode: Created 'in' filter: time_base=1/48000:sample_rate=48000:sample_fmt=s32:channel_layout=0x3
[ SPAM]   ffmpeg: Setting 'sample_fmts' to value 's16'
[ SPAM]   ffmpeg: Setting 'sample_rates' to value '44100'
[ SPAM]   ffmpeg: Setting 'channel_layouts' to value '0x3'
[DEBUG]    xcode: Created 'format' filter: sample_fmts=s16:sample_rates=44100:channel_layouts=0x3
[DEBUG]   ffmpeg: auto-inserting filter 'auto_resampler_0' between the filter 'in' and the filter 'format'
[ SPAM]   ffmpeg: query_formats: 3 queried, 3 merged, 3 already done, 0 delayed
[ SPAM]   ffmpeg: Using fltp internally between filters
[DEBUG]   ffmpeg: ch:2 chl:stereo fmt:s32 r:48000Hz -> ch:2 chl:stereo fmt:s16 r:44100Hz
[DEBUG]     raop: startup_options: Sending pair-pin-start to 'Roku Library'
[  LOG]     raop: Starting device verification for 'Roku Library', go to the web interface and enter PIN
[DEBUG]   player: Callback request received, id is 0
[DEBUG]   player: Unsubscription request for quality 44100/16/2 (now 0 subscribers)
[DEBUG]   player: Making deferred callback to device_activate_cb, id was 0
[DEBUG]   player: Callback from AirPlay 2 device Roku Library to device_activate_cb (status -2)
[  LOG]   player: The AirPlay 2 device 'Roku Library' requires a valid PIN or password
[DEBUG]     main: Command has 0 pending events
[DEBUG]   player: Status update - status: 4, events: 12, caller: speaker_generic_bh
[DEBUG]      mpd: Asynchronous listener callback called with event type 12.
[DEBUG]      mpd: Notify clients waiting for idle results: 12
[  LOG]      web: JSON api request failed with error code 500 (/api/outputs/152221340618663)
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70002300: fd 83 events 1 -> 5
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70000b80: fd 82 events 1 -> 5
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70000b80: fd 82 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff70000b80: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70002300: fd 83 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff70002300: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing
[DEBUG]      web: JSON api request: '/api/outputs'
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing
[DEBUG]      web: JSON api request: '/api/outputs'
[DEBUG]     mdns: Avahi Browser: NEW service 'Samsung Library' type '_airplay._tcp' proto 0
[DEBUG]     mdns: Avahi Resolver: resolved service 'Samsung Library' type '_airplay._tcp' proto 0, host Samsung.local, address 192.168.1.201
[DEBUG]     mdns: Connection test to 192.168.1.201:51913 completed successfully
[DEBUG]     raop: Event for AirPlay device 'Samsung Library' (port 51913, id 641cae9e62e0)
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 7: 'SupportsAirPlayScreen'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 9: 'SupportsAirPlayAudio'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 11: 'AudioRedunant'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 15: 'MetadataFeatures_0'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 16: 'MetadataFeatures_1'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 17: 'MetadataFeatures_2'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 18: 'AudioFormats_0'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 19: 'AudioFormats_1'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 20: 'AudioFormats_2'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 21: 'AudioFormats_3'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 33: 'SupportsAirPlayVideoPlayQueue'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 34: 'SupportsAirPlayFromCloud'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 38: 'SupportsUnifiedMediaControl'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 40: 'SupportsBufferedAudio'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 41: 'SupportsPTP'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 43: 'SupportsSystemPairing'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 46: 'SupportsHKPairingAndAccessControl'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 48: 'SupportsCoreUtilsPairingAndEncryption'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 49: 'SupportsAirPlayVideoV2'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 51: 'SupportsUnifiedPairSetupAndMFi'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 55: 'SupportsWoL'
[DEBUG]     raop: Speaker 'Samsung Library' supports feature 56: 'SupportsWoL'
[ INFO]     raop: Adding AirPlay device 'Samsung Library': password: 0, verification: 0, encrypt: 0, authsetup: 0, metadata: 7, type Other, address 192.168.1.201:51913
[DEBUG]       db: Running query 'SELECT s.selected, s.volume, s.name, s.auth_key FROM speakers s WHERE s.id = 110074351477472;'
[DEBUG]   player: Status update - status: 4, events: 12, caller: device_add
[DEBUG]      mpd: Asynchronous listener callback called with event type 12.
[DEBUG]      mpd: Notify clients waiting for idle results: 12
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70002300: fd 83 events 1 -> 5
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70000b80: fd 82 events 1 -> 5
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70000b80: fd 82 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff70000b80: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[ SPAM]      web: LWS rops_handle_POLLOUT_ws: notify: wsi->ws->tx_draining_ext 0
[ SPAM]      web: LWS _lws_change_pollfd: wsi 0xffff70002300: fd 83 events 5 -> 1
[ SPAM]      web: LWS lws_handle_POLLOUT_event: 0xffff70002300: non mux: wsistate 0x20000119, ops ws
[DEBUG]      web: notify callback reason: 11
[ SPAM]      web: LWS lws_issue_raw: ssl_capable_write (39) says 39
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing
[DEBUG]      web: JSON api request: '/api/outputs'
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing
[DEBUG]      web: JSON api request: '/api/outputs'

It is interesting that it has a different feature list to others, and the Samsung and Roku have the same features. Reading:

"Further research showed that at the moment, all available third-party AirPlay mirroring receivers (servers) are using this legacy protocol, including the open source implementation of dsafa22, which is the base for RPiPlay. Given Apple considers this a legacy protocol, it can be expected to be removed entirely in the future. This means that all third-party AirPlay receivers will have to be updated to the new (fully encrypted) protocol at some point."

From https://github.com/FD-/RPiPlay still gives me some level of hope that it will respond to the old protocols.

ejurgensen commented 3 years ago

Ok, log shows that as expected the OPTIONS request gets a 403, which should mean pairing is required. It does seem like it could be a clue that only the working ATV announces support for "legacy pairing".

I notice the pairing gets a 403 very early, which is a bit strange since at this point forked-daapd is just preparing the pairing.

It would of course be interesting if you could try with RPiPlay - if that works it is super interesting.

ghost commented 3 years ago

Ok so this is interesting. Cloned and built RPIPlay and turned up the debug. forked-daapd doesn't seem to want to connect to RPIPlay either. Hope that's useful infos. Here's the RPIPlay log and the one from forked-daapd trying to connect.

Also a successful iPhone connect to the RPIPlay server:

Forked to RPIPLAY

conn_request
Handling request OPTIONS with URL *
httpd receiving on socket 14
Connection closed for socket 14
Destroying connection
Accepted IPv4 client on socket 14
Local: 127.0.0.1
Remote: 127.0.0.1
httpd receiving on socket 14
conn_request
Handling request OPTIONS with URL *
httpd receiving on socket 14
conn_request
Handling request ANNOUNCE with URL rtsp://127.0.0.1/3072613878
httpd receiving on socket 14
conn_request
Handling request SETUP with URL rtsp://127.0.0.1/3072613878
DACP-ID: 34798EC137933F71
Active-Remote: 847168050
Transport: RTP/AVP/UDP;unicast;interleaved=0-1;mode=record;control_port=44832;timing_port=37855
httpd receiving on socket 14
Connection closed for socket 14
Destroying connection

Here's what forked does:

[DEBUG]    xcode: Created 'format' filter: sample_fmts=s32:sample_rates=48000:channel_layouts=0x3
[DEBUG]   ffmpeg: auto-inserting filter 'auto_resampler_0' between the filter 'in' and the filter 'format'
[ SPAM]   ffmpeg: query_formats: 3 queried, 3 merged, 3 already done, 0 delayed
[ SPAM]   ffmpeg: Using fltp internally between filters
[DEBUG]   ffmpeg: ch:2 chl:stereo fmt:fltp r:48000Hz -> ch:2 chl:stereo fmt:s32 r:48000Hz
[DEBUG]   player: Starting input read loop for item 'http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_q' (item id 40), seek 0
[DEBUG]   player: Registered callback to device_activate_cb with id 0 (device 0xaaaac90e4c90, RPiPlay)
[DEBUG]   player: Number of active callbacks: 1
[DEBUG]   player: Subscription request for quality 44100/16/2 (now 1 subscribers)
[DEBUG]     raop: device_start: Sending OPTIONS to 'RPiPlay'
[DEBUG]     raop: startup_options: Sending ANNOUNCE to 'RPiPlay'
[DEBUG]     raop: Local address: 127.0.0.1 (LL: no) port 58724
[ INFO]     raop: Setting up AirPlay session 3072613878 (127.0.0.1 -> 127.0.0.1)
[DEBUG]     raop: startup_announce: Sending SETUP to 'RPiPlay'
[  LOG]     raop: Missing Session header in SETUP reply
[DEBUG]   player: Callback request received, id is 0
[DEBUG]   player: Unsubscription request for quality 44100/16/2 (now 0 subscribers)
[DEBUG]   player: Making deferred callback to device_activate_cb, id was 0
[DEBUG]   player: Callback from AirPlay device RPiPlay to device_activate_cb (status -1)
[  LOG]   player: The AirPlay device 'RPiPlay' failed to activate
[DEBUG]     main: Command has 0 pending events
[DEBUG]   player: Status update - status: 4, events: 13, caller: playback_start_bh
[DEBUG]      mpd: Asynchronous listener callback called with event type 13.
[DEBUG]      mpd: Notify clients waiting for idle results: 13
[DEBUG]      web: JSON api request: '/api/player'
[DEBUG]   player: Player status: playing (buffering)

With iPhone, you can see the pair setup stuff and such before "SETUP"

Accepted IPv4 client on socket 14
Local: 192.168.1.181
Remote: 192.168.1.224
httpd receiving on socket 14
conn_request
Handling request GET with URL /info
INFO len = -1414708584
httpd receiving on socket 14
conn_request
Handling request POST with URL /pair-setup
httpd receiving on socket 14
conn_request
Handling request POST with URL /pair-verify
httpd receiving on socket 14
conn_request
Handling request POST with URL /pair-verify
httpd receiving on socket 14
conn_request
Handling request POST with URL /fp-setup
httpd receiving on socket 14
conn_request
Handling request POST with URL /fp-setup
httpd receiving on socket 14
conn_request
Handling request SETUP with URL rtsp://192.168.1.181/2815273128112834459
DACP-ID: 7142432D655B479C
Active-Remote: 2246713023
Transport: null
SETUP 1
eiv_len = 16
ekey_len = 72
fairplay_decrypt ret = 0
timing_rport = 52056
raop_ntp parse remote ip = 192.168.1.224
raop_ntp starting time
raop_rtp parse remote ip = 192.168.1.224
raop_rtp_mirror parse remote ip = 192.168.1.224
eport = 33163, tport = 46338
raop_ntp send_len = 32
raop_ntp receive time type_t packetlen = 32
raop_ntp sync correction = -1606401536214326
Accepted IPv4 client on socket 16
Local: 192.168.1.181
Remote: 192.168.1.224
httpd receiving on socket 14
conn_request
Handling request GET with URL /info
INFO len = -1414708584
httpd receiving on socket 14
conn_request
Handling request GET_PARAMETER with URL rtsp://192.168.1.181/2815273128112834459
httpd receiving on socket 14
conn_request
Handling request RECORD with URL rtsp://192.168.1.181/2815273128112834459
raop_handler_record
httpd receiving on socket 14
conn_request
Handling request SET_PARAMETER with URL rtsp://192.168.1.181/2815273128112834459
httpd receiving on socket 14
conn_request
Handling request SETUP with URL rtsp://192.168.1.181/2815273128112834459
DACP-ID: 7142432D655B479C
Active-Remote: 2246713023
Transport: null
type = 96
raop_rtp starting audio
RAOP initialized success
raop_rtp type_c 0x54, packetlen = 20
raop_rtp sync: ntp=199404634806, local ntp: 1606600940849132, rtp=4207524558, rtp_next=4207612758
raop_rtp sync correction=-1606505532128996
raop_rtp type_c 0x54, packetlen = 20
raop_rtp sync: ntp=199404659924, local ntp: 1606600940874250, rtp=4207525666, rtp_next=4207613866
raop_rtp sync correction=3
httpd receiving on socket 14
raop_rtp audio: ntp = 1606600942896226, now = 1606600940881608, latency=-2014618, rtp=4207614835
conn_request
Handling request FLUSH with URL rtsp://192.168.1.181/2815273128112834459
Flush with RTP-Info: seq=33475;rtptime=4207620347
raop_rtp audio: ntp = 1606600942904208, now = 1606600940881823, latency=-2022385, rtp=4207615187
httpd receiving on socket 14
Request not complete, waiting for more data...
httpd receiving on socket 14
Request not complete, waiting for more data...
httpd receiving on socket 14
Request not complete, waiting for more data...
httpd receiving on socket 14
Request not complete, waiting for more data...
raop_rtp audio: ntp = 1606600942912190, now = 1606600940908235, latency=-2003955, rtp=4207615539
raop_rtp audio: ntp = 1606600942920172, now = 1606600940908521, latency=-2011651, rtp=4207615891
raop_rtp audio: ntp = 1606600942928153, now = 1606600940908679, latency=-2019474, rtp=4207616243
httpd receiving on socket 14
ejurgensen commented 3 years ago

Oh thought RPiPlay was a sender, not a receiver. Then it isn't quite so useful. The reason forked-daapd isn't connecting to it is unrelated.

ejurgensen commented 3 years ago

One more thing: The forked-daapd request that fails is to /pair-setup-pin, while your iPhone and the docs you link use /pair-setup. So maybe the former is legacy pairing and the latter is system pairing? I will try if my ATV responds to /pair-setup, and if I can complete pairing setup with that endpoint.

ghost commented 3 years ago

Yeah I tried that by hardcoding in airplay.c to be pair-setup. still 403's:

[DEBUG]   player: Subscription request for quality 44100/16/2 (now 1 subscribers)
[ INFO]     raop: CUFF: Making verification request step 1 to 'Roku Library' /pair-setup
[  LOG]     raop: Verification step 1 to 'Roku Library' failed with error code 403: Forbidden
[DEBUG]   player: Callback request received, id is 0

I also read the piece in the code about airplay_send_req_auth_setup(struct airplay_session *rs, evrtsp_req_cb cb, const char *log_caller) and the piece about auth-setup:

The purpose of auth-setup is to authenticate the device and to exchange keys for encryption. We don't do that, but some AirPlay 2 speakers (Sonos beam, Airport Express fw 7.8) require this step anyway, otherwise we get a 403 to our ANNOUNCE. So we do it with a flag for no encryption, and without actually authenticating the device.

So poked it here, because the Roku doesn't announce any type of "Authentication_8 or 4" etc.

//CUFF -- forceauth 
//  if (keyval_get(&features, "Authentication_8"))
    re->supports_auth_setup = 1;

But to no success either. Hope this is helpful. I'm going to keep digging!

ghost commented 3 years ago

If it helps this is the logic code from RPIPlay (yeah it's a server, but this is how an Airplay2 device listens, and the client sends this stuff). This might have to be the path to do the set up?


    *response = http_response_init("RTSP/1.0", 200, "OK");

    http_response_add_header(*response, "CSeq", cseq);
    //http_response_add_header(*response, "Apple-Jack-Status", "connected; type=analog");
    http_response_add_header(*response, "Server", "AirTunes/220.68");

    logger_log(conn->raop->logger, LOGGER_DEBUG, "Handling request %s with URL %s", method, url);
    raop_handler_t handler = NULL;
    if (!strcmp(method, "GET") && !strcmp(url, "/info")) {
        handler = &raop_handler_info;
    } else if (!strcmp(method, "POST") && !strcmp(url, "/pair-setup")) {
        handler = &raop_handler_pairsetup;
    } else if (!strcmp(method, "POST") && !strcmp(url, "/pair-verify")) {
        handler = &raop_handler_pairverify;
    } else if (!strcmp(method, "POST") && !strcmp(url, "/fp-setup")) {
        handler = &raop_handler_fpsetup;
    } else if (!strcmp(method, "OPTIONS")) {
        handler = &raop_handler_options;
    } else if (!strcmp(method, "SETUP")) {
        handler = &raop_handler_setup;
    } else if (!strcmp(method, "GET_PARAMETER")) {
        handler = &raop_handler_get_parameter;
    } else if (!strcmp(method, "SET_PARAMETER")) {
        handler = &raop_handler_set_parameter;
    } else if (!strcmp(method, "POST") && !strcmp(url, "/feedback")) {
        handler = &raop_handler_feedback;
    } else if (!strcmp(method, "RECORD")) {
        handler = &raop_handler_record;
    } else if (!strcmp(method, "FLUSH")) {
        const char *rtpinfo;
        int next_seq = -1;

I'll try and stick more debug in RPIPlay and see if I can discover what the phone is actually sending, right now I only have this. My theory is we are trying to make forked-daapd be an "iPhone" kinda... a client of the Roku and Samsung "server". Let me know if I'm barking up the wrong tree?

Handling request GET with URL /info
Handling request POST with URL /pair-setup
Handling request POST with URL /pair-verify
Handling request POST with URL /pair-verify
Handling request POST with URL /fp-setup
Handling request POST with URL /fp-setup
Handling request SETUP with URL rtsp://192.168.1.181/2815273128112834459
ghost commented 3 years ago

Yes this is all the gubbins that RPIPlay uses for the setup to construct the plists and the other stuffs to auth and connect each of the URL handlers are listed in this header.

https://github.com/FD-/RPiPlay/blob/master/lib/raop_handlers.h

ghost commented 3 years ago

Confirming the order for a standard laptop to connect to the Roku goes like:

egrep 'GET|POST' rokuconnect.txt 
GET /info RTSP/1.0. 
POST /pair-verify RTSP/1.0
POST /pair-verify RTSP/1.0
ghost commented 3 years ago

Wasn't able to get rid of the "paired key" from the Roku, but the Samsung does allow you to change the request to force it to ask for a pin again, it has a slightly different connection flow. It looks like it does indeed try to do the pair-pin-start, but then rocks on after that with all the verify stuff.

Sorry for the noise, but thought this might be useful. The roku clearly has a key stored for my laptop and goes right into POST /pair-verify after the GET /info. The Samsung did pop up the enter pin dialog and reflected the dialog to the laptop with the same - entered that pin and it connected and started playing. This is using standard laptop airplay stuffs and a spot of sharking...

MacBook:wireshark jcuff$ egrep "CSeq|POST|OK|GET" samsung.txt
GET /info RTSP/1.0
CSeq: 0
RTSP/1.0 200 OK
CSeq: 0
POST /pair-verify RTSP/1.0
CSeq: 1
RTSP/1.0 200 OK
CSeq: 1
POST /pair-verify RTSP/1.0
CSeq: 2
RTSP/1.0 200 OK
CSeq: 2
POST /pair-pin-start RTSP/1.0
CSeq: 3
RTSP/1.0 200 OK
CSeq: 3
GET /info RTSP/1.0
CSeq: 0
RTSP/1.0 200 OK
CSeq: 0
POST /pair-setup RTSP/1.0
CSeq: 1
RTSP/1.0 200 OK
CSeq: 1
POST /pair-setup RTSP/1.0
CSeq: 2
RTSP/1.0 200 OK
CSeq: 2
POST /pair-setup RTSP/1.0
CSeq: 3
RTSP/1.0 200 OK
CSeq: 3
POST /pair-verify RTSP/1.0
CSeq: 4
RTSP/1.0 200 OK
CSeq: 4
POST /pair-verify RTSP/1.0
CSeq: 5
RTSP/1.0 200 OK
CSeq: 5

(all binary packets from here on in)
ghost commented 3 years ago

In forked-daapd messing about with the sequence in here... I think this is the right place where the chatter all starts, it's going to need more time to grock, I'm about as deep into my comfort level right now :-) also thanks again for all the pointers and suggestions, feel free to let me know if I'm off track or not, and sorry for all the messages! We will get there!

airplay_verification_request_send(int step, struct airplay_session *rs, void (*cb)(struct evrtsp_request *, void *))
{
  struct evrtsp_request *req;
  uint8_t *body;
  uint32_t len;
  const char *errmsg;
  const char *url;
  const char *ctype;
  int ret;

  switch (step)
    {
      case 1:
        body    = verification_setup_request1(&len, rs->verification_setup_ctx);
        errmsg  = verification_setup_errmsg(rs->verification_setup_ctx);
        url     = "/pair-verify";
        ctype   = "application/x-apple-binary-plist";
        break;
      case 2:
        body    = verification_setup_request2(&len, rs->verification_setup_ctx);
        errmsg  = verification_setup_errmsg(rs->verification_setup_ctx);
        url     = "/pair-verify";
        ctype   = "application/x-apple-binary-plist";
        break;
      case 3:
        body    = verification_setup_request3(&len, rs->verification_setup_ctx);
        errmsg  = verification_setup_errmsg(rs->verification_setup_ctx);
        url     = "/pair-pin-start";
        ctype   = "application/x-apple-binary-plist";
        break;
      case 4:
        body    = verification_verify_request1(&len, rs->verification_verify_ctx);
        errmsg  = verification_verify_errmsg(rs->verification_verify_ctx);
        url     = "/pair-verify";
        ctype   = "application/octet-stream";
        break;
      case 5:
        body    = verification_verify_request2(&len, rs->verification_verify_ctx);
        errmsg  = verification_verify_errmsg(rs->verification_verify_ctx);
        url     = "/pair-verify";
        ctype   = "application/octet-stream";
        break;
      default:
        body    = NULL;
        errmsg  = "Bug! Bad step number";
    }
ghost commented 3 years ago

One last thing for now. These Samsung and Roku devices do only advertise SupportsUnifiedPairSetupAndMFi, which I think means that all of this:

https://openairplay.github.io/airplay-spec/audio/rtsp_requests/post_auth_setup.html

will need to happen inside of forked-daapd. Which is a bit beyond my skill set to implement. Especially all the "Generation of Curve25119 key pairs on both client and server" stuff. :-(

Did find some sender code though!

https://github.com/openairplay/ap2-sender/blob/master/pairing.txt

and:https://github.com/openairplay/ap2-sender. which all looks very new. I'll have a look at that also. Possible to lift this maybe?

ghost commented 3 years ago

Ok confirmed!

Good news - so the ap2-sender can connect to the Roku!

So that's the recipe inside that code, built inside of Xcode and it worked first time. Nightmare of porting over to forked-daapd but at least it connect.

rokuairplay

ghost commented 3 years ago

Also, ap2-sender works and pairs with the Samsung also. It's one call to pair-pin-start, and three calls to pair-setup and then two to pair-verify. Both Samsung and Roku follow the exact same pattern, I'm guessing it's basically the same licensed code that will no doubt be found on all third party non apple things - probably the LG which is how this whole long saga started! hehe. The code is inside AirPlaySenderConnection.m that will need to lift over and all the csrp, ed25519 and curve25519 and chachapoly stuff. It's going to be a lot of work, but at least we know it can happen.

MacBook:ap2-sender jcuff$ egrep "POST|GET|OK|key|HTTP" samsungcuff.txt
POST /pair-pin-start
HTTP/1.1 200
POST /pair-setup
HTTP/1.1 200
POST /pair-setup
HTTP/1.1 200
SRP Shared key:
session_key:
POST /pair-setup
HTTP/1.1 200
session_key:
POST /pair-verify
HTTP/1.1 200
POST /pair-verify
HTTP/1.1 200
HTTP/1.0 200

Here's the roku trace:

MacBook:ap2-sender jcuff$ egrep "POST|GET|OK|key|HTTP" rokucuff.txt 
POST /pair-pin-start
HTTP/1.1 200
POST /pair-setup
HTTP/1.1 200
POST /pair-setup
HTTP/1.1 200
SRP Shared key:
session_key:
POST /pair-setup
HTTP/1.1 200
session_key:
POST /pair-verify
HTTP/1.1 200
POST /pair-verify
HTTP/1.1 200
HTTP/1.0 200
ejurgensen commented 3 years ago

Yes, ap2-sender is promising. To me it looks like it is doing Homekit pairing, which is also what the Airplay2 docs mention, so hopefully that can work. It's not too far from the pairing that forked-daapd already has. I tried sending the ap2-sender first setup request to my ATV4, but it didn't respond as quite as pairing.txt said - it returned a plist, not a tlv response. I don't have a mac/xcode, but I will try to compile ap2-sender anyway and see if it works with my ATV4. Then I can make a version of forked-daapd with the same pairing - but only if I have a device to test with, otherwise it is too difficult.

ghost commented 3 years ago

Great stuff. I hear you. If you are able to flesh out where to put all the crypto and new pairing in forked-daapd I am more than happy to hack around it and let you know what works. Me and your super smart event driven stuff had me mostly worried quite where to insert it all. Hey, the main thing is it does look promising. These devices remember pairing keys all differently and each take a different path depending on if you have a stored token or not. Having the new pairing code is I think going to be time well spent given what we’ve seen with these devices and should scale to others as the protocols move over to this new AP2 auth stuff. I’m sure there will be more shenanigans at some point. :-)

ejurgensen commented 3 years ago

@jamesdotcuff I've made a test program which implements this new pairing, and I hope you could try it with your devices. If it works I can then include it in forked-daapd. Right now it only pairs and tries to make an OPTIONS request. If it can do that, then I hope the rest will also work.

Here's how to build and test (the dependencies should already be in place if you can build forked-daapd):

git clone https://github.com/ejurgensen/atv_verification.git
git checkout ap2test2
make
./pair-example ip-adress port

You then enter the PIN that is displayed. If it works you will see OPTIONS completed, and if you see something else it didn't work.

ghost commented 3 years ago

Tada!! Nicely done captain! Roku yes! Samsung also YES!

Superb result!

gcc -Wall -DCONFIG_GCRYPT  -DDEBUG_PAIR -g pair-example.c pair_homekit.c tlv.c evrtsp/rtsp.c -o pair-example -levent -lplist -lgcrypt -lsodium
root@mediasrv:~/forked-daapd/atv_verification# ./pair-example 192.168.1.159 7000
[warn] event_del_: event has no event_base set.
Making request 1 to '/pair-pin-start'... success

Enter pin: 4453
Making request 2 to '/pair-setup'... success

(snipped out the TLV debug stuff)

Verify complete
Making request 7 to '*'... 
Decrypted:
0x000000: 52 54 53 50 2f 31 2e 30 20 32 30 30 20 4f 4b 0d RTSP/1.0 200 OK.
0x000010: 0a 50 75 62 6c 69 63 3a 20 41 4e 4e 4f 55 4e 43 .Public: ANNOUNC
0x000020: 45 2c 20 53 45 54 55 50 2c 20 52 45 43 4f 52 44 E, SETUP, RECORD
0x000030: 2c 20 50 41 55 53 45 2c 20 46 4c 55 53 48 2c 20 , PAUSE, FLUSH, 
0x000040: 46 4c 55 53 48 42 55 46 46 45 52 45 44 2c 20 54 FLUSHBUFFERED, T
0x000050: 45 41 52 44 4f 57 4e 2c 20 4f 50 54 49 4f 4e 53 EARDOWN, OPTIONS
0x000060: 2c 20 50 4f 53 54 2c 20 47 45 54 2c 20 50 55 54 , POST, GET, PUT
0x000070: 0d 0a 53 65 72 76 65 72 3a 20 41 69 72 54 75 6e ..Server: AirTun
0x000080: 65 73 2f 33 37 37 2e 32 38 2e 30 31 0d 0a 43 53 es/377.28.01..CS
0x000090: 65 71 3a 20 37 0d 0a 0d 0a                      eq: 7....       
success

OPTIONS complete
Done
ejurgensen commented 3 years ago

Awesome. Thanks for the quick test, that is much appreciated. I will clean it up and include it, then I'll ping you for another test.

ejurgensen commented 3 years ago

I've now added the modifications into forked-daapd, and I could succesfully pair and start playback on my Apple TV. So now I'm very excited to hear if it will work for you!

The changes are in the branch you tried before, so here: https://github.com/ejurgensen/forked-daapd/tree/airplay2_1. If everything works you should in the log see verification complete succesfully, a notice that encrypted mode will be used and then the playback session should start.

ghost commented 3 years ago

You are a coding genius!

Alas we see a 501 not implemented on the Samsung and on the Roku after completing the pairing attempt. I do see it succesfully pop the enc key into the sqlite database:

[ INFO]     raop: Making verification request step 1 to 'Samsung Library'
[ INFO]     raop: Making verification request step 2 to 'Samsung Library'
[ INFO]     raop: Making verification request step 3 to 'Samsung Library'
[  LOG]     raop: Verification setup stage complete, saving authorization key
[DEBUG]       db: Running query 'INSERT OR REPLACE INTO speakers (id, selected, volume, name, auth_key) VALUES (110074351477472, 0, 50, 'Samsung Library', 'b9. GIANT STRING HERE!

So close!

Samsung on play:

[ INFO]     raop: Making verification request step 5 to 'Samsung Library'
[ INFO]     raop: Verification of 'Samsung Library' completed succesfully, now using encrypted mode
[DEBUG]     raop: verify_step2: Sending OPTIONS to 'Samsung Library'
[DEBUG]     raop: startup_options: Sending ANNOUNCE to 'Samsung Library'
[DEBUG]     raop: Local address: 192.168.1.181 (LL: no) port 34696
[ INFO]     raop: Setting up AirPlay session 3674176603 (192.168.1.181 -> 192.168.1.203)
[  LOG]     raop: ANNOUNCE request failed in session startup: 501 Not Implemented
[DEBUG]   player: Callback request received, id is 0

And the Roku on play:

[ INFO]     raop: Verification of 'Roku Library' completed succesfully, now using encrypted mode
[DEBUG]     raop: verify_step2: Sending OPTIONS to 'Roku Library'
[DEBUG]     raop: startup_options: Sending ANNOUNCE to 'Roku Library'
[DEBUG]     raop: Local address: 192.168.1.181 (LL: no) port 55498
[ INFO]     raop: Setting up AirPlay session 1707633614 (192.168.1.181 -> 192.168.1.159)
[  LOG]     raop: ANNOUNCE request failed in session startup: 501 Not Implemented
[DEBUG]   player: Callback request received, id is 0
ghost commented 3 years ago

Sorry was meaning to add, now you have done the hard lift I can have a poke at the API for these two, there’s clearly something they stripped down that they don’t like in the announce I’ll do some more digging and report back. Hopefully this is all still useful!

ghost commented 3 years ago

Quick notice: The Apple 4K TV doesn't seem to take the encrypted code path, debug showsVerification of 'Basement TV' completed succesfully, rather thanVerification of 'Roku Library' completed succesfully, **now using encrypted mode**

Apple TV:

[ INFO]     raop: Making verification request step 5 to 'Basement TV'
[ INFO]     raop: Verification of 'Basement TV' completed succesfully
[DEBUG]     raop: verify_step2: Sending OPTIONS to 'Basement TV'
[DEBUG]     raop: startup_options: Sending ANNOUNCE to 'Basement TV'
[DEBUG]     raop: Local address: fde6:85af:aa8a:0:61d7:bcc:432:3324 (LL: no) port 51304
[ INFO]     raop: Setting up AirPlay session 3802689459 (fde6:85af:aa8a:0:61d7:bcc:432:3324 -> fde6:85af:aa8a:0:8e9:9127:5de7:df69)
[DEBUG]     raop: startup_announce: Sending SETUP to 'Basement TV'

Roku:

[ INFO]     raop: Verification of 'Roku Library' completed succesfully, now using encrypted mode
[DEBUG]     raop: verify_step2: Sending OPTIONS to 'Roku Library'
[DEBUG]     raop: startup_options: Sending ANNOUNCE to 'Roku Library'
[DEBUG]     raop: Local address: 192.168.1.181 (LL: no) port 55498
[ INFO]     raop: Setting up AirPlay session 1707633614 (192.168.1.181 -> 192.168.1.159)
[  LOG]     raop: ANNOUNCE request failed in session startup: 501 Not Implemented
[DEBUG]   player: Callback request received, id is 0

Also announce capability for AppleTV vs Roku, I was kinda right, there are missing things in the OEM version of Airplay.

Apple 4K TV:

0x000010: 0a 44 61 74 65 3a 20 53 75 6e 2c 20 30 36 20 44 .Date: Sun, 06 D
0x000020: 65 63 20 32 30 32 30 20 31 35 3a 34 36 3a 34 34 ec 2020 15:46:44
0x000030: 20 47 4d 54 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65  GMT..Content-Le
0x000040: 6e 67 74 68 3a 20 30 0d 0a 50 75 62 6c 69 63 3a ngth: 0..Public:
0x000050: 20 41 4e 4e 4f 55 4e 43 45 2c 20 53 45 54 55 50  ANNOUNCE, SETUP
0x000060: 2c 20 52 45 43 4f 52 44 2c 20 50 41 55 53 45 2c , RECORD, PAUSE,
0x000070: 20 46 4c 55 53 48 2c 20 54 45 41 52 44 4f 57 4e  FLUSH, TEARDOWN
0x000080: 2c 20 4f 50 54 49 4f 4e 53 2c 20 47 45 54 5f 50 , OPTIONS, GET_P
0x000090: 41 52 41 4d 45 54 45 52 2c 20 53 45 54 5f 50 41 ARAMETER, SET_PA
0x0000a0: 52 41 4d 45 54 45 52 2c 20 50 4f 53 54 2c 20 47 RAMETER, POST, G
0x0000b0: 45 54 2c 20 50 55 54 0d 0a 53 65 72 76 65 72 3a ET, PUT..Server:
0x0000c0: 20 41 69 72 54 75 6e 65 73 2f 35 32 35 2e 33 38  AirTunes/525.38
0x0000d0: 2e 34 32 0d 0a 43 53 65 71 3a 20 37 0d 0a 0d 0a .42..CSeq: 7....

Roku:

0x000000: 52 54 53 50 2f 31 2e 30 20 32 30 30 20 4f 4b 0d RTSP/1.0 200 OK.
0x000010: 0a 50 75 62 6c 69 63 3a 20 41 4e 4e 4f 55 4e 43 .Public: ANNOUNC
0x000020: 45 2c 20 53 45 54 55 50 2c 20 52 45 43 4f 52 44 E, SETUP, RECORD
0x000030: 2c 20 50 41 55 53 45 2c 20 46 4c 55 53 48 2c 20 , PAUSE, FLUSH, 
0x000040: 46 4c 55 53 48 42 55 46 46 45 52 45 44 2c 20 54 FLUSHBUFFERED, T
0x000050: 45 41 52 44 4f 57 4e 2c 20 4f 50 54 49 4f 4e 53 EARDOWN, OPTIONS
0x000060: 2c 20 50 4f 53 54 2c 20 47 45 54 2c 20 50 55 54 , POST, GET, PUT
0x000070: 0d 0a 53 65 72 76 65 72 3a 20 41 69 72 54 75 6e ..Server: AirTun
0x000080: 65 73 2f 33 37 37 2e 32 38 2e 30 31 0d 0a 43 53 es/377.28.01..CS
0x000090: 65 71 3a 20 37 0d 0a 0d 0a                      eq: 7....       

Don't worry at all about the GET/SET_PARAMETER, we already know that Roku doesn't take volume commands, that's a whole different and unrelated fiasco :-)

ejurgensen commented 3 years ago

Thanks for the kind words, but I'm standing on the shoulders of some really bright people here. It's great to hear that the pairing and the OPTIONS now work, so we are moving closer. Seems AirPlay 2 doesn't use ANNOUNCE. If I understand correctly that data exchange is now part of SETUP. So I will make some more modifications. There is some documentation here that looks useful.

Your ATV 4K is announcing _raop._tcp, so for that forked-daapd is using the old non-encrypted Airplay 1 (which also uses ANNOUNCE).

ghost commented 3 years ago

Ah. Perfect. Yes makes sense on both parts. Keep cooking on gas my friend! Glad this stuff is useful.

ejurgensen commented 3 years ago

Bad news, I made the updates outlined in the unofficial docs, but it doesn't work. The SETUP requests work fine, but when the RECORD request is made to my ATV, it hangs for 10 seconds and then returns an internal error. So something isn't right. I've tried various permutations/experiments, but no dice. I will keep trying, but I am not very optimistic.

There is one thing you could do to help, which is try to grab the traffic between iTunes/Apple Music and your Roku with Wireshark. It will be encrypted, but it will provide clues as to which connections are made, how many requests there are, and via the size of them also which ones. If you are up for that, then please follow this method:

  1. If you haven't already, pair with the Roku
  2. Unselect the Roku and quit iTunes/Apple Music
  3. Start iTunes/Apple Music, start playback of some song locally on the computer (so don't select the Roku yet)
  4. Start Wireshark, start sniffing all traffic to the Roku's IP address
  5. In iTunes/Apple Music, select the Roku
  6. When you can hear the song, stop Wireshark and save the dump

It is important that the speaker is not selected before you start playback, because then the session might have the same requests repeated, or "probing" requests that aren't strictly necessary and just muddy the picture. You are welcome to send the result to me at espenjurgensen@gmail.com if you prefer not sharing it here.

ejurgensen commented 3 years ago

@jamesdotcuff, good news, with the input of an open source angel I was able to identify the issue with RECORD, and now I have working Airplay 2 playback on my ATV4. So I'm hoping you are still around to pull the latest commits from the airplay2_1 branch and test if it also works with the Samsung or Roku. Of course, I would also like to hear from anyone else in this thread who can test.

If it works the next step will be to clean up the code in the branch, it has become rather messy.

ghost commented 3 years ago

Awesome sauce - definite progress, sorry for the delay I had reimaged my test raspberry pi for another project (hehe!). I'll send you an email, some of this stuff is a bit identifiable. We are now authing and going much further unto CSeq 6, but complaining about some device specific things like volume.

More in the email, but the Samsung gets mad with our volume call:

 0000  52 54 53 50 2f 31 2e 30 20 35 30 30 20 49 6e 74  RTSP/1.0 500 Int
 0010  65 72 6e 61 6c 20 53 65 72 76 65 72 20 45 72 72  ernal Server Err
 0020  6f 72 0d 0a 43 6f 6e 74 65 6e 74 2d 4c 65 6e 67  or..Content-Leng
 0030  74 68 3a 20 30 0d 0a 53 65 72 76 65 72 3a 20 41  th: 0..Server: A
 0040  69 72 54 75 6e 65 73 2f 33 37 37 2e 31 37 2e 32  irTunes/377.17.2
 0050  34 2e 36 0d 0a 43 53 65 71 3a 20 36 0d 0a 0d 0a  4.6..CSeq: 6....
[2020-12-21 12:29:32] [  LOG]     raop: SET_PARAMETER request failed for startup volume: 500 Internal Server Error
[2020-12-21 12:29:32] [DEBUG]   player: Callback request received, id is 0

And the Roku is sad about something in SETUP:

[2020-12-21 12:30:14] [  LOG]     raop: SETUP request failed in session startup: 400 Bad Request
[2020-12-21 12:30:14] [DEBUG]   player: Callback request received, id is 0
[2020-12-21 12:30:14] [DEBUG]   player: Unsubscription request for quality 44100/16/2 (now 0 subscribers)

Did manage to get a image artwork displayed on the screen though. Hope this helps!!

EDIT: Neither of these two things do "volume" correctly (they never even implemented it), so I'm thinking this may well smell like the culprit.

ejurgensen commented 3 years ago

Thanks for the logs. Interesting that the results are so different. I've quickly added a commit to the branch that simply skips setting volume, please test again if you can. Let's see if that brings us to playback on the Samsung. The Roku is more tricky, I'm not sure what it is unhappy about, so that will require some more experimenting.

ghost commented 3 years ago

I've emailed you the new stuff. Good news is now the Samsung and the Roku now stop at the same place! The Samsung now correctly skips over the volume but at least we know that neither device likes the binary plist we are sending after a successful SETPEERS. That plist the one at CSeq: 6 is the one that has the audioFormat, audioMode and latency pieces inside it - you'll see this in the full email log.

[2020-12-21 15:49:16] [  LOG]     raop: SETUP request failed in session startup: 400 Bad Request

EDIT: I'll have a monkey around with that plist and see if I can make progress, there's obviously something it don't support in there and I'll write you back.

ghost commented 3 years ago

Yep - got all the way up to CSeq 10 and up to RECORD by taking out this line:

//  wplist_dict_add_uint(stream, "type", RAOP_RTP_PAYLOADTYPE); // RTP type, 0x06 = 96 real time, 103 buffered

Here's what happens now:

[2020-12-21 16:20:31] [DEBUG]     raop: Decrypted incoming response
 0000  52 54 53 50 2f 31 2e 30 20 32 30 30 20 4f 4b 0d  RTSP/1.0 200 OK.
 0010  0a 53 65 72 76 65 72 3a 20 41 69 72 54 75 6e 65  .Server: AirTune
 0020  73 2f 33 37 37 2e 31 37 2e 32 34 2e 36 0d 0a 43  s/377.17.24.6..C
 0030  53 65 71 3a 20 31 30 0d 0a 0d 0a                 Seq: 10....
[2020-12-21 16:20:31] [ INFO]     raop: RECORD reply from 'Samsung Library' did not have an Audio-Latency header
[2020-12-21 16:20:31] [DEBUG]   player: Callback request received, id is 0
[2020-12-21 16:20:31] [DEBUG]   player: Making deferred callback to device_activate_cb, id was 0
[2020-12-21 16:20:31] [DEBUG]   player: Callback from AirPlay 2 device Samsung Library to device_activate_cb (status 2)
[2020-12-21 16:20:31] [DEBUG]   player: Registered callback to device_streaming_cb with id 0 (device 0xab46d8, Samsung Library)

The Roku gives a similar (ish) error, but does hit the RECORD part:

[2020-12-21 16:29:08] [ SPAM]      web: LWS fd=75, revents=4
[2020-12-21 16:29:08] [ SPAM]      web: LWS lws_calllback_as_writeable: 0xaab005c8 (user=0xaab00a88)
[2020-12-21 16:29:08] [DEBUG]      web: notify callback reason: 11
[2020-12-21 16:29:08] [ SPAM]      web: LWS _lws_rx_flow_control: no pending change
[2020-12-21 16:29:08] [ SPAM]      web: LWS fd=77, revents=4
[2020-12-21 16:29:08] [ SPAM]      web: LWS lws_calllback_as_writeable: 0xaab00828 (user=0xaab02d98)
[2020-12-21 16:29:08] [DEBUG]      web: notify callback reason: 11
[2020-12-21 16:29:08] [ SPAM]      web: LWS _lws_rx_flow_control: no pending change
[2020-12-21 16:29:08] [ WARN]   player: Output delay detected: player is 25 ticks behind, catching up
[2020-12-21 16:29:08] [DEBUG]     raop: Decrypted incoming response
 0000  52 54 53 50 2f 31 2e 30 20 32 30 30 20 4f 4b 0d  RTSP/1.0 200 OK.
 0010  0a 53 65 72 76 65 72 3a 20 41 69 72 54 75 6e 65  .Server: AirTune
 0020  73 2f 33 37 37 2e 32 38 2e 30 31 0d 0a 43 53 65  s/377.28.01..CSe
 0030  71 3a 20 31 30 0d 0a 0d 0a                       q: 10....
[2020-12-21 16:29:08] [DEBUG]      web: JSON api request: '/api/player'
[2020-12-21 16:29:08] [DEBUG]   player: Player status: playing
[2020-12-21 16:29:08] [DEBUG]      web: JSON api request: '/api/player'
[2020-12-21 16:29:08] [DEBUG]   player: Player status: playing
[2020-12-21 16:29:09] [  LOG]     raop: Could not send playback sync to device 'Roku Library': Invalid argument
[2020-12-21 16:29:10] [  LOG]     raop: Could not send playback sync to device 'Roku Library': Invalid argument
[2020-12-21 16:29:11] [  LOG]     raop: Could not send playback sync to device 'Roku Library': Invalid argument

Tried different values for this piece of code in airplay.c also:

// AirTunes v2 number of samples per packet
// Probably using this value because 44100/352 and 48000/352 has good 32 byte
// alignment, which improves performance of some encoders
#define RAOP_SAMPLES_PER_PACKET              352

#define RAOP_RTP_PAYLOADTYPE                 0x60

Only 0x60 gives the 400 bad request error we had before, but anything else then causes it to complain about latency headers missing, tried 0x96 and 0x103. Also tried to comment out all the other setup in the bplist, but all things point at the RTP line, not sure where you pulled this piece from - maybe worth looking back at the airsend code again? Open to other things to try.

ejurgensen commented 3 years ago

Try changing RAOP_RTP_PAYLOADTYPE to 0x67 (= 103, which means buffered mode instead of realtime). I think it will still fail, but would be interesting to see how. If your devices only support buffered mode then we have new problem. I think a Wireshark dump of the traffic from e.g. Apple Music to one of your devices would still be interesting, that would reveal the RTP payload type.

ghost commented 3 years ago

Yeah 0x67 also didn't get it still gave a 400 Bad request - so SORRY for not using the right value, 0x103... hehe idiot cuff! Let me keep poking, we are on to something here, at least that line can perturb the box in the right way, 0x0 actually gets accepted but then fails later as we know - and both Samsung and Roku seem to behave similar, I'll get the Wireshark out now and see what is going on... thanks for the great advice, this is good stuff!

Doh - of course everything after pair-verify in the Wireshark is encrypted, because "iTunes".... meh. urrm, need to think of something else.

ejurgensen commented 3 years ago

The interesting part is the audio packets that Apple Music/iTunes sends to the speaker. Even though the payload is encrypted, the RTP type isn't. It's the second byte in each packet. You should also be able to check that the audio is sent with UDP (I have read that buffered mode uses TCP).

ghost commented 3 years ago

Ah! Ok gotcha. You are a great mentor, I’ll have a look see at that tomorrow. Sorry my network capture is too noisy to send. More soon. We are on the home stretch now!

On Mon, Dec 21, 2020 at 6:11 PM ejurgensen notifications@github.com wrote:

The interesting part is the audio packets that Apple Music/iTunes sends to the speaker. Even though the payload is encrypted, the RTP type isn't. It's the second byte in each packet. You should also be able to check that the audio is sent with UDP (I have read that buffered mode uses TCP).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ejurgensen/forked-daapd/issues/1010#issuecomment-749247259, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALKKBMHVVZROMK5WS2KDQTSV7IZVANCNFSM4ND67M4Q .

-- (Via iPhone)