iOS音频播放(五)AudioUnit实现一款音频播放器

·  阅读 1382

结合前几章的学习,我们可以实现一款简单的音频播放器。

初始化

自定义初始化方法,需要传入音频文件路径。

- (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/…)是代码

分类:
阅读
标签:
分类:
阅读
标签:
收藏成功!
已添加到「」, 点击更改