Airplay 2 Receiver written in go

Go Play 2

This is a work in progress Airplay 2 Speaker implementation largely inspired by airplay2-receiver

Status

Can

  • be registered with the Home App and be directed by Siri !
  • Play AAC 44100 with buffered audio
  • Play/Pause/Stop/Seek
  • PTP supported and sync with homepod mini

Next Step

  • Play ALAC
  • Need to be hardened
  • Supports Audio UDP (spotify)

Multi Room accuracy

PTP (Precision Time protocol) is implemented, but it does not (yet) use NIC hardware timestamps. Therefore, the accuracy is around 1ms of offset between clocks.

How to build

  • Clone the repository

  • Get Dependencies (-d means no direct build)

go get -d 
  • Build dependency (go-fdkacc), and the program
make 

Dependencies

You need to have binutils, portaudio-dev, gcc and go runtime installed to build this program

Raspberry Pi

TODO

Docker image

You can build the image to test Linux build and that the service run properly

  • Build the image
docker build -t albanseurat/goplay2:latest .
  • Run the container
docker run -p 7000:7000 -it albanseurat/goplay2:latest

Acknowledgments

  • Docker build is intended to test building the program on Linux platform
  • Bonjour/mDns implementation needs to be changed to allow exposing airplay service outside docker container

Run

goplay2 by default run only on the ipv4 interface (because this issue on ipv6 parsing)

Parameters

delay (ms) is subtracted from the local "clock"
Ex: It takes around 60ms on my mac to launch the audio stream at the Anchor Time

i (interface) used to listen (by default eth0)

n (name) used as accessory name (Bonjour)

alsa (alsa port name) to replace default pcm port (default : pcm.default)

./goplay2 -alsa pcm.default -i en0 -n aiwa

By AlbanSeurat

