Module Name:    src
Committed By:   nat
Date:           Thu Oct 26 22:38:27 UTC 2017

Modified Files:
        src/sys/dev: audio.c audiovar.h

Log Message:
Add latency sysctl to adjust hw blocksize and hence latency of the mixer.

        usage: sysctl -w hw.hdafg0.lantency="value in milliseconds"

It is possible to set the latency of the mixer unless a static blocksize
is configured by the underlying hardware driver (pad, vcaudio on RPI).

Documentation updates to audio.4 will occur in a follow up commit.

OK christos@.  XXX pullup-8.


To generate a diff of this commit:
cvs rdiff -u -r1.414 -r1.415 src/sys/dev/audio.c
cvs rdiff -u -r1.65 -r1.66 src/sys/dev/audiovar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/audio.c
diff -u src/sys/dev/audio.c:1.414 src/sys/dev/audio.c:1.415
--- src/sys/dev/audio.c:1.414	Wed Oct 25 08:12:38 2017
+++ src/sys/dev/audio.c	Thu Oct 26 22:38:27 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: audio.c,v 1.414 2017/10/25 08:12:38 maya Exp $	*/
+/*	$NetBSD: audio.c,v 1.415 2017/10/26 22:38:27 nat Exp $	*/
 
 /*-
  * Copyright (c) 2016 Nathanial Sloss <nathanialsl...@yahoo.com.au>
@@ -148,7 +148,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.414 2017/10/25 08:12:38 maya Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.415 2017/10/26 22:38:27 nat Exp $");
 
 #ifdef _KERNEL_OPT
 #include "audio.h"
@@ -205,6 +205,7 @@ int	audiodebug = AUDIO_DEBUG;
 #define DPRINTFN(n,x)
 #endif
 
+#define PREFILL_BLOCKS	3	/* no. audioblocks required to start stream */
 #define ROUNDSIZE(x)	(x) &= -16	/* round to nice boundary */
 #define SPECIFIED(x)	((int)(x) != ~0)
 #define SPECIFIED_CH(x)	((x) != (u_char)~0)
@@ -313,6 +314,7 @@ int	audio_set_defaults(struct audio_soft
 static int audio_sysctl_frequency(SYSCTLFN_PROTO);
 static int audio_sysctl_precision(SYSCTLFN_PROTO);
 static int audio_sysctl_channels(SYSCTLFN_PROTO);
+static int audio_sysctl_latency(SYSCTLFN_PROTO);
 
 static int	audiomatch(device_t, cfdata_t, void *);
 static void	audioattach(device_t, device_t, void *);
@@ -498,6 +500,7 @@ audioattach(device_t parent, device_t se
 	sc->sc_recopens = 0;
 	sc->sc_aivalid = false;
  	sc->sc_ready = true;
+	sc->sc_latency = audio_blk_ms * PREFILL_BLOCKS;
 
  	sc->sc_format[0].mode = AUMODE_PLAY | AUMODE_RECORD;
  	sc->sc_format[0].encoding =
@@ -793,6 +796,15 @@ audioattach(device_t parent, device_t se
 
 		sysctl_createv(&sc->sc_log, 0, NULL, NULL,
 			CTLFLAG_READWRITE,
+			CTLTYPE_INT, "latency",
+			SYSCTL_DESCR("latency"),
+			audio_sysctl_latency, 0,
+			(void *)sc, 0,
+			CTL_HW, node->sysctl_num,
+			CTL_CREATE, CTL_EOL);
+
+		sysctl_createv(&sc->sc_log, 0, NULL, NULL,
+			CTLFLAG_READWRITE,
 			CTLTYPE_BOOL, "multiuser",
 			SYSCTL_DESCR("allow multiple user acess"),
 			NULL, 0,
@@ -2634,8 +2646,8 @@ audio_calc_blksize(struct audio_softc *s
 {
 	int blksize;
 
-	blksize = parm->sample_rate * audio_blk_ms / 1000 *
-	     parm->channels * parm->precision / NBBY;
+	blksize = parm->sample_rate * sc->sc_latency * parm->channels /
+	    1000 * parm->precision / NBBY / PREFILL_BLOCKS;
 	return blksize;
 }
 
@@ -4106,7 +4118,7 @@ audio_set_vchan_defaults(struct audio_so
 	    &sc->sc_encodings);
 
 	if (error == 0)
-		error = audiosetinfo(sc, &ai, false, vc);
+		error = audiosetinfo(sc, &ai, true, vc);
 
 	return error;
 }
@@ -5955,6 +5967,64 @@ audio_sysctl_channels(SYSCTLFN_ARGS)
 	return error;
 }
 
+/* sysctl helper to set audio latency */
+static int
+audio_sysctl_latency(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct audio_softc *sc;
+	int t, error;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+
+	t = sc->sc_latency;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	mutex_enter(sc->sc_lock);
+
+	/* This may not change when a virtual channel is open */
+	if (sc->sc_opens || sc->sc_recopens) {
+		mutex_exit(sc->sc_lock);
+		return EBUSY;
+	}
+
+	if (t < 0 || t > 4000) {
+		mutex_exit(sc->sc_lock);
+		return EINVAL;
+	}
+
+	if (t == 0)
+		sc->sc_latency = audio_blk_ms * PREFILL_BLOCKS;
+	else
+		sc->sc_latency = (unsigned int)t;
+
+	error = audio_set_vchan_defaults(sc,
+	    AUMODE_PLAY | AUMODE_PLAY_ALL | AUMODE_RECORD);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "Error setting latency, "
+				 "latency restored to default\n");
+		sc->sc_latency = audio_blk_ms * PREFILL_BLOCKS;
+		error = audio_set_vchan_defaults(sc,
+	    	    AUMODE_PLAY | AUMODE_PLAY_ALL | AUMODE_RECORD);
+	}
+
+	if (sc->sc_vchan_params.sample_rate > 0 &&
+	    sc->sc_vchan_params.channels > 0 &&
+	    sc->sc_vchan_params.precision > 0) {
+		    sc->sc_latency = sc->sc_hwvc->sc_mpr.blksize * 1000 * 
+		    PREFILL_BLOCKS / sc->sc_vchan_params.sample_rate /
+		    sc->sc_vchan_params.channels * NBBY /
+		    sc->sc_vchan_params.precision;
+	}
+	mutex_exit(sc->sc_lock);
+
+	return error;
+}
+
 static int
 vchan_autoconfig(struct audio_softc *sc)
 {

Index: src/sys/dev/audiovar.h
diff -u src/sys/dev/audiovar.h:1.65 src/sys/dev/audiovar.h:1.66
--- src/sys/dev/audiovar.h:1.65	Sun Sep 24 23:40:41 2017
+++ src/sys/dev/audiovar.h	Thu Oct 26 22:38:27 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: audiovar.h,v 1.65 2017/09/24 23:40:41 nat Exp $	*/
+/*	$NetBSD: audiovar.h,v 1.66 2017/10/26 22:38:27 nat Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -205,6 +205,7 @@ struct audio_softc {
 	bool		sc_rec_started;
 	bool		sc_writeme;
 	bool		sc_ready;	/* audio hw configured properly */
+	unsigned int	sc_latency;
 	int		sc_opens;
 	int		sc_recopens;
 	bool		sc_dying;

Reply via email to