#import #import #import #import OSStatus MyFileRenderCallback(void * inRefCon, AudioUnitRenderActionFlags *inActionFlag, const AudioTimeStamp *timeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData); OSStatus MyACComplexInputProc(AudioConverterRef inAudioConverter, UInt32 * ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription ** ioDataPacketDescription, void * inUserData); OSStatus OpenAudioFile(AudioFileID * fileID, AudioStreamBasicDescription * fileASBD, AudioStreamBasicDescription * clientASBD, const char * filename); UInt64 totalPacketCount = 0; UInt64 fileByteCount = 0; UInt32 packetSize = 0; AudioConverterRef audioConverter; Boolean isPlaying = NO; UInt64 playedPacketOffset = 0; UInt64 playedByteOffset = 0; char * audioBuffer = NULL; char * sourceBuffer = NULL; int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; ComponentDescription desc; Component audioComp; AudioUnit outputUnit; AudioFileID fileID; OSStatus err; desc.componentFlags = 0; desc.componentFlagsMask = 0; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentType = kAudioUnitType_Output; audioComp = FindNextComponent(NULL, &desc); if (audioComp == NULL) printf("Connot found default output device\n"); err = OpenAComponent(audioComp, &outputUnit); if (outputUnit == NULL) printf("Cannot open AudioUnit from description\n"); if (err) { [pool drain]; exit(-1); } UInt32 size; Boolean isWritable; AudioStreamBasicDescription outputASBD; AudioStreamBasicDescription inputASBD; err = AudioUnitGetPropertyInfo(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &size, &isWritable); err = AudioUnitGetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputASBD, &size); err = AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outputASBD, size); err = AudioUnitInitialize(outputUnit); AURenderCallbackStruct renderCallback; memset(&renderCallback, 0, sizeof(AURenderCallbackStruct)); renderCallback.inputProc = MyFileRenderCallback; renderCallback.inputProcRefCon = 0; err = AudioUnitSetProperty(outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct)); if (argc == 2) { err = OpenAudioFile(&fileID, &inputASBD, &outputASBD, argv[1]); } else { printf("input error\n"); [pool drain]; exit(-1); } if (err) { printf("cannot open file: %s\n", argv[1]); [pool drain]; exit(-1); } AudioConverterNew(&inputASBD, &outputASBD, &audioConverter); UInt32 bytesReturned = 0; UInt32 packets = totalPacketCount; audioBuffer = malloc(fileByteCount); err = AudioFileReadPackets(fileID, NO, &bytesReturned, NULL, 0, &packets, audioBuffer); if (err) return -1; isPlaying = YES; AudioOutputUnitStart(outputUnit); printf("Playing...\n"); while (isPlaying) { usleep(10000); } usleep(10000); AudioOutputUnitStop(outputUnit); AudioConverterDispose(audioConverter); free(audioBuffer); if (sourceBuffer) free(sourceBuffer); AudioFileClose(fileID); AudioUnitUninitialize(outputUnit); [pool drain]; return 0; } OSStatus OpenAudioFile(AudioFileID * fileID, AudioStreamBasicDescription * fileASBD, AudioStreamBasicDescription * clientASBD, const char * filename) { OSStatus err = noErr; UInt32 size; CFURLRef fileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)filename, strlen(filename), NO); err = AudioFileOpenURL(fileURL, kAudioFileReadPermission, 0, fileID); if (err == kAudioFileUnsupportedFileTypeError) { printf("Unsupported File Type!\n"); return err; } size = sizeof(AudioStreamBasicDescription); memset(fileASBD, 0, size); err = AudioFileGetProperty(*fileID, kAudioFilePropertyDataFormat, &size, fileASBD); size = sizeof(totalPacketCount); err = AudioFileGetProperty(*fileID, kAudioFilePropertyAudioDataPacketCount, &size, &totalPacketCount); size = sizeof(fileByteCount); err = AudioFileGetProperty(*fileID, kAudioFilePropertyAudioDataByteCount, &size, &fileByteCount); size = sizeof(packetSize); err = AudioFileGetProperty(*fileID, kAudioFilePropertyMaximumPacketSize, &size, &packetSize); return err; } OSStatus MyFileRenderCallback(void * inRefCon, AudioUnitRenderActionFlags *inActionFlag, const AudioTimeStamp *timeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData) { OSStatus err = noErr; AudioConverterFillComplexBuffer(audioConverter, MyACComplexInputProc, 0, &inNumFrames, ioData, 0); return err; } OSStatus MyACComplexInputProc(AudioConverterRef inAudioConverter, UInt32 * ioNumberDataPackets, AudioBufferList * ioData, AudioStreamPacketDescription ** ioDataPacketDescription, void * inUserData) { OSStatus err = noErr; UInt32 bytesCopied = 0; ioData->mBuffers[0].mData = NULL; ioData->mBuffers[0].mDataByteSize = 0; if (playedPacketOffset + *ioNumberDataPackets > totalPacketCount) *ioNumberDataPackets = totalPacketCount - playedPacketOffset; if (*ioNumberDataPackets) { if (sourceBuffer != NULL) { free(sourceBuffer); sourceBuffer = NULL; } bytesCopied = *ioNumberDataPackets * packetSize; sourceBuffer = calloc(1, bytesCopied); memcpy(sourceBuffer, audioBuffer + playedByteOffset, bytesCopied); playedByteOffset += bytesCopied; playedPacketOffset += *ioNumberDataPackets; ioData->mBuffers[0].mData = sourceBuffer; ioData->mBuffers[0].mDataByteSize = bytesCopied; } else { ioData->mBuffers[0].mData = NULL; ioData->mBuffers[0].mDataByteSize = 0; isPlaying = NO; err = noErr; } return err; }