Audio Unit 实现音频播放功能

489 篇文章 14 订阅
464 篇文章 13 订阅

1、Audio Unit 实现音频播放功能

使用Audio Unit播放音频的时候,我们使用一个I/O Unit就可以完成了,整体步骤和录制时差不多,具体如下:

  1. 设置好AudioComponentDescription,确定我们使用的Audio Unit类型

  2. 获取Audio Unit实例,我们有两种获取方式,通过AUGraph获取,通过AudioComponent获取。

  3. 设置Audio Unit的属性,告诉系统我们需要使用Audio Unit的哪些功能以及需要采集什么样的数据。

  4. 开始播放和停止播放。

  5. 从回调函数中将音频数据传给播放器。

1.1 初始化

- (instancetype)initWithAsbd:(AudioStreamBasicDescription)asbd {
    self = [super init];
    if (self) {
        _asbd = asbd;
        _queue = dispatch_queue_create("zf.audioPlayer", DISPATCH_QUEUE_SERIAL);
        [self setupDescription];
        [self getAudioUnits];
        [self setupAudioUnits];
    }
    return self;
}

1.2 设置AudioComponentDescription

- (void)setupAcd {
    _ioUnitDesc.componentType = kAudioUnitType_Output;
    //vpio模式
    _ioUnitDesc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    _ioUnitDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
    _ioUnitDesc.componentFlags = 0;
    _ioUnitDesc.componentFlagsMask = 0;
}

1.3 获取Audio Unit实例

通过AUGraph获取实例

- (void)getAudioUnits {
    OSStatus status = NewAUGraph(&_graph);
    printf("create graph %d \n", (int)status);
​
    AUNode ioNode;
    status = AUGraphAddNode(_graph, &_ioUnitDesc, &ioNode);
    printf("add ioNote %d \n", (int)status);
​
    //instantiate the audio units
    status = AUGraphOpen(_graph);
    printf("open graph %d \n", (int)status);
​
    //obtain references to the audio unit instances
    status = AUGraphNodeInfo(_graph, ioNode, NULL, &_ioUnit);
    printf("get ioUnit %d \n", (int)status);
}

通过AudioComponent获取实例

- (void)createInputUnit {
    AudioComponent comp = AudioComponentFindNext(NULL, &_ioUnitDesc);
    if (comp == NULL) {
    printf("can't get AudioComponent");
    }
    OSStatus status = AudioComponentInstanceNew(comp, &(_ioUnit));
    printf("creat audio unit %d \n", (int)status);
}
【学习地址】: FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击 1079654574加群领取哦~

1.4 设置Audio Unit属性

- (void)setupAudioUnits {
    OSStatus status;
    //设置io输入格式
    status = AudioUnitSetProperty(_ioUnit,
    kAudioUnitProperty_StreamFormat,
    kAudioUnitScope_Input,
    0,
    &_asbd,
    sizeof(_asbd));
    CheckError(status, "set ioUnit StreamFormat");
​
    NSTimeInterval bufferDuration = kSampleTime;
    NSError *error;
    [[AVAudioSession sharedInstance] setPreferredIOBufferDuration:bufferDuration error:&error];
​
    //设置输入回调
    AURenderCallbackStruct rcbs;
    rcbs.inputProc = &InputRenderCallback;
    rcbs.inputProcRefCon = (__bridge void *_Nullable)(self);
    status =  AudioUnitSetProperty(_ioUnit,
    kAudioUnitProperty_SetRenderCallback,
    kAudioUnitScope_Input,
    0,
    &rcbs,
    sizeof(rcbs));
    CheckError(status, "set render callback");
}

1.5 开始播放

注释的部分是不使用AUGraph的方式。

- (void)startRecord {
    dispatch_async(_queue, ^{
        OSStatus status;
        //  status = AudioUnitInitialize(self.ioUnit);
        //  printf("AudioUnitInitialize %d \n", (int)status);
        //  status = AudioOutputUnitStart(self.ioUnit);
        //  printf("AudioOutputUnitStart %d \n", (int)status);
​
        status = AUGraphInitialize(self.graph);
        printf("AUGraphInitialize %d \n", (int)status);
        status = AUGraphStart(self.graph);
        printf("AUGraphStart %d \n", (int)status);
    });
}

1.6 停止播放

- (void)stopRecord {
    dispatch_async(_queue, ^{
        OSStatus status;
        status = AUGraphStop(self.graph);
        printf("AUGraphStop %d \n", (int)status);
    });
}

1.7 回调中AURenderCallback填充数据

static OSStatus InputRenderCallback(void *inRefCon,
                                    AudioUnitRenderActionFlags *ioActionFlags,
                                    const AudioTimeStamp *inTimeStamp,
                                    UInt32 inBusNumber,
                                    UInt32 inNumberFrames,
                                    AudioBufferList *ioData) {
    ZFAudioUnitPlayer *player = (__bridge ZFAudioUnitPlayer *)inRefCon;
​
    [player.dataSource readDataToBuffer:ioData length:inNumberFrames];
​
    return noErr;
}

dataSource,从其他地方获取数据。这里是从文件中读取的数据,使用的是ExtAudioFile相关的API。

ExtAudioFile的使用-简书地址 完整代码请到我的Github中下载-项目地址

原文链接:Audio Unit 实现音频播放功能 - 知乎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值