Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/make_and_publish_pkgs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ on:
type: choice
options:
- amd64
- arm64


env:
APTLY_API_USER: ${{secrets.APTLY_API_USER}}
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
#
SRCNAME = ASL3
PKGNAME = asl3
RELVER = 3.18
RELVER = 3.18.2
DEBVER = 2
RELPLAT ?= deb$(shell lsb_release -rs 2> /dev/null)

BUILDABLES = \
apt.conf.d \
bin \
broadcastify \
etc \
keys \
polkit \
Expand Down
1 change: 1 addition & 0 deletions broadcastify/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rpt_audio_writer
28 changes: 28 additions & 0 deletions broadcastify/1999.conf.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Broadcastify stream configuration for node 1999
# This file must be named NODE.conf - e.g. 1999.conf

# FIFO path (where rpt_audio_writer is configured in outstreamcmd=)
# This path needs to be readable by the asterisk user.
# Replace "NODE" with the node number.
FIFO=/var/lib/asterisk/NODE.fifo

# Icecast server details
# This configuration info found in your "Feed Technical Details"
# section of your configured Broadcastify Stream
ICECAST_HOST=audio9.radioreference.com
ICECAST_PORT=80
ICECAST_MOUNT=/abcdefg
ICECAST_USER=source
ICECAST_PASSWORD=abcd1234

# Stream metadata - This can be wahtever you want within quotes
STREAM_NAME=""
STREAM_DESCRIPTION=""
STREAM_URL=""

# Don't change these unless you know why you're changing it
STREAM_PUBLIC=1
STREAM_GENRE="Amateur Radio"
INPUT_SAMPLERATE=8000
INPUT_CHANNELS=1
OUTPUT_BITRATE=16k
36 changes: 36 additions & 0 deletions broadcastify/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
bin_prefix ?= /usr/bin
libexec_prefix ?= /usr/libexec/asl3
sysconfdir ?= /etc/asterisk/broadcastify

BUILDABLES = \
rpt_audio_writer

BINS = asl-broadcastify
BINS_EXP = $(patsubst %, $(DESTDIR)$(bin_prefix)/%, $(BINS))

LIBEXECS = rpt_audio_writer
LIBEXECS_EXP = $(patsubst %, $(DESTDIR)$(libexec_prefix)/%, $(LIBEXECS))

CONF = 1999.conf.example
CONF_EXP = $(patsubst %, $(DESTDIR)$(sysconfdir)/%, $(CONF))

build: $(BUILDABLES)

install: build $(BINS_EXP) $(LIBEXECS_EXP) $(CONF_EXP)

clean:
rm $(BUILDABLES)

%: %.c
cc -o $@ $<

$(DESTDIR)$(bin_prefix)/%: %
install -D -m 0755 $< $@

$(DESTDIR)$(libexec_prefix)/%: %
install -D -m 0755 $< $@

$(DESTDIR)$(sysconfdir)/%: %
install -D -m 0644 $< $@
chmod 750 $(DESTDIR)$(sysconfdir)

63 changes: 63 additions & 0 deletions broadcastify/asl-broadcastify
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/bash
#
# Usage: broadcastify <node_id>
# Reads /etc/asterisk/broadcastify/<node_id>.conf and streams audio
# from the configured FIFO to the configured icecast mount.

set -e

NODE_ID="${1:?Usage: $0 <node_id>}"
CONFIG="/etc/asterisk/broadcastify/${NODE_ID}.conf"

if [ ! -r "$CONFIG" ]; then
echo "Cannot read config: $CONFIG" >&2
exit 1
fi

# shellcheck source=/dev/null
. "$CONFIG"

# Validate required values
: "${FIFO:?FIFO not set in $CONFIG}"
: "${ICECAST_HOST:?ICECAST_HOST not set in $CONFIG}"
: "${ICECAST_PORT:?ICECAST_PORT not set in $CONFIG}"
: "${ICECAST_MOUNT:?ICECAST_MOUNT not set in $CONFIG}"
: "${ICECAST_USER:?ICECAST_USER not set in $CONFIG}"
: "${ICECAST_PASSWORD:?ICECAST_PASSWORD not set in $CONFIG}"

# Sensible defaults
INPUT_SAMPLERATE="${INPUT_SAMPLERATE:-8000}"
INPUT_CHANNELS="${INPUT_CHANNELS:-1}"
OUTPUT_BITRATE="${OUTPUT_BITRATE:-16k}"
STREAM_NAME="${STREAM_NAME:-app_rpt stream}"
STREAM_DESCRIPTION="${STREAM_DESCRIPTION:-}"
STREAM_GENRE="${STREAM_GENRE:-Amateur Radio}"
STREAM_URL="${STREAM_URL:-}"
STREAM_PUBLIC="${STREAM_PUBLIC:-1}"

# Ensure FIFO exists as a FIFO
if [ ! -p "$FIFO" ]; then
[ -e "$FIFO" ] && rm -f "$FIFO"
mkfifo -m 660 "$FIFO"
fi

# Background holder so ffmpeg never sees EOF when app_rpt is idle
sleep infinity > "$FIFO" &
HOLDER_PID=$!
trap "kill $HOLDER_PID 2>/dev/null" EXIT INT TERM

# Brief settle so the holder's open() completes
sleep 0.1

