1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <string.h>
31*0Sstevel@tonic-gate #include <ctype.h>
32*0Sstevel@tonic-gate #include <math.h>
33*0Sstevel@tonic-gate #include <AudioHdr.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #define	irint(d)	((int)d)
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate // Convert a string to lowercase and return an allocated copy of it.
38*0Sstevel@tonic-gate // XXX - There really should be a string-insensitive 8-bit compare routine.
39*0Sstevel@tonic-gate static char *
40*0Sstevel@tonic-gate to_lowercase(
41*0Sstevel@tonic-gate 	char	*str)
42*0Sstevel@tonic-gate {
43*0Sstevel@tonic-gate 	unsigned char	*oldstr;
44*0Sstevel@tonic-gate 	unsigned char	*newstr;
45*0Sstevel@tonic-gate 	int		i;
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate 	oldstr = (unsigned char *) str;
48*0Sstevel@tonic-gate 	newstr = new unsigned char [strlen(str) + 1];
49*0Sstevel@tonic-gate 	for (i = 0; ; i++) {
50*0Sstevel@tonic-gate 		if (isupper(oldstr[i]))
51*0Sstevel@tonic-gate 			newstr[i] = tolower(oldstr[i]);
52*0Sstevel@tonic-gate 		else
53*0Sstevel@tonic-gate 			newstr[i] = oldstr[i];
54*0Sstevel@tonic-gate 		if (oldstr[i] == '\0')
55*0Sstevel@tonic-gate 			break;
56*0Sstevel@tonic-gate 	}
57*0Sstevel@tonic-gate 	return ((char *)newstr);
58*0Sstevel@tonic-gate }
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate // class AudioHdr parsing methods
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate // Return a string containing the sample rate
66*0Sstevel@tonic-gate char *AudioHdr::
67*0Sstevel@tonic-gate RateString() const
68*0Sstevel@tonic-gate {
69*0Sstevel@tonic-gate 	char	*str;
70*0Sstevel@tonic-gate 	int	ratek;
71*0Sstevel@tonic-gate 	int	rateh;
72*0Sstevel@tonic-gate 	int	prec;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	str = new char[32];
75*0Sstevel@tonic-gate 	ratek = sample_rate / 1000;
76*0Sstevel@tonic-gate 	rateh = sample_rate % 1000;
77*0Sstevel@tonic-gate 	if (rateh == 0) {
78*0Sstevel@tonic-gate 		(void) sprintf(str, "%dkHz", ratek);
79*0Sstevel@tonic-gate 	} else {
80*0Sstevel@tonic-gate 		// scale down to print minimum digits after the decimal point
81*0Sstevel@tonic-gate 		prec = 3;
82*0Sstevel@tonic-gate 		if ((rateh % 10) == 0) {
83*0Sstevel@tonic-gate 			prec--;
84*0Sstevel@tonic-gate 			rateh /= 10;
85*0Sstevel@tonic-gate 		}
86*0Sstevel@tonic-gate 		if ((rateh % 10) == 0) {
87*0Sstevel@tonic-gate 			prec--;
88*0Sstevel@tonic-gate 			rateh /= 10;
89*0Sstevel@tonic-gate 		}
90*0Sstevel@tonic-gate 		(void) sprintf(str, "%d.%0*dkHz", ratek, prec, rateh);
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 	return (str);
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate // Return a string containing the number of channels
96*0Sstevel@tonic-gate char *AudioHdr::
97*0Sstevel@tonic-gate ChannelString() const
98*0Sstevel@tonic-gate {
99*0Sstevel@tonic-gate 	char	*str;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	str = new char[32];
102*0Sstevel@tonic-gate 	switch (channels) {
103*0Sstevel@tonic-gate 	case 1:
104*0Sstevel@tonic-gate 		(void) sprintf(str, "mono");
105*0Sstevel@tonic-gate 		break;
106*0Sstevel@tonic-gate 	case 2:
107*0Sstevel@tonic-gate 		(void) sprintf(str, "stereo");
108*0Sstevel@tonic-gate 		break;
109*0Sstevel@tonic-gate 	case 4:
110*0Sstevel@tonic-gate 		(void) sprintf(str, "quad");
111*0Sstevel@tonic-gate 		break;
112*0Sstevel@tonic-gate 	default:
113*0Sstevel@tonic-gate 		(void) sprintf(str, "%d-channel", channels);
114*0Sstevel@tonic-gate 		break;
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 	return (str);
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate // Return a string containing the encoding
120*0Sstevel@tonic-gate char *AudioHdr::
121*0Sstevel@tonic-gate EncodingString() const
122*0Sstevel@tonic-gate {
123*0Sstevel@tonic-gate 	char	*str;
124*0Sstevel@tonic-gate 	Double	prec;
125*0Sstevel@tonic-gate 	int	iprec;
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	str = new char[64];
128*0Sstevel@tonic-gate 	if ((samples_per_unit == 0) || (bytes_per_unit == 0) ||
129*0Sstevel@tonic-gate 	    (encoding == NONE)) {
130*0Sstevel@tonic-gate 		(void) sprintf(str, "???");
131*0Sstevel@tonic-gate 	} else {
132*0Sstevel@tonic-gate 		// First encode precision
133*0Sstevel@tonic-gate 		iprec = (bytes_per_unit * 8) / samples_per_unit;
134*0Sstevel@tonic-gate 		prec = ((Double)bytes_per_unit * 8.) / (Double)samples_per_unit;
135*0Sstevel@tonic-gate 		if (prec == (Double) iprec) {
136*0Sstevel@tonic-gate 			(void) sprintf(str, "%d-bit ", iprec);
137*0Sstevel@tonic-gate 		} else {
138*0Sstevel@tonic-gate 			(void) sprintf(str, "%.1f-bit ", double(prec));
139*0Sstevel@tonic-gate 		}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 		// Then encode format
142*0Sstevel@tonic-gate 		switch (encoding) {
143*0Sstevel@tonic-gate 		case ULAW:
144*0Sstevel@tonic-gate 			// XXX - See bug 1121000
145*0Sstevel@tonic-gate 			// XXX - (void) strcat(str, "�-law");
146*0Sstevel@tonic-gate 			(void) strcat(str, "u-law");
147*0Sstevel@tonic-gate 			break;
148*0Sstevel@tonic-gate 		case ALAW:
149*0Sstevel@tonic-gate 			(void) strcat(str, "A-law");
150*0Sstevel@tonic-gate 			break;
151*0Sstevel@tonic-gate 		case LINEAR:
152*0Sstevel@tonic-gate 			(void) strcat(str, "linear");
153*0Sstevel@tonic-gate 			break;
154*0Sstevel@tonic-gate 		case FLOAT:
155*0Sstevel@tonic-gate 			(void) strcat(str, "float");
156*0Sstevel@tonic-gate 			break;
157*0Sstevel@tonic-gate 		case G721:
158*0Sstevel@tonic-gate 			(void) strcat(str, "G.721 ADPCM");
159*0Sstevel@tonic-gate 			break;
160*0Sstevel@tonic-gate 		case G722:
161*0Sstevel@tonic-gate 			(void) strcat(str, "G.722 ADPCM");
162*0Sstevel@tonic-gate 			break;
163*0Sstevel@tonic-gate 		case G723:
164*0Sstevel@tonic-gate 			(void) strcat(str, "G.723 ADPCM");
165*0Sstevel@tonic-gate 			break;
166*0Sstevel@tonic-gate 		case DVI:
167*0Sstevel@tonic-gate 			(void) strcat(str, "DVI ADPCM");
168*0Sstevel@tonic-gate 			break;
169*0Sstevel@tonic-gate 		default:
170*0Sstevel@tonic-gate 			(void) strcat(str, "???");
171*0Sstevel@tonic-gate 			break;
172*0Sstevel@tonic-gate 		}
173*0Sstevel@tonic-gate 	}
174*0Sstevel@tonic-gate 	return (str);
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate // Return a string containing the entire audio encoding
178*0Sstevel@tonic-gate char *AudioHdr::
179*0Sstevel@tonic-gate FormatString() const
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	char	*str;
182*0Sstevel@tonic-gate 	char	*rate;
183*0Sstevel@tonic-gate 	char	*chan;
184*0Sstevel@tonic-gate 	char	*enc;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	str = new char[4 * 32];
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	enc = EncodingString();
189*0Sstevel@tonic-gate 	rate = RateString();
190*0Sstevel@tonic-gate 	chan = ChannelString();
191*0Sstevel@tonic-gate 	(void) sprintf(str, "%s, %s, %s", enc, rate, chan);
192*0Sstevel@tonic-gate 	delete rate;
193*0Sstevel@tonic-gate 	delete chan;
194*0Sstevel@tonic-gate 	delete enc;
195*0Sstevel@tonic-gate 	return (str);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate // Parse a string containing the sample rate
199*0Sstevel@tonic-gate AudioError AudioHdr::
200*0Sstevel@tonic-gate RateParse(
201*0Sstevel@tonic-gate 	char		*str)
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate static char		*lib_khz = NULL;
204*0Sstevel@tonic-gate static char		*lib_hz = NULL;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	double		r;
207*0Sstevel@tonic-gate 	int		rate;
208*0Sstevel@tonic-gate 	char		khzbuf[16];
209*0Sstevel@tonic-gate 	char		*khz;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	if (str == NULL)
212*0Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	// Init i18n string translations
215*0Sstevel@tonic-gate 	if (lib_khz == NULL) {
216*0Sstevel@tonic-gate 		lib_khz = to_lowercase(_MGET_("khz"));
217*0Sstevel@tonic-gate 		lib_hz = to_lowercase(_MGET_("hz"));
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	// Scan for a number followed by an optional khz designator
221*0Sstevel@tonic-gate 	switch (sscanf(str, " %lf %15s", &r, khzbuf)) {
222*0Sstevel@tonic-gate 	case 2:
223*0Sstevel@tonic-gate 		// Process 'khz', if present, and fall through
224*0Sstevel@tonic-gate 		khz = to_lowercase(khzbuf);
225*0Sstevel@tonic-gate 		if ((strcmp(khz, "khz") == 0) ||
226*0Sstevel@tonic-gate 		    (strcmp(khz, "khertz") == 0) ||
227*0Sstevel@tonic-gate 		    (strcmp(khz, "kilohertz") == 0) ||
228*0Sstevel@tonic-gate 		    (strcmp(khz, "k") == 0) ||
229*0Sstevel@tonic-gate 		    (strcoll(khz, lib_khz) == 0)) {
230*0Sstevel@tonic-gate 			r *= 1000.;
231*0Sstevel@tonic-gate 		} else if ((strcmp(khz, "hz") != 0) &&
232*0Sstevel@tonic-gate 		    (strcmp(khz, "hertz") != 0) &&
233*0Sstevel@tonic-gate 		    (strcoll(khz, lib_hz) != 0)) {
234*0Sstevel@tonic-gate 			delete khz;
235*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
236*0Sstevel@tonic-gate 		}
237*0Sstevel@tonic-gate 		delete khz;
238*0Sstevel@tonic-gate 	case 1:
239*0Sstevel@tonic-gate 		rate = irint(r);
240*0Sstevel@tonic-gate 		break;
241*0Sstevel@tonic-gate 	default:
242*0Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 	// Check for reasonable bounds
245*0Sstevel@tonic-gate 	if ((rate <= 0) || (rate > 500000)) {
246*0Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 	sample_rate = (unsigned int) rate;
249*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate // Parse a string containing the number of channels
253*0Sstevel@tonic-gate AudioError AudioHdr::
254*0Sstevel@tonic-gate ChannelParse(
255*0Sstevel@tonic-gate 	char		*str)
256*0Sstevel@tonic-gate {
257*0Sstevel@tonic-gate static char		*lib_chan = NULL;
258*0Sstevel@tonic-gate static char		*lib_mono = NULL;
259*0Sstevel@tonic-gate static char		*lib_stereo = NULL;
260*0Sstevel@tonic-gate 	char		cstrbuf[16];
261*0Sstevel@tonic-gate 	char		*cstr;
262*0Sstevel@tonic-gate 	char		xtra[4];
263*0Sstevel@tonic-gate 	int		chan;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	// Init i18n string translations
266*0Sstevel@tonic-gate 	if (lib_chan == NULL) {
267*0Sstevel@tonic-gate 		lib_chan = to_lowercase(_MGET_("channel"));
268*0Sstevel@tonic-gate 		lib_mono = to_lowercase(_MGET_("mono"));
269*0Sstevel@tonic-gate 		lib_stereo = to_lowercase(_MGET_("stereo"));
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	// Parse a number, followed by optional "-channel"
273*0Sstevel@tonic-gate 	switch (sscanf(str, " %d %15s", &chan, cstrbuf)) {
274*0Sstevel@tonic-gate 	case 2:
275*0Sstevel@tonic-gate 		cstr = to_lowercase(cstrbuf);
276*0Sstevel@tonic-gate 		if ((strcmp(cstr, "-channel") != 0) &&
277*0Sstevel@tonic-gate 		    (strcmp(cstr, "-chan") != 0) &&
278*0Sstevel@tonic-gate 		    (strcoll(cstr, lib_chan) != 0)) {
279*0Sstevel@tonic-gate 			delete cstr;
280*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
281*0Sstevel@tonic-gate 		}
282*0Sstevel@tonic-gate 		delete cstr;
283*0Sstevel@tonic-gate 	case 1:
284*0Sstevel@tonic-gate 		break;
285*0Sstevel@tonic-gate 	default:
286*0Sstevel@tonic-gate 		// If no number, look for reasonable keywords
287*0Sstevel@tonic-gate 		if (sscanf(str, " %15s %1s", cstrbuf, xtra) != 1) {
288*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 		cstr = to_lowercase(cstrbuf);
291*0Sstevel@tonic-gate 		if ((strcmp(cstr, "mono") == 0) ||
292*0Sstevel@tonic-gate 		    (strcmp(cstr, "monaural") == 0) ||
293*0Sstevel@tonic-gate 		    (strcoll(cstr, lib_mono) == 0)) {
294*0Sstevel@tonic-gate 			chan = 1;
295*0Sstevel@tonic-gate 		} else if ((strcmp(cstr, "stereo") == 0) ||
296*0Sstevel@tonic-gate 		    (strcmp(cstr, "dual") == 0) ||
297*0Sstevel@tonic-gate 		    (strcoll(cstr, lib_stereo) == 0)) {
298*0Sstevel@tonic-gate 			chan = 2;
299*0Sstevel@tonic-gate 		} else if ((strcmp(cstr, "quad") == 0) ||
300*0Sstevel@tonic-gate 		    (strcmp(cstr, "quadrophonic") == 0)) {
301*0Sstevel@tonic-gate 			chan = 4;
302*0Sstevel@tonic-gate 		} else {
303*0Sstevel@tonic-gate 			delete cstr;
304*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 		delete cstr;
307*0Sstevel@tonic-gate 	}
308*0Sstevel@tonic-gate 	if ((chan <= 0) || (chan > 256)) {
309*0Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 	channels = (unsigned int) chan;
312*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate // Parse a string containing the audio encoding
316*0Sstevel@tonic-gate AudioError AudioHdr::
317*0Sstevel@tonic-gate EncodingParse(
318*0Sstevel@tonic-gate 	char		*str)
319*0Sstevel@tonic-gate {
320*0Sstevel@tonic-gate static char		*lib_bit = NULL;
321*0Sstevel@tonic-gate static char		*lib_ulaw = NULL;
322*0Sstevel@tonic-gate static char		*lib_Alaw = NULL;
323*0Sstevel@tonic-gate static char		*lib_linear = NULL;
324*0Sstevel@tonic-gate 	int		i;
325*0Sstevel@tonic-gate 	char		*p;
326*0Sstevel@tonic-gate 	char		estrbuf[64];
327*0Sstevel@tonic-gate 	char		*estr;
328*0Sstevel@tonic-gate 	char		xtrabuf[32];
329*0Sstevel@tonic-gate 	char		*xtra;
330*0Sstevel@tonic-gate 	char		*xp;
331*0Sstevel@tonic-gate 	char		buf[BUFSIZ];
332*0Sstevel@tonic-gate 	char		*cp;
333*0Sstevel@tonic-gate 	double		prec;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	// Init i18n string translations
336*0Sstevel@tonic-gate 	if (lib_bit == NULL) {
337*0Sstevel@tonic-gate 		lib_bit = to_lowercase(_MGET_("bit"));
338*0Sstevel@tonic-gate 		lib_ulaw = to_lowercase(_MGET_("u-law"));
339*0Sstevel@tonic-gate 		lib_Alaw = to_lowercase(_MGET_("A-law"));
340*0Sstevel@tonic-gate 		lib_linear = to_lowercase(_MGET_("linear8"));
341*0Sstevel@tonic-gate 		lib_linear = to_lowercase(_MGET_("linear"));
342*0Sstevel@tonic-gate 	}
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	// first copy and remove leading spaces
345*0Sstevel@tonic-gate 	(void) strncpy(buf, str, BUFSIZ);
346*0Sstevel@tonic-gate 	for (cp = buf; *cp == ' '; cp++)
347*0Sstevel@tonic-gate 		continue;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	// Delimit the precision.  If there is one, parse it.
350*0Sstevel@tonic-gate 	prec = 0.;
351*0Sstevel@tonic-gate 	p = strchr(cp, ' ');
352*0Sstevel@tonic-gate 	if (p != NULL) {
353*0Sstevel@tonic-gate 		*p++ = '\0';
354*0Sstevel@tonic-gate 		i = sscanf(cp, " %lf %15s", &prec, xtrabuf);
355*0Sstevel@tonic-gate 		if (i == 0) {
356*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
357*0Sstevel@tonic-gate 		}
358*0Sstevel@tonic-gate 		if (i == 2) {
359*0Sstevel@tonic-gate 			// convert to lowercase and skip leading "-", if any
360*0Sstevel@tonic-gate 			xtra = to_lowercase(xtrabuf);
361*0Sstevel@tonic-gate 			xp = (xtra[0] == '-') ? &xtra[1] : &xtra[0];
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 			if ((strcmp(xp, "bit") != 0) &&
364*0Sstevel@tonic-gate 			    (strcoll(xp, lib_bit) != 0)) {
365*0Sstevel@tonic-gate 				delete xtra;
366*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
367*0Sstevel@tonic-gate 			}
368*0Sstevel@tonic-gate 			delete xtra;
369*0Sstevel@tonic-gate 		}
370*0Sstevel@tonic-gate 		if ((prec <= 0.) || (prec > 512.)) {
371*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
372*0Sstevel@tonic-gate 		}
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		// Don't be fooled by "8 bit"
375*0Sstevel@tonic-gate 		i = sscanf(p, " %15s", xtrabuf);
376*0Sstevel@tonic-gate 		if (i == 1) {
377*0Sstevel@tonic-gate 			// convert to lowercase and skip leading "-", if any
378*0Sstevel@tonic-gate 			xtra = to_lowercase(xtrabuf);
379*0Sstevel@tonic-gate 			xp = (xtra[0] == '-') ? &xtra[1] : &xtra[0];
380*0Sstevel@tonic-gate 			if ((strcmp(xp, "bit") == 0) ||
381*0Sstevel@tonic-gate 			    (strcoll(xp, lib_bit) == 0)) {
382*0Sstevel@tonic-gate 				    xp = strchr(p, ' ');
383*0Sstevel@tonic-gate 				    if (xp != NULL)
384*0Sstevel@tonic-gate 					    p = xp;
385*0Sstevel@tonic-gate 				    else
386*0Sstevel@tonic-gate 					    p += strlen(xtrabuf);
387*0Sstevel@tonic-gate 			}
388*0Sstevel@tonic-gate 			delete xtra;
389*0Sstevel@tonic-gate 		}
390*0Sstevel@tonic-gate 	} else {
391*0Sstevel@tonic-gate 		p = cp;
392*0Sstevel@tonic-gate 	}
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	i = sscanf(p, " %31s %31s", estrbuf, xtrabuf);
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	// If "adpcm" appended with a space, concatenate it
397*0Sstevel@tonic-gate 	if (i == 2) {
398*0Sstevel@tonic-gate 		xtra = to_lowercase(xtrabuf);
399*0Sstevel@tonic-gate 		if (strcmp(xtra, "adpcm") == 0) {
400*0Sstevel@tonic-gate 			(void) strcat(estrbuf, xtra);
401*0Sstevel@tonic-gate 			i = 1;
402*0Sstevel@tonic-gate 		}
403*0Sstevel@tonic-gate 		delete xtra;
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 	if (i == 1) {
406*0Sstevel@tonic-gate 		estr = to_lowercase(estrbuf);
407*0Sstevel@tonic-gate 		if ((strcmp(estr, "ulaw") == 0) ||
408*0Sstevel@tonic-gate 		    (strcmp(estr, "u-law") == 0) ||
409*0Sstevel@tonic-gate 		    (strcmp(estr, "�law") == 0) ||
410*0Sstevel@tonic-gate 		    (strcmp(estr, "�-law") == 0) ||
411*0Sstevel@tonic-gate 		    (strcmp(estr, "mulaw") == 0) ||
412*0Sstevel@tonic-gate 		    (strcmp(estr, "mu-law") == 0) ||
413*0Sstevel@tonic-gate 		    (strcoll(estr, lib_ulaw) == 0)) {
414*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 8.))
415*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
416*0Sstevel@tonic-gate 			encoding = ULAW;
417*0Sstevel@tonic-gate 			samples_per_unit = 1;
418*0Sstevel@tonic-gate 			bytes_per_unit = 1;
419*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "alaw") == 0) ||
420*0Sstevel@tonic-gate 		    (strcmp(estr, "a-law") == 0) ||
421*0Sstevel@tonic-gate 		    (strcoll(estr, lib_Alaw) == 0)) {
422*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 8.))
423*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
424*0Sstevel@tonic-gate 			encoding = ALAW;
425*0Sstevel@tonic-gate 			samples_per_unit = 1;
426*0Sstevel@tonic-gate 			bytes_per_unit = 1;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "linear") == 0) ||
429*0Sstevel@tonic-gate 		    (strcmp(estr, "lin") == 0) ||
430*0Sstevel@tonic-gate 		    (strcmp(estr, "pcm") == 0) ||
431*0Sstevel@tonic-gate 		    (strcoll(estr, lib_linear) == 0)) {
432*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 8.) && (prec != 16.) &&
433*0Sstevel@tonic-gate 			    (prec != 24.) && (prec != 32.))
434*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
435*0Sstevel@tonic-gate 			if (prec == 0.)
436*0Sstevel@tonic-gate 				prec = 16.;
437*0Sstevel@tonic-gate 			encoding = LINEAR;
438*0Sstevel@tonic-gate 			samples_per_unit = 1;
439*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "linear8") == 0) ||
442*0Sstevel@tonic-gate 		    (strcmp(estr, "lin8") == 0) ||
443*0Sstevel@tonic-gate 		    (strcmp(estr, "pcm8") == 0)) {
444*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 8.))
445*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
446*0Sstevel@tonic-gate 			prec = 8.;
447*0Sstevel@tonic-gate 			encoding = LINEAR;
448*0Sstevel@tonic-gate 			samples_per_unit = 1;
449*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "linear16") == 0) ||
452*0Sstevel@tonic-gate 		    (strcmp(estr, "lin16") == 0) ||
453*0Sstevel@tonic-gate 		    (strcmp(estr, "pcm16") == 0)) {
454*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 16.))
455*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
456*0Sstevel@tonic-gate 			prec = 16.;
457*0Sstevel@tonic-gate 			encoding = LINEAR;
458*0Sstevel@tonic-gate 			samples_per_unit = 1;
459*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "linear24") == 0) ||
462*0Sstevel@tonic-gate 		    (strcmp(estr, "lin24") == 0) ||
463*0Sstevel@tonic-gate 		    (strcmp(estr, "pcm24") == 0)) {
464*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 24.))
465*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
466*0Sstevel@tonic-gate 			prec = 24.;
467*0Sstevel@tonic-gate 			encoding = LINEAR;
468*0Sstevel@tonic-gate 			samples_per_unit = 1;
469*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "linear32") == 0) ||
472*0Sstevel@tonic-gate 		    (strcmp(estr, "lin32") == 0) ||
473*0Sstevel@tonic-gate 		    (strcmp(estr, "pcm32") == 0)) {
474*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 32.))
475*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
476*0Sstevel@tonic-gate 			prec = 32.;
477*0Sstevel@tonic-gate 			encoding = LINEAR;
478*0Sstevel@tonic-gate 			samples_per_unit = 1;
479*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "float") == 0) ||
482*0Sstevel@tonic-gate 		    (strcmp(estr, "floatingpoint") == 0) ||
483*0Sstevel@tonic-gate 		    (strcmp(estr, "floating-point") == 0)) {
484*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 32.) && (prec != 64.))
485*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
486*0Sstevel@tonic-gate 			if (prec == 0.)
487*0Sstevel@tonic-gate 				prec = 64.;
488*0Sstevel@tonic-gate 			encoding = FLOAT;
489*0Sstevel@tonic-gate 			samples_per_unit = 1;
490*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "float32") == 0) ||
493*0Sstevel@tonic-gate 		    (strcmp(estr, "floatingpoint32") == 0) ||
494*0Sstevel@tonic-gate 		    (strcmp(estr, "floating-point32") == 0)) {
495*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 32.))
496*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
497*0Sstevel@tonic-gate 			prec = 32.;
498*0Sstevel@tonic-gate 			encoding = FLOAT;
499*0Sstevel@tonic-gate 			samples_per_unit = 1;
500*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "float64") == 0) ||
503*0Sstevel@tonic-gate 		    (strcmp(estr, "double") == 0) ||
504*0Sstevel@tonic-gate 		    (strcmp(estr, "floatingpoint64") == 0) ||
505*0Sstevel@tonic-gate 		    (strcmp(estr, "floating-point64") == 0)) {
506*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 64.))
507*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
508*0Sstevel@tonic-gate 			prec = 64.;
509*0Sstevel@tonic-gate 			encoding = FLOAT;
510*0Sstevel@tonic-gate 			samples_per_unit = 1;
511*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec / 8.);
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "g.721") == 0) ||
514*0Sstevel@tonic-gate 		    (strcmp(estr, "g721") == 0) ||
515*0Sstevel@tonic-gate 		    (strcmp(estr, "g.721adpcm") == 0) ||
516*0Sstevel@tonic-gate 		    (strcmp(estr, "g721adpcm") == 0)) {
517*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 4.))
518*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
519*0Sstevel@tonic-gate 			encoding = G721;
520*0Sstevel@tonic-gate 			samples_per_unit = 2;
521*0Sstevel@tonic-gate 			bytes_per_unit = 1;
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "g.722") == 0) ||
524*0Sstevel@tonic-gate 		    (strcmp(estr, "g722") == 0) ||
525*0Sstevel@tonic-gate 		    (strcmp(estr, "g.722adpcm") == 0) ||
526*0Sstevel@tonic-gate 		    (strcmp(estr, "g722adpcm") == 0)) {
527*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 8.))
528*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
529*0Sstevel@tonic-gate 			encoding = G722;
530*0Sstevel@tonic-gate 			samples_per_unit = 1;
531*0Sstevel@tonic-gate 			bytes_per_unit = 1;
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "g.723") == 0) ||
534*0Sstevel@tonic-gate 		    (strcmp(estr, "g723") == 0) ||
535*0Sstevel@tonic-gate 		    (strcmp(estr, "g.723adpcm") == 0) ||
536*0Sstevel@tonic-gate 		    (strcmp(estr, "g723adpcm") == 0)) {
537*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 3.) && (prec != 5.))
538*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
539*0Sstevel@tonic-gate 			if (prec == 0.)
540*0Sstevel@tonic-gate 				prec = 3.;
541*0Sstevel@tonic-gate 			encoding = G723;
542*0Sstevel@tonic-gate 			samples_per_unit = 8;
543*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec);
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "g.723-3") == 0) ||
546*0Sstevel@tonic-gate 		    (strcmp(estr, "g.723_3") == 0) ||
547*0Sstevel@tonic-gate 		    (strcmp(estr, "g.723.3") == 0) ||
548*0Sstevel@tonic-gate 		    (strcmp(estr, "g723-3") == 0) ||
549*0Sstevel@tonic-gate 		    (strcmp(estr, "g723_3") == 0) ||
550*0Sstevel@tonic-gate 		    (strcmp(estr, "g723.3") == 0)) {
551*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 3.))
552*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
553*0Sstevel@tonic-gate 			prec = 3.;
554*0Sstevel@tonic-gate 			encoding = G723;
555*0Sstevel@tonic-gate 			samples_per_unit = 8;
556*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec);
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "g.723-5") == 0) ||
559*0Sstevel@tonic-gate 		    (strcmp(estr, "g.723_5") == 0) ||
560*0Sstevel@tonic-gate 		    (strcmp(estr, "g.723.5") == 0) ||
561*0Sstevel@tonic-gate 		    (strcmp(estr, "g723-5") == 0) ||
562*0Sstevel@tonic-gate 		    (strcmp(estr, "g723_5") == 0) ||
563*0Sstevel@tonic-gate 		    (strcmp(estr, "g723.5") == 0)) {
564*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 5.))
565*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
566*0Sstevel@tonic-gate 			prec = 5.;
567*0Sstevel@tonic-gate 			encoding = G723;
568*0Sstevel@tonic-gate 			samples_per_unit = 8;
569*0Sstevel@tonic-gate 			bytes_per_unit = irint(prec);
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 		} else if ((strcmp(estr, "dvi") == 0) ||
572*0Sstevel@tonic-gate 		    (strcmp(estr, "dviadpcm") == 0)) {
573*0Sstevel@tonic-gate 			if ((prec != 0.) && (prec != 4.))
574*0Sstevel@tonic-gate 				return (AUDIO_ERR_BADARG);
575*0Sstevel@tonic-gate 			encoding = DVI;
576*0Sstevel@tonic-gate 			samples_per_unit = 2;
577*0Sstevel@tonic-gate 			bytes_per_unit = 1;
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 		} else {
580*0Sstevel@tonic-gate 			delete estr;
581*0Sstevel@tonic-gate 			return (AUDIO_ERR_BADARG);
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 		delete estr;
584*0Sstevel@tonic-gate 	} else {
585*0Sstevel@tonic-gate 		return (AUDIO_ERR_BADARG);
586*0Sstevel@tonic-gate 	}
587*0Sstevel@tonic-gate 	return (AUDIO_SUCCESS);
588*0Sstevel@tonic-gate }
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate // Parse a string containing the comma-separated audio encoding
591*0Sstevel@tonic-gate // Format is: "enc, chan, rate"
592*0Sstevel@tonic-gate //	XXX - some countries use comma instead of decimal point
593*0Sstevel@tonic-gate //	so there may be a problem with "44,1 khz"
594*0Sstevel@tonic-gate AudioError AudioHdr::
595*0Sstevel@tonic-gate FormatParse(
596*0Sstevel@tonic-gate 	char		*str)
597*0Sstevel@tonic-gate {
598*0Sstevel@tonic-gate 	char		*pstr;
599*0Sstevel@tonic-gate 	char		*ptr;
600*0Sstevel@tonic-gate 	char		*p;
601*0Sstevel@tonic-gate 	AudioHdr	newhdr;
602*0Sstevel@tonic-gate 	AudioError	err;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	pstr = new char[strlen(str) + 1];
605*0Sstevel@tonic-gate 	(void) strcpy(pstr, str);
606*0Sstevel@tonic-gate 	ptr = pstr;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	// Delimit and parse the precision string
609*0Sstevel@tonic-gate 	p = strchr(ptr, ',');
610*0Sstevel@tonic-gate 	if (p == NULL)
611*0Sstevel@tonic-gate 		p = strchr(ptr, ' ');
612*0Sstevel@tonic-gate 	if (p == NULL) {
613*0Sstevel@tonic-gate 		err = AUDIO_ERR_BADARG;
614*0Sstevel@tonic-gate 		goto errret;
615*0Sstevel@tonic-gate 	}
616*0Sstevel@tonic-gate 	*p++ = '\0';
617*0Sstevel@tonic-gate 	err = newhdr.EncodingParse(ptr);
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	// Delimit and parse the sample rate string
620*0Sstevel@tonic-gate 	if (!err) {
621*0Sstevel@tonic-gate 		ptr = p;
622*0Sstevel@tonic-gate 		p = strchr(ptr, ',');
623*0Sstevel@tonic-gate 		if (p == NULL)
624*0Sstevel@tonic-gate 			p = strchr(ptr, ' ');
625*0Sstevel@tonic-gate 		if (p == NULL) {
626*0Sstevel@tonic-gate 			err = AUDIO_ERR_BADARG;
627*0Sstevel@tonic-gate 			goto errret;
628*0Sstevel@tonic-gate 		}
629*0Sstevel@tonic-gate 		*p++ = '\0';
630*0Sstevel@tonic-gate 		err = newhdr.RateParse(ptr);
631*0Sstevel@tonic-gate 	}
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	// Finally, parse the channels string
634*0Sstevel@tonic-gate 	if (!err) {
635*0Sstevel@tonic-gate 		err = newhdr.ChannelParse(p);
636*0Sstevel@tonic-gate 	}
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	// Validate the resulting header
639*0Sstevel@tonic-gate 	if (!err)
640*0Sstevel@tonic-gate 		err = newhdr.Validate();
641*0Sstevel@tonic-gate 	if (!err)
642*0Sstevel@tonic-gate 		*this = newhdr;
643*0Sstevel@tonic-gate errret:
644*0Sstevel@tonic-gate 	delete pstr;
645*0Sstevel@tonic-gate 	return (err);
646*0Sstevel@tonic-gate }
647