DSP

IOS音频架构之Audio Unit

2019-07-13 16:42发布

        在前面的章节部分我们已经对IOS音频结构有了一个清晰的认识,知道Audio Unit是位于整个音频结构的最底层,这一层很多API已经开始和硬件打交道了。所以比较复杂,有了前面的基础再来看这个部分就比较的容易了。 先来看看Audio Unit的结构图: 结构图很简单了,就不做过多的描述了。重点说下中间那部分DSP。因为以前读研的时候学的是DSP嵌入式驱动开发算法移植,所以对这部分比较熟悉,就和大家摆摆龙门阵。DSP全名是digital signal processing 数字信号处理。音频信号经过设备采样之后都变成了数字信号。所以采用专门的信号处理芯片来处理效率会非常的高。DSP是个大家族,常见的有TI公司,AD公司。每个公司下有很多系列,每个系列下又有很多种类。这是一个专门的学科,如果大家有兴趣可以花点时间研究研究,这里就不说了。 下面我们还是来看看从软件层面上如何使用这个东东: (1)Audio Unit 初始化参数设置 这里可以设置音频流的各种参数,比如采样频率、量化位数、通道个数、每包中帧的个数等等。 status=AudioUnitSetProperty(audioUnit, kAudioUnitProperty_StreamFormat,                                 kAudioUnitScope_Input,                                 kOutputBus, &audioFormat, sizeof(audioFormat)); 这里是为了设置音频回调方法,我们在这个回调方法中,将所有的需要播放的音频信号一帧帧传递给硬件设备。     status=AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback,                                 kAudioUnitScope_Global, kOutputBus, &callbackStruct, sizeof(callbackStruct)); 这里又多出一个属性设置,我们对Audio Session属性设置,可以设置硬件DSP每次处理音频数据的最小个数。音频处理周期越短,CPU使用越多,但是好处是音频时间间隔较短。用于音视频同步都是非常有好处的。 AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration,                                             sizeof(preferredBufferSize),                                             &preferredBufferSize) 最后启动Aduio Unit     status=AudioUnitInitialize(audioUnit);      (2)音频数据解析 音频设备我们已经初始化好了,下面我们就来看看怎么吧音频数据拿到。可以分两个部分,ffmpeg部分,以及AudioFile IOS处理两个方面。FFmpeg我们会专门拿出几个部分,在IOS架构音视频专栏中详细讲解。我们先来看看用AduioFile怎么吧数据拿出来。        其实使用起来非常简单: result=AudioFileReadPackets(audioFile, false, &numBytesRead, NULL, 0, &packetReads, audioData); 使用这个方法就可以吧音频数据解析出来。数据都放在audioData中。 (3)回调方法中处理音频数据 在ffmpeg中音频数据装载比较复杂,音频ffmpeg音频处理是以包为单位来进行处理,所以处理的音频数据不一定满足,或者说是大部分情况都不满足DSP对音频数据长度处理的需求,所以这里就要在逻辑上作一定的转换。详细请参阅专栏中FFmpeg部分。这里看看我们读取本地文件如何处理的: static OSStatus playbackCallback(void *inRefCon,AudioUnitRenderActionFlags *ioActionFlags,                                   const AudioTimeStamp *inTimeStamp,                                   UInt32 inBusNumber,                                   UInt32 inNumberFrames,                                   AudioBufferList *ioData){     记得我们上面已经把音频数据拿到audioData中,(在读取之前包的大小设定为DSP音频处理数据长度),所以每次取一包数据放到ioData中。 } 另外还有一点需要补充,这里硬件处理音频数据的长度必须是2的N次方,为啥呢?因为DSP在处理一些如:FFT、蝶形运算时,必须是以2为基的。(如果不太明白,相见 数字信号处理这本书),所以我们长见到的数据长度多为512、1024、2048、4096、8192等.