diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build-on-push.yaml similarity index 96% rename from .github/workflows/docker-build.yaml rename to .github/workflows/docker-build-on-push.yaml index cb186043..072e9218 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build-on-push.yaml @@ -1,6 +1,5 @@ # Builds & pushes a docker image when a commit is made to one of the branches specified below. # Tag pattern: 'unstable-[BRANCH NAME]' & 'unstable-[BRANCH NAME]-airplay1' -# See docker-build-releases.yaml for release build process. name: Build and push docker image based on commit to specified branches. @@ -9,7 +8,7 @@ on: branches: [ development ] env: - DOCKER_PLATFORMS: linux/386,linux/amd64,linux/arm/v6,linux/arm64,linux/arm/v7 + DOCKER_PLATFORMS: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 jobs: main: diff --git a/.github/workflows/docker-build-releases.yaml b/.github/workflows/docker-build-on-tag.yaml similarity index 65% rename from .github/workflows/docker-build-releases.yaml rename to .github/workflows/docker-build-on-tag.yaml index 6894a0e7..d345bd89 100644 --- a/.github/workflows/docker-build-releases.yaml +++ b/.github/workflows/docker-build-on-tag.yaml @@ -1,15 +1,16 @@ -# Builds & pushes a docker image when a release occurs. +# Builds & pushes a docker image when a tag occurs. +# It seems this yaml has to exist on the branch the tag refers to. -# The following tags are created: -# 'latest' & 'latest-airplay1' -# '[RELEASE TAG]' & '[RELEASE TAG]-airplay1' +# The following docker tags are created & pushed: +# [RELEASE TAG], [RELEASE TAG]-airplay1, name: Build and push docker images on releases. on: - release: - types: [ ] - + push: + tags: + - '*' # Push events to every tag (not containing '/') + env: DOCKER_PLATFORMS: linux/386,linux/amd64,linux/arm/v6,linux/arm64,linux/arm/v7 @@ -21,9 +22,15 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 - + - name: Set SHAIRPORT_SYNC_BRANCH env. - run: echo "SHAIRPORT_SYNC_BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV + run: | + raw=$(git branch -r --contains ${{ github.ref }}) + branch=${raw##*/} + echo "SHAIRPORT_SYNC_BRANCH=${branch}" >> $GITHUB_ENV + + - name: Set tag env + run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Determine NQPTP env (part 1). if: ${{ env.SHAIRPORT_SYNC_BRANCH == 'development' }} @@ -51,9 +58,9 @@ jobs: with: context: ./ file: ./docker/Dockerfile - platforms: ${{ env.PLATFORMS }} + platforms: ${{ env.DOCKER_PLATFORMS }} push: true - tags: ${{ secrets.DOCKER_IMAGE_NAME }}:latest ${{ secrets.DOCKER_IMAGE_NAME }}:${{ github.event.release.tag_name }} + tags: ${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.GIT_TAG }} build-args: | SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }} NQPTP_BRANCH=${{ env.NQPTP_BRANCH }} @@ -62,9 +69,9 @@ jobs: uses: docker/build-push-action@v2 with: context: ./ - file: ./docker/airplay1/Dockerfile-AirPlay1 - platforms: ${{ env.PLATFORMS }} + file: ./docker/airplay1/Dockerfile + platforms: ${{ env.DOCKER_PLATFORMS }} push: true - tags: ${{ secrets.DOCKER_IMAGE_NAME }}:latest-airplay1, ${{ secrets.DOCKER_IMAGE_NAME }}:${{ github.event.release.tag_name }}-airplay1 + tags: ${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.GIT_TAG }}-airplay1 build-args: | SHAIRPORT_SYNC_BRANCH=${{ env.SHAIRPORT_SYNC_BRANCH }} \ No newline at end of file diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml deleted file mode 100644 index be61da3d..00000000 --- a/.github/workflows/stale.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: 'Close stale issues and PRs' -on: - schedule: - - cron: '0 0 * * *' - -permissions: - issues: write - pull-requests: write - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v4 - with: - stale-issue-message: 'This issue has been inactive for 60 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.' - stale-pr-message: 'This PR has been inactive for 60 days so will be closed 7 days from now. To prevent this, please remove the "stale" label or post a comment.' - # These are the defaults at the time of writing. https://github.com/marketplace/actions/close-stale-issues - # days-before-stale: 60 - # days-before-close: 7 diff --git a/README.md b/README.md index 6025505c..39c57da0 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,4 @@ For the development of AirPlay 2 support, special thanks are due to: * [invano](https://github.com/invano) for showing what might be possible and for initial Python development. * [Charles Omer](https://github.com/charlesomer) for Docker automation, repository management automation, testing, encouragement, enthusiasm. -And of course, thanks to everyone who has supported and improved Shairport Sync over the years. +And of course, thanks to everyone who has supported and improved Shairport Sync over the years. \ No newline at end of file diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index c91f6307..001f7c43 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -1,3 +1,8 @@ +Version-4.1-dev-?? +==== +#### Enhancement +* Update the Docker workflow to automatically do Docker tagging and to use an s6-overlay implementation. Many thanks to [Robert Casties](https://github.com/robcast) for his s6-overlay Pull Request [#1349](https://github.com/mikebrady/shairport-sync/pull/1349) which formed the basis of this work. + Version-4.1-dev-115-g8656149d ==== * Simplify and improve timing when a play session from a new device is started. diff --git a/docker/Dockerfile b/docker/Dockerfile index 98a3900c..d8241654 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,8 +1,12 @@ -FROM alpine:3.12 AS builder-base -# Version 3.12 is required for now since libplist has breaking changes in v3.13 and above which are not yet standard -# in debian/ubuntu. +FROM alpine:3.12 AS builder + +# Check required arguments exist. These will be provided by the Github Action +# Workflow and are required to ensure the correct branches are being used. +ARG SHAIRPORT_SYNC_BRANCH +RUN test -n "$SHAIRPORT_SYNC_BRANCH" +ARG NQPTP_BRANCH +RUN test -n "$NQPTP_BRANCH" -# General Build System: RUN apk -U add \ git \ build-base \ @@ -10,9 +14,7 @@ RUN apk -U add \ automake \ libtool \ dbus \ - su-exec \ alsa-lib-dev \ - libdaemon-dev \ popt-dev \ mbedtls-dev \ soxr-dev \ @@ -30,68 +32,42 @@ RUN apk -U add \ libplist-dev \ libgcrypt-dev -# ALAC Build System: -FROM builder-base AS builder-alac - +##### ALAC ##### RUN git clone https://github.com/mikebrady/alac WORKDIR /alac RUN autoreconf -fi RUN ./configure RUN make RUN make install +WORKDIR / +##### ALAC END ##### -# Shairport Sync Build System: -FROM builder-base AS builder-sps - -# These will be modified by the Github Action Workflow and are required -# to ensure the correct branches are being used. -ARG SHAIRPORT_SYNC_BRANCH -RUN test -n "$SHAIRPORT_SYNC_BRANCH" -ARG NQPTP_BRANCH -RUN test -n "$NQPTP_BRANCH" - -COPY --from=builder-alac /usr/local/lib/libalac.* /usr/local/lib/ -COPY --from=builder-alac /usr/local/lib/pkgconfig/alac.pc /usr/local/lib/pkgconfig/alac.pc -COPY --from=builder-alac /usr/local/include /usr/local/include - +##### NQPTP ##### RUN git clone https://github.com/mikebrady/nqptp WORKDIR /nqptp -# Use development branch for now. RUN git checkout "$NQPTP_BRANCH" RUN autoreconf -fi RUN ./configure RUN make RUN make install WORKDIR / +##### NQPTP END ##### +##### SPS ##### WORKDIR /shairport-sync COPY . . RUN git checkout "$SHAIRPORT_SYNC_BRANCH" RUN autoreconf -fi -# RUN ./configure \ -# --with-alsa \ -# --with-dummy \ -# --with-pipe \ -# --with-stdout \ -# --with-avahi \ -# --with-ssl=mbedtls \ -# --with-soxr \ -# --sysconfdir=/etc \ -# --with-dbus-interface \ -# --with-mpris-interface \ -# --with-mqtt-client \ -# --with-apple-alac \ -# --with-convolution \ -# --with-airplay-2 -# RUN make -j $(nproc) -RUN CFLAGS="-O0 -g" CXXFLAGS="-O0 -g" ./configure --sysconfdir=/etc --with-metadata --with-dummy --with-pipe \ - --with-alsa --with-soxr --with-avahi --with-ssl=openssl --with-dbus-interface --with-stdout \ - --with-mpris-interface --with-mqtt-client --with-apple-alac --with-convolution --with-airplay-2 +RUN ./configure --sysconfdir=/etc --with-alsa --with-soxr --with-avahi --with-ssl=openssl --with-airplay-2 \ + --with-metadata --with-dummy --with-pipe --with-dbus-interface \ + --with-stdout --with-mpris-interface --with-mqtt-client \ + --with-apple-alac --with-convolution RUN make -j RUN make install +##### SPS END ##### -# Shairport Sync Runtime System: -FROM alpine:3.12 +# Shairport Sync Runtime System +FROM crazymax/alpine-s6:3.12 RUN apk -U add \ alsa-lib \ @@ -104,21 +80,20 @@ RUN apk -U add \ libconfig \ libsndfile \ mosquitto \ - su-exec \ libuuid \ ffmpeg \ libsodium \ libplist \ libgcrypt -RUN rm -rf /lib/apk/db/* +# Copy build files. +COPY --from=builder /usr/local/bin/shairport-sync /usr/local/bin/shairport-sync +COPY --from=builder /usr/local/bin/nqptp /usr/local/bin/nqptp +COPY --from=builder /usr/local/lib/libalac.* /usr/local/lib/ +COPY --from=builder /etc/dbus-1/system.d/shairport-sync-dbus.conf /etc/dbus-1/system.d/ +COPY --from=builder /etc/dbus-1/system.d/shairport-sync-mpris.conf /etc/dbus-1/system.d/ -COPY --from=builder-alac /usr/local/lib/libalac.* /usr/local/lib/ -COPY --from=builder-sps /etc/shairport-sync* /etc/ -COPY --from=builder-sps /etc/dbus-1/system.d/shairport-sync-dbus.conf /etc/dbus-1/system.d/ -COPY --from=builder-sps /etc/dbus-1/system.d/shairport-sync-mpris.conf /etc/dbus-1/system.d/ -COPY --from=builder-sps /usr/local/bin/shairport-sync /usr/local/bin/shairport-sync -COPY --from=builder-sps /usr/local/bin/nqptp /usr/local/bin/nqptp +COPY ./docker/etc /etc # Create non-root user for running the container -- running as the user 'shairport-sync' also allows # Shairport Sync to provide the D-Bus and MPRIS interfaces within the container @@ -129,8 +104,7 @@ RUN adduser -D shairport-sync -G shairport-sync # Add the shairport-sync user to the pre-existing audio group, which has ID 29, for access to the ALSA stuff RUN addgroup -g 29 docker_audio && addgroup shairport-sync docker_audio && addgroup shairport-sync audio -COPY ./docker/start.sh / +# Remove anything we don't need. +RUN rm -rf /lib/apk/db/* -RUN chmod +x ./start.sh - -ENTRYPOINT [ "/start.sh" ] \ No newline at end of file +ENTRYPOINT [ "/init" ] \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index 1ee9b4ba..8ba67faa 100644 --- a/docker/README.md +++ b/docker/README.md @@ -12,15 +12,14 @@ When using the below commands, you should replace mikebrady/shairport-sync with ## Example Docker Compose File See the `docker-compose.yaml` file in this folder for an example. -## Basic Usage +## Docker Run ``` $ docker run -d --restart unless-stopped --net host --device /dev/snd \ mikebrady/shairport-sync ``` -The above command will run Shairport Sync as a daemon in a Docker container, accessing the computer's ALSA audio infrastructure. It will send audio to the default output device and make no use of any hardware mixers the default device might have. The AirPlay service name will be the host's `hostname` with the first letter capitalised, e.g. `Ubuntu`. -## Options +### Options Any options you add to the command above will be passed to Shairport Sync. Here is an example: ``` @@ -31,24 +30,25 @@ This will sent audio to alsa hardware device `hw:0` and make use of the that dev ## Configuration File -Edit the configuration file `/etc/shairport-sync.conf` in the container (or use the `-v` option to mirror an external copy of `shairport-sync.conf` in to `/etc/shairport-sync.conf`) to get access to the full range of configuration options. +To get access to the full range of configuration options, pass the configuration file to `/etc/shairport-sync.conf` in the container using the `-v` option or docker compose. -## Build Example (for arm7 devices) +## Building +### Build Example (for arm7 devices) ``` docker buildx build --platform linux/arm/v7 -f ./docker/Dockerfile --build-arg SHAIRPORT_SYNC_BRANCH=development --build-arg NQPTP_BRANCH=development -t shairport-sync:unstable-development . ``` -`SHAIRPORT_SYNC_BRANCH` is required to ensure the image is built using the expected branch. +`SHAIRPORT_SYNC_BRANCH` and `NQPTP_BRANCH` are required to ensure the image is built using the expected branch. -## AirPlay 1 Only +### AirPlay 1 Only -The AirPlay1 only dockerfile is in the `airplay1` folder. This also includes the `start.sh` script used by the container. Please note that the AirPlay 1 image build via the AirPlay 2 branch does not work with multiple instances on the same hardware. +The AirPlay1 only dockerfile is in the `airplay1` folder. This also includes the `start.sh` script used by the container. Please note that the AirPlay 1 image built via the AirPlay 2 branch has missing functionality, e.g. it does not work with multiple instances on the same hardware; does not support iTunes for Windows etc. -## GitHub Action Builds +### GitHub Action Builds Requires the following secrets to be set in the repo: - `DOCKER_REGISTRY` - docker.io if using Docker Hub, else set to your registry URL. - `DOCKER_REGISTRY_TOKEN` - Access token for your registry. - `DOCKER_REGISTRY_USER` - Login user for your registry. -- `DOCKER_IMAGE_NAME` - The name of the image, for example `your-registry.com/shairport-sync` or just `your-username/shairport-sync` if using Docker Hub. \ No newline at end of file +- `DOCKER_IMAGE_NAME` - The name of the image, for example `your-registry.com/shairport-sync` or just `your-username/shairport-sync` if using Docker Hub. diff --git a/docker/airplay1/Dockerfile b/docker/airplay1/Dockerfile index e60fd0b5..6276f08d 100644 --- a/docker/airplay1/Dockerfile +++ b/docker/airplay1/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.12 AS builder-base +FROM alpine AS builder-base # General Build System: RUN apk -U add \ git \ @@ -63,7 +63,7 @@ RUN make -j $(nproc) RUN make install # Shairport Sync Runtime System: -FROM alpine:3.12 +FROM alpine RUN apk -U add \ alsa-lib \ diff --git a/docker/airplay1/start.sh b/docker/airplay1/start.sh index f68a122f..5e24ff59 100644 --- a/docker/airplay1/start.sh +++ b/docker/airplay1/start.sh @@ -10,4 +10,4 @@ dbus-daemon --system avahi-daemon --daemonize --no-chroot -su-exec shairport-sync shairport-sync $@ \ No newline at end of file +su-exec shairport-sync shairport-sync "$@" \ No newline at end of file diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 74ed09ac..13b5bac7 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -8,4 +8,8 @@ services: devices: - "/dev/snd" # volumes: - # - ./volumes/shairport-sync/shairport-sync.conf:/etc/shairport-sync.conf # Customised Shairport Sync configuration file. \ No newline at end of file + # - ./volumes/shairport-sync/shairport-sync.conf:/etc/shairport-sync.conf # Customised Shairport Sync configuration file. + logging: + options: + max-size: "200k" + max-file: "10" \ No newline at end of file diff --git a/docker/etc/services.d/01-dbus-daemon/finish b/docker/etc/services.d/01-dbus-daemon/finish new file mode 100644 index 00000000..1809d88d --- /dev/null +++ b/docker/etc/services.d/01-dbus-daemon/finish @@ -0,0 +1,2 @@ +#!/usr/bin/execlineb -P +rm -f /var/run/dbus.pid \ No newline at end of file diff --git a/docker/etc/services.d/01-dbus-daemon/run b/docker/etc/services.d/01-dbus-daemon/run new file mode 100644 index 00000000..488884bd --- /dev/null +++ b/docker/etc/services.d/01-dbus-daemon/run @@ -0,0 +1,2 @@ +#!/usr/bin/execlineb -P +dbus-daemon --system --nofork \ No newline at end of file diff --git a/docker/etc/services.d/02-avahi/run b/docker/etc/services.d/02-avahi/run new file mode 100644 index 00000000..848dd8dd --- /dev/null +++ b/docker/etc/services.d/02-avahi/run @@ -0,0 +1,2 @@ +#!/usr/bin/execlineb -P +avahi-daemon --no-chroot \ No newline at end of file diff --git a/docker/etc/services.d/03-nqptp/run b/docker/etc/services.d/03-nqptp/run new file mode 100644 index 00000000..7ddde248 --- /dev/null +++ b/docker/etc/services.d/03-nqptp/run @@ -0,0 +1,2 @@ +#!/usr/bin/execlineb -P +/usr/local/bin/nqptp \ No newline at end of file diff --git a/docker/etc/services.d/04-shairport-sync/finish b/docker/etc/services.d/04-shairport-sync/finish new file mode 100644 index 00000000..c9e22a21 --- /dev/null +++ b/docker/etc/services.d/04-shairport-sync/finish @@ -0,0 +1,2 @@ +#!/usr/bin/execlineb -S0 +s6-svscanctl -t /var/run/s6/services \ No newline at end of file diff --git a/docker/etc/services.d/04-shairport-sync/run b/docker/etc/services.d/04-shairport-sync/run new file mode 100644 index 00000000..395ff814 --- /dev/null +++ b/docker/etc/services.d/04-shairport-sync/run @@ -0,0 +1,2 @@ +#!/usr/bin/execlineb -P +/usr/local/bin/shairport-sync -vu --statistics \ No newline at end of file diff --git a/docker/start.sh b/docker/start.sh deleted file mode 100644 index 7221417a..00000000 --- a/docker/start.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -set -e - -rm -rf /var/run/dbus.pid -#mkdir -p /var/run/dbus - -dbus-uuidgen --ensure -dbus-daemon --system - -avahi-daemon --daemonize --no-chroot - -# TODO: This should probably be implemented in a better way. -nqptp & - -# su-exec shairport-sync shairport-sync $@ - -shairport-sync -vu --statistics \ No newline at end of file diff --git a/player.c b/player.c index 2e9819c9..db7ec169 100644 --- a/player.c +++ b/player.c @@ -1063,12 +1063,12 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { int64_t lt = conn->first_packet_time_to_play - local_time_now; - if (lt < 150000000) { + if (lt < 130000000) { debug(1, "Connection %d: Short lead time for first frame %" PRId64 ": %f seconds. Flushing 0.5 seconds", conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001); do_flush(conn->first_packet_timestamp + 5 * 4410, conn); } else { - debug(1, "Connection %d: Lead time for first frame %" PRId64 ": %f seconds.", + debug(2, "Connection %d: Lead time for first frame %" PRId64 ": %f seconds.", conn->connection_number, conn->first_packet_timestamp, lt * 0.000000001); } /* diff --git a/ptp-utilities.c b/ptp-utilities.c index 2b60aaaf..fa1c6407 100644 --- a/ptp-utilities.c +++ b/ptp-utilities.c @@ -148,7 +148,7 @@ int ptp_shm_interface_close() { } void ptp_send_control_message_string(const char *msg) { - debug(1, "Send control message to NQPTP: \"%s\"", msg); + debug(2, "Send control message to NQPTP: \"%s\"", msg); int s; unsigned short port = htons(NQPTP_CONTROL_PORT); struct sockaddr_in server;