/ src / CoreAudio / AudioFileTools / afrecord.cpp
afrecord.cpp
  1  /*	Copyright: 	� Copyright 2005 Apple Computer, Inc. All rights reserved.
  2  
  3  	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  4  			("Apple") in consideration of your agreement to the following terms, and your
  5  			use, installation, modification or redistribution of this Apple software
  6  			constitutes acceptance of these terms.  If you do not agree with these terms,
  7  			please do not use, install, modify or redistribute this Apple software.
  8  
  9  			In consideration of your agreement to abide by the following terms, and subject
 10  			to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
 11  			copyrights in this original Apple software (the "Apple Software"), to use,
 12  			reproduce, modify and redistribute the Apple Software, with or without
 13  			modifications, in source and/or binary forms; provided that if you redistribute
 14  			the Apple Software in its entirety and without modifications, you must retain
 15  			this notice and the following text and disclaimers in all such redistributions of
 16  			the Apple Software.  Neither the name, trademarks, service marks or logos of
 17  			Apple Computer, Inc. may be used to endorse or promote products derived from the
 18  			Apple Software without specific prior written permission from Apple.  Except as
 19  			expressly stated in this notice, no other rights or licenses, express or implied,
 20  			are granted by Apple herein, including but not limited to any patent rights that
 21  			may be infringed by your derivative works or by other works in which the Apple
 22  			Software may be incorporated.
 23  
 24  			The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
 25  			WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
 26  			WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 27  			PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
 28  			COMBINATION WITH YOUR PRODUCTS.
 29  
 30  			IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
 31  			CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 32  			GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 33  			ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
 34  			OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
 35  			(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
 36  			ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37  */
 38  /*=============================================================================
 39  	afrecord.cpp
 40  	
 41  =============================================================================*/
 42  
 43  #include "CAAudioFileRecorder.h"
 44  #include "CAXException.h"
 45  #include <unistd.h>
 46  #include "AFToolsCommon.h"
 47  #include "CAFilePathUtils.h"
 48  #include "CAAudioFileFormats.h"
 49  
 50  static void usage()
 51  {
 52  	fprintf(stderr,
 53  			"Usage:\n"
 54  			"%s [option...] audio_file\n\n"
 55  			"Options: (may appear before or after arguments)\n"
 56  			"    { -f | --file } file_format:\n"
 57  			, getprogname());
 58  	PrintAudioFileTypesAndFormats(stderr);
 59  	fprintf(stderr,
 60  			"    { -d | --data } data_format[@sample_rate_hz]:\n"
 61  			"        [-][BE|LE]{F|[U]I}{8|16|24|32|64}          (PCM)\n"
 62  			"            e.g. -BEI16 -F32@44100\n"
 63  			"        or a data format appropriate to file format, as above\n"
 64  			"    { -c | --channels } number_of_channels\n"
 65  			"        add/remove channels without regard to order\n"
 66  			"    { -l | --channellayout } layout_tag\n"
 67  			"        layout_tag: name of a constant from CoreAudioTypes.h\n"
 68  			"          (prefix \"kAudioChannelLayoutTag_\" may be omitted)\n"
 69  			"        if specified once, applies to output file; if twice, the first\n"
 70  			"          applies to the input file, the second to the output file\n"
 71  			"    { -b | --bitrate } bit_rate_bps\n"
 72  			"         e.g. 128000\n"
 73  			"    { -q | --quality } quality\n"
 74  			"        quality: 0-127\n"
 75  			"    { -v | --verbose }\n"
 76  			"        print progress verbosely\n"
 77  			"    { -p | --profile }\n"
 78  			"        collect and print performance profile\n"
 79  			);
 80  	exit(1);
 81  }
 82  
 83  static void	MissingArgument()
 84  {
 85  	fprintf(stderr, "missing argument\n\n");
 86  	usage();
 87  }
 88  
 89  static OSType Parse4CharCode(const char *arg, const char *name)
 90  {
 91  	OSType t;
 92  	StrToOSType(arg, t);
 93  	if (t == 0) {
 94  		fprintf(stderr, "invalid 4-char-code argument for %s: '%s'\n\n", name, arg);
 95  		usage();
 96  	}
 97  	return t;
 98  }
 99  
