Subject: kern/3357: Short writes to /dev/audio are padded with silence.
To: None <gnats-bugs@gnats.netbsd.org>
From: Lennart Augustsson <augustss@cs.chalmers.se>
List: netbsd-bugs
Date: 03/19/1997 01:33:19
>Number:         3357
>Category:       kern
>Synopsis:       Short writes to /dev/audio are padded with silence.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Mar 18 16:50:02 1997
>Last-Modified:
>Originator:     Lennart Augustsson
>Organization:
Department of Computing Science, Chalmers University
>Release:        NetBSD-current 970319
>Environment:
System: NetBSD calvin.cs.chalmers.se 1.2D NetBSD 1.2D (CALVIN) #130: Wed Mar 19 00:55:02 MET 1997 augustss@calvin.cs.chalmers.se:/usr/src/sys/arch/i386/compile/CALVIN i386


>Description:
	If a write to the audio device is not a multiple of the audio
	blocksize it is padded with silence.
	This is contrary to the behaviour on most systems (e.g. Solaris
	and Linux), and is in my opinion counter-intuitive.

	The fix here adds a flag to remove the silence padding.  It also
	makes this mode (AUMODE_NO_PAD) and the AUMODE_PLAY_ALL the default.
	This is a change of behaviour, but there don't seem to be many
	NetBSD audio applications out there that would suffer.  It will also
	make NetBSD much more compatible with other systems.
	If we don't make these modes the default then some hacking is
	needed in all emulation modes to set these flags when /dev/audio
	is opened.  I think making them default is a better idea.

	This patch together with my previous patch for Linux audio
	emulation makes raplayer work nicely.

>How-To-Repeat:
	Try this and listen
	dd if=some-file.au of=/dev/audio bs=88
>Fix:
	Apply this patch:


diff -c -r /usr/src/sys/auold/dev/audio.c /usr/src/sys/dev/audio.c
*** /usr/src/sys/auold/dev/audio.c	Wed Mar 19 00:26:54 1997
--- /usr/src/sys/dev/audio.c	Wed Mar 19 00:53:35 1997
***************
*** 608,613 ****
--- 608,615 ----
  		audiostartr(sc);
  	    }
  	}
+ 	/* Play all sample, and don't pad short writes by default */
+ 	sc->sc_mode |= AUMODE_PLAY_ALL | AUMODE_NO_PAD;
  	splx(s);
  	return (0);
  }
***************
*** 957,962 ****
--- 959,990 ----
  	error = 0;
  
  	while (uio->uio_resid > 0) {
+ 		if ((sc->sc_mode & AUMODE_NO_PAD) && cb->fill > 0) {
+ 			if (sc->sc_pbus == 0) {
+ 				/* playing has stopped, ignore fill */
+ 				cb->fill = 0;
+ 			} else {
+ 				/* Write samples in the silence fill space.
+ 				 * We don't know where the DMA is
+ 				 * happening in the buffer, but if we
+ 				 * are lucky we will fill the buffer before
+ 				 * playing has reached the point we move to.
+ 				 * If we are unlucky some sample will
+ 				 * not be played.
+ 				 */
+ 				cc = min(cb->fill, uio->uio_resid);
+ 				error = uiomove(cb->otp, cc, uio);
+ 				if (error == 0) {
+ 					if (hw->sw_encode) {
+ 						hw->sw_encode(sc->hw_hdl, sc->sc_pencoding, 
+ 							      cb->otp, cc);
+ 					}
+ 					cb->fill -= cc;
+ 					cb->otp += cc;
+ 				}
+ 				continue;
+ 			}
+ 		}
  		if (cb->nblk >= sc->sc_hiwat) {
  			do {
  				DPRINTF(("audio_write: nblk=%d hiwat=%d lowat=%d\n", cb->nblk, sc->sc_hiwat, sc->sc_lowat));
***************
*** 1028,1033 ****
--- 1056,1063 ----
  				/* fill with audio silence */
  				tp += cc;
  				cc = blocksize - cc;
+ 				cb->fill = cc;
+ 				cb->otp = tp;
  				audio_fill_silence(sc->sc_pencoding, tp, cc);
  				DPRINTF(("audio_write: auzero 0x%x %d 0x%x\n",
  				         tp, cc, *(int *)tp));
diff -c -r /usr/src/sys/auold/dev/audiovar.h /usr/src/sys/dev/audiovar.h
*** /usr/src/sys/auold/dev/audiovar.h	Wed Mar 19 00:26:54 1997
--- /usr/src/sys/dev/audiovar.h	Wed Mar 19 00:54:42 1997
***************
*** 78,83 ****
--- 78,86 ----
  	u_short	cb_pause;	/* io paused */
  	u_long	cb_drops;	/* missed samples from over/underrun */
  	u_long	cb_pdrops;	/* paused samples */
+ 
+ 	u_char	*otp;		/* point where silence padding started */
+ 	int	fill;		/* number of silence pad bytes */
  };
  
  /*
diff -c -r /usr/src/sys/auold/sys/audioio.h /usr/src/sys/sys/audioio.h
*** /usr/src/sys/auold/sys/audioio.h	Wed Jan 22 18:46:50 1997
--- /usr/src/sys/sys/audioio.h	Wed Mar 19 00:31:08 1997
***************
*** 74,79 ****
--- 74,80 ----
  #define AUMODE_PLAY	0x01
  #define AUMODE_RECORD	0x02
  #define AUMODE_PLAY_ALL	0x04	/* play all samples--no real-time correction */
+ #define AUMODE_NO_PAD	0x08	/* don't silence pad short writes */
  };
  typedef struct audio_info audio_info_t;
  
>Audit-Trail:
>Unformatted: