views:

438

answers:

1

I have to record audio on an iPhone that will play back on Windows Media Player, using no non-standard codecs; that is, using no codecs that don't already ship with WMP. (Corporate requirement.) The audio has to go base-64 to a server, so I need to get the audio size as small as possible. Even at 8Kb recording frequency, AIFF files take ginormous amounts of space. I can't seem to find a compressed AIFF format that WMP will swallow.

+2  A: 

Best bet is to write WAV files with ulaw or alaw compression (the mFormatId of your AudioStreamBasicDescription would be kAudioFormatULaw or kAudioFormatALaw. Test to see which one gives you the smallest file sizes for your application.

Here's some code to set up an ExtAudioFile instance to write ulaw:

NSArray * docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * docDir = [docs objectAtIndex:0]; 
NSURL * outFile = [NSURL fileURLWithPath:[docDir stringByAppendingPathComponent:@"OutFile.wav"]];
AudioStreamBasicDescription asbd;
bzero(&asbd, sizeof(asbd));
asbd.mSampleRate = 11025; // or whatever
asbd.mFramesPerPacket = 1;
asbd.mChannelsPerFrame = 1;
asbd.mFormatID = kAudioFormatULaw; //or kAudioFormatALaw
ExtAudioFileRef theFile;
err = ExtAudioFileCreateWithURL((CFURLRef)outFile,
        kAudioFileWAVEType,
        &asbd,
        0,
        kAudioFileFlags_EraseFile,
        &theFile);

Hope that helps.

--- ADDED ---

Here are modifications to the SpeakHere sample code to get ulaw compression:

SpeakHereController.mm:116

recordFilePath = (CFStringRef)[NSTemporaryDirectory() stringByAppendingPathComponent: @"recordedFile.wav"];

SpeakHereController.mm:158

recorder->startRecord(CFSTR("recordedFile.wav"));

AQRecorder.mm:192

SetupAudioFormat(kAudioFormatULaw);

AQRecorder.mm:215

XThrowIfError(AudioFileCreateWithURL(url, kAudioFileWAVEType, &mRecordFormat, kAudioFileFlags_EraseFile,
           &mRecordFile), "AudioFileCreateWithURL failed");
Art Gillespie
Hmmm, I'm using the SpeakHere code sample as a base, and managed to switch the file type and format to WAVE and uLaw with no problem. (The sample doesn't use the extended audio services, but it seemed similar enough.) The app records and plays back with no complaint.HOWEVER, weird thing is that it works if the file is written to NSTemporaryDirectory(), but not to a file in the app's Documents folder. Do you know why?
Exactly how is it failing?
Art Gillespie
AudioFileCreateWithURL failed (-50)
-50 is `paramErr`. My guess is that if it's working with `NSTemporaryDirectory()` but not with another file URL, that the file URL isn't valid for some reason. What value are you passing for `AudioFileCreateWithURL` flags parameter?
Art Gillespie
kAudioFileFlags_EraseFile
Dunno, then. In my experience, I've only gotten `paramErr` when I've used a munged URL for the file's path. Without looking at your code, I couldn't say.
Art Gillespie
// NSString *recordFile = [NSTemporaryDirectory() stringByAppendingPathComponent: (NSString*)inRecordFile]; NSArray *docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docDir = [docs objectAtIndex:0]; NSString *recordFile = [docDir stringByAppendingPathComponent:(NSString*)inRecordFile]; CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)recordFile, NULL);The first line, commented out, is the original code; the three lines following were my replacement. The resulting path is reasonable, and I'm stumped.
I just modified the SpeakHere sample project to record directly to ulaw—the relevant changes are appended to the answer above. Let me know if you'd like me to email you an archive of the modified project.
Art Gillespie
Thanks, Art, I appreciate the help.I'd gotten as far as modifying SpeakHere to save the WAV file; I'd just gotten confused as to why NSTemporaryDirectory worked and the sandboxed Documents folder didn't. More academic curiosity than anything else--I just copied the resulting file out of the temp directory and it works fine. Thanks again.