oss-audio: Improve /dev/sndstat parsing on FreeBSD

This commit targets FreeBSD and potentially DragonFly BSD. The commit
fixes issue parsing /dev/sndstat when hw.snd.verbose is greater than 0.
Besides, the commit also adds support for audio devices created by
user space daemons, such as virtual_oss.
This commit is contained in:
Ka Ho Ng 2020-08-05 02:55:24 +08:00
parent 5803504c36
commit a1e99d7903

View file

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <util/threading.h>
#include <obs-module.h>
#include <ctype.h>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
@ -38,6 +39,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define OSS_RATE_DEFAULT 48000
#define OSS_CHANNELS_DEFAULT 2
#define OSS_DEVICE_BEGIN "Installed devices:"
#define OSS_USERDEVICE_BEGIN "Installed devices from userspace:"
#define OSS_FV_BEGIN "File Versions:"
/**
* Control block of plugin instance
*/
@ -215,6 +220,7 @@ static void *oss_reader_thr(void *vptr)
size_t framesize;
framesize = oss_calc_framesize(handle->channels, handle->sample_fmt);
fds[0].fd = handle->dsp_fd;
fds[0].events = POLLIN;
fds[1].fd = handle->notify_pipe[0];
@ -460,6 +466,8 @@ static void oss_prop_add_devices(obs_property_t *p)
char *line = NULL;
size_t linecap = 0;
FILE *fp;
bool ud_matching = false;
bool skipall = false;
fp = fopen(OSS_SNDSTAT_PATH, "r");
if (fp == NULL) {
@ -470,35 +478,83 @@ static void oss_prop_add_devices(obs_property_t *p)
while (getline(&line, &linecap, fp) > 0) {
int pcm;
char *ptr, *pdesc, *descr, *devname, *pmode;
char *ptr, *pdesc, *pmode;
char *descr = NULL, *devname = NULL;
char *udname = NULL;
if (sscanf(line, "pcm%i: ", &pcm) != 1)
if (!strncmp(line, OSS_FV_BEGIN, strlen(OSS_FV_BEGIN))) {
skipall = true;
continue;
}
if (!strncmp(line, OSS_DEVICE_BEGIN,
strlen(OSS_DEVICE_BEGIN))) {
ud_matching = false;
skipall = false;
continue;
}
if (!strncmp(line, OSS_USERDEVICE_BEGIN,
strlen(OSS_USERDEVICE_BEGIN))) {
ud_matching = true;
skipall = false;
continue;
}
if (skipall || isblank(line[0]))
continue;
if (!ud_matching) {
if (sscanf(line, "pcm%i: ", &pcm) != 1)
continue;
} else {
char *end = strchr(line, ':');
if (end == NULL || end - line == 0)
continue;
udname = strndup(line, end - line);
if (udname == NULL)
continue;
}
if ((ptr = strchr(line, '<')) == NULL)
continue;
goto free_all_str;
pdesc = ptr + 1;
if ((ptr = strrchr(pdesc, '>')) == NULL)
continue;
goto free_all_str;
*ptr++ = '\0';
if (*ptr++ != ' ' || *ptr++ != '(')
continue;
pmode = ptr;
if ((pmode = strchr(ptr, '(')) == NULL)
goto free_all_str;
pmode++;
if ((ptr = strrchr(pmode, ')')) == NULL)
continue;
goto free_all_str;
*ptr++ = '\0';
if (strcmp(pmode, "rec") != 0 && strcmp(pmode, "play/rec") != 0)
continue;
if (asprintf(&descr, "pcm%i: %s", pcm, pdesc) == -1)
continue;
if (asprintf(&devname, "/dev/dsp%i", pcm) == -1) {
free(descr);
continue;
if (!isdigit(pmode[0])) {
if (strcmp(pmode, "rec") != 0 &&
strcmp(pmode, "play/rec") != 0)
goto free_all_str;
} else {
int npcs, nrcs;
if (sscanf(pmode, "%dp:%*dv/%dr:%*dv", &npcs, &nrcs) !=
2)
goto free_all_str;
if (nrcs < 1)
goto free_all_str;
}
if (!ud_matching) {
if (asprintf(&descr, "pcm%i: %s", pcm, pdesc) == -1)
goto free_all_str;
if (asprintf(&devname, "/dev/dsp%i", pcm) == -1)
goto free_all_str;
} else {
if (asprintf(&descr, "%s: %s", udname, pdesc) == -1)
goto free_all_str;
if (asprintf(&devname, "/dev/%s", udname) == -1)
goto free_all_str;
}
obs_property_list_add_string(p, descr, devname);
free_all_str:
free(descr);
free(devname);
free(udname);
}
free(line);