Comments
  • ALSA output

    ALSA output

    I see this thing is hard coded for pcm.default for the ALSA output. It would be great to have a command line option for the ALSA output. A cmd line option for the listen port would also be great. I have a few 7.1 ch sound cards in my server and have an elaborate ALSA config that busts them up into several outputs and then I run several instances of shairport-sync and each one is on it's own port and set to output to different ALSA outputs. I would love to be able to do this with AirPlay 2.

  • Dockerfile broken

    Dockerfile broken

    Hey Alban

    Thanks a lot for this project!!!

    Seems like the provided Dockerfile currently does not build (no makefile).

    Happy to send a PR for a working one though.

  • Thanks for making this a reality! Requests: Multiple instances, Audio output routing, Volume Control

    Thanks for making this a reality! Requests: Multiple instances, Audio output routing, Volume Control

    Extremely excited about this initiative. Thanks so much for all the work you're putting into this. Tested it out on OSX and got it working no problem.

    My use case is that I'd love to be able to run several airplay receivers at the same time with different names and then route audio to from each to different virtual devices. I could do the routing in a separate program like Loopback but would need to be able to direct the output of goplay to a specific output device (ex. "audio capture 1").

    Let me know if this is possible. I think the features needed would be:

    1. Running goplay on different ports so you can run multiple instances (command line param?)
    2. Pointing audio output at a specific output device
    3. Unrelated but I noticed that changing the volume doesn't do anything. Is this something that could be supported so you can still control volume from the sending device?

    Random question out of curiosity, why do all apps work except Spotify?

    Thanks again and happy to help test.

  • Multi-architecture, runnable Docker image

    Multi-architecture, runnable Docker image

    Fix #18

    Title says all.

    This is a dockerfile allowing one to cross-compile goplay2 and produce a usable, runnable multi-architecture image.

    The invocation command is a bit of a mouthful though that could be made simpler.

    The main "limitation" right now is that it expects pulseaudio to be running on the host or in another docker image (I really did not feel like cramming in pulseaudio here).

    I'm running this in docker on a RPI 3.

  • Build fails on Mac OS

    Build fails on Mac OS

    arya@Aryas-Mac-mini goplay2 % neofetch
                        'c.          [email protected]
                     ,xNMM.          -------------------------
                   .OMMMMo           OS: macOS 11.6 20G165 arm64
                   OMMM0,            Host: Macmini9,1
         .;loddo:' loolloddol;.      Kernel: 20.6.0
       cKMMMMMMMMMMNWMMMMMMMMMM0:    Uptime: 1 hour, 18 mins
     .KMMMMMMMMMMMMMMMMMMMMMMMWd.    Packages: 126 (brew)
     XMMMMMMMMMMMMMMMMMMMMMMMX.      Shell: zsh 5.8
    ;MMMMMMMMMMMMMMMMMMMMMMMM:       Resolution: 1920x1080
    :MMMMMMMMMMMMMMMMMMMMMMMM:       DE: Aqua
    .MMMMMMMMMMMMMMMMMMMMMMMMX.      WM: Quartz Compositor
     kMMMMMMMMMMMMMMMMMMMMMMMMWd.    WM Theme: Blue (Dark)
     .XMMMMMMMMMMMMMMMMMMMMMMMMMMk   Terminal: iTerm2
      .XMMMMMMMMMMMMMMMMMMMMMMMMK.   Terminal Font: Monaco 12
        kMMMMMMMMMMMMMMMMMMMMMMd     CPU: Apple M1
         ;KMMMMMMMWXXWMMMMMMMk.      GPU: Apple M1
           .cooc,.    .,coo:.        Memory: 1381MiB / 8192MiB
    
    
    
    
    arya@Aryas-Mac-mini goplay2 % brew install portaudio fdk-aac go
    Updating Homebrew...
    Warning: portaudio 19.7.0 is already installed and up-to-date.
    To reinstall 19.7.0, run:
      brew reinstall portaudio
    Warning: fdk-aac 2.0.2 is already installed and up-to-date.
    To reinstall 2.0.2, run:
      brew reinstall fdk-aac
    Warning: go 1.17.2 is already installed and up-to-date.
    To reinstall 1.17.2, run:
      brew reinstall go
    
    arya@Aryas-Mac-mini goplay2 % go build
    # goplay2/codec
    codec/aac.go:32:10: fatal error: 'aacdecoder_lib.h' file not found
    #include "aacdecoder_lib.h"
             ^~~~~~~~~~~~~~~~~~
    1 error generated.
    
  • SIGSEGV when switching songs fast

    SIGSEGV when switching songs fast

    When switching song fast I get a segfault. After looking at Filter on audio/ring.go I didn't see anything wrong (I'm not that experienced in Go, tbh).

    I'm running features/audio-sync commit d110dd6

    If you need any other info I'll gladly provide everything needed.

    Have a nice day!

    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4216b9d]
    
    goroutine 10 [running]:
    container/list.(*Element).Next(...)
    	/usr/local/Cellar/go/1.16.6/libexec/src/container/list/list.go:32
    goplay2/audio.(*Ring).Filter(0xc000216000, 0xc000285ea0)
    	/Users/eliseomartelli/Projects/goplay2/audio/ring.go:155 +0x13d
    goplay2/audio.(*Player).skipUntil(0xc000012a50, 0x0, 0xb6cb71)
    	/Users/eliseomartelli/Projects/goplay2/audio/player.go:123 +0x105
    goplay2/audio.(*Player).Run(0xc000012a50)
    	/Users/eliseomartelli/Projects/goplay2/audio/player.go:110 +0x485
    main.main.func1(0xc000012a50, 0xc00001cfa0)
    	/Users/eliseomartelli/Projects/goplay2/main.go:71 +0x2b
    created by main.main
    	/Users/eliseomartelli/Projects/goplay2/main.go:70 +0x97d
    
  • Issues with CFLAGS and LDFLAGS

    Issues with CFLAGS and LDFLAGS

    Hey @AlbanSeurat

    This https://github.com/openairplay/goplay2/blob/main/codec/aac.go#L27-L30 is problematic.

    • on linux, the use of a static version of libfdk is forced
    • on mac & linux, the path information (-I, -L) may or may not work / make sense, override proper system values to something undesirable

    Both points are problematic for cross-compilation and for systems that do not ship a static version of libfdk - typically Debian Buster in the Dockerfile already requires live-patching the source (https://github.com/openairplay/goplay2/pull/19/files#diff-dd2c0eb6ea5cfc6c4bd4eac30934e2d5746747af48fef6da689e85b752f39557R9)

    Suggestion would be to leave the responsibility of picking these to the build system / command (eg: "-extldflags -static(-pie)") for people who would really want to be specific about these.

    For most normal people, things will just continue building by default, and this should make life easier for advanced users (looking for cross-compilation, or more control over static vs. dynamic).

    Let me know your thoughts and if you agree I can send a small PR to change that.

  • Conf dir

    Conf dir

    Fix #20

    New flag -c allows one to point to a base directory where configuration will live.

    If unspecified, pwd will be used, which should match the previous behavior.

    This is just a quick suggestion at this point, but I thought I would send it over early for feedback / modifications.

  • build failure on Raspberry Pi B+

    build failure on Raspberry Pi B+

    Architecture: armv7l

    pi@raspBplus-api:~/Development/goplay2 $ cat /etc/issue Raspbian GNU/Linux 10 \n \l

    pi@raspBplus-api:~/Development/goplay2 $ go version go version go1.16.6 linux/arm

    pi@raspBplus-api:~/Development/goplay2 $ ./goplay2 -i eth0 -n pitunes

    2021/08/04 23:38:56 pitunes/config.json is not valid - at new file will be created at program exit
    2021/08/04 23:38:56 Starting goplay for device Pi: 24e650f4-3d3f-4832-ad39-6a1c3bff81a6, guid: 24e650f4-3d3f-4832-ad39-6a1c3bff81a6, Psi: 24e650f4-3d3f-4832-ad39-6a1c3bff81a6
    2021/08/04 23:38:56 dial unix /run/user/1000/pulse/native: connect: no such file or directory
    2021/08/04 23:38:56 Warning : impossible to store config file pitunes/config.json
    panic: dial unix /run/user/1000/pulse/native: connect: no such file or directory
    
    goroutine 1 [running]:
    log.Panic(0x293deb0, 0x1, 0x1)
    	/usr/local/go/src/log/log.go:354 +0x84
    goplay2/codec.NewStream(0x2f8f00, 0x64)
    	/home/pi/Development/goplay2/codec/pulseaudio.go:45 +0x80
    goplay2/audio.NewPlayer(0x289a828, 0x28980c0, 0x147ae)
    	/home/pi/Development/goplay2/audio/player.go:32 +0x40
    main.main()
    	/home/pi/Development/goplay2/main.go:71 +0x950
    

    What am I missing?

  • Stopped working with iOS version 15.1

    Stopped working with iOS version 15.1

    arya@Aryas-Mac-mini goplay2 % ./goplay2 -n Airplay2 -i en0
    2021/10/27 13:10:07 Airplay2/config.json is not valid - at new file will be created at program exit
    2021/10/27 13:10:07 Starting goplay for device Pi: bf832c73-77c2-47b5-9212-544192fb2a17, guid: bf832c73-77c2-47b5-9212-544192fb2a17, Psi: bf832c73-77c2-47b5-9212-544192fb2a17
    2021/10/27 13:11:29 request received : GET /info body 70
    2021/10/27 13:11:29 response sent : body 374
    2021/10/27 13:11:29 request received : POST /pair-verify body 37
    2021/10/27 13:11:29 response sent : body 140
    2021/10/27 13:11:29 request received : POST /pair-setup body 6
    2021/10/27 13:11:29 response sent : body 409
    2021/10/27 13:11:29 request received : POST /pair-setup body 457
    2021/10/27 13:11:29 response sent : body 69
    2021/10/27 13:11:29 request received : POST /pair-setup body 159
    2021/10/27 13:11:29 response sent : body 143
    2021/10/27 13:11:29 request received : POST /pair-verify body 37
    2021/10/27 13:11:29 server.go:82: Error:Error handling RSTP request Invalid internal pairing verify step Waiting
    
  • Don't run.

    Don't run.

    Hello, this is my issue pi@raspberrypi:/home/raye/goplay2 $ ./goplay2 -sink default:b1

    2021/08/22 19:15:04 goplay/config.json is not valid - at new file will be created at program exit 2021/08/22 19:15:04 Starting goplay for device Pi: ca7e2ab8-ff55-49a2-b6ae-84385eb0323e, guid: ca7e2ab8-ff55-49a2-b6ae-84385eb0323e, Psi: ca7e2ab8-ff55-49a2-b6ae-84385eb0323e 2021/08/22 19:15:04 dial unix /run/user/1000/pulse/native: connect: connection refused 2021/08/22 19:15:04 Warning : impossible to store config file goplay/config.json panic: dial unix /run/user/1000/pulse/native: connect: connection refused

    goroutine 1 [running]: log.Panic(0xd3feb0, 0x1, 0x1) /usr/local/go/src/log/log.go:354 +0x84 goplay2/codec.NewStream(0x2875b8, 0x64) /home/raye/goplay2/codec/pulseaudio.go:45 +0x80 goplay2/audio.NewPlayer(0xc9e438, 0xc94150, 0x147ae) /home/raye/goplay2/audio/player.go:32 +0x40 main.main() /home/raye/goplay2/main.go:71 +0x950

    What it's wrong ? Thanks

  • fix: remove difference between linux and macOS paths

    fix: remove difference between linux and macOS paths

    Since brew symlinks fdk-aac under /usr/local/include/ it isn't necessary to split the include for Linux and macOS systems as long as the user has properly configured brew on their system.

    For macOS you need to be sure that you have /usr/local/include in your path.

    ➜  ~ tree /usr/local/include/fdk-aac
    /usr/local/include/fdk-aac
    ├── FDK_audio.h
    ├── aacdecoder_lib.h
    ├── aacenc_lib.h
    ├── genericStds.h
    ├── machine_type.h
    └── syslib_channelMapDescr.h
    
    0 directories, 6 files
    

    Inside bashrc/zshrc:

    export PATH="/usr/local/include:$PATH"
    
  • Unable to Pair on iOS 15 beta 6

    Unable to Pair on iOS 15 beta 6

    It seems like something has changed in the pairing mechanism for the latest iOS beta. On attempted casting the following is logged with an error Unable to connect:

    2021/08/24 18:50:45 request received : GET /info body 70
    2021/08/24 18:50:45 response sent : body 374
    2021/08/24 18:50:45 request received : POST /pair-verify body 37
    2021/08/24 18:50:45 response sent : body 140
    2021/08/24 18:50:45 request received : POST /pair-setup body 6
    2021/08/24 18:50:45 response sent : body 409
    2021/08/24 18:50:45 request received : POST /pair-setup body 457
    2021/08/24 18:50:45 response sent : body 69
    2021/08/24 18:50:45 request received : POST /pair-setup body 159
    2021/08/24 18:50:45 response sent : body 143
    2021/08/24 18:50:45 request received : POST /pair-verify body 37
    2021/08/24 18:50:45 server.go:82: Error:Error handling RSTP request Invalid internal pairing verify step Waiting
    

    When paired through the home app there are no errors. However the following is in the log:

    2021/08/24 18:57:20 request received : POST /configure body 148
    2021/08/24 18:57:20 response sent : body 237
    2021/08/24 18:57:20 request received : TEARDOWN rtsp://192.168.1.73/7350123517057450268 body 42
    2021/08/24 18:57:20 response sent : body 0
    2021/08/24 18:57:20 server.go:37: Error:Event error : EOF
    2021/08/24 18:57:20 server.go:76: Error:Error parsing RSTP request EOF 
    

    And the same error when trying to cast.

    Casting works on iOS 14.7.1 and macOS devices.

  • Error after several minutes

    Error after several minutes

    Hello, after 45min - 1 hours I have a lot of error Capture d’écran 2021-08-23 à 00 23 59 I have take testing on divers Apple Device. I think this issue can come when divers Apple devices is connected in same time AirPlay.

    Sorry for bad english :)

  • "Error parsing RSTP request close tcp4" when playing to two GoPlay2 devices at once

    I have GoPlay2 setup on two Raspberry Pi's right now (a 3 and a 4). Both are on the same network and I have no trouble playing to each one individually. However, when I try to play to both at once from an iPhone, the following error is thrown and they both disconnect:

    2021/08/20 14:52:29 server.go:37: Error:Event error : EOF
    2021/08/20 14:52:29 server.go:76: Error:Error parsing RSTP request close tcp4 192.168.1.67:7000->192.168.1.64:52259: use of closed network connection
    2021/08/20 14:52:29 server.go:76: Error:Error parsing RSTP request close tcp4 192.168.1.67:7000->192.168.1.64:52259: use of closed network connection
    2021/08/20 14:52:29 server.go:37: Error:Event error : EOF
    

    In the above error, .67 is the Pi throwing the error and .64 is the phone playing the music.

    Also of possible significance, when I attempted to add each device to the Home app, I saw the following error in the log (though they were both added to the app just fine):

    2021/08/20 14:51:27 server.go:37: Error:Event error : EOF
    2021/08/20 14:51:27 server.go:76: Error:Error parsing RSTP request EOF
    
  • Feature request: ability to have configuration in a user specified directory

    Feature request: ability to have configuration in a user specified directory

    Right now, the config is always stored under $(pwd)/$name

    Having the flexibility to point to a completely different base directory where to store config would be nice and particularly useful in the context of hardened docker images where typically only a specific volume is rw while the rest of the image is read-only.

    I'll send a PR as a suggestion to allow this.

