瀏覽代碼

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.
Ka Ho Ng 5 年之前
父節點
當前提交
a1e99d7903
共有 1 個文件被更改,包括 71 次插入15 次删除
  1. 71 15
      plugins/oss-audio/oss-input.c

+ 71 - 15
plugins/oss-audio/oss-input.c

@@ -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 ((ptr = strchr(line, '<')) == NULL)
+		}
+		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)
+			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);