SSB_HighSpeed_Modem/hsmodem/libkmaudio/libkmaudio_getDevices_Linux.cpp
Christoph Berg 32c9a2c8c5 Support Pulseaudio "monitor" devices
In Pulseaudio, each output device has a corresponding input device.
These are actually useful, e.g. when listening to a received signal on
the headphones (perhaps from the websdr or some SDR software), it makes
sense to attach the HS modem to "Monitor of Headphones" to have it
decode it. Pulseaudio also supports virtual sinks that can be fed from
SDR software, and letting the HS modem listen on "Monitor of virtual
sink" will enable decoding.
2021-04-27 23:46:25 +02:00

216 lines
6.6 KiB
C++
Executable File

/*
* Audio Library for Linux and Windows
* ===================================
* Author: DJ0ABR
*
* Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr
* License: GPL-3
*
* compilation:
* Windows ... Visual Studio
* Linux ... make
*
* Documentation see: libkmaudio.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* libkmaudio_getDevices_linux.cpp
* like libkmaudio_getDevices.cpp, but uses libsoundio under Linux
* to get the device list. Portaudio does not work under Linux because
* it does not support pulseaudio. Therefore the linux functions
* use libsoundio
*
*/
#ifndef WIN32 // Linux
#include "libkmaudio.h"
int scan_devices();
int kmaudio_getDeviceList()
{
if (soundio == NULL)
{
printf("kmaudio_getDeviceList: soundio not initialized\n");
return -1;
}
soundio_flush_events(soundio); // to get actual data
if (scan_devices() == -1) // read devices
{
printf("cannot read audio devices\n");
return -1;
}
io_buildAudioDevString();
// close stream if a device does not exist any more
for (int i = 0; i < devanz; i++)
{
if (devlist[i].active == 0)
{
if (devlist[i].instream != NULL)
{
printf("capture device %s disconnected, stop stream\n", devlist[i].name);
soundio_instream_destroy(devlist[i].instream);
devlist[i].instream = NULL;
devlist[i].working = 0;
}
if(devlist[i].outstream != NULL)
{
printf("playback device %s disconnected, stop stream\n", devlist[i].name);
soundio_outstream_destroy(devlist[i].outstream);
devlist[i].outstream = NULL;
devlist[i].working = 0;
}
}
}
static int csum = 0;
int sum = 0;
uint8_t* p = (uint8_t*)&(devlist[0].index);
for (int i = 0; i < (int)sizeof(devlist); i++)
sum += *p++;
if (csum != sum)
{
csum = sum;
printf("====== Linux Devices found: ======\n");
for (int i = 0; i < devanz; i++)
{
printf("Index: %d\n", devlist[i].index);
printf("Name: %s\n", devlist[i].name);
printf("ID: %s\n", devlist[i].id);
printf("Cap/PB: %d\n", devlist[i].in_out);
printf("Channels: %d\n", devlist[i].stereo_mono);
printf("SR 44100: %d\n", devlist[i].supports_44100);
printf("SR 48000: %d\n", devlist[i].supports_48000);
printf("is active: %s\n", devlist[i].active ? "yes" : "no");
printf("--------------------------------------\n");
}
}
return 0;
}
static void get_channel_layout(const struct SoundIoChannelLayout* layout)
{
if (layout->name)
{
if (strstr(layout->name, "ereo"))
devlist[devanz].stereo_mono = 2;
if (strstr(layout->name, "ono"))
devlist[devanz].stereo_mono = 1;
}
}
int getDeviceParameters(int idx, struct SoundIoDevice* device)
{
strncpy(devlist[idx].id, device->id, sizeof(devlist[0].id) - 1);
devlist[idx].id[sizeof(devlist[0].id) - 1] = 0;
strncpy(devlist[idx].name, device->name, sizeof(devlist[0].name) - 1);
devlist[idx].name[sizeof(devlist[0].name) - 1] = 0;
for (int i = 0; i < device->layout_count; i++)
get_channel_layout(&device->layouts[i]);
int min = 999999, max = 0;
for (int i = 0; i < device->sample_rate_count; i++)
{
struct SoundIoSampleRateRange* range = &device->sample_rates[i];
if (range->min < min)
min = range->min;
if (range->max > max)
max = range->max;
}
if (min <= 44100) devlist[idx].supports_44100 = 1;
if (max >= 48000) devlist[idx].supports_48000 = 1;
if (devlist[idx].supports_44100 == 0 && devlist[idx].supports_48000 == 0) return 0;
return 1;
}
int getDevlistIndex(char* name, char* id)
{
for (int i = 0; i < devanz; i++)
{
// check if already exists
if (!strcmp(devlist[i].id, id) && !strcmp(devlist[i].name, name))
return i;
}
int newidx = devanz;
devanz++;
//printf("New Dev:%s Idx:%d\n", name, newidx);
return newidx;
}
int scan_devices()
{
for (int i = 0; i < devanz; i++)
devlist[i].active = 0;
int didx;
for (int i = 0; i < soundio_input_device_count(soundio); i++)
{
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
if (device == NULL) continue;
if (device->probe_error) continue;
didx = getDevlistIndex(device->name, device->id);
if (getDeviceParameters(didx, device) == 1)
{
//printf("%d %d ====CAP:\nid:<%s>\nname:<%s>\n", i,devanz,device->id, device->name);
devlist[didx].in_out = 0;
devlist[didx].index = didx;
devlist[didx].active = 1;
}
else
{
*devlist[didx].name = 0;
*devlist[didx].id = 0;
}
soundio_device_unref(device);
}
for (int i = 0; i < soundio_output_device_count(soundio); i++)
{
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
if (device == NULL) continue;
if (device->probe_error) continue;
didx = getDevlistIndex(device->name, device->id);
if (getDeviceParameters(didx, device) == 1)
{
//printf("====PB :\nid:<%s>\nname:<%s>\n", device->id, device->name);
devlist[didx].in_out = 1;
devlist[didx].index = didx;
devlist[didx].active = 1;
}
else
{
*devlist[didx].name = 0;
*devlist[didx].id = 0;
}
soundio_device_unref(device);
}
return 0;
}
#endif // ifndef WIN32