fldigi - Initial work to enable PnP support for fldigi. Wrote a custom tool to map between an ALSA device and a PortAudio device.

This commit is contained in:
thetechprepper
2025-10-01 21:28:06 -07:00
parent ea5207e25e
commit e73679ce90
6 changed files with 186 additions and 5 deletions
+3
View File
@@ -0,0 +1,3 @@
et-portaudio
*.o
conf.tmp
+14
View File
@@ -0,0 +1,14 @@
CC = gcc
CFLAGS = -Wall -O2
LDFLAGS = -lportaudio -lasound
TARGET = et-portaudio
SRC = main.c
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS)
clean:
rm -f $(TARGET) *.o
+26
View File
@@ -0,0 +1,26 @@
# et-portaudio
A utility program intended for script use to convert a supported
EmComm Tools ALSA audio device (i.e. `ET_AUDIO`) to a PulseAudio device.
## Usage
Returns a JSON object with the PulseAudio device details on success.
```bash
./et-portaudio 2>/dev/null
{
"device": "USB Audio Device: - (hw:1,0)",
"index": 6
}
```
If no supported device is found or on error, the utility exits with an
exit status of 1.
## Build
``bash
make
```
+49
View File
@@ -0,0 +1,49 @@
#!/bin/bash
# Author : Gaston Gonzalez
# Date : 1 October 2025
# Purpose : Temporary script to fast-fail dynamic fldigi config for PnP
#
# NOTE:
#
# THIS IS JUST USED DURING DEVELOPMENT. AN XML PARSER WILL BE USED TO MODIFY
# THE FLDIGI CONFIG FOR THE FINAL PNP SOLUTION. SO THAT USER CHANGES CAN STILL
# BE PERSISTED.
CMD=et-portaudio
PORT_AUDIO_CONF=conf.tmp
FLDIGI_CONF_FILE="${HOME}/.fldigi/fldigi_def.xml"
# clean up temporary config that may exist
[[ -e ${PORT_AUDIO_CONF} ]] && rm ${PORT_AUDIO_CONF}
[[ ! -e ${CMD} ]] && make
./${CMD} 2>/dev/null > ${PORT_AUDIO_CONF}
if [[ $? -ne 0 ]]; then
echo "No supported ET_AUDIO device found"
exit 1
fi
DEVICE=$(jq -r -e '.device' ${PORT_AUDIO_CONF})
if [[ $? -ne 0 ]]; then
echo "Error getting PulseAudio device name for ET_AUDIO device"
exit 1
fi
INDEX=$(jq -r -e '.index' ${PORT_AUDIO_CONF})
if [[ $? -ne 0 ]]; then
echo "Error getting PulseAudio device index for ET_AUDIO device"
exit 1
fi
et-log "Copying fldigi template..."
cp -v ../../overlay/etc/skel/.fldigi/fldigi_def.xml ~/.fldigi/
et-log "Updating PortAudio devices..."
sed -i "s|^<AUDIOIO>.*|<AUDIOIO>1</AUDIOIO>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTINDEVICE>.*|<PORTINDEVICE>${DEVICE}</PORTINDEVICE>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTININDEX>.*|<PORTININDEX>${INDEX}</PORTININDEX>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTOUTDEVICE>.*|<PORTOUTDEVICE>${DEVICE}</PORTOUTDEVICE>|" ${FLDIGI_CONF_FILE}
sed -i "s|^<PORTOUTINDEX>.*|<PORTOUTINDEX>${INDEX}</PORTOUTINDEX>|" ${FLDIGI_CONF_FILE}
+89
View File
@@ -0,0 +1,89 @@
/*
* Author : Gaston Gonzalez
* Date : 1 October 2025
* Purpose : Maps an ET_AUDIO ALSA device to a PortAudio device.
*
* This utility enumerates all ALSA audio devices using PortAudio
* to identify a currently plugged-in ET_AUDIO device. If a matching
* device is found, it generates a JSON object on STDOUT containing:
*
* - PortAudio device name
* - PortAudio device index
*
* Exit Status:
* 0 - ET_AUDIO device found and JSON output generated successfully
* 1 - ET_AUDIO device not found
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "portaudio.h"
#define PROC_ALSA_PATH_FMT "/proc/asound/card%d/id"
// Read the ALSA card ID from the /proc filesystem
int get_alsa_card_id(int card, char *id_buf, size_t buf_size) {
char path[64];
snprintf(path, sizeof(path), PROC_ALSA_PATH_FMT, card);
FILE *f = fopen(path, "r");
if (!f) return -1;
if (!fgets(id_buf, buf_size, f)) {
fclose(f);
return -1;
}
id_buf[strcspn(id_buf, "\n")] = 0;
fclose(f);
return 0;
}
int main(void) {
PaError err;
int i, numDevices;
const PaDeviceInfo *deviceInfo;
const PaHostApiInfo *hostApiInfo;
int found = 0;
err = Pa_Initialize();
if (err != paNoError) {
fprintf(stderr, "PortAudio error: %s\n", Pa_GetErrorText(err));
return 1;
}
numDevices = Pa_GetDeviceCount();
if (numDevices < 0) {
fprintf(stderr, "No audio devices found");
Pa_Terminate();
return 1;
}
for (i = 0; i < numDevices; i++) {
deviceInfo = Pa_GetDeviceInfo(i);
hostApiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);
// Only show ALSA devices
if (hostApiInfo && strcmp(hostApiInfo->name, "ALSA") == 0) {
int card = -1, device = -1;
// Extract ALSA card and device (hw:X,Y)
if (sscanf(deviceInfo->name, "%*[^()](hw:%d,%d)", &card, &device) == 2) {
char card_id[64];
if (get_alsa_card_id(card, card_id, sizeof(card_id)) == 0) {
// Only print if card ID matches ET_AUDIO
if (strcmp(card_id, "ET_AUDIO") == 0) {
found = 1;
printf("{\n");
printf(" \"device\": \"%s\",\n", deviceInfo->name);
printf(" \"index\": %d\n", i);
printf("}\n");
}
}
}
}
}
Pa_Terminate();
return found ? 0 : 1;
}