Fast cross-platform HTTP benchmarking tool written in Go

bombardier bombardier is a HTTP(S) benchmarking tool. It is written in Go programming language and uses excellent fasthttp instead of Go's default htt

Jan 2, 2023
:rocket: Modern cross-platform HTTP load-testing tool written in Go
:rocket: Modern cross-platform HTTP load-testing tool written in Go

English | 中文 Cassowary is a modern HTTP/S, intuitive & cross-platform load testing tool built in Go for developers, testers and sysadmins. Cassowary d

Dec 29, 2022
A task runner / simpler Make alternative written in Go
A task runner / simpler Make alternative written in Go

Task Task is a task runner / build tool that aims to be simpler and easier to use than, for example, GNU Make. See taskfile.dev for the documentation.

Jan 8, 2023
Highly configurable prompt builder for Bash, ZSH and PowerShell written in Go.
Highly configurable prompt builder for Bash, ZSH and PowerShell written in Go.

Go Bullet Train (GBT) Highly configurable prompt builder for Bash, ZSH and PowerShell written in Go. It's inspired by the Oh My ZSH Bullet Train theme

Dec 17, 2022
Beagle is a CLI written in Go to search for an specific username across the Internet.

Beagle __ \,--------/_/'--o Use beagle with /_ ___ /~" responsibility. /_/_/ /_/_/ ^^^^^^^^^^^^^^^^^^ Beagle is a CLI w

