$NetBSD: patch-src_netbsd.c,v 1.1 2024/02/29 14:15:41 bsiegert Exp $
Add NetBSD native audio support
--- src/netbsd.c.orig 2024-01-30 02:16:50.046541412 +0000
+++ src/netbsd.c
@@ -0,0 +1,193 @@
+/* Netbsd Output.
+ *
+ * Based on Oss Output by Reece H. Dunn
+ *
+ * This file is part of pcaudiolib.
+ *
+ * pcaudiolib 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * pcaudiolib 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 pcaudiolib. If not, see .
+ */
+
+#include "config.h"
+#include "audio_priv.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct netbsd_object
+{
+ struct audio_object vtable;
+ int fd;
+ int ctlfd;
+ char *device;
+
+};
+
+#define to_netbsd_object(object) container_of(object, struct netbsd_object, vtable)
+
+int
+netbsd_object_open(struct audio_object *object,
+ enum audio_object_format format,
+ uint32_t rate,
+ uint8_t channels)
+{
+ struct netbsd_object *self = to_netbsd_object(object);
+
+ if (self->fd != -1)
+ return EEXIST;
+
+ struct aformat_sun
+ {
+ int audio_object_format;
+ int netbsd_format;
+ int netbsd_precision;
+ };
+ struct aformat_sun aformat_netbsd_tbl[] = {
+ {AUDIO_OBJECT_FORMAT_ALAW, AUDIO_ENCODING_ALAW, 8},
+ {AUDIO_OBJECT_FORMAT_ULAW, AUDIO_ENCODING_ULAW, 8},
+ {AUDIO_OBJECT_FORMAT_S8, AUDIO_ENCODING_SLINEAR, 8},
+ {AUDIO_OBJECT_FORMAT_U8, AUDIO_ENCODING_ULINEAR, 8},
+ {AUDIO_OBJECT_FORMAT_S16LE, AUDIO_ENCODING_SLINEAR_LE, 16},
+ {AUDIO_OBJECT_FORMAT_S16BE, AUDIO_ENCODING_SLINEAR_BE, 16},
+ {AUDIO_OBJECT_FORMAT_U16LE, AUDIO_ENCODING_ULINEAR_LE, 16},
+ {AUDIO_OBJECT_FORMAT_U16BE, AUDIO_ENCODING_ULINEAR_BE, 16},
+ {AUDIO_OBJECT_FORMAT_S18LE, AUDIO_ENCODING_SLINEAR_LE, 18},
+ {AUDIO_OBJECT_FORMAT_S18BE, AUDIO_ENCODING_SLINEAR_BE, 18},
+ {AUDIO_OBJECT_FORMAT_U18LE, AUDIO_ENCODING_ULINEAR_LE, 18},
+ {AUDIO_OBJECT_FORMAT_U18BE, AUDIO_ENCODING_ULINEAR_BE, 18},
+ {AUDIO_OBJECT_FORMAT_S20LE, AUDIO_ENCODING_SLINEAR_LE, 20},
+ {AUDIO_OBJECT_FORMAT_S20BE, AUDIO_ENCODING_SLINEAR_BE, 20},
+ {AUDIO_OBJECT_FORMAT_U20LE, AUDIO_ENCODING_ULINEAR_LE, 20},
+ {AUDIO_OBJECT_FORMAT_U20BE, AUDIO_ENCODING_ULINEAR_BE, 20},
+ {AUDIO_OBJECT_FORMAT_S24LE, AUDIO_ENCODING_SLINEAR_LE, 24},
+ {AUDIO_OBJECT_FORMAT_S24BE, AUDIO_ENCODING_SLINEAR_BE, 24},
+ {AUDIO_OBJECT_FORMAT_U24LE, AUDIO_ENCODING_ULINEAR_LE, 24},
+ {AUDIO_OBJECT_FORMAT_U24BE, AUDIO_ENCODING_ULINEAR_BE, 24},
+ {AUDIO_OBJECT_FORMAT_S32LE, AUDIO_ENCODING_SLINEAR_LE, 32},
+ {AUDIO_OBJECT_FORMAT_S32BE, AUDIO_ENCODING_SLINEAR_BE, 32},
+ {AUDIO_OBJECT_FORMAT_U32LE, AUDIO_ENCODING_ULINEAR_LE, 32},
+ {AUDIO_OBJECT_FORMAT_U32BE, AUDIO_ENCODING_ULINEAR_BE, 32},
+ {AUDIO_OBJECT_FORMAT_ADPCM, AUDIO_ENCODING_ADPCM, 8},
+ };
+#define NETBSDFORMATS (sizeof(aformat_netbsd_tbl)/sizeof(aformat_netbsd_tbl[0]))
+ int i;
+ for(i=0; i < NETBSDFORMATS; i++)
+ if(aformat_netbsd_tbl[i].audio_object_format == format)
+ break;
+ if(i >= NETBSDFORMATS)
+ return EINVAL;
+
+ audio_info_t audioinfo;
+ if ((self->fd = open(self->device ? self->device : "/dev/audio", O_WRONLY, 0)) == -1)
+ return errno;
+ AUDIO_INITINFO(&audioinfo);
+ audioinfo.play.sample_rate = rate;
+ audioinfo.play.channels = channels;
+ audioinfo.play.precision = aformat_netbsd_tbl[i].netbsd_precision;
+ audioinfo.play.encoding = aformat_netbsd_tbl[i].netbsd_format;
+ if (ioctl(self->fd, AUDIO_SETINFO, &audioinfo) == -1)
+ goto error;
+ return 0;
+error:
+ close(self->fd);
+ self->fd = -1;
+ return errno;
+}
+
+void
+netbsd_object_close(struct audio_object *object)
+{
+ struct netbsd_object *self = to_netbsd_object(object);
+
+ if (self->fd != -1) {
+ close(self->fd);
+ self->fd = -1;
+ }
+}
+
+void
+netbsd_object_destroy(struct audio_object *object)
+{
+ struct netbsd_object *self = to_netbsd_object(object);
+
+ free(self->device);
+ free(self);
+}
+
+int
+netbsd_object_drain(struct audio_object *object)
+{
+ struct netbsd_object *self = to_netbsd_object(object);
+
+ if (ioctl(self->fd, AUDIO_DRAIN, NULL) == -1)
+ return errno;
+ return 0;
+}
+
+int
+netbsd_object_flush(struct audio_object *object)
+{
+ struct netbsd_object *self = to_netbsd_object(object);
+
+ if (ioctl(self->fd, AUDIO_FLUSH, NULL) == -1)
+ return errno;
+ return 0;
+}
+
+int
+netbsd_object_write(struct audio_object *object,
+ const void *data,
+ size_t bytes)
+{
+ struct netbsd_object *self = to_netbsd_object(object);
+
+ if (write(self->fd, data, bytes) == -1)
+ return errno;
+ return 0;
+}
+
+const char *
+netbsd_object_strerror(struct audio_object *object,
+ int error)
+{
+ return strerror(error);
+}
+
+struct audio_object *
+create_netbsd_object(const char *device,
+ const char *application_name,
+ const char *description)
+{
+ struct netbsd_object *self = malloc(sizeof(struct netbsd_object));
+ if (!self)
+ return NULL;
+
+ self->fd = -1;
+ self->device = device ? strdup(device) : NULL;
+
+ self->vtable.open = netbsd_object_open;
+ self->vtable.close = netbsd_object_close;
+ self->vtable.destroy = netbsd_object_destroy;
+ self->vtable.write = netbsd_object_write;
+ self->vtable.drain = netbsd_object_drain;
+ self->vtable.flush = netbsd_object_flush;
+ self->vtable.strerror = netbsd_object_strerror;
+
+ return &self->vtable;
+}