vx 搜索『gjzkeyframe』 关注『关键帧Keyframe』来及时获得最新的音视频技术文章。
这个公众号会路线图 式的遍历分享音视频技术:音视频基础(完成) → 音视频工具(完成) → 音视频工程示例(进行中) → 音视频工业实战(准备)。
iOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对音视频基础概念知识有一定了解后,再借助 iOS/Android 平台的音视频能力上手去实践音视频的采集 → 编码 → 封装 → 解封装 → 解码 → 渲染过程,并借助音视频工具来分析和理解对应的音视频数据。
在音视频工程示例这个栏目的前面 6 篇 AVDemo 文章中,我们拆解了音频的采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并基于 iOS 系统 API 实现了 Demo:
- iOS AVDemo(1):音频采集
- iOS AVDemo(2):音频编码
- iOS AVDemo(3):音频封装
- iOS AVDemo(4):音频解封装
- iOS AVDemo(5):音频解码
- iOS AVDemo(6):音频渲染
你可以在关注本公众号后,在公众号发送消息『AVDemo』来获取 Demo 的全部源码。
如果你看完这些 Demo,对 iOS 平台的音视频开发多多少少会有一些认识了,在这个基础上我们来总结一下 iOS 音频处理框架,以及在前面的 Demo 中我们用到的主要 API 和数据结构有哪些。
1、iOS 音频框架
当我们想要了解 iOS 的音频处理框架时,以下是我们能比较容易找到的两张官方架构图。它们分别出自 Audio Unit Hosting Guide for iOS[1] 和 Core Audio Overview[2] 这两篇文档。
iOS Audio Frameworks
Core Audio API Layers
但这两篇文档已经比较陈旧了,是多年之前的文档,以至于和最新的 iOS 15 的框架有不少的出入。而新版本的 iOS 官方技术文档也没有给出比较清晰的音频架构图。所以在这里我们就按照 Demo 中涉及的系统 API 来挑选介绍几个相关的 Framework:
- Audio Unit Framework
- Core Media Framework
- Audio Toolbox Framework
- AVFoundation Framework
2、Audio Unit Framework
Audio Unit Framework[3]:最底层的音频处理 API,功能强大,直接驱动底层硬件,提供快速、模块化的音频处理。当你要实现低延迟的音频处理(比如 VoIP)、对合成声音进行响应式的播放(比如音乐游戏、合成乐器声音)、实现特定的音频能力(比如回声消除、混音、声音均衡)、实现音频处理链支持灵活组装音频处理单元时,你可以选择使用 Audio Unit 的 API。
需要注意的是,在最新的 iOS 系统库架构中,Audio Unit Framework 的实现都已经迁移到 Audio Toolbox Framework 中去了。
下面是 Audio Unit 框架的主要模块:
1)Audio Component Services[4]:定义了发现、开启和关闭音频单元(audio unit)以及音频编解码器的接口。
常用的数据类型:
- AudioComponent[5]:表示音频组件。一种音频组件通常由 type、subtype、manufacturer 三属性来唯一标识。
- AudioComponentDescription[6]:表示音频组件的描述。其中 type、subtype、manufacturer 三属性组合起来标识一种音频组件。
- AudioComponentInstance[7]:表示音频组件的实例。通常我们使用
查找方法(AudioComponentFindNext)来找到符合描述的音频组件,然后再去使用创建方法(AudioComponentInstanceNew)创建一个对应的音频组件实例。
常用的接口:
- AudioComponentFindNext(...)[8]:用于查找符合描述的音频组件。
- AudioComponentGetDescription(...)[9]:用于获取一种音频组件对应的描述。
- AudioComponentInstanceNew(...)[10]:创建一个音频组件实例。
- AudioComponentInstanceDispose(...)[11]:释放一个音频组件实例。
2)Audio Unit Component Services[12]:提供了使用音频单元(audio unit)的 C 语言接口。一个音频单元(audio unit)是用来进行音频数据处理或者音频数据生成的插件单元。要发现、开启、关闭音频单元(audio unit)则可以使用 Audio Component Services。
常用的数据类型:
- AudioUnit[13],
typedef AudioComponentInstance AudioUnit;。AudioUnit 就是一种 AudioComponentInstance。 - AudioUnitParameter[14]:表示 AudioUnit 的参数,一个 AudioUnit 参数由 scope、element、parameterID 三属性定义。
- AudioUnitProperty[15]:表示 AudioUnit 的属性,一个 AudioUnitProperty 由 scope、element、propertyID 三属性定义。
常用的接口:
- AudioUnitInitialize(...)[16]:初始化一个 AudioUnit。如果初始化成功,说明 input/output 的格式是可支持的,并且处于可以开始渲染的状态。
- AudioUnitUninitialize(...)[17]:卸载一个 AudioUnit。一旦一个 AudioUnit 被初始化后,要想改变它的状态来响应某些环境变化,就需要先卸载。这时候会使得 AudioUnit 释放它的资源。此后,调用者可以重新配置这个 AudioUnit 来适配新的环境,比如处理与之前不同的采样率。在这之后,可以重新初始化这个 AudioUnit 来应用这些更改。
- AudioUnitRender(...)[18]:渲染输入的音频数据,数据量为 inNumberOfFrames。渲染结果的数据存储在 ioData 中。注意调用方需要提供音频时间戳,这个时间戳应该满足单调递增。
- AudioUnitGetProperty(...)[19]:获取 AudioUnit 的属性。
- AudioUnitSetProperty(...)[20]:设置 AudioUnit 的属性。
- AudioUnitGetParameter(...)[21]:获取 AudioUnit 的参数。
- AudioUnitSetParameter(...)[22]:设置 AudioUnit 的参数。
常用的回调:
- AURenderCallback[23]:在以下几种情况会被系统调用:当 AudioUnit 需要输入采样数据;在一个渲染操作前;在一个渲染操作后。
- AudioUnitPropertyListenerProc[24]:当一个指定的 AudioUnit 的 property 发生改变时,会被系统调用。
3)Output Audio Unit Services[25]:提供了 start、stop 用于 I/O 的音频单元(通常是用于输出的音频单元)的 C 语言接口。
常用的接口:
-
AudioOutputUnitStart(...)[26]:启动一个 I/O AudioUnit,同时会启动与之连接的 AudioUnit Processing Graph。
-
AudioOutputUnitStop(...)[27]:关闭一个 I/O AudioUnit,同时会关闭与之连接的 AudioUnit Processing Graph。
3、Core Media Framework
Core Media Framework[28]:定义和封装了 AVFoundation 等更上层的媒体框架需要的媒体处理流水线(包含时间信息)以及其中使用的接口和数据类型。使用 Core Media 层的接口和数据类型可以高效的处理媒体采样数据、管理采样数据队列。下面是 Core Media 框架的主要模块:
1)Sample Processing[29]:采样数据处理。常用的数据类型:
- CMSampleBuffer[30]:系统用来在音视频处理的 pipeline 中使用和传递媒体采样数据的核心数据结构。你可以认为它是 iOS 音视频处理 pipeline 中的流通货币,摄像头采集的视频数据接口、麦克风采集的音频数据接口、编码和解码数据接口、读取和存储视频接口、视频渲染接口等等,都以它作为参数。通常,CMSampleBuffer 中要么包含一个或多个媒体采样的 CMBlockBuffer,要么包含一个 CVImageBuffer。
-
- CMSampleBufferCreateReady(...)[31]:基于媒体数据创建一个 CMSampleBuffer。
- CMSampleBufferCreate(...)[32]:创建一个 CMSampleBuffer,支持设置数据已准备好的回调。
- CMSampleBufferSetDataBufferFromAudioBufferList(...)[33]:为指定的 CMSampleBuffer 创建其对应的 CMBlockBuffer,其中的数据拷贝自 AudioBufferList。
- CMSampleBufferGetFormatDescription(...)[34]:返回 CMSampleBuffer 中的采样数据对应的 CMFormatDescription。
- CMSampleBufferGetDataBuffer(...)[35]:返回 CMSampleBuffer 中的 CMBlockBuffer。注意调用方不会持有返回的 CMBlockBuffer,如果想要维护指向它的指针,需要显式 retain 一下。
- CMSampleBufferGetPresentationTimeStamp(...)[36]:获取 CMSampleBuffer 中所有采样的最小的 pts 时间戳。
- CMBlockBuffer[37]:一个或多个媒体采样的的裸数据。其中可以封装:音频采集后、编码后、解码后的数据(如:PCM 数据、AAC 数据);视频编码后的数据(如:H.264 数据)。
-
- CMBlockBufferCreateWithMemoryBlock(...)[38]:基于内存数据创建一个 CMBlockBuffer。
- CMBlockBufferGetDataPointer(...)[39]:获取访问 CMBlockBuffer 中数据的地址。
- CMFormatDescription[40]:用于描述 CMSampleBuffer 中采样的格式信息。
-
- CMFormatDescriptionCreate(...)[41]:创建一个 CMFormatDescription。
- CMAudioFormatDescription[42]:
typedef CMFormatDescriptionRef CMAudioFormatDescriptionRef;。CMAudioFormatDescription 是一种 CMFormatDescriptionRef。 -
- CMAudioFormatDescriptionCreate(...)[43]:基于 AudioStreamBasicDescription 来创建一个 CMAudioFormatDescription。
- CMAudioFormatDescriptionGetStreamBasicDescription(...)[44]:返回一个指向 CMFormatDescription(通常应该是一个 CMAudioFormatDescription) 中的 AudioStreamBasicDescription 的指针。如果是非音频格式,就返回 NULL。
- CMAttachment[45]:为 CMSampleBuffer 添加支持的 metadata。
这里我们还要补充介绍 CoreAudioTypes Framework 中的几种数据类型:
- AudioStreamBasicDescription[46]:用于描述音频流数据格式信息,比如采样位深、声道数、采样率、每帧字节数、每包帧数、每包字节数、格式标识等。
- AudioBuffer[47]:存储并描述音频数据的缓冲区。mData 中存储着数据。可以存储两种不同类型的音频:1)单声道音频数据;2)多声道的交错音频数据,这时候 mNumberChannels 指定了声道数。
- AudioBufferList[48]:一组 AudioBuffer。
- AudioTimeStamp[49]:从多维度来表示一个时间戳的数据结构。
2)Time Representation[50]:时间信息表示。常用的数据类型:
- CMTime[51]:用 value/timescale 的方式表示时间。这样可以解决浮点运算时的精度损失问题。timescale 表示时间刻度,通常在处理视频内容时常见的时间刻度为 600,这是大部分常用视频帧率 24fps、25fps、30fps 的公倍数,音频数据常见的时间刻度就是采样率,比如 44100 或 48000。
- CMTimeRange[52]:用 start+duration 的方式表示一段时间。
- CMSampleTimingInfo[53]:一个 CMSampleBuffer 的时间戳信息,包括 pts、dts、duration。
3)Queues[54]:数据容器。常用的数据类型:
- CMSimpleQueue[55]:一个简单地、无锁的 FIFO 队列,可以放
(void *)元素,元素不能是 NULL 或 0,如果元素是指向分配内存的指针,其内存生命周期要在外面自己管理。可以用作音视频采样数据(CMSampleBufferRef)的队列,不过要自己加锁。 - CMBufferQueue[56]:支持存储任何 CFTypeRef 类型的数据,但是数据类型需要有 duration 的概念,在创建 CMBufferQueue 的时候,会有一些回调,其中一个必须的回调是要返回队列中对象的 duration。CMBufferQueue 是设计用于在生产者/消费者模型中在不同的线程中读写数据。通常是两个线程(一个是生产者入队线程,一个是消费者出队线程),当然更多的线程也是可以的。
- CMMemoryPool[57]:内存池容器,对使用大块的内存有优化。一个 CMMemoryPool 的实例实际上维护一个最近释放内存的池子用于内存分配服务。这样的目的是加快随后的内存分配。在需要重复分配大块内存时,比如输出视频编码数据,可以使用这个数据结构。
4、Audio Toolbox Framework
Audio Toolbox Framework[58]:提供了音频录制、播放、流解析、编码格式转换、Audio Session 管理等功能接口。下面是 Audio Toolbox 框架的主要模块:
1)Audio Units[59]:音频单元。关于 Audio Unit 的内容,还可以参考上面讲到的 Audio Unit Framework。
- Audio Unit v3 Plug-Ins[60]:基于 AUv3 应用扩展接口来提供自定义的音效、乐器及其他音频能力。
- Audio Components[61]:定义了发现、加载、配置和关闭音频组件(包括音频单元(audio unit)、音频编解码器(audio codec))的接口。
- Audio Unit v2 (C) API[62]:配置一个音频单元(audio unit)以及进行音频渲染。
- Audio Unit Properties[63]:获取有关内置混音器、均衡器、滤波器、特效及音频应用扩展的信息。
- Audio Unit Voice I/O[64]:配置系统语音处理、响应语音事件。
2)Playback and Recording[65]:音频播放和录制。
- Audio Queue Services[66]:提供了简单的、低开销的方式来录制和播放音频的 C 语言接口。支持 Linear PCM、AAC 的录制和播放。实现了连接音频硬件、管理内存、根据需要使用解码器解码音频、调解录音和播放。但是要实现低延迟、回声消除、混音等功能,还得使用 AudioUnit。
- Audio Services[67]:提供了一组 C 语言接口来实现播放短声或触发 iOS 设备的振动效果。
- Music Player[68]:支持播放一组音轨,并管理播放的各种的事件。
3)Audio Files and Formats[69]:音频文件和格式。
- Audio Format Services[70]:获取音频格式和编解码器的信息。
- Audio File Services[71]:从磁盘或内存读写各种音频数据。
- Extended Audio File Services[72]:通过组合 Audio File Services 和 Audio Converter Services 来提供读写音频编码文件或 LPCM 音频文件。
- Audio File Stream Services[73]:解析音频流数据。
- Audio File Components[74]:获取音频文件格式以及文件中包含的数据的信息。
- Core Audio File Format[75]:解析 Core Audio 文件的结构。
4)Utilities[76]:其他音频功能支持。
- Audio Converter Services[77]:音频编解码。支持 LPCM 各种格式转换,以及 LPCM 与编码格式(如 AAC)的转换。常用的接口:
-
AudioConverterNew(...)[78]:根据指定的输入和输出音频格式创建对应的转换器(编解码器)实例。
-
AudioConverterNewSpecific(...)[79]:根据指定的 codec 来创建一个新的音频转换器(编解码器)实例。
-
AudioConverterReset(...)[80]:重置音频转换器(编解码器)实例,并清理它的缓冲区。
-
AudioConverterDispose(...)[81]:释放音频转换器(编解码器)实例。
-
AudioConverterGetProperty(...)[82]:获取音频转换器(编解码器)的属性。
-
AudioConverterSetProperty(...)[83]:设置音频转换器(编解码器)的属性。
-
AudioConverterConvertBuffer(...)[84]:只用于一种特殊的情况下将音频数据从一种 LPCM 格式转换为另外一种,并且前后采样率一致。这个接口不支持大多数压缩编码格式。
-
AudioConverterFillComplexBuffer(...)[85]:转换(编码)回调函数提供的音频数据,支持不交错和包格式。大部分情况下都建议用这个接口,除非是要将音频数据从一种 LPCM 格式转换为另外一种。
-
AudioConverterComplexInputDataProc[86]:为
AudioConverterFillComplexBuffer(...)接口提供输入数据的回调。 -
Audio Codec[87]:提供了支持将音频数据进行编码格式转换的 API。具体支持哪些编码格式取决于系统提供了哪些编解码器。
-
5、AVFoundation Framework
AVFoundation Framework[88] 是更上层的面向对象的一个音视频处理框架。它提供了音视频资源管理、相机设备管理、音视频处理、系统级音频交互管理的能力,功能非常强大。如果对其功能进行细分,可以分为如下几个模块:
- Assets,音视频资源管理。
- Playback,媒体播放及自定义播放行为支持。
- Capture,内置及外置的相机、麦克风等采集设备管理,图片、音视频录制。
- Editing,音视频编辑。
- Audio,音频播放、录制和处理,App 系统音频行为配置。
- Speech,文本语音转换。
在我们前面的 Demo 中封装 Muxer 和 Demuxer 及设置 AudioSession 时会用到 AVFoundation Framework 的一些能力,我们这里对应地介绍一下。
- AVAssetWriter[89]:支持将媒体数据写入 QuickTime 或 MPEG-4 格式的文件中,支持对多轨道的媒体数据进行交错处理来提高播放和存储的效率,支持对媒体采样进行转码,支持写入 metadata。需要注意的是,一个 AVAssetWriter 实例只能对应写一个文件,如果要写入多个文件,需要创建多个 AVAssetWriter 实例。
- canAddInput:[90]:检查 AVAssetWriter 是否支持添加对应的 AVAssetWriterInput。
- addInput:[91]:给 AVAssetWriter 添加一个 AVAssetWriterInput。注意必须在 AVAssetWriter 开始写入之前添加。
- startWriting[92]:开始写入。必须在配置好 AVAssetWriter 添加完 AVAssetWriterInput 做好准备后再调用这个方法。在调用完这个方法后,需要调用
startSessionAtSourceTime:开始写入会话,此后就可以使用对应的 AVAssetWriterInput 来写入媒体采样数据。 - startSessionAtSourceTime:[93]:开启写入会话。在
startWriting后调用,在写入媒体采样数据之前调用。 - endSessionAtSourceTime:[94]:结束写入会话。结束时间是会话结束时样本数据在时间轴上的时刻。如果没有显示调用这个方法,系统会在你调用
finishWritingWithCompletionHandler:结束写入时自动调用。 - finishWritingWithCompletionHandler:[95]:标记 AVAssetWriter 的所有 input 为结束,完成写入。为了保证 AVAssetWriter 完成所有采样数据的写入,要在调用添加数据正确返回后调用这个方法。
- cancelWriting[96]:取消创建输出文件。如果 AVAssetWriter 的状态是 Failed 或 Completed,调用这个方法无效,否则,调用它会阻塞调用线程,直到会话取消完成。如果 AVAssetWriter 已经创建了输出文件,调用这个方法会删除这个文件。
- AVAssetWriterInput[97]:用于向 AVAssetWriter 实例的输出文件的一个轨道添加媒体采样数据。一个实例只能对应一个轨道媒体数据或 metadata 数据的写入,当使用多个实例向多个轨道写入数据时,需要注意检查 AVAssetWriterInput 的 readyForMoreMediaData 属性。
- expectsMediaDataInRealTime[98]:输入是否为实时数据源,比如相机采集。当设置这个值为 YES 时,会优化用于实时使用的输入来精准计算
readyForMoreMediaData的状态。 - readyForMoreMediaData[99]:表示 AVAssetWriterInput 是否已经准备好接收媒体数据。
- requestMediaDataWhenReadyOnQueue:usingBlock:[100]:告诉 AVAssetWriterInput 在方便的时候去请求数据并写入输出文件。在对接拉取式的数据源时,可以用这个方法。
- appendSampleBuffer:[101]:通过 AVAssetWriterInput 向输出文件添加媒体数据,但是添加之前媒体数据的顺序需要自己处理。注意,调用这个方法添加采样数据后,不要更改采样数据的内容。
- markAsFinished[102]:标记 AVAssetWriterInput 为完成,表示已经完成向它添加媒体数据了。
- expectsMediaDataInRealTime[98]:输入是否为实时数据源,比如相机采集。当设置这个值为 YES 时,会优化用于实时使用的输入来精准计算
- AVAssetReader[103]:用于从 AVAsset 资源中读取媒体数据。这个 AVAsset 可以是 QuickTime 或 MPEG-4 文件,也可以是编辑创作的 AVComposition。
- canAddOutput:[104]:检查 AVAssetReader 是否支持添加对应的 AVAssetReaderOutput。
- addOutput:[105]:给 AVAssetReader 添加一个 AVAssetReaderOutput。注意必须在 AVAssetReader 开始读取之前添加。
- startReading[106]:开始读取。
- cancelReading[107]:在读完数据之前取消读取可以调用这个接口。
- AVAssetReaderOutput[108]:一个抽象类,定义了从 AVAsset 资源中读取媒体采样数据的接口。通常我们可以使用
AVAssetReaderTrackOutput、AVAssetReaderVideoCompositionOutput等具体的实现类。 - AVAssetReaderTrackOutput[109]:
- alwaysCopiesSampleData[110]:是否总是拷贝采样数据。如果要修改读取的采样数据,可以设置 YES,否则就设置 NO,这样性能会更好。
- copyNextSampleBuffer[111]:从 Output 拷贝下一个 CMSampleBuffer。
- AVAudioSession[112]:在最新版本的 iOS 系统库中,AVAudioSession 已经迁移到 AVFAudio Framework 中了。AVAudioSession 是系统用来管理 App 对音频硬件资源的使用的,比如:设置当前 App 与其他 App 同时使用音频时,是否混音、打断或降低其他 App 的声音;手机静音键打开时是否还可以播放声音;指定音频输入或者输出设备;是否支持录制或边录制边播放;声音被打断时的通知。我们这里只简单介绍下 Demo 中用到的接口:
- setCategory:withOptions:error:[113]:设置 AudioSession 的类型和选项参数。比如类型为 AVAudioSessionCategoryPlayback 表示支持播放;AVAudioSessionCategoryPlayAndRecord 表示同时支持播放和录制等等。
- setMode:error:[114]:设置 AudioSession 的模式。AudioSession 的类型和模式一起决定了 App 如何使用音频。通常需要在激活 AudioSession 之前设置类型和模式。比如模式为 AVAudioSessionModeVideoRecording 表示当期要录制视频;AVAudioSessionModeVoiceChat 表示语音聊天。
- setActive:withOptions:error:[115]:激活或释放 AudioSession 的使用。
以上这些框架及 API 基本上可以覆盖我们在前面的 Demo 中用到的能力了。
参考资料
[1]
Audio Unit Hosting Guide for iOS: developer.apple.com/library/arc…
[2]
Core Audio Overview: developer.apple.com/library/arc…
[3]
Audio Unit: developer.apple.com/documentati…
[4]
Audio Component Services: developer.apple.com/documentati…
[5]
AudioComponent: developer.apple.com/documentati…
[6]
AudioComponentDescription: developer.apple.com/documentati…
[7]
AudioComponentInstance: developer.apple.com/documentati…
[8]
AudioComponentFindNext(...): developer.apple.com/documentati…
[9]
AudioComponentGetDescription(...): developer.apple.com/documentati…
[10]
AudioComponentInstanceNew(...): developer.apple.com/documentati…
[11]
AudioComponentInstanceDispose(...): developer.apple.com/documentati…
[12]
Audio Unit Component Services: developer.apple.com/documentati…
[13]
AudioUnit: developer.apple.com/documentati…
[14]
AudioUnitParameter: developer.apple.com/documentati…
[15]
AudioUnitProperty: developer.apple.com/documentati…
[16]
AudioUnitInitialize(...): developer.apple.com/documentati…
[17]
AudioUnitUninitialize(...): developer.apple.com/documentati…
[18]
AudioUnitRender(...): developer.apple.com/documentati…
[19]
AudioUnitGetProperty(...): developer.apple.com/documentati…
[20]
AudioUnitSetProperty(...): developer.apple.com/documentati…
[21]
AudioUnitGetParameter(...): developer.apple.com/documentati…
[22]
AudioUnitSetParameter(...): developer.apple.com/documentati…
[23]
AURenderCallback: developer.apple.com/documentati…
[24]
AudioUnitPropertyListenerProc: developer.apple.com/documentati…
[25]
Output Audio Unit Services: developer.apple.com/documentati…
[26]
AudioOutputUnitStart(...): developer.apple.com/documentati…
[27]
AudioOutputUnitStop(...): developer.apple.com/documentati…
[28]
Core Media: developer.apple.com/documentati…
[29]
Sample Processing: developer.apple.com/documentati…
[30]
CMSampleBuffer: developer.apple.com/documentati…
[31]
CMSampleBufferCreateReady(...): developer.apple.com/documentati…
[32]
CMSampleBufferCreate(...): developer.apple.com/documentati…
[33]
CMSampleBufferSetDataBufferFromAudioBufferList(...): developer.apple.com/documentati…
[34]
CMSampleBufferGetFormatDescription(...): developer.apple.com/documentati…
[35]
CMSampleBufferGetDataBuffer(...): developer.apple.com/documentati…
[36]
CMSampleBufferGetPresentationTimeStamp(...): developer.apple.com/documentati…
[37]
CMBlockBuffer: developer.apple.com/documentati…
[38]
CMBlockBufferCreateWithMemoryBlock(...): developer.apple.com/documentati…
[39]
CMBlockBufferGetDataPointer(...): developer.apple.com/documentati…
[40]
CMFormatDescription: developer.apple.com/documentati…
[41]
CMFormatDescriptionCreate(...): developer.apple.com/documentati…
[42]
CMAudioFormatDescription: developer.apple.com/documentati…
[43]
CMAudioFormatDescriptionCreate(...): developer.apple.com/documentati…
[44]
CMAudioFormatDescriptionGetStreamBasicDescription(...): developer.apple.com/documentati…
[45]
CMAttachment: developer.apple.com/documentati…
[46]
AudioStreamBasicDescription: developer.apple.com/documentati…
[47]
AudioBuffer: developer.apple.com/documentati…
[48]
AudioBufferList: developer.apple.com/documentati…
[49]
AudioTimeStamp: developer.apple.com/documentati…
[50]
Time Representation: developer.apple.com/documentati…
[51]
CMTime: developer.apple.com/documentati…
[52]
CMTimeRange: developer.apple.com/documentati…
[53]
CMSampleTimingInfo: developer.apple.com/documentati…
[54]
Queues: developer.apple.com/documentati…
[55]
CMSimpleQueue: developer.apple.com/documentati…
[56]
CMBufferQueue: developer.apple.com/documentati…
[57]
CMMemoryPool: developer.apple.com/documentati…
[58]
Audio Toolbox: developer.apple.com/documentati…
[59]
Audio Units: developer.apple.com/documentati…
[60]
Audio Unit v3 Plug-Ins: developer.apple.com/documentati…
[61]
Audio Components: developer.apple.com/documentati…
[62]
Audio Unit v2 (C) API: developer.apple.com/documentati…
[63]
Audio Unit Properties: developer.apple.com/documentati…
[64]
Audio Unit Voice I/O: developer.apple.com/documentati…
[65]
Playback and Recording: developer.apple.com/documentati…
[66]
Audio Queue Services: developer.apple.com/documentati…
[67]
Audio Services: developer.apple.com/documentati…
[68]
Music Player: developer.apple.com/documentati…
[69]
Audio Files and Formats: developer.apple.com/documentati…
[70]
Audio Format Services: developer.apple.com/documentati…
[71]
Audio File Services: developer.apple.com/documentati…
[72]
Extended Audio File Services: developer.apple.com/documentati…
[73]
Audio File Stream Services: developer.apple.com/documentati…
[74]
Audio File Components: developer.apple.com/documentati…
[75]
Core Audio File Format: developer.apple.com/documentati…
[76]
Utilities: developer.apple.com/documentati…
[77]
Audio Converter Services: developer.apple.com/documentati…
[78]
AudioConverterNew(...): developer.apple.com/documentati…
[79]
AudioConverterNewSpecific(...): developer.apple.com/documentati…
[80]
AudioConverterReset(...): developer.apple.com/documentati…
[81]
AudioConverterDispose(...): developer.apple.com/documentati…
[82]
AudioConverterGetProperty(...): developer.apple.com/documentati…
[83]
AudioConverterSetProperty(...): developer.apple.com/documentati…
[84]
AudioConverterConvertBuffer(...): developer.apple.com/documentati…
[85]
AudioConverterFillComplexBuffer(...): developer.apple.com/documentati…
[86]
AudioConverterComplexInputDataProc: developer.apple.com/documentati…
[87]
Audio Codec: developer.apple.com/documentati…
[88]
AVFoundation Framework: developer.apple.com/documentati…
[89]
AVAssetWriter: developer.apple.com/documentati…
[90]
canAddInput:: developer.apple.com/documentati…
[91]
addInput:: developer.apple.com/documentati…
[92]
startWriting: developer.apple.com/documentati…
[93]
startSession(atSourceTime:): developer.apple.com/documentati…
[94]
endSessionAtSourceTime:: developer.apple.com/documentati…
[95]
finishWritingWithCompletionHandler:: developer.apple.com/documentati…
[96]
cancelWriting: developer.apple.com/documentati…
[97]
AVAssetWriterInput: developer.apple.com/documentati…
[98]
expectsMediaDataInRealTime: developer.apple.com/documentati…
[99]
readyForMoreMediaData: developer.apple.com/documentati…
[100]
requestMediaDataWhenReadyOnQueue:usingBlock:: developer.apple.com/documentati…
[101]
appendSampleBuffer:: developer.apple.com/documentati…
[102]
markAsFinished: developer.apple.com/documentati…
[103]
AVAssetReader: developer.apple.com/documentati…
[104]
canAddOutput:: developer.apple.com/documentati…
[105]
addOutput:: developer.apple.com/documentati…
[106]
startReading: developer.apple.com/documentati…
[107]
cancelReading: developer.apple.com/documentati…
[108]
AVAssetReaderOutput: developer.apple.com/documentati…
[109]
AVAssetReaderTrackOutput: developer.apple.com/documentati…
[110]
alwaysCopiesSampleData: developer.apple.com/documentati…
[111]
copyNextSampleBuffer: developer.apple.com/documentati…
[112]
AVAudioSession: developer.apple.com/documentati…
[113]
setCategory:withOptions:error:: developer.apple.com/documentati…
[114]
setMode:error:: developer.apple.com/documentati…
[115]
setActive:withOptions:error:: developer.apple.com/documentati…
- 完 -
推荐阅读