100  static int	ParseInt(const char *arg, const char *name)
101  {
102  	int x;
103  	if (sscanf(arg, "%d", &x) != 1) {
104  		fprintf(stderr, "invalid integer argument for %s: '%s'\n\n", name, arg);
105  		usage();
106  	}
107  	return x;
108  }
109  
110  static void Record(CAAudioFileRecorder &recorder)
111  {
112  	recorder.Start();
113  	printf("Recording, press any key to stop:");
114  	fflush(stdout);
115  	getchar();
116  	//sleep(10);
117  	recorder.Stop();
118  }
119  
120  int main(int argc, const char *argv[])
121  {
122  	const char *recordFileName = NULL;
123  
124  	// set up defaults
125  	AudioFileTypeID filetype = kAudioFileAIFFType;
126  	
127  	bool gotOutDataFormat = false;
128  	CAStreamBasicDescription dataFormat;
129  	dataFormat.mSampleRate = 44100.;	// later get this from the hardware
130  	dataFormat.mFormatID = kAudioFormatLinearPCM;
131  	dataFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
132  	dataFormat.mFramesPerPacket = 1;
133  	dataFormat.mChannelsPerFrame = 2;
134  	dataFormat.mBitsPerChannel = 16;
135  	dataFormat.mBytesPerPacket = dataFormat.mBytesPerFrame = 4;
136  	
137  	SInt32 bitrate = -1, quality = -1;
138  	
139  	// parse arguments
140  	for (int i = 1; i < argc; ++i) {
141  		const char *arg = argv[i];
142  		if (arg[0] != '-') {
143  			if (recordFileName != NULL) {
144  				fprintf(stderr, "may only specify one record file\n");
145  				usage();
146  			}
147  			recordFileName = arg;
148  		} else {
149  			arg += 1;
150  			if (arg[0] == 'f' || !strcmp(arg, "-file")) {
151  				if (++i == argc) MissingArgument();
152  				filetype = Parse4CharCode(argv[i], "-f | --file");
153  			} else if (arg[0] == 'd' || !strcmp(arg, "-data")) {
154  				if (++i == argc) MissingArgument();
155  				if (!ParseStreamDescription(argv[i], dataFormat))
156  					usage();
157  				gotOutDataFormat = true;
158  			} else if (arg[0] == 'b' || !strcmp(arg, "-bitrate")) {
159  				if (++i == argc) MissingArgument();
160  				bitrate = ParseInt(argv[i], "-b | --bitrate");
161  			} else if (arg[0] == 'q' || !strcmp(arg, "-quality")) {
162  				if (++i == argc) MissingArgument();
163  				quality = ParseInt(argv[i], "-q | --quality");
164  			} else {
165  				fprintf(stderr, "unknown argument: %s\n\n", arg - 1);
166  				usage();
167  			}
168  		}
169  	}
170  	
171  	if (recordFileName == NULL)
172  		usage();
173  	
174  	if (!gotOutDataFormat) {
175  		if (filetype == 0) {
176  			fprintf(stderr, "no output file or data format specified\n\n");
177  			usage();
178  		}
179  		if (!CAAudioFileFormats::Instance()->InferDataFormatFromFileFormat(filetype, dataFormat)) {
180  			fprintf(stderr, "Couldn't infer data format from file format\n\n");
181  			usage();
182  		}
183  	} else if (filetype == 0) {
184  		if (!CAAudioFileFormats::Instance()->InferFileFormatFromDataFormat(dataFormat, filetype)) {
185  			dataFormat.PrintFormat(stderr, "", "Couldn't infer file format from data format");
186  			usage();
187  		}
188  	}
189  
190  	unlink(recordFileName);
191  	
192  	if (dataFormat.IsPCM())
193  		dataFormat.ChangeNumberChannels(2, true);
194  	else
195  		dataFormat.mChannelsPerFrame = 2;
196  	
197  	try {
198  		const int kNumberBuffers = 3;
199  		const unsigned kBufferSize = 0x8000;
200  		CAAudioFileRecorder recorder(kNumberBuffers, kBufferSize);
201  		FSRef parentDir;
202  		CFStringRef filename;
203  		XThrowIfError(PosixPathToParentFSRefAndName(recordFileName, parentDir, filename), "couldn't find output directory");
204  		recorder.SetFile(parentDir, filename, filetype, dataFormat, NULL);
205  		
206  		CAAudioFile &recfile = recorder.GetFile();
207  		if (bitrate >= 0)
208  			recfile.SetConverterProperty(kAudioConverterEncodeBitRate, sizeof(UInt32), &bitrate);
209  		if (quality >= 0)
210  			recfile.SetConverterProperty(kAudioConverterCodecQuality, sizeof(UInt32), &quality);
211  
212  		Record(recorder);
213  	}
214  	catch (CAXException &e) {
215  		char buf[256];
216  		fprintf(stderr, "Error: %s (%s)\n", e.mOperation, CAXException::FormatError(buf, sizeof(buf), e.mError));
217  		return 1;
218  	}
219  	catch (...) {
220  		fprintf(stderr, "An unknown error occurred\n");
221  		return 1;
222  	}
223  	return 0;
224  }
225