美文网首页
Audio Unit采集音频

Audio Unit采集音频

作者: AntKing | 来源:发表于2019-12-16 14:12 被阅读0次

使用Audio Unit采集音频主要步骤有三步

GitHub源码地址

1 配置AudioStreamBasicDescription


struct AudioStreamBasicDescription
{
    Float64             mSampleRate;
    AudioFormatID       mFormatID;
    AudioFormatFlags    mFormatFlags;
    UInt32              mBytesPerPacket;
    UInt32              mFramesPerPacket;
    UInt32              mBytesPerFrame;
    UInt32              mChannelsPerFrame;
    UInt32              mBitsPerChannel;
    UInt32              mReserved;
}

#pragma mark - ASBD Audio Format
-(void)configureAudioToAudioFormat:(AudioStreamBasicDescription *)audioFormat
                   byParamFormatID:(UInt32)formatID
                        sampleRate:(Float64)sampleRate
                      channelCount:(UInt32)channelCount {
    
    
    AudioStreamBasicDescription dataFormat = {0};
    UInt32 size = sizeof(dataFormat.mSampleRate);
    // Get hardware origin sample rate. (Recommended it)
    Float64 hardwareSampleRate = 0;
    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate,
                            &size,
                            &hardwareSampleRate);
    // Manual set sample rate
    dataFormat.mSampleRate = sampleRate;

    size = sizeof(dataFormat.mChannelsPerFrame);
    // Get hardware origin channels number. (Must refer to it)
    UInt32 hardwareNumberChannels = 0;
    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels,
                            &size,
                            &hardwareNumberChannels);
    dataFormat.mChannelsPerFrame = channelCount;
    
    dataFormat.mFormatID = formatID;
    
    if (formatID == kAudioFormatLinearPCM) {
        dataFormat.mFormatFlags     = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
        dataFormat.mBitsPerChannel  = KXDXAudioBitsPerChannel;
        dataFormat.mBytesPerPacket  = dataFormat.mBytesPerFrame = (dataFormat.mBitsPerChannel / 8) * dataFormat.mChannelsPerFrame;
        dataFormat.mFramesPerPacket = kXDXAudioPCMFramesPerPacket;
    }

    memcpy(audioFormat, &dataFormat, sizeof(dataFormat));
    NSLog(@"%@:  %s - sample rate:%f, channel count:%d",kModuleName, __func__,sampleRate,channelCount);
}

步骤2 设置sample time

The typical maximum I/O buffer duration is 0.93 s (corresponding to 4096 sample frames at a sample rate of 44.1 kHz). The minimum I/O buffer duration is at least 0.005 s (256 frames) but might be lower depending on the hardware in use.
You can set a preferred I/O buffer duration before or after activating the audio session.

范围在0.005s 至0.93s之间


// Set sample time
    [[AVAudioSession sharedInstance] setPreferredIOBufferDuration:durationSec error:NULL];

步骤3 配置Audio Unit

3.1 创建Audio Unit


- (AudioUnit)createAudioUnitObject {
    AudioUnit audioUnit;
    AudioComponentDescription audioDesc;
    audioDesc.componentType         = kAudioUnitType_Output;
    audioDesc.componentSubType      = kAudioUnitSubType_VoiceProcessingIO;//kAudioUnitSubType_RemoteIO;
    audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
    audioDesc.componentFlags        = 0;
    audioDesc.componentFlagsMask    = 0;
    
    AudioComponent inputComponent = AudioComponentFindNext(NULL, &audioDesc);
    OSStatus status = AudioComponentInstanceNew(inputComponent, &audioUnit);
    if (status != noErr)  {
        NSLog(@"%@:  %s - create audio unit failed, status : %d \n",kModuleName, __func__, status);
        return NULL;
    }else {
        return audioUnit;
    }
}

3.2 设置AudioBufferList


- (void)initCaptureAudioBufferWithAudioUnit:(AudioUnit)audioUnit channelCount:(int)channelCount dataByteSize:(int)dataByteSize {
    // Disable AU buffer allocation for the recorder, we allocate our own.
    UInt32 flag     = 0;
    OSStatus status = AudioUnitSetProperty(audioUnit,
                                           kAudioUnitProperty_ShouldAllocateBuffer,
                                           kAudioUnitScope_Output,
                                           INPUT_BUS,
                                           &flag,
                                           sizeof(flag));
    if (status != noErr) {
        NSLog(@"%@:  %s - couldn't allocate buffer of callback, status : %d \n", kModuleName, __func__, status);
    }

    AudioBufferList * buffList = (AudioBufferList*)malloc(sizeof(AudioBufferList));
    buffList->mNumberBuffers               = 1;
    buffList->mBuffers[0].mNumberChannels  = channelCount;//1
    buffList->mBuffers[0].mDataByteSize    = dataByteSize;//2048
    buffList->mBuffers[0].mData            = (UInt32 *)malloc(dataByteSize);//2048
    m_buffList = buffList;
}

3.3 设置Audio Unit property


- (void)setAudioUnitPropertyWithAudioUnit:(AudioUnit)audioUnit dataFormat:(AudioStreamBasicDescription)dataFormat {
    
    OSStatus status;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  INPUT_BUS,
                                  &dataFormat,
                                  sizeof(dataFormat));
    if (status != noErr) {
        NSLog(@"%@:  %s - set audio unit stream format failed, status : %d \n",kModuleName, __func__,status);
    }
    
    /*
     // remove echo but can't effect by testing.
     UInt32 echoCancellation = 0;
     AudioUnitSetProperty(m_audioUnit,
     kAUVoiceIOProperty_BypassVoiceProcessing,
     kAudioUnitScope_Global,
     0,
     &echoCancellation,
     sizeof(echoCancellation));
     */
    
    UInt32 enableFlag = 1;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_EnableIO,
                                  kAudioUnitScope_Input,
                                  INPUT_BUS,
                                  &enableFlag,
                                  sizeof(enableFlag));
    if (status != noErr) {
        NSLog(@"%@:  %s - could not enable input on AURemoteIO, status : %d \n",kModuleName, __func__, status);
    }
    
    UInt32 disableFlag = 0;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_EnableIO,
                                  kAudioUnitScope_Output,
                                  OUTPUT_BUS,
                                  &disableFlag,
                                  sizeof(disableFlag));
    if (status != noErr) {
        NSLog(@"%@:  %s - could not enable output on AURemoteIO, status : %d \n",kModuleName, __func__,status);
    }
}

3.4 设置录音回调

- (void)initCaptureCallbackWithAudioUnit:(AudioUnit)audioUnit callBack:(AURenderCallback)callBack {
    AURenderCallbackStruct captureCallback;
    captureCallback.inputProc        = callBack;
    captureCallback.inputProcRefCon  = (__bridge void *)self;
    OSStatus status                  = AudioUnitSetProperty(audioUnit,
                                                            kAudioOutputUnitProperty_SetInputCallback,
                                                            kAudioUnitScope_Global,
                                                            INPUT_BUS,
                                                            &captureCallback,
                                                            sizeof(captureCallback));
    
    if (status != noErr) {
        NSLog(@"%@:  %s - Audio Unit set capture callback failed, status : %d \n",kModuleName, __func__,status);
    }
}


3.5 录音回调中我们既可以拿到从音频设备录音得到的数据


// 音频录制回调
static OSStatus AudioCaptureCallback(void                       *inRefCon,
                                     AudioUnitRenderActionFlags *ioActionFlags,
                                     const AudioTimeStamp       *inTimeStamp,
                                     UInt32                     inBusNumber,
                                     UInt32                     inNumberFrames,
                                     AudioBufferList            *ioData) {
    //这个函数的作用是播放声音
    AudioUnitRender(m_audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, m_buffList);
    
    if (g_av_base_time == 0) {
        return noErr;
    }
    
    XDXAudioCaptureManager *manager = (__bridge XDXAudioCaptureManager *)inRefCon;
    
    Float64 currentTime = CMTimeGetSeconds(CMClockMakeHostTimeFromSystemUnits(inTimeStamp->mHostTime));
    int64_t pts = (int64_t)((currentTime - g_av_base_time) * 1000);
    
    /*  Test audio fps
     static Float64 lastTime = 0;
     Float64 currentTime = CMTimeGetSeconds(CMClockMakeHostTimeFromSystemUnits(inTimeStamp->mHostTime))*1000;
     NSLog(@"Test duration - %f",currentTime - lastTime);
     lastTime = currentTime;
     */
    
    void    *bufferData = m_buffList->mBuffers[0].mData;
    UInt32   bufferSize = m_buffList->mBuffers[0].mDataByteSize;
    
    //    NSLog(@"demon = %d",bufferSize);
    
    struct XDXCaptureAudioData audioData = {
        .data           = bufferData,
        .size           = bufferSize,
        .inNumberFrames = inNumberFrames,
        .pts            = pts,
    };
    
    XDXCaptureAudioDataRef audioDataRef = &audioData;
    
    if ([manager.delegate respondsToSelector:@selector(receiveAudioDataByDevice:)]) {
        [manager.delegate receiveAudioDataByDevice:audioDataRef];
    }
        
    return noErr;
}


相关文章

  • Audio Unit采集音频实战

    需求 iOS中使用Audio unit实现音频数据采集,直接采集PCM无损数据, Audio Unit不能直接采集...

  • Audio Unit采集音频

    使用Audio Unit采集音频主要步骤有三步 GitHub源码地址 1 配置AudioStreamBasicDe...

  • 如何使用Audio Unit 播放音频

    Audio Unit 实现音频播放功能 使用Audio Unit播放音频的时候,我们使用一个I/O Unit就可以...

  • 如何使用Audio Unit 录制音频

    Audio Unit 实现音频录制功能 使用Audio Unit录制的时候,过程相对简单,我们使用一个Audio ...

  • 关于AudioUnit的一些基础知识

    Audio Unit 能做什么 Audio Unit 可以实现混音、均衡器、音频格式转化、实时的音频录制和播放等功...

  • AudioUnit使用

    在iOS上Audio Unit是比较底层的接口,可以理解为其是对音频硬件驱动的封装。用来进行低延迟的音频采集和播放...

  • AVFondation 之音频

    核心音频概述(音频是一个值得研究的方向) Core Audio Overview iOS Audio Unit i...

  • Mac os 使用Audio Unit 采集音频

    需要使用的头文件 设置+初始化 开始 结束 建议在回调函数里把数据写到本地然后用FFMpeg播放一下看看采集到的数...

  • AudioUnit 基础知识

    Overwrite 个人理解的名词解释: Audio Unit:音频单元,通常指一个音频单元实例,或者 Audio...

  • Webrtc音频采集和播放

    一:音频采集和播放 音频的采集和播放使用模块AudioDeviceModule,定义在modules/audio_...

网友评论

      本文标题:Audio Unit采集音频

      本文链接:https://www.haomeiwen.com/subject/ttxdnctx.html