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 2004 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 <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <stdlib.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 #include <Audio.h> 39*7c478bd9Sstevel@tonic-gate #include <AudioFile.h> 40*7c478bd9Sstevel@tonic-gate #include <AudioPipe.h> 41*7c478bd9Sstevel@tonic-gate #include <AudioRawPipe.h> 42*7c478bd9Sstevel@tonic-gate #include <AudioLib.h> 43*7c478bd9Sstevel@tonic-gate #include <AudioTypePcm.h> 44*7c478bd9Sstevel@tonic-gate #include <AudioTypeG72X.h> 45*7c478bd9Sstevel@tonic-gate #include <AudioTypeChannel.h> 46*7c478bd9Sstevel@tonic-gate #include <AudioTypeMux.h> 47*7c478bd9Sstevel@tonic-gate #include <AudioTypeSampleRate.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #include <convert.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate // Maximum sizes of buffer to convert, in seconds and bytes 53*7c478bd9Sstevel@tonic-gate #define CVTMAXTIME ((double)5.0) 54*7c478bd9Sstevel@tonic-gate #define CVTMAXBUF (64 * 1024) 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate // maintain a list of conversions 57*7c478bd9Sstevel@tonic-gate struct conv_list { 58*7c478bd9Sstevel@tonic-gate struct conv_list *next; // next conversion in chain 59*7c478bd9Sstevel@tonic-gate unsigned bufcnt; // number of buffers to process 60*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; // conversion class 61*7c478bd9Sstevel@tonic-gate AudioHdr hdr; // what to convert to 62*7c478bd9Sstevel@tonic-gate char *desc; // describe conversion (for errs) 63*7c478bd9Sstevel@tonic-gate }; 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate // check if this is a valid conversion. return -1 if not, 0 if OK. 67*7c478bd9Sstevel@tonic-gate int 68*7c478bd9Sstevel@tonic-gate verify_conversion( 69*7c478bd9Sstevel@tonic-gate AudioHdr ihdr, 70*7c478bd9Sstevel@tonic-gate AudioHdr ohdr) 71*7c478bd9Sstevel@tonic-gate { 72*7c478bd9Sstevel@tonic-gate char *enc1; 73*7c478bd9Sstevel@tonic-gate char *enc2; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate if (((ihdr.encoding != ULAW) && 76*7c478bd9Sstevel@tonic-gate (ihdr.encoding != ALAW) && 77*7c478bd9Sstevel@tonic-gate (ihdr.encoding != LINEAR) && 78*7c478bd9Sstevel@tonic-gate (ihdr.encoding != FLOAT) && 79*7c478bd9Sstevel@tonic-gate (ihdr.encoding != G721) && 80*7c478bd9Sstevel@tonic-gate (ihdr.encoding != G723)) || 81*7c478bd9Sstevel@tonic-gate ((ohdr.encoding != ULAW) && 82*7c478bd9Sstevel@tonic-gate (ohdr.encoding != ALAW) && 83*7c478bd9Sstevel@tonic-gate (ohdr.encoding != LINEAR) && 84*7c478bd9Sstevel@tonic-gate (ohdr.encoding != FLOAT) && 85*7c478bd9Sstevel@tonic-gate (ohdr.encoding != G721) && 86*7c478bd9Sstevel@tonic-gate (ohdr.encoding != G723))) { 87*7c478bd9Sstevel@tonic-gate enc1 = ihdr.EncodingString(); 88*7c478bd9Sstevel@tonic-gate enc2 = ohdr.EncodingString(); 89*7c478bd9Sstevel@tonic-gate Err(MGET("can't convert from %s to %s\n"), enc1, enc2); 90*7c478bd9Sstevel@tonic-gate delete enc1; 91*7c478bd9Sstevel@tonic-gate delete enc2; 92*7c478bd9Sstevel@tonic-gate return (-1); 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate return (0); 95*7c478bd9Sstevel@tonic-gate } 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate // check if this conversion is a no-op 98*7c478bd9Sstevel@tonic-gate int 99*7c478bd9Sstevel@tonic-gate noop_conversion( 100*7c478bd9Sstevel@tonic-gate AudioHdr ihdr, 101*7c478bd9Sstevel@tonic-gate AudioHdr ohdr, 102*7c478bd9Sstevel@tonic-gate format_type i_fmt, 103*7c478bd9Sstevel@tonic-gate format_type o_fmt, 104*7c478bd9Sstevel@tonic-gate off_t i_offset, 105*7c478bd9Sstevel@tonic-gate off_t /* o_offset */) 106*7c478bd9Sstevel@tonic-gate { 107*7c478bd9Sstevel@tonic-gate if ((ihdr == ohdr) && 108*7c478bd9Sstevel@tonic-gate (i_fmt == o_fmt) && 109*7c478bd9Sstevel@tonic-gate (i_offset == 0)) { 110*7c478bd9Sstevel@tonic-gate return (1); 111*7c478bd9Sstevel@tonic-gate } 112*7c478bd9Sstevel@tonic-gate return (0); 113*7c478bd9Sstevel@tonic-gate } 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate // Conversion list maintenance routines 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate // Return a pointer to the last conversion entry in the list 119*7c478bd9Sstevel@tonic-gate struct conv_list 120*7c478bd9Sstevel@tonic-gate *get_last_conv( 121*7c478bd9Sstevel@tonic-gate struct conv_list *list) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate struct conv_list *lp; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate for (lp = list; lp != NULL; lp = lp->next) { 126*7c478bd9Sstevel@tonic-gate if (lp->next == NULL) 127*7c478bd9Sstevel@tonic-gate break; 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate return (lp); 130*7c478bd9Sstevel@tonic-gate } 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate // Release the conversion list 133*7c478bd9Sstevel@tonic-gate void 134*7c478bd9Sstevel@tonic-gate free_conv_list( 135*7c478bd9Sstevel@tonic-gate struct conv_list *&list) 136*7c478bd9Sstevel@tonic-gate { 137*7c478bd9Sstevel@tonic-gate unsigned int i; 138*7c478bd9Sstevel@tonic-gate unsigned int bufs; 139*7c478bd9Sstevel@tonic-gate struct conv_list *tlp; 140*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate while (list != NULL) { 143*7c478bd9Sstevel@tonic-gate bufs = list->bufcnt; 144*7c478bd9Sstevel@tonic-gate conv = list->conv; 145*7c478bd9Sstevel@tonic-gate for (i = 0; i < bufs; i++) { 146*7c478bd9Sstevel@tonic-gate // Delete the conversion string 147*7c478bd9Sstevel@tonic-gate if (list[i].desc != NULL) 148*7c478bd9Sstevel@tonic-gate free(list[i].desc); 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate // Delete the conversion class if unique 151*7c478bd9Sstevel@tonic-gate if ((list[i].conv != NULL) && 152*7c478bd9Sstevel@tonic-gate ((i == 0) || (list[i].conv != conv))) 153*7c478bd9Sstevel@tonic-gate delete(list[i].conv); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate tlp = list->next; 156*7c478bd9Sstevel@tonic-gate free((char *)list); 157*7c478bd9Sstevel@tonic-gate list = tlp; 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate // Append a new entry on the end of the conversion list 162*7c478bd9Sstevel@tonic-gate void 163*7c478bd9Sstevel@tonic-gate append_conv_list( 164*7c478bd9Sstevel@tonic-gate struct conv_list *&list, // list to modify 165*7c478bd9Sstevel@tonic-gate AudioHdr tohdr, // target format 166*7c478bd9Sstevel@tonic-gate unsigned int bufs, // number of buffers involved 167*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv, // NULL, if multiple buffers 168*7c478bd9Sstevel@tonic-gate char *desc) // string describing the transform 169*7c478bd9Sstevel@tonic-gate { 170*7c478bd9Sstevel@tonic-gate unsigned int i; 171*7c478bd9Sstevel@tonic-gate struct conv_list *lp; 172*7c478bd9Sstevel@tonic-gate struct conv_list *nlp; 173*7c478bd9Sstevel@tonic-gate Boolean B; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate nlp = new struct conv_list[bufs]; 176*7c478bd9Sstevel@tonic-gate if (nlp == NULL) { 177*7c478bd9Sstevel@tonic-gate Err(MGET("out of memory\n")); 178*7c478bd9Sstevel@tonic-gate exit(1); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate B = tohdr.Validate(); 181*7c478bd9Sstevel@tonic-gate // Initialize a conversion entry for each expected buffer 182*7c478bd9Sstevel@tonic-gate for (i = 0; i < bufs; i++) { 183*7c478bd9Sstevel@tonic-gate nlp[i].next = NULL; 184*7c478bd9Sstevel@tonic-gate nlp[i].hdr = tohdr; 185*7c478bd9Sstevel@tonic-gate B = nlp[i].hdr.Validate(); 186*7c478bd9Sstevel@tonic-gate nlp[i].bufcnt = bufs; 187*7c478bd9Sstevel@tonic-gate nlp[i].conv = conv; 188*7c478bd9Sstevel@tonic-gate if (desc && *desc) { 189*7c478bd9Sstevel@tonic-gate nlp[i].desc = strdup(desc); 190*7c478bd9Sstevel@tonic-gate } else { 191*7c478bd9Sstevel@tonic-gate nlp[i].desc = NULL; 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate // Link in the new entry 196*7c478bd9Sstevel@tonic-gate if (list == NULL) { 197*7c478bd9Sstevel@tonic-gate list = nlp; 198*7c478bd9Sstevel@tonic-gate } else { 199*7c478bd9Sstevel@tonic-gate lp = get_last_conv(list); 200*7c478bd9Sstevel@tonic-gate lp->next = nlp; 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate // Routines to establish specific conversions. 206*7c478bd9Sstevel@tonic-gate // These routines append the proper conversion to the list, and update 207*7c478bd9Sstevel@tonic-gate // the audio header structure to reflect the resulting data format. 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate // Multiplex/Demultiplex interleaved data 210*7c478bd9Sstevel@tonic-gate // If the data is multi-channel, demultiplex into multiple buffer streams. 211*7c478bd9Sstevel@tonic-gate // If there are multiple buffers, multiplex back into one interleaved stream. 212*7c478bd9Sstevel@tonic-gate AudioError 213*7c478bd9Sstevel@tonic-gate add_mux_convert( 214*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 215*7c478bd9Sstevel@tonic-gate AudioHdr& ihdr, 216*7c478bd9Sstevel@tonic-gate unsigned int& bufs) 217*7c478bd9Sstevel@tonic-gate { 218*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 219*7c478bd9Sstevel@tonic-gate unsigned int n; 220*7c478bd9Sstevel@tonic-gate char *msg; 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate conv = new AudioTypeMux; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate // Verify conversion 225*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 226*7c478bd9Sstevel@tonic-gate error: delete conv; 227*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate if (bufs == 1) { 231*7c478bd9Sstevel@tonic-gate // Demultiplex multi-channel data 232*7c478bd9Sstevel@tonic-gate n = ihdr.channels; // save the target number of buffers 233*7c478bd9Sstevel@tonic-gate ihdr.channels = 1; // each output buffer will be mono 234*7c478bd9Sstevel@tonic-gate msg = MGET("Split multi-channel data"); 235*7c478bd9Sstevel@tonic-gate } else { 236*7c478bd9Sstevel@tonic-gate // Multiplex multiple buffers 237*7c478bd9Sstevel@tonic-gate ihdr.channels = bufs; // set the target interleave 238*7c478bd9Sstevel@tonic-gate n = 1; 239*7c478bd9Sstevel@tonic-gate bufs = 1; // just one conversion necessary 240*7c478bd9Sstevel@tonic-gate msg = MGET("Interleave multi-channel data"); 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) 243*7c478bd9Sstevel@tonic-gate goto error; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate append_conv_list(list, ihdr, bufs, conv, msg); 246*7c478bd9Sstevel@tonic-gate bufs = n; 247*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate // Convert to PCM (linear, ulaw, alaw) 251*7c478bd9Sstevel@tonic-gate AudioError 252*7c478bd9Sstevel@tonic-gate add_pcm_convert( 253*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 254*7c478bd9Sstevel@tonic-gate AudioHdr& ihdr, 255*7c478bd9Sstevel@tonic-gate AudioEncoding tofmt, 256*7c478bd9Sstevel@tonic-gate unsigned int unitsz, 257*7c478bd9Sstevel@tonic-gate unsigned int& bufs) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 260*7c478bd9Sstevel@tonic-gate char msg[BUFSIZ]; 261*7c478bd9Sstevel@tonic-gate char *infmt; 262*7c478bd9Sstevel@tonic-gate char *outfmt; 263*7c478bd9Sstevel@tonic-gate AudioError err; 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate conv = new AudioTypePcm; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate // Verify conversion 268*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 269*7c478bd9Sstevel@tonic-gate error: delete conv; 270*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate // Set up conversion, get encoding strings 274*7c478bd9Sstevel@tonic-gate infmt = ihdr.EncodingString(); 275*7c478bd9Sstevel@tonic-gate ihdr.encoding = tofmt; 276*7c478bd9Sstevel@tonic-gate ihdr.bytes_per_unit = unitsz; 277*7c478bd9Sstevel@tonic-gate ihdr.samples_per_unit = 1; 278*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) 279*7c478bd9Sstevel@tonic-gate goto error; 280*7c478bd9Sstevel@tonic-gate outfmt = ihdr.EncodingString(); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate sprintf(msg, MGET("Convert %s to %s"), infmt, outfmt); 283*7c478bd9Sstevel@tonic-gate delete infmt; 284*7c478bd9Sstevel@tonic-gate delete outfmt; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate append_conv_list(list, ihdr, bufs, conv, msg); 287*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate // Convert multi-channel data to mono, or vice versa 291*7c478bd9Sstevel@tonic-gate AudioError 292*7c478bd9Sstevel@tonic-gate add_channel_convert( 293*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 294*7c478bd9Sstevel@tonic-gate AudioHdr& ihdr, 295*7c478bd9Sstevel@tonic-gate unsigned int tochans, 296*7c478bd9Sstevel@tonic-gate unsigned int& bufs) 297*7c478bd9Sstevel@tonic-gate { 298*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 299*7c478bd9Sstevel@tonic-gate char msg[BUFSIZ]; 300*7c478bd9Sstevel@tonic-gate char *inchans; 301*7c478bd9Sstevel@tonic-gate char *outchans; 302*7c478bd9Sstevel@tonic-gate AudioError err; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate // Make sure we're converting to/from mono with an interleaved buffer 305*7c478bd9Sstevel@tonic-gate if (((ihdr.channels != 1) && (tochans != 1)) || (bufs != 1)) 306*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate conv = new AudioTypeChannel; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate // Verify conversion; if no good, try converting to 16-bit pcm first 311*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr) || (ihdr.channels != 1)) { 312*7c478bd9Sstevel@tonic-gate if (err = add_pcm_convert(list, ihdr, LINEAR, 2, bufs)) { 313*7c478bd9Sstevel@tonic-gate delete conv; 314*7c478bd9Sstevel@tonic-gate return (err); 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 317*7c478bd9Sstevel@tonic-gate error: delete conv; 318*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate // Set up conversion, get channel strings 323*7c478bd9Sstevel@tonic-gate inchans = ihdr.ChannelString(); 324*7c478bd9Sstevel@tonic-gate ihdr.channels = tochans; 325*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) 326*7c478bd9Sstevel@tonic-gate goto error; 327*7c478bd9Sstevel@tonic-gate outchans = ihdr.ChannelString(); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate sprintf(msg, MGET("Convert %s to %s"), inchans, outchans); 330*7c478bd9Sstevel@tonic-gate delete inchans; 331*7c478bd9Sstevel@tonic-gate delete outchans; 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate append_conv_list(list, ihdr, bufs, conv, msg); 334*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate // Compress data 338*7c478bd9Sstevel@tonic-gate AudioError 339*7c478bd9Sstevel@tonic-gate add_compress( 340*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 341*7c478bd9Sstevel@tonic-gate AudioHdr& ihdr, 342*7c478bd9Sstevel@tonic-gate AudioEncoding tofmt, 343*7c478bd9Sstevel@tonic-gate unsigned int unitsz, 344*7c478bd9Sstevel@tonic-gate unsigned int& bufs) 345*7c478bd9Sstevel@tonic-gate { 346*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 347*7c478bd9Sstevel@tonic-gate char msg[BUFSIZ]; 348*7c478bd9Sstevel@tonic-gate char *infmt; 349*7c478bd9Sstevel@tonic-gate char *outfmt; 350*7c478bd9Sstevel@tonic-gate struct conv_list *lp; 351*7c478bd9Sstevel@tonic-gate int i; 352*7c478bd9Sstevel@tonic-gate AudioError err; 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate // Make sure we're converting something we understand 355*7c478bd9Sstevel@tonic-gate if ((tofmt != G721) && (tofmt != G723)) 356*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate conv = new AudioTypeG72X; 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate // Verify conversion; if no good, try converting to 16-bit pcm first 361*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 362*7c478bd9Sstevel@tonic-gate if (err = add_pcm_convert(list, ihdr, LINEAR, 2, bufs)) { 363*7c478bd9Sstevel@tonic-gate delete conv; 364*7c478bd9Sstevel@tonic-gate return (err); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 367*7c478bd9Sstevel@tonic-gate error: delete conv; 368*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate // Set up conversion, get encoding strings 373*7c478bd9Sstevel@tonic-gate infmt = ihdr.EncodingString(); 374*7c478bd9Sstevel@tonic-gate ihdr.encoding = tofmt; 375*7c478bd9Sstevel@tonic-gate switch (tofmt) { 376*7c478bd9Sstevel@tonic-gate case G721: 377*7c478bd9Sstevel@tonic-gate ihdr.bytes_per_unit = unitsz; 378*7c478bd9Sstevel@tonic-gate ihdr.samples_per_unit = 2; 379*7c478bd9Sstevel@tonic-gate break; 380*7c478bd9Sstevel@tonic-gate case G723: 381*7c478bd9Sstevel@tonic-gate ihdr.bytes_per_unit = unitsz; 382*7c478bd9Sstevel@tonic-gate ihdr.samples_per_unit = 8; 383*7c478bd9Sstevel@tonic-gate break; 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) 386*7c478bd9Sstevel@tonic-gate goto error; 387*7c478bd9Sstevel@tonic-gate outfmt = ihdr.EncodingString(); 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate sprintf(msg, MGET("Convert %s to %s"), infmt, outfmt); 390*7c478bd9Sstevel@tonic-gate delete infmt; 391*7c478bd9Sstevel@tonic-gate delete outfmt; 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate append_conv_list(list, ihdr, bufs, NULL, msg); 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate // Need a separate converter instantiation for each channel 396*7c478bd9Sstevel@tonic-gate lp = get_last_conv(list); 397*7c478bd9Sstevel@tonic-gate for (i = 0; i < bufs; i++) { 398*7c478bd9Sstevel@tonic-gate if (i == 0) 399*7c478bd9Sstevel@tonic-gate lp[i].conv = conv; 400*7c478bd9Sstevel@tonic-gate else 401*7c478bd9Sstevel@tonic-gate lp[i].conv = new AudioTypeG72X; 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate // Decompress data 407*7c478bd9Sstevel@tonic-gate AudioError 408*7c478bd9Sstevel@tonic-gate add_decompress( 409*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 410*7c478bd9Sstevel@tonic-gate AudioHdr& ihdr, 411*7c478bd9Sstevel@tonic-gate AudioEncoding tofmt, 412*7c478bd9Sstevel@tonic-gate unsigned int unitsz, 413*7c478bd9Sstevel@tonic-gate unsigned int& bufs) 414*7c478bd9Sstevel@tonic-gate { 415*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 416*7c478bd9Sstevel@tonic-gate char msg[BUFSIZ]; 417*7c478bd9Sstevel@tonic-gate char *infmt; 418*7c478bd9Sstevel@tonic-gate char *outfmt; 419*7c478bd9Sstevel@tonic-gate struct conv_list *lp; 420*7c478bd9Sstevel@tonic-gate int i; 421*7c478bd9Sstevel@tonic-gate AudioError err; 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate // Make sure we're converting something we understand 424*7c478bd9Sstevel@tonic-gate if ((ihdr.encoding != G721) && (ihdr.encoding != G723)) 425*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate conv = new AudioTypeG72X; 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate // Verify conversion 430*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 431*7c478bd9Sstevel@tonic-gate error: delete conv; 432*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 433*7c478bd9Sstevel@tonic-gate } 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate // Set up conversion, get encoding strings 436*7c478bd9Sstevel@tonic-gate infmt = ihdr.EncodingString(); 437*7c478bd9Sstevel@tonic-gate ihdr.encoding = tofmt; 438*7c478bd9Sstevel@tonic-gate ihdr.bytes_per_unit = unitsz; 439*7c478bd9Sstevel@tonic-gate ihdr.samples_per_unit = 1; 440*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 441*7c478bd9Sstevel@tonic-gate // Try converting to 16-bit linear 442*7c478bd9Sstevel@tonic-gate ihdr.encoding = LINEAR; 443*7c478bd9Sstevel@tonic-gate ihdr.bytes_per_unit = 2; 444*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) 445*7c478bd9Sstevel@tonic-gate goto error; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate outfmt = ihdr.EncodingString(); 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate sprintf(msg, MGET("Convert %s to %s"), infmt, outfmt); 450*7c478bd9Sstevel@tonic-gate delete infmt; 451*7c478bd9Sstevel@tonic-gate delete outfmt; 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate append_conv_list(list, ihdr, bufs, NULL, msg); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate // Need a separate converter instantiation for each channel 456*7c478bd9Sstevel@tonic-gate lp = get_last_conv(list); 457*7c478bd9Sstevel@tonic-gate for (i = 0; i < bufs; i++) { 458*7c478bd9Sstevel@tonic-gate if (i == 0) 459*7c478bd9Sstevel@tonic-gate lp[i].conv = conv; 460*7c478bd9Sstevel@tonic-gate else 461*7c478bd9Sstevel@tonic-gate lp[i].conv = new AudioTypeG72X; 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate // Sample rate conversion 467*7c478bd9Sstevel@tonic-gate AudioError 468*7c478bd9Sstevel@tonic-gate add_rate_convert( 469*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 470*7c478bd9Sstevel@tonic-gate AudioHdr& ihdr, 471*7c478bd9Sstevel@tonic-gate unsigned int torate, 472*7c478bd9Sstevel@tonic-gate unsigned int& bufs) 473*7c478bd9Sstevel@tonic-gate { 474*7c478bd9Sstevel@tonic-gate AudioTypeConvert* conv; 475*7c478bd9Sstevel@tonic-gate unsigned int fromrate; 476*7c478bd9Sstevel@tonic-gate char msg[BUFSIZ]; 477*7c478bd9Sstevel@tonic-gate char *inrate; 478*7c478bd9Sstevel@tonic-gate char *outrate; 479*7c478bd9Sstevel@tonic-gate struct conv_list *lp; 480*7c478bd9Sstevel@tonic-gate int i; 481*7c478bd9Sstevel@tonic-gate AudioError err; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate fromrate = ihdr.sample_rate; 484*7c478bd9Sstevel@tonic-gate conv = new AudioTypeSampleRate(fromrate, torate); 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate // Verify conversion; if no good, try converting to 16-bit pcm first 487*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 488*7c478bd9Sstevel@tonic-gate if (err = add_pcm_convert(list, ihdr, LINEAR, 2, bufs)) { 489*7c478bd9Sstevel@tonic-gate delete conv; 490*7c478bd9Sstevel@tonic-gate return (err); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) { 493*7c478bd9Sstevel@tonic-gate error: delete conv; 494*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate // Set up conversion, get encoding strings 499*7c478bd9Sstevel@tonic-gate inrate = ihdr.RateString(); 500*7c478bd9Sstevel@tonic-gate ihdr.sample_rate = torate; 501*7c478bd9Sstevel@tonic-gate if (!conv->CanConvert(ihdr)) 502*7c478bd9Sstevel@tonic-gate goto error; 503*7c478bd9Sstevel@tonic-gate outrate = ihdr.RateString(); 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate sprintf(msg, MGET("Convert %s to %s"), inrate, outrate); 506*7c478bd9Sstevel@tonic-gate delete inrate; 507*7c478bd9Sstevel@tonic-gate delete outrate; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate append_conv_list(list, ihdr, bufs, NULL, msg); 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate // Need a separate converter instantiation for each channel 512*7c478bd9Sstevel@tonic-gate lp = get_last_conv(list); 513*7c478bd9Sstevel@tonic-gate for (i = 0; i < bufs; i++) { 514*7c478bd9Sstevel@tonic-gate if (i == 0) 515*7c478bd9Sstevel@tonic-gate lp[i].conv = conv; 516*7c478bd9Sstevel@tonic-gate else 517*7c478bd9Sstevel@tonic-gate lp[i].conv = new AudioTypeSampleRate(fromrate, torate); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate return (AUDIO_SUCCESS); 520*7c478bd9Sstevel@tonic-gate } 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate // Returns TRUE if the specified header has a pcm type encoding 523*7c478bd9Sstevel@tonic-gate Boolean 524*7c478bd9Sstevel@tonic-gate pcmtype( 525*7c478bd9Sstevel@tonic-gate AudioHdr& hdr) 526*7c478bd9Sstevel@tonic-gate { 527*7c478bd9Sstevel@tonic-gate if (hdr.samples_per_unit != 1) 528*7c478bd9Sstevel@tonic-gate return (FALSE); 529*7c478bd9Sstevel@tonic-gate switch (hdr.encoding) { 530*7c478bd9Sstevel@tonic-gate case LINEAR: 531*7c478bd9Sstevel@tonic-gate case FLOAT: 532*7c478bd9Sstevel@tonic-gate case ULAW: 533*7c478bd9Sstevel@tonic-gate case ALAW: 534*7c478bd9Sstevel@tonic-gate return (TRUE); 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate return (FALSE); 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate #define IS_PCM(ihp) (pcmtype(ihp)) 540*7c478bd9Sstevel@tonic-gate #define IS_MONO(ihp) (ihp.channels == 1) 541*7c478bd9Sstevel@tonic-gate #define RATE_CONV(ihp, ohp) (ihp.sample_rate != ohp.sample_rate) 542*7c478bd9Sstevel@tonic-gate #define ENC_CONV(ihp, ohp) ((ihp.encoding != ohp.encoding) || \ 543*7c478bd9Sstevel@tonic-gate (ihp.samples_per_unit != \ 544*7c478bd9Sstevel@tonic-gate ohp.samples_per_unit) || \ 545*7c478bd9Sstevel@tonic-gate (ihp.bytes_per_unit != ohp.bytes_per_unit)) 546*7c478bd9Sstevel@tonic-gate #define CHAN_CONV(ihp, ohp) (ihp.channels != ohp.channels) 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate // Build the conversion list to get from input to output format 550*7c478bd9Sstevel@tonic-gate AudioError 551*7c478bd9Sstevel@tonic-gate build_conversion_list( 552*7c478bd9Sstevel@tonic-gate struct conv_list *&list, 553*7c478bd9Sstevel@tonic-gate AudioStream* ifp, 554*7c478bd9Sstevel@tonic-gate AudioStream* ofp) 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate AudioHdr ihdr; 557*7c478bd9Sstevel@tonic-gate AudioHdr ohdr; 558*7c478bd9Sstevel@tonic-gate unsigned int bufs; 559*7c478bd9Sstevel@tonic-gate AudioError err; 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate ihdr = ifp->GetHeader(); 562*7c478bd9Sstevel@tonic-gate ohdr = ofp->GetHeader(); 563*7c478bd9Sstevel@tonic-gate bufs = 1; 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate // Each pass, add another conversion, until there's no more to do 566*7c478bd9Sstevel@tonic-gate while (((ihdr != ohdr) || (bufs != 1)) && !err) { 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate // First off, if the target is mono, convert the source to mono 569*7c478bd9Sstevel@tonic-gate // before doing harder stuff, like sample rate conversion. 570*7c478bd9Sstevel@tonic-gate if (IS_MONO(ohdr)) { 571*7c478bd9Sstevel@tonic-gate if (!IS_MONO(ihdr)) { 572*7c478bd9Sstevel@tonic-gate if (IS_PCM(ihdr)) { 573*7c478bd9Sstevel@tonic-gate // If multi-channel pcm, 574*7c478bd9Sstevel@tonic-gate // mix the channels down to one 575*7c478bd9Sstevel@tonic-gate err = add_channel_convert(list, 576*7c478bd9Sstevel@tonic-gate ihdr, 1, bufs); 577*7c478bd9Sstevel@tonic-gate } else { 578*7c478bd9Sstevel@tonic-gate // If not pcm, demultiplex in order 579*7c478bd9Sstevel@tonic-gate // to decompress 580*7c478bd9Sstevel@tonic-gate err = add_mux_convert(list, ihdr, bufs); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate continue; 583*7c478bd9Sstevel@tonic-gate } else if (bufs != 1) { 584*7c478bd9Sstevel@tonic-gate // Multi-channel data was demultiplexed 585*7c478bd9Sstevel@tonic-gate if (IS_PCM(ihdr)) { 586*7c478bd9Sstevel@tonic-gate // If multi-channel pcm, recombine them 587*7c478bd9Sstevel@tonic-gate // for mixing down to one 588*7c478bd9Sstevel@tonic-gate err = add_mux_convert(list, ihdr, bufs); 589*7c478bd9Sstevel@tonic-gate } else { 590*7c478bd9Sstevel@tonic-gate // If not pcm, decompress it 591*7c478bd9Sstevel@tonic-gate err = add_decompress(list, ihdr, 592*7c478bd9Sstevel@tonic-gate ohdr.encoding, ohdr.bytes_per_unit, 593*7c478bd9Sstevel@tonic-gate bufs); 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate continue; 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate // At this point, input and output are both mono 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate } else if (ihdr.channels != 1) { 600*7c478bd9Sstevel@tonic-gate // Here if input and output are both multi-channel. 601*7c478bd9Sstevel@tonic-gate // If sample rate conversion or compression, 602*7c478bd9Sstevel@tonic-gate // split into multiple streams 603*7c478bd9Sstevel@tonic-gate if (RATE_CONV(ihdr, ohdr) || 604*7c478bd9Sstevel@tonic-gate (ENC_CONV(ihdr, ohdr) && 605*7c478bd9Sstevel@tonic-gate (!IS_PCM(ihdr) || !IS_PCM(ohdr)))) { 606*7c478bd9Sstevel@tonic-gate err = add_mux_convert(list, ihdr, bufs); 607*7c478bd9Sstevel@tonic-gate continue; 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate // Input is either mono, split into multiple buffers, or 612*7c478bd9Sstevel@tonic-gate // this is a conversion that can be handled multi-channel. 613*7c478bd9Sstevel@tonic-gate if (RATE_CONV(ihdr, ohdr)) { 614*7c478bd9Sstevel@tonic-gate // Decompress before sample-rate conversion 615*7c478bd9Sstevel@tonic-gate if (!IS_PCM(ihdr)) { 616*7c478bd9Sstevel@tonic-gate err = add_decompress(list, ihdr, 617*7c478bd9Sstevel@tonic-gate ohdr.encoding, ohdr.bytes_per_unit, 618*7c478bd9Sstevel@tonic-gate bufs); 619*7c478bd9Sstevel@tonic-gate } else { 620*7c478bd9Sstevel@tonic-gate err = add_rate_convert(list, ihdr, 621*7c478bd9Sstevel@tonic-gate ohdr.sample_rate, bufs); 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate continue; 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate if (ENC_CONV(ihdr, ohdr)) { 627*7c478bd9Sstevel@tonic-gate // Encoding is changing: 628*7c478bd9Sstevel@tonic-gate if (!IS_PCM(ihdr)) { 629*7c478bd9Sstevel@tonic-gate // if we start compressed, decompress 630*7c478bd9Sstevel@tonic-gate err = add_decompress(list, ihdr, 631*7c478bd9Sstevel@tonic-gate ohdr.encoding, ohdr.bytes_per_unit, 632*7c478bd9Sstevel@tonic-gate bufs); 633*7c478bd9Sstevel@tonic-gate } else if (IS_PCM(ohdr)) { 634*7c478bd9Sstevel@tonic-gate // we should be able to convert to PCM now 635*7c478bd9Sstevel@tonic-gate err = add_pcm_convert(list, ihdr, 636*7c478bd9Sstevel@tonic-gate ohdr.encoding, ohdr.bytes_per_unit, 637*7c478bd9Sstevel@tonic-gate bufs); 638*7c478bd9Sstevel@tonic-gate } else { 639*7c478bd9Sstevel@tonic-gate // we should be able to compress now 640*7c478bd9Sstevel@tonic-gate err = add_compress(list, ihdr, 641*7c478bd9Sstevel@tonic-gate ohdr.encoding, ohdr.bytes_per_unit, 642*7c478bd9Sstevel@tonic-gate bufs); 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate continue; 645*7c478bd9Sstevel@tonic-gate } 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate // The sample rate and encoding match. 648*7c478bd9Sstevel@tonic-gate // All that's left to do is get the channels right 649*7c478bd9Sstevel@tonic-gate if (bufs > 1) { 650*7c478bd9Sstevel@tonic-gate // Combine channels back into an interleaved stream 651*7c478bd9Sstevel@tonic-gate err = add_mux_convert(list, ihdr, bufs); 652*7c478bd9Sstevel@tonic-gate continue; 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate if (!IS_MONO(ohdr)) { 655*7c478bd9Sstevel@tonic-gate // If multi-channel output, try to accomodate 656*7c478bd9Sstevel@tonic-gate err = add_channel_convert(list, 657*7c478bd9Sstevel@tonic-gate ihdr, ohdr.channels, bufs); 658*7c478bd9Sstevel@tonic-gate continue; 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate // Everything should be done at this point. 662*7c478bd9Sstevel@tonic-gate // XXX - this should never be reached 663*7c478bd9Sstevel@tonic-gate return (AUDIO_ERR_FORMATLOCK); 664*7c478bd9Sstevel@tonic-gate } 665*7c478bd9Sstevel@tonic-gate return (err); 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate // Set up the conversion list and execute it 669*7c478bd9Sstevel@tonic-gate int 670*7c478bd9Sstevel@tonic-gate do_convert( 671*7c478bd9Sstevel@tonic-gate AudioStream* ifp, 672*7c478bd9Sstevel@tonic-gate AudioStream* ofp) 673*7c478bd9Sstevel@tonic-gate { 674*7c478bd9Sstevel@tonic-gate struct conv_list *list = NULL; 675*7c478bd9Sstevel@tonic-gate struct conv_list *lp; 676*7c478bd9Sstevel@tonic-gate AudioBuffer* obuf; 677*7c478bd9Sstevel@tonic-gate AudioBuffer** multibuf; 678*7c478bd9Sstevel@tonic-gate AudioError err; 679*7c478bd9Sstevel@tonic-gate AudioHdr ihdr; 680*7c478bd9Sstevel@tonic-gate AudioHdr ohdr; 681*7c478bd9Sstevel@tonic-gate Double pos = 0.0; 682*7c478bd9Sstevel@tonic-gate size_t len; 683*7c478bd9Sstevel@tonic-gate unsigned int i; 684*7c478bd9Sstevel@tonic-gate Double cvtlen; 685*7c478bd9Sstevel@tonic-gate char *msg1; 686*7c478bd9Sstevel@tonic-gate char *msg2; 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate ihdr = ifp->GetHeader(); 689*7c478bd9Sstevel@tonic-gate ohdr = ofp->GetHeader(); 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate // create conversion list 692*7c478bd9Sstevel@tonic-gate if ((err = build_conversion_list(list, ifp, ofp)) != AUDIO_SUCCESS) { 693*7c478bd9Sstevel@tonic-gate free_conv_list(list); 694*7c478bd9Sstevel@tonic-gate msg1 = ohdr.FormatString(); 695*7c478bd9Sstevel@tonic-gate Err(MGET("Cannot convert %s to %s\n"), ifp->GetName(), msg1); 696*7c478bd9Sstevel@tonic-gate delete msg1; 697*7c478bd9Sstevel@tonic-gate return (-1); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate // Print warnings for exceptional conditions 701*7c478bd9Sstevel@tonic-gate if ((ohdr.sample_rate < 8000) || (ohdr.sample_rate > 48000)) { 702*7c478bd9Sstevel@tonic-gate msg1 = ohdr.RateString(); 703*7c478bd9Sstevel@tonic-gate Err(MGET("Warning: converting %s to %s\n"), 704*7c478bd9Sstevel@tonic-gate ifp->GetName(), msg1); 705*7c478bd9Sstevel@tonic-gate delete msg1; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate if (ohdr.channels > 2) { 708*7c478bd9Sstevel@tonic-gate msg1 = ohdr.ChannelString(); 709*7c478bd9Sstevel@tonic-gate Err(MGET("Warning: converting %s to %s\n"), 710*7c478bd9Sstevel@tonic-gate ifp->GetName(), msg1); 711*7c478bd9Sstevel@tonic-gate delete msg1; 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate if (Debug) { 715*7c478bd9Sstevel@tonic-gate msg1 = ihdr.FormatString(); 716*7c478bd9Sstevel@tonic-gate msg2 = ohdr.FormatString(); 717*7c478bd9Sstevel@tonic-gate Err(MGET("Converting %s:\n\t\tfrom: %s\n\t\tto: %s\n"), 718*7c478bd9Sstevel@tonic-gate ifp->GetName(), msg1, msg2); 719*7c478bd9Sstevel@tonic-gate delete msg1; 720*7c478bd9Sstevel@tonic-gate delete msg2; 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate // Print each entry in the conversion list 723*7c478bd9Sstevel@tonic-gate for (lp = list; lp; lp = lp->next) { 724*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MGET("\t%s %s\n"), lp->desc, 725*7c478bd9Sstevel@tonic-gate (lp->bufcnt == 1) ? "" : MGET("(multi-channel)")); 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate } 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate // Calculate buffer size, obeying maximums 730*7c478bd9Sstevel@tonic-gate cvtlen = ihdr.Bytes_to_Time(CVTMAXBUF); 731*7c478bd9Sstevel@tonic-gate if (cvtlen > CVTMAXTIME) 732*7c478bd9Sstevel@tonic-gate cvtlen = CVTMAXTIME; 733*7c478bd9Sstevel@tonic-gate if (cvtlen > ohdr.Bytes_to_Time(CVTMAXBUF * 4)) 734*7c478bd9Sstevel@tonic-gate cvtlen = ohdr.Bytes_to_Time(CVTMAXBUF * 4); 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate // create output buf 737*7c478bd9Sstevel@tonic-gate if (!(obuf = new AudioBuffer(cvtlen, MGET("Audio Convert Buffer")))) { 738*7c478bd9Sstevel@tonic-gate Err(MGET("Can't create conversion buffer\n")); 739*7c478bd9Sstevel@tonic-gate exit(1); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate while (1) { 743*7c478bd9Sstevel@tonic-gate // Reset length 744*7c478bd9Sstevel@tonic-gate len = (size_t)ihdr.Time_to_Bytes(cvtlen); 745*7c478bd9Sstevel@tonic-gate if ((err = obuf->SetHeader(ihdr)) != AUDIO_SUCCESS) { 746*7c478bd9Sstevel@tonic-gate Err(MGET("Can't set buffer header: %s\n"), err.msg()); 747*7c478bd9Sstevel@tonic-gate return (-1); 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate // If growing buffer, free the old one rather than copy data 750*7c478bd9Sstevel@tonic-gate if (obuf->GetSize() < cvtlen) 751*7c478bd9Sstevel@tonic-gate obuf->SetSize(0.); 752*7c478bd9Sstevel@tonic-gate obuf->SetSize(cvtlen); 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate // Read a chunk of input and set the real length of buffer 755*7c478bd9Sstevel@tonic-gate // XXX - Use Copy() method?? Check for errors? 756*7c478bd9Sstevel@tonic-gate if (err = ifp->ReadData(obuf->GetAddress(), len, pos)) 757*7c478bd9Sstevel@tonic-gate break; 758*7c478bd9Sstevel@tonic-gate obuf->SetLength(ihdr.Bytes_to_Time(len)); 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate // Process each entry in the conversion list 761*7c478bd9Sstevel@tonic-gate for (lp = list; lp; lp = lp->next) { 762*7c478bd9Sstevel@tonic-gate if (lp->conv) { 763*7c478bd9Sstevel@tonic-gate // If multiple buffers, make multiple calls 764*7c478bd9Sstevel@tonic-gate if (lp->bufcnt == 1) { 765*7c478bd9Sstevel@tonic-gate err = lp->conv->Convert(obuf, lp->hdr); 766*7c478bd9Sstevel@tonic-gate } else { 767*7c478bd9Sstevel@tonic-gate multibuf = (AudioBuffer**)obuf; 768*7c478bd9Sstevel@tonic-gate for (i = 0; i < lp->bufcnt; i++) { 769*7c478bd9Sstevel@tonic-gate err = lp[i].conv->Convert( 770*7c478bd9Sstevel@tonic-gate multibuf[i], lp[i].hdr); 771*7c478bd9Sstevel@tonic-gate if (err) 772*7c478bd9Sstevel@tonic-gate break; 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate if (err) { 776*7c478bd9Sstevel@tonic-gate Err(MGET( 777*7c478bd9Sstevel@tonic-gate "Conversion failed: %s (%s)\n"), 778*7c478bd9Sstevel@tonic-gate lp->desc ? lp->desc : MGET("???"), 779*7c478bd9Sstevel@tonic-gate err.msg()); 780*7c478bd9Sstevel@tonic-gate return (-1); 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate if ((err = write_output(obuf, ofp)) != AUDIO_SUCCESS) { 786*7c478bd9Sstevel@tonic-gate Err(MGET("Error writing to output file %s (%s)\n"), 787*7c478bd9Sstevel@tonic-gate ofp->GetName(), err.msg()); 788*7c478bd9Sstevel@tonic-gate return (-1); 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate // Now flush any left overs from conversions w/state 793*7c478bd9Sstevel@tonic-gate obuf->SetLength(0.0); 794*7c478bd9Sstevel@tonic-gate for (lp = list; lp; lp = lp->next) { 795*7c478bd9Sstevel@tonic-gate if (lp->conv) { 796*7c478bd9Sstevel@tonic-gate // First check if there's any residual to convert. 797*7c478bd9Sstevel@tonic-gate // If not, just set the header to this type. 798*7c478bd9Sstevel@tonic-gate // If multiple buffers, make multiple calls 799*7c478bd9Sstevel@tonic-gate if (lp->bufcnt == 1) { 800*7c478bd9Sstevel@tonic-gate err = lp->conv->Convert(obuf, lp->hdr); 801*7c478bd9Sstevel@tonic-gate if (!err) 802*7c478bd9Sstevel@tonic-gate err = lp->conv->Flush(obuf); 803*7c478bd9Sstevel@tonic-gate } else { 804*7c478bd9Sstevel@tonic-gate multibuf = (AudioBuffer**)obuf; 805*7c478bd9Sstevel@tonic-gate for (i = 0; i < lp->bufcnt; i++) { 806*7c478bd9Sstevel@tonic-gate err = lp[i].conv->Convert( 807*7c478bd9Sstevel@tonic-gate multibuf[i], lp[i].hdr); 808*7c478bd9Sstevel@tonic-gate if (!err) { 809*7c478bd9Sstevel@tonic-gate err = lp[i].conv->Flush( 810*7c478bd9Sstevel@tonic-gate multibuf[i]); 811*7c478bd9Sstevel@tonic-gate } 812*7c478bd9Sstevel@tonic-gate if (err) 813*7c478bd9Sstevel@tonic-gate break; 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate if (err) { 817*7c478bd9Sstevel@tonic-gate Err(MGET( 818*7c478bd9Sstevel@tonic-gate "Warning: Flush of final bytes failed: " 819*7c478bd9Sstevel@tonic-gate "%s (%s)\n"), 820*7c478bd9Sstevel@tonic-gate lp->desc ? lp->desc : MGET("???"), 821*7c478bd9Sstevel@tonic-gate err.msg()); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate /* return (-1); ignore errors for now */ 824*7c478bd9Sstevel@tonic-gate break; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate if (obuf->GetLength() > 0.0) { 830*7c478bd9Sstevel@tonic-gate if ((err = write_output(obuf, ofp)) != AUDIO_SUCCESS) { 831*7c478bd9Sstevel@tonic-gate Err(MGET("Warning: Final write to %s failed (%s)\n"), 832*7c478bd9Sstevel@tonic-gate ofp->GetName(), err.msg()); 833*7c478bd9Sstevel@tonic-gate /* return (-1); ignore errors for now */ 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate delete obuf; 838*7c478bd9Sstevel@tonic-gate free_conv_list(list); 839*7c478bd9Sstevel@tonic-gate return (0); 840*7c478bd9Sstevel@tonic-gate } 841