exec ffmpeg -nostdin -hide_banner -loglevel warning \
-f s16le -ar "$INPUT_SAMPLERATE" -ac "$INPUT_CHANNELS" -i "$FIFO" \
-c:a libmp3lame -b:a "$OUTPUT_BITRATE" \
-content_type audio/mpeg \
-legacy_icecast 1 \
-ice_name "$STREAM_NAME" \
-ice_description "$STREAM_DESCRIPTION" \
-ice_genre "$STREAM_GENRE" \
-ice_url "$STREAM_URL" \
-ice_public "$STREAM_PUBLIC" \
-f mp3 \
"icecast://${ICECAST_USER}:${ICECAST_PASSWORD}@${ICECAST_HOST}:${ICECAST_PORT}${ICECAST_MOUNT}"
81 changes: 81 additions & 0 deletions broadcastify/rpt_audio_writer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* rpt_audio_writer.c
* Build: gcc -O2 -Wall -o rpt_audio_writer rpt_audio_writer.c
* Usage: rpt_audio_writer <fifo_path>
*/
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define CHUNK 320

int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <fifo_path>\n", argv[0]);
return 1;
}

const char *fifo_path = argv[1];

/* Create the FIFO if it doesn't exist. If it exists as a FIFO, fine.
* If it exists as something else (regular file, socket), bail out. */
if (mkfifo(fifo_path, 0660) < 0) {
if (errno != EEXIST) {
fprintf(stderr, "mkfifo(%s): %s\n", fifo_path, strerror(errno));
return 1;
}
struct stat st;
if (stat(fifo_path, &st) < 0) {
fprintf(stderr, "stat(%s): %s\n", fifo_path, strerror(errno));
return 1;
}
if (!S_ISFIFO(st.st_mode)) {
fprintf(stderr, "%s exists but is not a FIFO\n", fifo_path);
return 1;
}
}

/* Ignore SIGPIPE; we handle EPIPE on write() ourselves */
signal(SIGPIPE, SIG_IGN);

unsigned char buf[CHUNK];
int fifo_fd = -1;

for (;;) {
ssize_t n = read(STDIN_FILENO, buf, CHUNK);
if (n == 0)
break; /* stdin closed */
if (n < 0) {
if (errno == EINTR)
continue;
break;
}

if (fifo_fd < 0) {
fifo_fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
if (fifo_fd < 0)
continue; /* no reader, drop */
}

ssize_t w = write(fifo_fd, buf, n);
if (w < 0) {
if (errno == EAGAIN) {
continue; /* reader slow, drop chunk */
}
if (errno == EPIPE || errno == EBADF) {
close(fifo_fd);
fifo_fd = -1;
continue;
}
break;
}
}

if (fifo_fd >= 0)
close(fifo_fd);
return 0;
}
27 changes: 27 additions & 0 deletions debian/asl-broadcastify@.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[Unit]
Description=Broadcastify stream encoder for node %i
After=asterisk.service network-online.target
Wants=network-online.target
PartOf=asterisk.service

# Don't restart forever if the config is broken
StartLimitIntervalSec=300
StartLimitBurst=5

[Service]
Type=simple
User=asterisk
Group=asterisk
ExecStart=/usr/bin/asl-broadcastify %i
Restart=always
RestartSec=5

# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/asterisk
PrivateTmp=true

[Install]
WantedBy=multi-user.target
12 changes: 12 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
asl3 (3.18.2-2) stable; urgency=medium

* Add ffmpeg to control

-- Helium <jason@mfamily.org> Sun, 17 May 2026 17:21:16 -0400

asl3 (3.18.2-1) stable; urgency=medium

* This is a beta package for broadcastify improvements

-- Helium <jason@mfamily.org> Thu, 14 May 2026 17:46:43 -0400

asl3 (3.18-1) stable; urgency=medium

* asl-node-auth-check: node changed to s in lookup (#183)
Expand Down
4 changes: 2 additions & 2 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ Vcs-Git: https://github.com/AllStarLink/ASL3.git
Rules-Requires-Root: binary-targets

Package: asl3
Architecture: all
Architecture: any
Depends: ${misc:Depends}, asl3-asterisk, asl3-menu, lsb-release,
bind9-dnsutils, uuid, curl, lame, sox, whiptail, python3-serial,
python3-requests
python3-requests, ffmpeg
Breaks: asl3-pi-appliance (<< 1.8.0)
Suggests: allmon3, asl3-update-nodelist
Description: AllStarLink 3
Expand Down
9 changes: 9 additions & 0 deletions debian/postinst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ function do_configure() {
echo "options snd_usb_audio lowlatency=1" > \
/etc/modprobe.d/asl3-snd-usb-audio.conf
fi

if getent passwd asterisk >/dev/null; then
chown -R asterisk:asterisk /etc/asterisk/broadcastify/
chmod 750 /etc/asterisk/broadcastify/
fi

#DEBHELPER#

exit 0
}

case "$1" in
Expand Down
1 change: 1 addition & 0 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ endif
override_dh_installsystemd:
dh_installsystemd --name=asl-telemetry asl-telemetry.timer
dh_installsystemd --name=asl3-boot-oneshot --no-restart-after-upgrade --no-start
dh_installsystemd --name=asl-broadcastify@ --no-enable --no-start --no-restart-after-upgrade
Empty file.