CoreAudio中和讀寫音頻文件有關(guān)的有ExtAudioFile和AudioFile,這里介紹ExtAudioFile讀寫音頻文件的相關(guān)API和操作。
基礎(chǔ)知識介紹
音頻數(shù)據(jù)格式
pcm、aac、opus等,代表音頻的原始數(shù)據(jù),是音頻的數(shù)字信號。
文件格式
aif、caf、mp3等,文件存儲可以壓縮數(shù)據(jù)進行存儲如mp3,其中caf是指Core Audio Format,里面可以存儲所CoreAudio支持的數(shù)據(jù)格式。
讀文件
讀文件分為3步:
- 打開文件
- 讀取數(shù)據(jù)
- 關(guān)閉文件
打開文件
ExtAudioFile可以直接設(shè)置音頻數(shù)據(jù)格式(ClientDataFormat),如果有不同的采樣率、數(shù)據(jù)類型等,它會自動幫我們完成格式轉(zhuǎn)換的過程。
- (void)openFile:(NSString *)filePath format:(AudioStreamBasicDescription *)format {
CFURLRef cfurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filePath, kCFURLPOSIXPathStyle, false);
_dataFormat = format;
// 打開文件
OSStatus result = ExtAudioFileOpenURL(cfurl, &_fileId);
printf("ExtAudioFileOpenURL result %d \n", result);
// 讀取文件格式
UInt32 propSize = sizeof(AudioStreamBasicDescription);
result = ExtAudioFileGetProperty(_fileId, kExtAudioFileProperty_FileDataFormat, &propSize, &_fileFormat);
printf("get absd: %d \n", result);
// 設(shè)置音頻數(shù)據(jù)格式
propSize = sizeof(AudioStreamBasicDescription);
result = ExtAudioFileSetProperty(_fileId, kExtAudioFileProperty_ClientDataFormat, propSize, _dataFormat);
printf("set absd: %d \n", result);
}
讀取數(shù)據(jù)
將數(shù)據(jù)讀到AudioBufferList里面,inNumberFrames表示音頻幀數(shù)。
- (void)readData:(void *)data length:(int)length {
AudioBufferList ioData = {};
AudioBuffer buffer = {};
buffer.mData = data;
buffer.mDataByteSize = length;
buffer.mNumberChannels = _dataFormat->mChannelsPerFrame;
ioData.mBuffers[0] = buffer;
ioData.mNumberBuffers = 1;
UInt32 inNumberFrames = length / _dataFormat->mBytesPerFrame;
OSStatus result = ExtAudioFileRead(_fileId, &inNumberFrames, &ioData);
printf("ExtAudioFileRead %d \n", result);
}
關(guān)閉文件
使用完需要關(guān)閉文件,這是一個好習(xí)慣。
- (void)closeFile {
ExtAudioFileDispose(_fileId);
}
寫文件
寫文件也有3步:
- 創(chuàng)建文件
- 寫入數(shù)據(jù)
- 關(guān)閉文件
創(chuàng)建文件
需要按文件的類型創(chuàng)建文件。
- (void)createFile:(NSString *)filePath type:(AudioFileTypeID)type format:(AudioStreamBasicDescription *)format {
CFURLRef cfurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filePath, kCFURLPOSIXPathStyle, false);
_dataFormat = format;
// 創(chuàng)建文件
OSStatus result = ExtAudioFileCreateWithURL(cfurl, type, format, NULL, kAudioFileFlags_EraseFile, &_fileId);
printf("ExtAudioFileCreateWithURL result %d \n", result);
// 設(shè)置音頻數(shù)據(jù)格式
UInt32 propSize = sizeof(AudioStreamBasicDescription);
result = ExtAudioFileSetProperty(_fileId, kExtAudioFileProperty_ClientDataFormat, propSize, _dataFormat);
printf("set absd: %d \n", result);
}
寫入數(shù)據(jù)
寫入有兩個函數(shù)ExtAudioFileWriteAsync和ExtAudioFileWrite,看名字就知道了,一個是非阻塞的,一個是阻塞的,非阻塞的在關(guān)閉文件的時候會寫完數(shù)據(jù)。
- (void)writeData:(void *)data length:(int)length {
AudioBufferList ioData = {};
AudioBuffer buffer = {};
buffer.mData = data;
buffer.mDataByteSize = length;
buffer.mNumberChannels = _dataFormat->mChannelsPerFrame;
ioData.mBuffers[0] = buffer;
ioData.mNumberBuffers = 1;
UInt32 inNumberFrames = length / _dataFormat->mBytesPerFrame;
OSStatus result = ExtAudioFileWriteAsync(_fileId, inNumberFrames, &ioData);
printf("ExtAudioFileWriteAsync %d \n", result);
}
關(guān)閉文件
- (void)closeFile {
ExtAudioFileDispose(_fileId);
}