Subject: bin/12328: audioplay overruns with RIFF WAVE file
To: None <gnats-bugs@gnats.netbsd.org>
From: None <takashi.yamamoto@bigfoot.com>
List: netbsd-bugs
Date: 03/04/2001 19:59:48
>Number: 12328
>Category: bin
>Synopsis: audioplay overruns with RIFF WAVE file
>Confidential: yes
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Mar 04 03:03:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: YAMAMOTO Takashi
>Release: current
>Organization:
>Environment:
System: NetBSD capybara 1.5S NetBSD 1.5S (stg) #136: Sun Mar 4 17:23:02 JST 2001 takashi@capybara:/usr/src/sys/arch/i386/compile/stg i386
Architecture: i386
Machine: i386
>Description:
audioplay simply reads wav file until EOF.
so chunks after data chunk causes noises.
>How-To-Repeat:
play RIFF WAVE file which has any chunks after data chunk.
(ex. windows98's "%WINDIR%\media\The Microsoft Sount.wav")
>Fix:
apply following patches.
I'm not sure that it works with sun audio files because I don't know
their format.
Index: common/audio.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/audio/common/audio.c,v
retrieving revision 1.10
diff -u -r1.10 audio.c
--- audio.c 2000/12/13 08:19:54 1.10
+++ audio.c 2001/03/04 10:58:27
@@ -178,13 +178,14 @@
* find a .wav header, etc. returns header length on success
*/
size_t
-audio_parse_wav_hdr(hdr, sz, enc, prec, sample, channels)
+audio_parse_wav_hdr(hdr, sz, enc, prec, sample, channels, datasize)
void *hdr;
size_t sz;
int *enc;
int *prec;
int *sample;
int *channels;
+ size_t *datasize;
{
char *where = hdr;
wav_audioheaderpart *part;
@@ -274,6 +275,8 @@
*sample = getle32(fmt->sample_rate);
*enc = newenc;
*prec = newprec;
+ if (datasize)
+ *datasize = (size_t)getle32(part->len);
part++;
return ((char *)part - (char *)hdr);
}
Index: common/libaudio.h
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/audio/common/libaudio.h,v
retrieving revision 1.6
diff -u -r1.6 libaudio.h
--- libaudio.h 2000/12/22 11:38:42 1.6
+++ libaudio.h 2001/03/04 10:58:29
@@ -127,7 +127,7 @@
} wav_audioheaderfmt __attribute__((__packed__));
/* returns size of header, or -1 */
-size_t audio_parse_wav_hdr (void *, size_t, int *, int *, int *, int *);
+size_t audio_parse_wav_hdr (void *, size_t, int *, int *, int *, int *, size_t *);
/*
* audio routine error codes
Index: play/play.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/audio/play/play.c,v
retrieving revision 1.22
diff -u -r1.22 play.c
--- play.c 2001/02/19 23:03:44 1.22
+++ play.c 2001/03/04 10:56:53
@@ -49,7 +49,7 @@
void usage (void);
void play (char *);
void play_fd (char *, int);
-ssize_t audioctl_write_fromhdr (void *, size_t, int);
+ssize_t audioctl_write_fromhdr (void *, size_t, int, size_t *);
audio_info_t info;
int volume;
@@ -201,6 +201,7 @@
struct stat sb;
void *addr, *oaddr;
off_t filesize;
+ size_t datasize;
ssize_t hdrlen;
int fd;
@@ -242,7 +243,7 @@
* get the header length and set up the audio device
*/
if ((hdrlen = audioctl_write_fromhdr(addr,
- (size_t)filesize, ctlfd)) < 0) {
+ (size_t)filesize, ctlfd, &datasize)) < 0) {
if (play_errstring)
errx(1, "%s: %s", play_errstring, file);
else
@@ -251,14 +252,18 @@
filesize -= hdrlen;
addr = (char *)addr + hdrlen;
+ if (filesize < datasize || datasize == 0) {
+ warn("bogus datasize:%u", datasize);
+ datasize = filesize;
+ }
- while (filesize > bufsize) {
+ while (datasize > bufsize) {
if (write(audiofd, addr, bufsize) != bufsize)
err(1, "write failed");
addr = (char *)addr + bufsize;
- filesize -= bufsize;
+ datasize -= bufsize;
}
- if (write(audiofd, addr, (size_t)filesize) != (ssize_t)filesize)
+ if (write(audiofd, addr, (size_t)datasize) != (ssize_t)datasize)
err(1, "final write failed");
if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag)
@@ -279,7 +284,9 @@
{
char *buffer = malloc(bufsize);
ssize_t hdrlen;
- int n, m;
+ int n;
+ size_t datasize;
+ size_t datainbuf;
if (buffer == NULL)
err(1, "malloc of read buffer failed");
@@ -291,7 +298,7 @@
if (n == 0)
errx(1, "EOF on standard input");
- hdrlen = audioctl_write_fromhdr(buffer, n, ctlfd);
+ hdrlen = audioctl_write_fromhdr(buffer, n, ctlfd, &datasize);
if (hdrlen < 0) {
if (play_errstring)
errx(1, "%s: %s", play_errstring, file);
@@ -306,17 +313,26 @@
err(1, "bogus hdrlen %d > length %d?", (int)hdrlen, n);
memmove(buffer, buffer + hdrlen, n - hdrlen);
-
- m = read(fd, buffer + n, hdrlen);
- n += m;
}
- /* read until EOF or error */
+
+ datainbuf = n;
do {
- if (n == -1)
- err(1, "read of standard input failed");
- if (write(audiofd, buffer, n) != n)
+ if (datasize < datainbuf) {
+ datainbuf = datasize;
+ }
+ else {
+ n = read(fd, buffer + datainbuf, MIN(bufsize - datainbuf, datasize));
+ if (n == -1)
+ err(1, "read of %s failed", file);
+ datainbuf += n;
+ }
+ if (write(audiofd, buffer, datainbuf) != datainbuf)
err(1, "write failed");
- } while ((n = read(fd, buffer, bufsize)));
+
+ datasize -= datainbuf;
+ datainbuf = 0;
+ }
+ while (datasize);
if (ioctl(audiofd, AUDIO_DRAIN) < 0 && !qflag)
warn("audio drain ioctl failed");
@@ -329,10 +345,11 @@
* uses the local "info" variable. blah... fix me!
*/
ssize_t
-audioctl_write_fromhdr(hdr, fsz, fd)
+audioctl_write_fromhdr(hdr, fsz, fd, datasize)
void *hdr;
size_t fsz;
int fd;
+ size_t *datasize;
{
sun_audioheader *sunhdr;
ssize_t hdr_len;
@@ -354,11 +371,12 @@
info.play.channels = ntohl(sunhdr->channels);
hdr_len = ntohl(sunhdr->hdr_size);
+ *datasize = ntohl(sunhdr->data_size);
goto set_audio_mode;
}
hdr_len = audio_parse_wav_hdr(hdr, fsz, &info.play.encoding,
- &info.play.precision, &info.play.sample_rate, &info.play.channels);
+ &info.play.precision, &info.play.sample_rate, &info.play.channels, datasize);
switch (hdr_len) {
case AUDIO_ESHORTHDR:
>Release-Note:
>Audit-Trail:
>Unformatted: