iOS实现耳返功能

647 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情

iOS实现耳返功能

实现iOS 耳返的功能可以通过AudioUnit来进行实现。

实现的步骤如下:

  1. 创建AudioSession获取硬件的权限

    在iOS的音视频开发中,使用音频回话需要创建一个AudioSession,用于管理与获取iOS设备的音频信息。

    AVAudioSession *session = [AVAudioSession sharedInstance];
    

    根据我们的具体需求来设置类别:

    1)在类别中如果需要进行录音等操作,需要设置类别为record 类型

    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&error];
    

    2)设置I/O 的buffer,buffer越小说明延迟越低

    NSTimeInterval bufferTimer = 0.01;
    [session setPreferredIOBufferDuration:bufferTimer error:nil];
    

    3) 进行audioSession被打断进行监听

    /// 接收session 被打断的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    /// 处理监听
    - (void)handleInterruption:(NSNotification *)notification {
    NSDictionary *dic = notification.userInfo;
    if ([notification.userInfo[AVAudioSessionInterruptionTypeKey] intValue] == AVAudioSessionInterruptionTypeBegan) {
        // 开始被打断,暂停
    } else if ([dic[AVAudioSessionInterruptionTypeKey] intValue] == AVAudioSessionInterruptionTypeEnded) {
        // 结束打断了, 重开
    }
    

}

  1. 构建AudioUnit

    在创建并启用音频会话之后,就可以构建AudioUnit 了。构建的时候需要制定类型、子类型以及厂商。我们以RemoteIO 这个AudioUnit为例来讲解他的参设置,RemoteIO 这个AudioUnit 是一个和硬件相关的Unit,他分为输入端和输出端。输入端一般指的就是麦克风,输出端指的就是扬声器或者耳机。如果同时需要输入输出,即我们的耳返功能,则需要开发者做一些设置将他们联系起来。

     

    • 指定AudioUnit 的属性
    • 实例化AUGraph对象(代表 audio processing graph)。(可以通过其他方式创建audioUnit)
    • 实例化一个或多个AUNode对象(每一个代表一个 audio unit in the graph.)。
    • 添加nodes到graphgraph并且实例化
    • 打开graph并且实例化 audio units
    • 获取audioUnit引用
    • 使用属性配置AudioUnit  
      AudioComponentDescription audioDesc = {0};
      audioDesc.componentManufacturer =       kAudioUnitManufacturer_Apple;
      audioDesc.componentType = kAudioUnitType_Output;
      audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
      audioDesc.componentFlags = 0;
      audioDesc.componentFlagsMask = 0;
      // 创建augraph
      AUGraph processingGraph;
      NewAUGraph(&processingGraph);
      // 按照描述在AUGraph 中增加一个AUNode
      AUNode ioNode;
      AUGraphAddNode(processingGraph, &audioDesc, &ioNode);
      // 打开AUGraph
      AUGraphOpen(processingGraph);
      // 获得audioUnit 的引用
      AudioUnit audioUnit;
      AUGraphNodeInfo(processingGraph, ioNode, NULL, &audioUnit);
    
    //  配置属性
    UInt32 oneFlag = 1;
    AudioUnitSetProperty(remoteIOUnit,                  
       kAudioOutputUnitProperty_EnableIO,
                         kAudioUnitScope_Output,
                         0,
                         &oneFlag,
                         sizeof(oneFlag));
    
    AudioUnitSetProperty(remoteIOUnit,   // unit                 
    kAudioOutputUnitProperty_EnableIO, // ID
                         kAudioUnitScope_Input, // scope
                         1,  // element
                         &oneFlag,
                         sizeof(oneFlag));
    

3. 使用`AUGraphSetNodeInputCallback` 配置audioUnit回调函数

```Objc
    inputProc.inputProc = myInputCallBack;
    inputProc.inputProcRefCon = (__bridge void *)(self);
    AUGraphSetNodeInputCallback(auGraph, remoteIONode, 0, &inputProc)

4.使用audioGraph为audioUnit 分配内存

// 在调用initialize 之前可以先调用update 方法,如果update 成功,则graph 已经被动态配置就位
AUGraphUpdate(auGraph, NULL);
AUGraphInitialize(auGraph);

  1. 开始接收数据并回传给耳机
 AUGraphStart(auGraph);
 // cashow 是打印状态
 CAShow(auGraph);
  1. 停止使用
AUGraphStop(auGraph);

参考文章: Audio Unit: iOS中最底层最强大音频控制API