Nov 16, 2022
A template repository to quickly scaffold a Kubewarden policy written with Go language

go-policy-template This is a template repository that can be used to to quickly scaffold a Kubewarden policy written with Go language. Don't forget to

Sep 7, 2022
A lightweight Vault client module written in Go, with no dependencies, that is intuitive and user-friendly

libvault A lightweight Hashicorp Vault client written in Go, with no dependencies. It aims to provide an intuitive, simple API that is easy to use. Ju

Sep 18, 2022
Devtron is an open source software delivery workflow for kubernetes written in go.
Devtron is an open source software delivery workflow for kubernetes written in go.

Devtron is an open source software delivery workflow for kubernetes written in go.

Jan 8, 2023
Little Reversing CrackMe written in GO

Go_CrackMe Little Reversing CrackMe written in GO Info: I created little reversing crackme challenge written in GO language for educational purpose. A

Jul 22, 2022
exporter for Aliyun CloudMonitor. Written in Golang.

Aliyun CloudMonitor Exporter exporter for Aliyun CloudMonitor. Written in Golang. inspired by aliyun-exporter Develop cd aliyun-exporter make tidy Bui

Dec 12, 2022
Rest API for todoapp written in Golang, using clean architecture, CI/CD
Rest API for todoapp written in Golang, using clean architecture, CI/CD

