结合前几章的学习,我们可以实现一款简单的音频播放器。
初始化
自定义初始化方法,需要传入音频文件路径。
- (instancetype)initWithFilePath:(NSString *)path;
AUGraph回调
构造一个AURenderCallbackStruct的结构体,并制定一个回调函数,然后设置给RemoteIO Unit的输入端,当RemoteIO Unit需要数据输入的时候就会频繁回调该回调函数PlayCallback。
/// 回调方式
AURenderCallbackStruct playCallback;
playCallback.inputProc = PlayCallback;
playCallback.inputProcRefCon = (__bridge void *)self;
status = AUGraphSetNodeInputCallback(mPlayerGraph, mPlayerIONode, 0, &playCallback);
NSAssert(!status, @"AudioUnitSetProperty error");
//7:初始化Graph
status = AUGraphInitialize(mPlayerGraph);
CheckStatus(status, @"Couldn't Initialize the graph", YES);
//8:显示Graph结构
CAShow(mPlayerGraph);
/// 回调函数
OSStatus PlayCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
NAudioUnit *audioUnit = (__bridge NAudioUnit *)inRefCon;
audioUnit->buffList->mBuffers[0].mDataByteSize = CONST_BUFFER_SIZE;
OSStatus status = ExtAudioFileRead(audioUnit->exAudioFile, &inNumberFrames, audioUnit->buffList);
if (status) NSLog(@"转换格式失败");
if (!inNumberFrames) NSLog(@"播放结束");
NSLog(@"total size: %llu,out size: %d", audioUnit->totalSize, audioUnit->buffList->mBuffers[0].mDataByteSize);
memcpy(ioData->mBuffers[0].mData, audioUnit->buffList->mBuffers[0].mData, audioUnit->buffList->mBuffers[0].mDataByteSize);
ioData->mBuffers[0].mDataByteSize = audioUnit->buffList->mBuffers[0].mDataByteSize;
audioUnit->readedSize += audioUnit->buffList->mBuffers[0].mDataByteSize / audioUnit->outputFormat.mBytesPerFrame; //Bytes per Frame = 2,所以是每2bytes一帧
fwrite(audioUnit->buffList->mBuffers[0].mData, audioUnit->buffList->mBuffers[0].mDataByteSize, 1, [audioUnit pcmFile]);
/// 回调进度
UInt32 byteSize = audioUnit->buffList->mBuffers[0].mDataByteSize;
audioUnit.progress(byteSize);
dispatch_async(dispatch_get_main_queue(), ^{
if (byteSize <= 0) {
audioUnit->totalSize = 0;
audioUnit->readedSize = 0;
}
});
return noErr;
}
PlayCallback:函数通过ExtAudioFileRead读取文件数据,另一方面不停地向外面回调读取进度。
开始播放
调用AUGraphStart方法,开始播放音频数据。
- (BOOL)play;
停止播放
调用AUGraphStop方法,停止播放音频数据。
- (void)stop;
获取当前播放时间
读取的数据时长 / 文件总时长
- (double)getCurrentTime;
示例代码
这里(github.com/Nicholas86/…)是代码