Skip to content

Commit

Permalink
minor cleanups - buffer sizes, use asprintf when possible
Browse files Browse the repository at this point in the history
  • Loading branch information
ka9q committed Apr 11, 2024
1 parent 68c2466 commit 35d4bc9
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 59 deletions.
18 changes: 15 additions & 3 deletions README.md
Expand Up @@ -5,10 +5,17 @@ several respects:
1. Efficient multichannel reception. A single Raspberry Pi 4 can
simultaneously demodulate, in real time, every NBFM channel on a
VHF/UHF band (i.e., several hundred) with plenty of real time left
over. A mid-range x86 can handle the RX888 MkII at full sample rate
over.

A mid-range x86 can handle the RX888 MkII at full sample rate
(129.6 MHz), receiving multiple channels sumultaneously on all
LF/MF/HF ham bands (or anything else) plus 6 meters.

A Raspberry Pi 5 can handle the RX888 MkII at half sample rate (64.8
MHz), enough to receive up to 30 MHz. (An external hardware anti-alias
filter is required, and "FFTW Wisdom" must be generated for the Pi5 to
run this fast.)

2. All I/O (both signal and control/status) uses IP multicasting.
This makes it easy for more than one module, on the same computer or
on a LAN, to operate on the outputs of other modules, or for
Expand All @@ -34,7 +41,7 @@ downconverters and simple demodulators for various linear and FM
modes, including AM, SSB, CW and a raw IQ mode intended mainly for use
by other programs.

