1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1993-2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
30*7c478bd9Sstevel@tonic-gate #include <stdio.h>
31*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <Audio.h>
40*7c478bd9Sstevel@tonic-gate #include <AudioFile.h>
41*7c478bd9Sstevel@tonic-gate #include <AudioPipe.h>
42*7c478bd9Sstevel@tonic-gate #include <AudioRawPipe.h>
43*7c478bd9Sstevel@tonic-gate #include <AudioLib.h>
44*7c478bd9Sstevel@tonic-gate #include <AudioHdr.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #include <libaudio.h>
47*7c478bd9Sstevel@tonic-gate #include <audio/au.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate extern char *Stdin;
50*7c478bd9Sstevel@tonic-gate extern char *Stdout;
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include <convert.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate // append contents of buffer to output audio stream.
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate AudioError
57*7c478bd9Sstevel@tonic-gate write_output(AudioBuffer* buf, AudioStream* ofp)
58*7c478bd9Sstevel@tonic-gate {
59*7c478bd9Sstevel@tonic-gate 	unsigned char 	*cp;
60*7c478bd9Sstevel@tonic-gate 	size_t		len;
61*7c478bd9Sstevel@tonic-gate 	Double		pos;
62*7c478bd9Sstevel@tonic-gate 	AudioError	err;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	pos = ofp->GetLength();
65*7c478bd9Sstevel@tonic-gate 	len = (size_t)buf->GetHeader().Time_to_Bytes(buf->GetLength());
66*7c478bd9Sstevel@tonic-gate 	cp = (unsigned char *)buf->GetAddress();
67*7c478bd9Sstevel@tonic-gate 	err = ofp->WriteData(cp, len, pos);
68*7c478bd9Sstevel@tonic-gate 	return (err);
69*7c478bd9Sstevel@tonic-gate }
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate // open input file and return ptr to AudioUnixFile object
72*7c478bd9Sstevel@tonic-gate // path is the path to the file (or set to Stdin if standard input).
73*7c478bd9Sstevel@tonic-gate // ihdr is the input header (only used for openning raw files)
74*7c478bd9Sstevel@tonic-gate // israw flags if it's a raw file. if fflag is set, ignore an
75*7c478bd9Sstevel@tonic-gate // any existing header on raw files. offset indicates where to
76*7c478bd9Sstevel@tonic-gate // start reading the file (raw files only ??).
77*7c478bd9Sstevel@tonic-gate AudioUnixfile *open_input_file(const char *path, const AudioHdr ihdr,
78*7c478bd9Sstevel@tonic-gate 				    int israw, int fflag, off_t offset,
79*7c478bd9Sstevel@tonic-gate 				    format_type& fmt)
80*7c478bd9Sstevel@tonic-gate {
81*7c478bd9Sstevel@tonic-gate 	AudioUnixfile*	ifp;
82*7c478bd9Sstevel@tonic-gate 	int		fd;
83*7c478bd9Sstevel@tonic-gate 	int		file_type; // ignore this ...
84*7c478bd9Sstevel@tonic-gate 	int		infosize; // ignore this ...
85*7c478bd9Sstevel@tonic-gate 	au_filehdr_t	fhdr;
86*7c478bd9Sstevel@tonic-gate 	Audio_hdr	ohdr;	// ignore this ...
87*7c478bd9Sstevel@tonic-gate 	unsigned int	hsize;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	// need to let caller know what format this is. so far, only raw
90*7c478bd9Sstevel@tonic-gate 	// and sun are supported....
91*7c478bd9Sstevel@tonic-gate 	fmt = (israw ? F_RAW : F_SUN);
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	// no file
94*7c478bd9Sstevel@tonic-gate 	if (!path) {
95*7c478bd9Sstevel@tonic-gate 		// no file? shouldn't happen. bomb out.
96*7c478bd9Sstevel@tonic-gate 		Err(MGET("no input file specified\n"));
97*7c478bd9Sstevel@tonic-gate 		exit(1);
98*7c478bd9Sstevel@tonic-gate 	}
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	// deal with stdin
101*7c478bd9Sstevel@tonic-gate 	if (path == Stdin) {
102*7c478bd9Sstevel@tonic-gate 		if (isatty(fileno(stdin))) {
103*7c478bd9Sstevel@tonic-gate 			Err(MGET(
104*7c478bd9Sstevel@tonic-gate 			    "Stdin is a tty, please specify an input file\n"));
105*7c478bd9Sstevel@tonic-gate 			exit(1);
106*7c478bd9Sstevel@tonic-gate 		}
107*7c478bd9Sstevel@tonic-gate 		if (israw) {
108*7c478bd9Sstevel@tonic-gate 			// XXX - need to check if stdin has a file
109*7c478bd9Sstevel@tonic-gate 			// header and ignore it if fflag not set.
110*7c478bd9Sstevel@tonic-gate 			ifp = new AudioRawPipe(fileno(stdin),
111*7c478bd9Sstevel@tonic-gate 					    (FileAccess)ReadOnly, ihdr, path,
112*7c478bd9Sstevel@tonic-gate 					    offset);
113*7c478bd9Sstevel@tonic-gate 		} else {
114*7c478bd9Sstevel@tonic-gate 			ifp = new AudioPipe(fileno(stdin), (FileAccess)ReadOnly,
115*7c478bd9Sstevel@tonic-gate 					    path);
116*7c478bd9Sstevel@tonic-gate 		}
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 		if (!ifp) {
119*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't open pipe to %s, skipping...\n"),
120*7c478bd9Sstevel@tonic-gate 			    Stdin);
121*7c478bd9Sstevel@tonic-gate 		}
122*7c478bd9Sstevel@tonic-gate 		return (ifp);
123*7c478bd9Sstevel@tonic-gate 	}
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	// fall through for real files ...
126*7c478bd9Sstevel@tonic-gate 	if (israw) {
127*7c478bd9Sstevel@tonic-gate 		if ((fd = open(path, O_RDONLY)) < 0) {
128*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't open %s, skipping...\n"), path);
129*7c478bd9Sstevel@tonic-gate 			perror(MGET("open"));
130*7c478bd9Sstevel@tonic-gate 			return (NULL);
131*7c478bd9Sstevel@tonic-gate 		}
132*7c478bd9Sstevel@tonic-gate 		if (!fflag) {
133*7c478bd9Sstevel@tonic-gate 			// check if file already has a hdr.
134*7c478bd9Sstevel@tonic-gate 			if (hsize = read(fd, (char *)&fhdr, sizeof (fhdr))
135*7c478bd9Sstevel@tonic-gate 			    < 0) {
136*7c478bd9Sstevel@tonic-gate 				perror("read");
137*7c478bd9Sstevel@tonic-gate 				exit(1);
138*7c478bd9Sstevel@tonic-gate 			}
139*7c478bd9Sstevel@tonic-gate 			if (lseek(fd, 0, 0) < 0) {  // reset
140*7c478bd9Sstevel@tonic-gate 				perror("lseek");
141*7c478bd9Sstevel@tonic-gate 				exit(1);
142*7c478bd9Sstevel@tonic-gate 			}
143*7c478bd9Sstevel@tonic-gate 			if (hsize != sizeof (fhdr)) {
144*7c478bd9Sstevel@tonic-gate 				// no hdr - file too small,
145*7c478bd9Sstevel@tonic-gate 				// assume data is ok (tho it
146*7c478bd9Sstevel@tonic-gate 				// probably won't be) ...
147*7c478bd9Sstevel@tonic-gate 				ifp = new AudioRawPipe(fd, (FileAccess)ReadOnly,
148*7c478bd9Sstevel@tonic-gate 							    ihdr, path, offset);
149*7c478bd9Sstevel@tonic-gate 			} else {
150*7c478bd9Sstevel@tonic-gate 				// Check the validity of the
151*7c478bd9Sstevel@tonic-gate 				// header and get the size of
152*7c478bd9Sstevel@tonic-gate 				// the info field
153*7c478bd9Sstevel@tonic-gate 				if (audio_decode_filehdr(fd,
154*7c478bd9Sstevel@tonic-gate 				    (unsigned char *)&fhdr, &file_type, &ohdr,
155*7c478bd9Sstevel@tonic-gate 				    &infosize) == AUDIO_SUCCESS) {
156*7c478bd9Sstevel@tonic-gate 					close(fd); // create AudioFile()
157*7c478bd9Sstevel@tonic-gate 					// issue a warning
158*7c478bd9Sstevel@tonic-gate 					Err(
159*7c478bd9Sstevel@tonic-gate 				MGET("%s has a file header, ignoring -i ...\n"),
160*7c478bd9Sstevel@tonic-gate 					    path);
161*7c478bd9Sstevel@tonic-gate 					fmt = F_SUN; // was raw ...
162*7c478bd9Sstevel@tonic-gate 					ifp = new AudioFile(path,
163*7c478bd9Sstevel@tonic-gate 						    (FileAccess)ReadOnly);
164*7c478bd9Sstevel@tonic-gate 				} else {
165*7c478bd9Sstevel@tonic-gate 					// no hdr, create AudioRawPipe.
166*7c478bd9Sstevel@tonic-gate 					ifp = new AudioRawPipe(fd,
167*7c478bd9Sstevel@tonic-gate 						    (FileAccess)ReadOnly, ihdr,
168*7c478bd9Sstevel@tonic-gate 						    path, offset);
169*7c478bd9Sstevel@tonic-gate 				}
170*7c478bd9Sstevel@tonic-gate 			}
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 		} else {	// force flag - don't even look for header
173*7c478bd9Sstevel@tonic-gate 			ifp = new AudioRawPipe(fd, (FileAccess)ReadOnly, ihdr,
174*7c478bd9Sstevel@tonic-gate 						    path, offset);
175*7c478bd9Sstevel@tonic-gate 		}
176*7c478bd9Sstevel@tonic-gate 	} else {
177*7c478bd9Sstevel@tonic-gate 		ifp = new AudioFile(path, (FileAccess)ReadOnly);
178*7c478bd9Sstevel@tonic-gate 	}
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	if (!ifp) {
181*7c478bd9Sstevel@tonic-gate 		Err(MGET("can't open %s, skipping...\n"), path);
182*7c478bd9Sstevel@tonic-gate 	}
183*7c478bd9Sstevel@tonic-gate 	return (ifp);
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate // given a path, find the file it really points to (if it's a
187*7c478bd9Sstevel@tonic-gate // sym-link). return it's stat buf and real path.
188*7c478bd9Sstevel@tonic-gate void
189*7c478bd9Sstevel@tonic-gate get_realfile(char *&path, struct stat *st)
190*7c478bd9Sstevel@tonic-gate {
191*7c478bd9Sstevel@tonic-gate 	static char	tmpf[MAXPATHLEN]; // for reading sym-link
192*7c478bd9Sstevel@tonic-gate 	int		err;	// for stat err
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	// first see if it's a sym-link and find real file
195*7c478bd9Sstevel@tonic-gate 	err = 0;
196*7c478bd9Sstevel@tonic-gate 	while (err == 0) {
197*7c478bd9Sstevel@tonic-gate 		if (err = lstat(path, st) < 0) {
198*7c478bd9Sstevel@tonic-gate 			perror("lstat");
199*7c478bd9Sstevel@tonic-gate 			exit(1);
200*7c478bd9Sstevel@tonic-gate 		}
201*7c478bd9Sstevel@tonic-gate 		if (!err && S_ISLNK(st->st_mode)) {
202*7c478bd9Sstevel@tonic-gate 			err = readlink(path, tmpf,
203*7c478bd9Sstevel@tonic-gate 					(sizeof (tmpf) - 1));
204*7c478bd9Sstevel@tonic-gate 			if (err > 0) {
205*7c478bd9Sstevel@tonic-gate 				tmpf[err] = '\0';
206*7c478bd9Sstevel@tonic-gate 				path = tmpf;
207*7c478bd9Sstevel@tonic-gate 				err = 0;
208*7c478bd9Sstevel@tonic-gate 			}
209*7c478bd9Sstevel@tonic-gate 		} else {
210*7c478bd9Sstevel@tonic-gate 			break;
211*7c478bd9Sstevel@tonic-gate 		}
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate }
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate // create output audio file. if no path is supplied, use stdout.
217*7c478bd9Sstevel@tonic-gate // returns a ptr to an AudioUnixFile object.
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate AudioUnixfile*
220*7c478bd9Sstevel@tonic-gate create_output_file(
221*7c478bd9Sstevel@tonic-gate 	const char *path,
222*7c478bd9Sstevel@tonic-gate 	const AudioHdr ohdr,
223*7c478bd9Sstevel@tonic-gate 	format_type ofmt,
224*7c478bd9Sstevel@tonic-gate 	const char *infoString)
225*7c478bd9Sstevel@tonic-gate {
226*7c478bd9Sstevel@tonic-gate 	AudioUnixfile*	ofp = 0;
227*7c478bd9Sstevel@tonic-gate 	AudioError	err;	// for error msgs
228*7c478bd9Sstevel@tonic-gate 	int		fd;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	if (!path) {
231*7c478bd9Sstevel@tonic-gate 		if (isatty(fileno(stdout))) {
232*7c478bd9Sstevel@tonic-gate 			Err(
233*7c478bd9Sstevel@tonic-gate 		    MGET("Stdout is a tty, please specify an output file\n"));
234*7c478bd9Sstevel@tonic-gate 			exit(1);
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 		path = Stdout;
238*7c478bd9Sstevel@tonic-gate 		if (ofmt == F_RAW) {
239*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioRawPipe(fileno(stdout),
240*7c478bd9Sstevel@tonic-gate 						    (FileAccess)WriteOnly, ohdr,
241*7c478bd9Sstevel@tonic-gate 						    path))) {
242*7c478bd9Sstevel@tonic-gate 				Err(
243*7c478bd9Sstevel@tonic-gate 			    MGET("can't create audio raw stdout pipe\n"));
244*7c478bd9Sstevel@tonic-gate 				exit(1);
245*7c478bd9Sstevel@tonic-gate 			}
246*7c478bd9Sstevel@tonic-gate 		} else if (ofmt == F_SUN) {
247*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioPipe(fileno(stdout),
248*7c478bd9Sstevel@tonic-gate 					    (FileAccess)WriteOnly, path))) {
249*7c478bd9Sstevel@tonic-gate 				Err(
250*7c478bd9Sstevel@tonic-gate 			    MGET("can't create audio pipe for stdout\n"));
251*7c478bd9Sstevel@tonic-gate 				exit(1);
252*7c478bd9Sstevel@tonic-gate 			}
253*7c478bd9Sstevel@tonic-gate 		} else {
254*7c478bd9Sstevel@tonic-gate 			// XXX - should never happen ...
255*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't create output file, unknown format\n"));
256*7c478bd9Sstevel@tonic-gate 			exit(1);
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 	} else {
259*7c478bd9Sstevel@tonic-gate 		if (ofmt == F_RAW) {
260*7c478bd9Sstevel@tonic-gate 			// first open file, then attach pipe to it
261*7c478bd9Sstevel@tonic-gate 			if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC,
262*7c478bd9Sstevel@tonic-gate 				    0666)) < 0) {
263*7c478bd9Sstevel@tonic-gate 				perror(MGET("open"));
264*7c478bd9Sstevel@tonic-gate 				Err(MGET("can't create output file %s\n"),
265*7c478bd9Sstevel@tonic-gate 				    path);
266*7c478bd9Sstevel@tonic-gate 				exit(1);
267*7c478bd9Sstevel@tonic-gate 			}
268*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioRawPipe(fd, (FileAccess)WriteOnly,
269*7c478bd9Sstevel@tonic-gate 						    ohdr, path))) {
270*7c478bd9Sstevel@tonic-gate 				Err(MGET("can't create raw audio pipe %s\n"),
271*7c478bd9Sstevel@tonic-gate 				    path);
272*7c478bd9Sstevel@tonic-gate 				exit(1);
273*7c478bd9Sstevel@tonic-gate 			}
274*7c478bd9Sstevel@tonic-gate 		} else if (ofmt == F_SUN) {
275*7c478bd9Sstevel@tonic-gate 			if (!(ofp = new AudioFile(path,
276*7c478bd9Sstevel@tonic-gate 						    (FileAccess)ReadWrite))) {
277*7c478bd9Sstevel@tonic-gate 				Err(MGET("can't create output file %s\n"),
278*7c478bd9Sstevel@tonic-gate 				    path);
279*7c478bd9Sstevel@tonic-gate 				exit(1);
280*7c478bd9Sstevel@tonic-gate 			}
281*7c478bd9Sstevel@tonic-gate 		} else {
282*7c478bd9Sstevel@tonic-gate 			// XXX - should never happen ...
283*7c478bd9Sstevel@tonic-gate 			Err(MGET("can't create output file, unknown format\n"));
284*7c478bd9Sstevel@tonic-gate 			exit(1);
285*7c478bd9Sstevel@tonic-gate 		}
286*7c478bd9Sstevel@tonic-gate 	}
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	// set the info string.
289*7c478bd9Sstevel@tonic-gate 	ofp->SetInfostring(infoString, -1);
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	// set the header and create the output audio object
292*7c478bd9Sstevel@tonic-gate 	if ((err = ofp->SetHeader(ohdr)) != AUDIO_SUCCESS) {
293*7c478bd9Sstevel@tonic-gate 		Err(MGET("can't set hdr on output file: %s\n"), err.msg());
294*7c478bd9Sstevel@tonic-gate 		exit(1);
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 	if ((err = ofp->Create()) != AUDIO_SUCCESS) {
297*7c478bd9Sstevel@tonic-gate 		Err(MGET("can't create output file: %s\n"), err.msg());
298*7c478bd9Sstevel@tonic-gate 		exit(1);
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	return (ofp);
302*7c478bd9Sstevel@tonic-gate }
303