1 /* $NetBSD: play.c,v 1.49 2008/05/29 14:51:27 mrg Exp $ */
4 * Copyright (c) 1999 Matthew R. Green
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: play.c,v 1.49 2008/05/29 14:51:27 mrg Exp $");
35 #include <sys/param.h>
36 #include <sys/audioio.h>
37 #include <sys/ioctl.h>
54 int main(int, char *[]);
57 void play_fd(const char *, int);
58 ssize_t
audioctl_write_fromhdr(void *, size_t, int, size_t *, const char *);
59 void cleanup(int) __dead
;
74 char const *play_errstring
= NULL
;
77 int exitstatus
= EXIT_SUCCESS
;
87 const char *defdevice
= _PATH_SOUND
;
88 const char *device
= NULL
;
90 while ((ch
= getopt(argc
, argv
, "b:C:c:d:e:fhip:P:qs:Vv:")) != -1) {
93 decode_int(optarg
, &balance
);
94 if (balance
< 0 || balance
> 64)
95 errx(1, "balance must be between 0 and 63");
98 decode_int(optarg
, &channels
);
100 errx(1, "channels must be positive");
103 /* Ignore, compatibility */
109 encoding_str
= optarg
;
121 decode_int(optarg
, &precision
);
122 if (precision
!= 4 && precision
!= 8 &&
123 precision
!= 16 && precision
!= 24 &&
125 errx(1, "precision must be between 4, 8, 16, 24 or 32");
128 len
= strlen(optarg
);
130 if (strncmp(optarg
, "speaker", len
) == 0)
131 port
|= AUDIO_SPEAKER
;
132 else if (strncmp(optarg
, "headphone", len
) == 0)
133 port
|= AUDIO_HEADPHONE
;
134 else if (strncmp(optarg
, "line", len
) == 0)
135 port
|= AUDIO_LINE_OUT
;
138 "port must be `speaker', `headphone', or `line'");
141 decode_int(optarg
, &sample_rate
);
142 if (sample_rate
< 0 || sample_rate
> 48000 * 2) /* XXX */
143 errx(1, "sample rate must be between 0 and 96000");
149 volume
= atoi(optarg
);
150 if (volume
< 0 || volume
> 255)
151 errx(1, "volume must be between 0 and 255");
163 encoding
= audio_enc_to_val(encoding_str
);
165 errx(1, "unknown encoding, bailing...");
168 if (device
== NULL
&& (device
= getenv("AUDIODEVICE")) == NULL
&&
169 (device
= getenv("AUDIODEV")) == NULL
) /* Sun compatibility */
172 audiofd
= open(device
, O_WRONLY
);
173 if (audiofd
< 0 && device
== defdevice
) {
174 device
= _PATH_SOUND0
;
175 audiofd
= open(device
, O_WRONLY
);
179 err(1, "failed to open %s", device
);
181 if (ioctl(audiofd
, AUDIO_GETINFO
, &info
) < 0)
182 err(1, "failed to get audio info");
183 bufsize
= info
.play
.buffer_size
;
184 if (bufsize
< 32 * 1024)
187 signal(SIGINT
, cleanup
);
188 signal(SIGTERM
, cleanup
);
189 signal(SIGHUP
, cleanup
);
196 play_fd("standard input", STDIN_FILENO
);
206 (void)ioctl(audiofd
, AUDIO_FLUSH
, NULL
);
207 (void)ioctl(audiofd
, AUDIO_SETINFO
, &info
);
210 (void)raise_default_signal(signo
);
222 size_t sizet_filesize
;
227 if (file
[0] == '-' && file
[1] == 0) {
228 play_fd("standard input", STDIN_FILENO
);
232 fd
= open(file
, O_RDONLY
);
235 warn("could not open %s", file
);
236 exitstatus
= EXIT_FAILURE
;
240 if (fstat(fd
, &sb
) < 0)
241 err(1, "could not fstat %s", file
);
242 filesize
= sb
.st_size
;
243 sizet_filesize
= (size_t)filesize
;
246 * if the file is not a regular file, doesn't fit in a size_t,
247 * or if we failed to mmap the file, try to read it instead, so
248 * that filesystems, etc, that do not support mmap() work
250 if (S_ISREG(sb
.st_rdev
& S_IFMT
) == 0 ||
251 ((off_t
)sizet_filesize
!= filesize
) ||
252 (oaddr
= addr
= mmap(0, sizet_filesize
, PROT_READ
,
253 MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
260 * give the VM system a bit of a hint about the type
261 * of accesses we will make.
263 if (madvise(addr
, sizet_filesize
, MADV_SEQUENTIAL
) < 0 &&
265 warn("madvise failed, ignoring");
268 * get the header length and set up the audio device
270 if ((hdrlen
= audioctl_write_fromhdr(addr
,
271 sizet_filesize
, audiofd
, &datasize
, file
)) < 0) {
273 errx(1, "%s: %s", play_errstring
, file
);
275 errx(1, "unknown audio file: %s", file
);
279 addr
= (char *)addr
+ hdrlen
;
280 if ((uint64_t)filesize
< datasize
|| datasize
== 0) {
281 if ((uint64_t)filesize
< datasize
)
282 warnx("bogus datasize: %ld", (u_long
)datasize
);
286 while (datasize
> bufsize
) {
287 if ((size_t)write(audiofd
, addr
, bufsize
) != bufsize
)
288 err(1, "write failed");
289 addr
= (char *)addr
+ bufsize
;
292 if ((size_t)write(audiofd
, addr
, datasize
) != datasize
)
293 err(1, "final write failed");
295 if (ioctl(audiofd
, AUDIO_DRAIN
) < 0 && !qflag
)
296 warn("audio drain ioctl failed");
297 if (munmap(oaddr
, sizet_filesize
) < 0)
298 err(1, "munmap failed");
304 * play the file on the file descriptor fd
311 char *buffer
= malloc(bufsize
);
318 err(1, "malloc of read buffer failed");
320 nr
= read(fd
, buffer
, bufsize
);
328 err(1, "unexpected EOF");
330 hdrlen
= audioctl_write_fromhdr(buffer
, nr
, audiofd
, &datasize
, file
);
333 errx(1, "%s: %s", play_errstring
, file
);
335 errx(1, "unknown audio file: %s", file
);
338 if (hdrlen
> nr
) /* shouldn't happen */
339 errx(1, "header seems really large: %lld", (long long)hdrlen
);
340 memmove(buffer
, buffer
+ hdrlen
, nr
- hdrlen
);
343 while (datasize
== 0 || dataout
< datasize
) {
344 if (datasize
!= 0 && dataout
+ nr
> datasize
)
345 nr
= datasize
- dataout
;
346 nw
= write(audiofd
, buffer
, nr
);
350 nr
= read(fd
, buffer
, bufsize
);
356 /* something to think about: no message given for dataout < datasize */
357 if (ioctl(audiofd
, AUDIO_DRAIN
) < 0 && !qflag
)
358 warn("audio drain ioctl failed");
361 err(1, "read of standard input failed");
363 err(1, "audio device write failed");
367 * only support sun and wav audio files so far ...
369 * XXX this should probably be mostly part of libaudio, but it
370 * uses the local "info" variable. blah... fix me!
373 audioctl_write_fromhdr(hdr
, fsz
, fd
, datasize
, file
)
380 sun_audioheader
*sunhdr
;
383 AUDIO_INITINFO(&info
);
385 if (ntohl(sunhdr
->magic
) == AUDIO_FILE_MAGIC
) {
386 if (audio_sun_to_encoding(ntohl(sunhdr
->encoding
),
387 &info
.play
.encoding
, &info
.play
.precision
)) {
389 warnx("unknown unsupported Sun audio encoding"
390 " format %d", ntohl(sunhdr
->encoding
));
396 info
.play
.sample_rate
= ntohl(sunhdr
->sample_rate
);
397 info
.play
.channels
= ntohl(sunhdr
->channels
);
398 hdr_len
= ntohl(sunhdr
->hdr_size
);
400 *datasize
= ntohl(sunhdr
->data_size
);
404 hdr_len
= audio_wav_parse_hdr(hdr
, fsz
, &info
.play
.encoding
,
405 &info
.play
.precision
, &info
.play
.sample_rate
, &info
.play
.channels
,
409 case AUDIO_ESHORTHDR
:
410 case AUDIO_EWAVUNSUPP
:
411 case AUDIO_EWAVBADPCM
:
412 case AUDIO_EWAVNODATA
:
413 play_errstring
= audio_errstring(hdr_len
);
423 * if we don't know it, bail unless we are forcing.
429 info
.play
.port
= port
;
431 info
.play
.gain
= volume
;
433 info
.play
.balance
= balance
;
436 info
.play
.sample_rate
= sample_rate
;
438 info
.play
.channels
= channels
;
440 info
.play
.encoding
= encoding
;
442 info
.play
.precision
= precision
;
445 info
.mode
= AUMODE_PLAY_ALL
;
448 const char *enc
= audio_enc_from_val(info
.play
.encoding
);
450 printf("%s: sample_rate=%d channels=%d "
452 "precision=%d%s%s\n", file
,
453 info
.play
.sample_rate
,
455 (long long)*datasize
,
457 enc
? " encoding=" : "",
461 if (ioctl(fd
, AUDIO_SETINFO
, &info
) < 0)
462 err(1, "failed to set audio info");
471 fprintf(stderr
, "Usage: %s [-hiqV] [options] files\n", getprogname());
472 fprintf(stderr
, "Options:\n\t"
473 "-C audio control device\n\t"
474 "-b balance (0-63)\n\t"
475 "-d audio device\n\t"
476 "-f force settings\n\t"
477 "\t-c forced channels\n\t"
478 "\t-e forced encoding\n\t"
479 "\t-P forced precision\n\t"
480 "\t-s forced sample rate\n\t"
481 "-i header information\n\t"