Previous versions of ka9q-radio had separate programs (e.g.,
Previous versions (before mid-2023) of ka9q-radio had separate programs (e.g.,
*airspyd*) for talking to several makes of SDR front end hardware and
generated an I/Q multicast stream for *radiod*. Because of performance
problems, code and configuration complexity and general lack of
Expand All @@ -60,6 +67,11 @@ by much more sophisticated user interfaces. Various utilities are
provided to record or play back signal streams, compress PCM audio
into Opus, pipe a stream into digital demodulators, etc.

*Radiod* now periodically multicasts ("beacons") status information on
each output stream and user programs are being enhanced to make
use of it. For example, *monitor* now displays the frequency, mode and
signal-to-noise ratio of each channe.

Although I've been running all this myself for several years, it is
NOT yet ready for general use. A LOT of work still remains, especially
documentation. But you're welcome to look at it, make comments and
Expand All @@ -82,7 +94,7 @@ requirement is that the impulse response of the channel
filters be shorter than the (configurable) overlap interval in the forward
FFT.

Updated 10 September 2023
Updated 11 April 2024
Phil Karn, KA9Q
karn@ka9q.net

Expand Down
2 changes: 1 addition & 1 deletion aprsfeed.c
Expand Up @@ -223,7 +223,7 @@ int main(int argc,char *argv[]){
}

// Construct TNC2-style monitor string for APRS reporting
char monstring[2048]; // Should be large enough for any legal AX.25 frame; we'll assert this periodically
char monstring[PKTSIZE]; // Should be large enough for any legal AX.25 frame; we'll assert this periodically
int sspace = sizeof(monstring);
int infolen = 0;
int is_tcpip = 0;
Expand Down
18 changes: 10 additions & 8 deletions audio.c
@@ -1,6 +1,6 @@
// Audio multicast routines for ka9q-radio
// Handles linear 16-bit PCM, mono and stereo
// Copyright 2017-2023 Phil Karn, KA9Q
// Copyright 2017-2024 Phil Karn, KA9Q

#define _GNU_SOURCE 1
#include <assert.h>
Expand Down Expand Up @@ -90,14 +90,16 @@ int send_output(struct channel * restrict const chan,float const * restrict buff
int r = sendto(Output_fd,&packet,dp - packet,0,(struct sockaddr *)&chan->output.dest_socket,sizeof(chan->output.dest_socket));
chan->output.samples += chunk * chan->output.channels; // Count frames
if(r <= 0){
if(errno == EAGAIN && !TempSendFailure){
fprintf(stdout,"Temporary send failure, suggest increased buffering (see sysctl net.core.wmem_max, net.core.wmem_default\n");
fprintf(stdout,"Additional messages suppressed\n");
TempSendFailure = true;
return 0; // Treat as soft failure
if(errno == EAGAIN){
if(!TempSendFailure){
fprintf(stdout,"Temporary send failure, suggest increased buffering (see sysctl net.core.wmem_max, net.core.wmem_default\n");
fprintf(stdout,"Additional messages suppressed\n");
TempSendFailure = true;
}
} else {
fprintf(stdout,"audio send failure: %s\n",strerror(errno));
abort(); // Probably more serious, like the loss of an interface or route
}
fprintf(stdout,"audio send failure: %s\n",strerror(errno));
abort(); // Probably more serious, like the loss of an interface or route
}
frames -= chunk;
if(chan->output.pacing && frames > 0)
Expand Down
53 changes: 26 additions & 27 deletions avahi.c
Expand Up @@ -7,25 +7,37 @@
#include "avahi.h"

int avahi_start(char const *service_name,char const *service_type,int const service_port,char const *dns_name,int address,char const *description,void *sock,int *socksize){
int pid = getpid();
if(sock != NULL && socksize != NULL){
// Return sockaddr structure
if(*socksize >= sizeof(struct sockaddr_in)){
struct sockaddr_in *sin = sock;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = htonl(address);
sin->sin_port = htons(service_port);
*socksize = sizeof(struct sockaddr_in);
} else
*socksize = 0;
}
int pid = getpid(); // Advertise the parent's pid, not the child's
if(fork() == 0){
#if 0
fprintf(stdout,"avahi-publish-service child pid %d\n",getpid());
#endif
// run avahi-publish-service --no-fail --host=dns_name service_name service_type service_port description pid hostname in subprocess
char port_string[1024];
snprintf(port_string, sizeof(port_string), "%d", service_port);
// run "avahi-publish-service --no-fail --host=dns_name service_name service_type service_port description pid hostname" in subprocess
// No need to free the asprintf-allocated strings, we're calling exec anyway
char *port_string;
asprintf(&port_string, "%d", service_port);

char host_string[1024];
snprintf(host_string, sizeof(host_string), "--host=%s",dns_name);
char *host_string;
asprintf(&host_string, "--host=%s",dns_name);

char pid_string[1024];
snprintf(pid_string, sizeof(pid_string), "pid=%d", pid);
char *pid_string;
asprintf(&pid_string, "pid=%d", pid);

char hostname[sysconf(_SC_HOST_NAME_MAX)];
gethostname(hostname,sizeof(hostname));
char source_string[1024];
snprintf(source_string, sizeof(source_string), "source=%s", hostname);
char *source_string;
asprintf(&source_string, "source=%s", hostname);

#if 0
fprintf(stdout,"%s %s %s %s %s %s %s %s %s %s\n",
Expand All @@ -35,25 +47,12 @@ int avahi_start(char const *service_name,char const *service_type,int const serv
perror("exec avahi publish service");
return -1;
}
char ip_address_string[1024];
snprintf(ip_address_string,sizeof(ip_address_string),"%d.%d.%d.%d",(address >> 24) & 0xff, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff);
if(fork() == 0){
char *ip_address_string; // No need to free, we're calling exec
asprintf(&ip_address_string,"%d.%d.%d.%d",(address >> 24) & 0xff, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff);
#if 0
fprintf(stdout,"avahi start: ip address string = %s\n",ip_address_string);
fprintf(stdout,"avahi start: ip address string = %s\n",ip_address_string);
#endif

if(sock != NULL && socksize != NULL){
// Return sockaddr structure
if(*socksize >= sizeof(struct sockaddr_in)){
struct sockaddr_in *sin = sock;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = htonl(address);
sin->sin_port = htons(service_port);
*socksize = sizeof(struct sockaddr_in);
} else
*socksize = 0;
}

if(fork() == 0){
fprintf(stdout,"avahi-publish-address child pid %d\n",getpid());
// run "avahi-publish-address dns_name address"
#if 0
Expand Down
2 changes: 1 addition & 1 deletion main.c
Expand Up @@ -377,7 +377,7 @@ static int loadconfig(char const * const file){
// Set up status/command stream, global for all receiver channels
{
// Form default status dns name
char hostname[1024];
char hostname[sysconf(_SC_HOST_NAME_MAX)];
gethostname(hostname,sizeof(hostname));
// Edit off .domain, .local, etc
char *cp = strchr(hostname,'.');
Expand Down
10 changes: 5 additions & 5 deletions opusd.c
Expand Up @@ -246,12 +246,12 @@ int main(int argc,char * const argv[]){
Status_fd = listen_mcast(&Metadata_in_socket,iface);
}

char description[1024];
snprintf(description,sizeof(description),"pcm-source=%s",Input); // what if it changes?
int socksize = sizeof(Opus_out_socket);
uint32_t addr = (239U << 24) | (ElfHashString(Output) & 0xffffff);
avahi_start(Name,"_opus._udp",DEFAULT_RTP_PORT,Output,addr,description,&Opus_out_socket,&socksize);
{
char description[1024];
snprintf(description,sizeof(description),"pcm-source=%s",Input); // what if it changes?
int socksize = sizeof(Opus_out_socket);
uint32_t addr = (239U << 24) | (ElfHashString(Output) & 0xffffff);
avahi_start(Name,"_opus._udp",DEFAULT_RTP_PORT,Output,addr,description,&Opus_out_socket,&socksize);
struct sockaddr_in *sin = (struct sockaddr_in *)&Metadata_out_socket;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = htonl(addr);
Expand Down
2 changes: 1 addition & 1 deletion pcmrecord.c
@@ -1,5 +1,5 @@
// Read and record PCM audio streams
// Copyright 2021 Phil Karn, KA9Q
// Copyright 2021-2024 Phil Karn, KA9Q
#define _GNU_SOURCE 1
#include <assert.h>
#include <errno.h>
Expand Down
14 changes: 7 additions & 7 deletions pcmspawn.c
Expand Up @@ -48,7 +48,7 @@ struct session {


// Command line params
const char *App_path;
char const *App_path;
int Verbose; // Verbosity flag (currently unused)

// Global variables
Expand All @@ -61,9 +61,9 @@ int Status_out_fd = -1; // Writing to radio status
int Input_fd = -1; // Multicast receive socket
struct session *Sessions;
pthread_mutex_t Session_protect = PTHREAD_MUTEX_INITIALIZER;
char *Command;
char *Input;
char *Status;
char const *Command;
char const *Input;
char const *Status;

void closedown(int);
struct session *lookup_session(const struct sockaddr *,uint32_t,int);
Expand Down Expand Up @@ -223,7 +223,7 @@ int main(int argc,char * const argv[]){
// sample rate
// sending IP address & port

char command_line[2048];
char command_line[4096]; // I think that's the longest shell command
int const samprate = samprate_from_pt(sp->type);
int const channels = channels_from_pt(sp->type);

Expand Down Expand Up @@ -294,7 +294,7 @@ void * status(void *p){

while(true){
socklen_t socklen = sizeof(Status_input_source_address);
uint8_t buffer[16384];
uint8_t buffer[PKTSIZE];
int const length = recvfrom(Status_fd,buffer,sizeof(buffer),0,(struct sockaddr *)&Status_input_source_address,&socklen);
if(length <= 0){
if(errno == EAGAIN || errno == ETIMEDOUT)
Expand Down Expand Up @@ -459,7 +459,7 @@ void closedown(int s){
}
// Send empty poll command on specified descriptor
static int send_poll(int fd,int ssrc){
uint8_t cmdbuffer[128];
uint8_t cmdbuffer[PKTSIZE];
uint8_t *bp = cmdbuffer;
*bp++ = 1; // Command

Expand Down
8 changes: 4 additions & 4 deletions radio.c
@@ -1,5 +1,5 @@
// Core of 'radiod' program - control LOs, set frequency/mode, etc
// Copyright 2018-2023, Phil Karn, KA9Q
// Core of 'radiod' program - create/delete channels, control LOs, set frequency/mode, etc
// Copyright 2018-2024, Phil Karn, KA9Q
#define _GNU_SOURCE 1
#include <assert.h>
#include <stdlib.h>
Expand Down Expand Up @@ -388,7 +388,7 @@ void *sap_send(void *p){
int const sess_version = 1;

for(;;){
char message[1500],*wp;
char message[PKTSIZE],*wp;
int space = sizeof(message);
wp = message;

Expand Down Expand Up @@ -418,7 +418,7 @@ void *sap_send(void *p){

{
// Originator o=
char hostname[128];
char hostname[sysconf(_SC_HOST_NAME_MAX)];
gethostname(hostname,sizeof(hostname));

struct passwd pwd,*result = NULL;
Expand Down
4 changes: 2 additions & 2 deletions spectrum.c
@@ -1,5 +1,5 @@
// Spectral analysis service - far from complete - for ka9q-radio's radiod
// Copyright 2023, Phil Karn, KA9Q
// Copyright 2023-2024, Phil Karn, KA9Q
#define _GNU_SOURCE 1
#include <assert.h>
#include <pthread.h>
Expand All @@ -20,7 +20,7 @@ void *demod_spectrum(void *arg){

{
char name[100];
snprintf(name,sizeof(name),"spect %u",chan->output.rtp.ssrc); // SSRC is dummy for ID, there's no RTP stream
snprintf(name,sizeof(name),"spect %u",chan->output.rtp.ssrc);
pthread_setname(name);
}
pthread_mutex_init(&chan->status.lock,NULL);
Expand Down

0 comments on commit 35d4bc9

Please sign in to comment.