Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src The audio sub-system now supports the following features as



details:   https://anonhg.NetBSD.org/src/rev/461ed45fda22
branches:  trunk
changeset: 349350:461ed45fda22
user:      nat <nat%NetBSD.org@localhost>
date:      Thu Dec 08 10:28:44 2016 +0000

description:
The audio sub-system now supports the following features as
posted to tech-kern:

    * Simultaneous playback and mixing of multiple streams
    * Playback streams can be of different encoding, frequency, precision
      and number of channels
    * Simultaneous recording to different formats
    * One audio device per process
    * Sysctls to set the common format frequency, precision and channels
    * Independent mixer controls for recording/playback per stream
    * Utilizes little cpu time for multiple streams / good performance
    * Compatible with existing programs that use OSS/NetBSD audio
    * Changes to audioctl(1) to allow specifying process id for corresponding
      audio device

diffstat:

 sys/dev/audio.c                |  3094 +++++++++++++++++++++++++++++----------
 sys/dev/audiovar.h             |   130 +-
 sys/dev/files.audio            |     4 +-
 sys/miscfs/specfs/spec_vnops.c |     6 +-
 sys/sys/audioio.h              |     8 +-
 sys/sys/conf.h                 |     3 +-
 usr.bin/audio/ctl/audioctl.1   |    17 +-
 usr.bin/audio/ctl/ctl.c        |    24 +-
 8 files changed, 2402 insertions(+), 884 deletions(-)

diffs (truncated from 5100 to 300 lines):

diff -r 831dbadf7ae2 -r 461ed45fda22 sys/dev/audio.c
--- a/sys/dev/audio.c   Thu Dec 08 06:28:21 2016 +0000
+++ b/sys/dev/audio.c   Thu Dec 08 10:28:44 2016 +0000
@@ -1,6 +1,9 @@
-/*     $NetBSD: audio.c,v 1.268 2016/07/14 10:19:05 msaitoh Exp $      */
+/*     $NetBSD: audio.c,v 1.269 2016/12/08 10:28:44 nat Exp $  */
 
 /*-
+ * Copyright (c) 2016 Nathanial Sloss <nathanialsloss%yahoo.com.au@localhost>
+ * All rights reserved.
+ *
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
@@ -109,16 +112,6 @@
  *   sc_intr_lock.  This is to ensure that groups of hardware operations are
  *   made atomically.  SLEEPS CANNOT OCCUR WITH THIS LOCK HELD.
  *
- * - sc_dvlock, private to this module.  This is a custom reader/writer lock
- *   built on sc_lock and a condition variable.  Some operations release
- *   sc_lock in order to allocate memory, to wait for in-flight I/O to
- *   complete, to copy to/from user context, etc.  sc_dvlock serializes
- *   changes to filters and audio device settings while a read/write to the
- *   hardware is in progress.  A write lock is taken only under exceptional
- *   circumstances, for example when opening /dev/audio or changing audio
- *   parameters.  Long term sleeps and copy to/from user space may be done
- *   with this lock held.
- *
  * List of hardware interface methods, and which locks are held when each
  * is called by this module:
  *
@@ -155,11 +148,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.268 2016/07/14 10:19:05 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.269 2016/12/08 10:28:44 nat Exp $");
 
 #include "audio.h"
 #if NAUDIO > 0
 
+#include <sys/types.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/fcntl.h>
@@ -170,6 +164,7 @@
 #include <sys/malloc.h>
 #include <sys/proc.h>
 #include <sys/systm.h>
+#include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/kernel.h>
 #include <sys/signalvar.h>
@@ -177,10 +172,16 @@
 #include <sys/audioio.h>
 #include <sys/device.h>
 #include <sys/intr.h>
+#include <sys/kthread.h>
 #include <sys/cpu.h>
 
 #include <dev/audio_if.h>
 #include <dev/audiovar.h>
+#include <dev/auconv.h>
+#include <dev/auvolconv.h>
+#ifdef VAUDIOSPEAKER
+#include <dev/spkrvar.h>
+#endif
 
 #include <machine/endian.h>
 
@@ -198,6 +199,18 @@
 #define SPECIFIED(x)   (x != ~0)
 #define SPECIFIED_CH(x)        (x != (u_char)~0)
 
+#define VAUDIO_NFORMATS        1
+static const struct audio_format vaudio_formats[VAUDIO_NFORMATS] = {
+       { NULL, AUMODE_PLAY | AUMODE_RECORD,
+#if BYTE_ORDER == LITTLE_ENDIAN
+        AUDIO_ENCODING_SLINEAR_LE,
+#else
+        AUDIO_ENCODING_SLINEAR_BE,
+#endif
+        16, 16, 2, AUFMT_STEREO, 1, { 44100 }
+        }
+};
+
 /* #define AUDIO_PM_IDLE */
 #ifdef AUDIO_PM_IDLE
 int    audio_idle_timeout = 30;
@@ -205,14 +218,15 @@
 
 int    audio_blk_ms = AUDIO_BLK_MS;
 
-int    audiosetinfo(struct audio_softc *, struct audio_info *);
-int    audiogetinfo(struct audio_softc *, struct audio_info *, int);
+int    audiosetinfo(struct audio_softc *, struct audio_info *, bool, int);
+int    audiogetinfo(struct audio_softc *, struct audio_info *, int, int);
 
 int    audio_open(dev_t, struct audio_softc *, int, int, struct lwp *);
-int    audio_close(struct audio_softc *, int, int, struct lwp *);
+int    audio_close(struct audio_softc *, int, int, struct lwp *, int);
 int    audio_read(struct audio_softc *, struct uio *, int);
 int    audio_write(struct audio_softc *, struct uio *, int);
-int    audio_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *);
+int    audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int,
+                   struct lwp *);
 int    audio_poll(struct audio_softc *, int, struct lwp *);
 int    audio_kqfilter(struct audio_softc *, struct knote *);
 paddr_t        audio_mmap(struct audio_softc *, off_t, int);
@@ -223,35 +237,57 @@
 static void mixer_remove(struct audio_softc *);
 static void mixer_signal(struct audio_softc *);
 
-void   audio_init_record(struct audio_softc *);
-void   audio_init_play(struct audio_softc *);
-int    audiostartr(struct audio_softc *);
-int    audiostartp(struct audio_softc *);
+void   audio_init_record(struct audio_softc *, int);
+void   audio_init_play(struct audio_softc *, int);
+int    audiostartr(struct audio_softc *, int);
+int    audiostartp(struct audio_softc *, int);
 void   audio_rint(void *);
 void   audio_pint(void *);
+void   audio_mix(void *);
+void   audio_upmix(void *);
+void   audio_play_thread(void *);
+void   audio_rec_thread(void *);
+void   recswvol_func(struct audio_softc *, struct audio_ringbuffer *, int,
+                     size_t);
+void   recswvol_func8(struct audio_softc *, struct audio_ringbuffer *, int,
+                      size_t);
+void   recswvol_func16(struct audio_softc *, struct audio_ringbuffer *, int,
+                       size_t);
+void   recswvol_func32(struct audio_softc *, struct audio_ringbuffer *, int,
+                       size_t);
+void   saturate_func(struct audio_softc *);
+void   saturate_func8(struct audio_softc *);
+void   saturate_func16(struct audio_softc *);
+void   saturate_func32(struct audio_softc *);
+void   mix_func(struct audio_softc *, struct audio_ringbuffer *, int);
+void   mix_func8(struct audio_softc *, struct audio_ringbuffer *, int);
+void   mix_func16(struct audio_softc *, struct audio_ringbuffer *, int);
+void   mix_func32(struct audio_softc *, struct audio_ringbuffer *, int);
+void   mix_write(void *);
+void   mix_read(void *);
 int    audio_check_params(struct audio_params *);
 
-void   audio_calc_blksize(struct audio_softc *, int);
+void   audio_calc_blksize(struct audio_softc *, int, int);
 void   audio_fill_silence(struct audio_params *, uint8_t *, int);
 int    audio_silence_copyout(struct audio_softc *, int, struct uio *);
 
 void   audio_init_ringbuffer(struct audio_softc *,
                              struct audio_ringbuffer *, int);
-int    audio_initbufs(struct audio_softc *);
-void   audio_calcwater(struct audio_softc *);
-int    audio_drain(struct audio_softc *);
-void   audio_clear(struct audio_softc *);
-void   audio_clear_intr_unlocked(struct audio_softc *sc);
-static inline void audio_pint_silence
-       (struct audio_softc *, struct audio_ringbuffer *, uint8_t *, int);
-
-int    audio_alloc_ring
-       (struct audio_softc *, struct audio_ringbuffer *, int, size_t);
+int    audio_initbufs(struct audio_softc *, int);
+void   audio_calcwater(struct audio_softc *, int);
+int    audio_drain(struct audio_softc *, int);
+void   audio_clear(struct audio_softc *, int);
+void   audio_clear_intr_unlocked(struct audio_softc *sc, int);
+static inline void
+       audio_pint_silence(struct audio_softc *, struct audio_ringbuffer *,
+                          uint8_t *, int, int);
+int    audio_alloc_ring(struct audio_softc *, struct audio_ringbuffer *, int,
+                        size_t);
 void   audio_free_ring(struct audio_softc *, struct audio_ringbuffer *);
 static int audio_setup_pfilters(struct audio_softc *, const audio_params_t *,
-                               stream_filter_list_t *);
+                               stream_filter_list_t *, int);
 static int audio_setup_rfilters(struct audio_softc *, const audio_params_t *,
-                               stream_filter_list_t *);
+                               stream_filter_list_t *, int);
 static void audio_stream_dtor(audio_stream_t *);
 static int audio_stream_ctor(audio_stream_t *, const audio_params_t *, int);
 static void stream_filter_list_append