todoapp-backend Rest API for todoapp written in Golang, using Clean Architecture and CI/CD (includes unit tests and integration tests). Using: Web fra

Oct 23, 2022
Medieival Dynasty save backuper written in Go.
Medieival Dynasty save backuper written in Go.

Medieival-Dynasty-save-backup Medieival Dynasty save backupper written in Go. Windows binaries Setup Configure the config file. Option Info interval B

Apr 12, 2022
A Prometheus exporter, written in Golang, for Magento 2

Magento 2 Prometheus Exporter A Prometheus exporter, written in Golang, for Magento 2. Philosophy It might be abnormal to start with the "philosophy"

May 3, 2022
A cross platform CLI for Flyte. Written in Golang. Offers an intuitive interface to Flyte https://flytectl.readthedocs.io/en/latest/
A cross platform CLI for Flyte. Written in Golang. Offers an intuitive interface to Flyte https://flytectl.readthedocs.io/en/latest/

FlyteCTL Flyte's official command-line interface Documentation · Contribution Guide FlyteCTL was designed as a portable and lightweight command-line i

Nov 7, 2022
A package manager written in Go which uses the LFS Symlink method.

pacsym A package manager powered by symlinks. How to use The package manager assumes that all software installed is installed with /usr/pkg/<packagena

Dec 11, 2021
library for working with github api, written in Golang

gitdata library for working with github api, written in Golang Example: get user data package main import ( "fmt" "log" "github.com/a1excoder/git

May 19, 2022
A sed interpreter written in Golang

A sed interpreter written in Golang. Most behaviors of this program is implemented follow GNU-sed, except all those operations related to external fil

Dec 15, 2021
Fast, Docker-ready image processing server written in Go and libvips, with Thumbor URL syntax

Imagor Imagor is a fast, Docker-ready image processing server written in Go. Imagor uses one of the most efficient image processing library libvips (w

Dec 30, 2022
Minified version of Project Sherlock written in GO

Minified version of Project Sherlock written in GO

Dec 19, 2022