@@ -263,7 +299,10 @@
 static void stream_filter_list_set
        (stream_filter_list_t *, int, stream_filter_factory_t,
         const audio_params_t *);
-int    audio_set_defaults(struct audio_softc *, u_int);
+int    audio_set_defaults(struct audio_softc *, u_int, int);
+static int audio_sysctl_frequency(SYSCTLFN_PROTO);
+static int audio_sysctl_precision(SYSCTLFN_PROTO);
+static int audio_sysctl_channels(SYSCTLFN_PROTO);
 
 int    audioprobe(device_t, cfdata_t, void *);
 void   audioattach(device_t, device_t, void *);
@@ -295,6 +334,9 @@
 static void    audio_exit(struct audio_softc *);
 static int     audio_waitio(struct audio_softc *, kcondvar_t *);
 
+#define AUDIO_OUTPUT_CLASS 0
+#define AUDIO_INPUT_CLASS 1
+
 struct portname {
        const char *name;
        int mask;
@@ -320,6 +362,19 @@
 int    au_set_port(struct audio_softc *, struct au_mixer_ports *,
                        u_int);
 int    au_get_port(struct audio_softc *, struct au_mixer_ports *);
+static int
+       audio_get_port(struct audio_softc *, mixer_ctrl_t *);
+static int
+       audio_set_port(struct audio_softc *, mixer_ctrl_t *);
+static int
+       audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *);
+static int audio_set_params
+       (struct audio_softc *, int, int, audio_params_t *, audio_params_t *,
+        stream_filter_list_t *, stream_filter_list_t *, int);
+static int
+audio_query_encoding(struct audio_softc *, struct audio_encoding *);
+static int audio_set_vchan_defaults
+       (struct audio_softc *, u_int, const struct audio_format *, int);
 int    au_get_lr_value(struct audio_softc *, mixer_ctrl_t *, int *, int *);
 int    au_set_lr_value(struct audio_softc *, mixer_ctrl_t *, int, int);
 int    au_portof(struct audio_softc *, char *, int);
@@ -358,7 +413,20 @@
        .d_mmap = audiommap,
        .d_kqfilter = audiokqfilter,
        .d_discard = nodiscard,
-       .d_flag = D_OTHER | D_MPSAFE
+       .d_flag = D_MCLOSE | D_MPSAFE
+};
+
+/* The default vchan mode: 44.1 kHz stereo signed linear */
+struct audio_params vchan_default = {
+       .sample_rate = 44100,
+#if BYTE_ORDER == LITTLE_ENDIAN
+       .encoding = AUDIO_ENCODING_SLINEAR_LE,
+#else
+       .encoding = AUDIO_ENCODING_SLINEAR_BE,
+#endif
+       .precision = 16,
+       .validbits = 16,
+       .channels = 2,
 };
 
 /* The default audio mode: 8 kHz mono mu-law */
@@ -392,7 +460,9 @@
 {
        struct audio_softc *sc;
        struct audio_attach_args *sa;
+       struct virtual_channel *vc;
        const struct audio_hw_if *hwp;
+       const struct sysctlnode *node;
        void *hdlp;
        int error;
        mixer_devinfo_t mi;
@@ -405,10 +475,39 @@
        sa = aux;
        hwp = sa->hwif;
        hdlp = sa->hdl;
+       sc->sc_opens = 0;
+       sc->sc_recopens = 0;
+       sc->sc_aivalid = false;
+
+       sc->sc_trigger_started = false;
+       sc->sc_rec_started = false;
+       sc->sc_vchan[0] = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
+       vc = sc->sc_vchan[0];
+       memset(sc->sc_audiopid, -1, sizeof(sc->sc_audiopid));
+       memset(sc->sc_despid, -1, sizeof(sc->sc_despid));
+       vc->sc_open = 0;
+       vc->sc_mode = 0;
+       vc->sc_npfilters = 0;
+       memset(vc->sc_pfilters, 0,
+           sizeof(vc->sc_pfilters));
+       vc->sc_lastinfovalid = false;
+       vc->sc_swvol = 255;
+       vc->sc_recswvol = 255;
+       sc->sc_iffreq = 44100;
+       sc->sc_precision = 16;
+       sc->sc_channels = 2;
+
+       if (auconv_create_encodings(vaudio_formats, VAUDIO_NFORMATS,
+           &sc->sc_encodings) != 0) {
+               aprint_error_dev(self, "couldn't create encodings\n");
+               return;
+       }
 
        cv_init(&sc->sc_rchan, "audiord");
        cv_init(&sc->sc_wchan, "audiowr");
        cv_init(&sc->sc_lchan, "audiolk");
+       cv_init(&sc->sc_condvar,"play");
+       cv_init(&sc->sc_rcondvar,"record");
 
        if (hwp == 0 || hwp->get_locks == 0) {
                aprint_error(": missing method\n");
@@ -438,7 +537,6 @@
        sc->hw_if = hwp;



Home | Main Index | Thread Index | Old Index