CoderMrWu

生活诚可期,爱情价更高!

IOS多媒体:音频篇

介绍

IOS多媒体框架有以下功能:

  • 高品质的音频录制、播放和流传输
  • 高品质的游戏声音播放
  • 即时语言聊天
  • 播放用户IPod库中的内容
  • 播放和录制视频

Audio

IOS中提供丰富的工具来处理应用程序中的声音,以下就是这些框架的详细介绍:

  • 使用MediaPlayer框架来播放IPod库中的歌曲,有声读物或者博客。
  • 使用AVFoundation框架中的类实现音频的录制和播放
  • 使用AudioToolbox框架可以播放具有同步功能的音频,访问音频的数据包、解析音频流、转换音频格式以及可以访问单个数据包来记录音频。
  • 使用AudioUnit框架连接到并使用音频处理插件。
  • 使用OpenAL框架在游戏中和其他应用程序提供位置音频播放

实现IOS音频功能的快速介绍:

  • 播放用户iPod库中的歌曲,音频博客和有声读物
  • 以最少的代码播放和录制音频,请使用AVFoundation框架
  • 要提供功能齐全的音频播放,包括立体声定位,电平控制和同步声音,请使用OpenAL
  • 要提供最低延迟的音频,尤其是在同时进行输入输出(例如VoIP应用程序)时,请使用 I/O unit 或者 Voice Processing I/O unit
  • 如果在播放音频的时候,需要对音频的控制度较高的,请使用Audio Queue Services 框架。Audio Queue Services还支持录制,并提供对传入音频数据包的访问。
  • 要解析从网络连接流式传输的音频,请使用 Audio File Stream Services。
  • 若需要用户界面的声音效果或者在该设备上调用振动,请使用 System Audio Services

基础知识:音频编解码,支持的音频格式和音频会话

IOS硬件和软件音频编解码器

为了确保最佳性能和质量,您需要选择正确的音频格式和音频编解码器类型。从iOS 3.0开始,大多数音频格式可以使用基于软件的编码(用于记录)和解码(用于播放)。软件编解码器支持同时播放多种声音,但可能会占用大量CPU开销。

硬件辅助解码可提供出色的性能,但不支持同时播放多种声音。如果需要在应用程序中最大程度地提高视频帧速率,请使用未压缩的音频或IMA4格式,或者对压缩的音频资产进行硬件辅助解码,以最大程度地降低音频播放对CPU的影响。

IOS设备上可用的播放音频编码器
音频解码器/播放格式 硬件辅助解码 基于软件的解码
AAC(MPEG-4高级音频编码) 是的,从iOS 3.0开始
ALAC(无损苹果) 是的,从iOS 3.0开始
HE-AAC(MPEG-4高效AAC)
iLBC(互联网低比特率编解码器,另一种语音格式)
IMA4(IMA / ADPCM)
线性PCM(未压缩的线性脉冲编码调制)
MP3(MPEG-1音频第3层)
µ-law和a-law

 

使用硬件辅助解码时,设备一次只能播放一种受支持格式的单个实例。例如,如果您正在使用硬件编解码器播放立体声MP3声音,则第二个同时的MP3声音将使用软件解码。同样,您不能使用硬件同时播放AAC和ALAC声音。如果iPod应用程序在后台播放AAC或MP3声音,则说明已声明了硬件编解码器;然后,您的应用程序将使用软件解码来播放AAC,ALAC和MP3音频。

要以最佳性能播放多种声音,或在iPod在后台播放时有效播放声音,请使用线性PCM(未压缩)或IMA4(压缩)音频

总结IOS如何支持单次或者多次播放的音频格式
  • 线性PCM和IMA4(IMA / ADPCM)您可以在iOS中同时播放多个线性PCM或IMA4声音,而不会引起CPU资源问题。对于iLBC语音质量格式以及µ-law和a-law压缩格式也是如此。使用压缩格式时,请检查声音质量以确保其满足您的需求。
  • AAC,HE-AAC,MP3和ALAC声音的AAC,HE-AAC,MP3和ALAC(Apple无损)播放可以在iOS设备上使用高效的硬件辅助解码,但是这些编解码器都共享一条硬件路径。设备使用硬件辅助解码一次只能播放这些格式之一的单个实例。
录音格式和编解码器:
音频编码器/记录格式 硬件辅助编码 基于软件的编码
AAC(MPEG-4高级音频编码) 是的,从iPhone 3GS和iPod touch(第二代)的iOS 3.1开始 是的,从iPad的iOS 3.2开始 是的,从适用于iPhone 3GS和iPod touch(第二代)的iOS 4.0开始
ALAC(无损苹果)
iLBC(互联网低比特率编解码器,用于语音)
IMA4(IMA / ADPCM)
线性PCM(未压缩的线性脉冲编码调制)
µ-law和a-law

 

Audio Sessions

IOS Audio Sessions API 可以让你自定义应用程序的常规音频行为,在使用上具有较大的灵活性!

  • 是否通过静音开关使音频静音(在iPhone上,这称为“ 铃声/静音”开关)
  • 屏幕锁定时是否应停止音频
  • 开始播放音频时,是否应继续播放其他音频(例如iPod中的音频)或将其静音

Audio Sessions 还可以相应用户的操作(例如,耳机的插入和拔出)以及使用设备的声音硬件的事件(例如,时钟和日历警报以及来电)。

AudioSessions提供的功能:

1、设定类别: 类别是用于标识应用程序的一组音频行为的键。通过设置类别,您可以将音频意图指示给iOS,例如在屏幕锁定时是否应继续音频。

2、处理中断和路线变更: 音频会话在音频中断,中断结束以及硬件音频路由更改时发布消息。这些消息使您可以优雅地响应较大的音频环境中的更改,例如由于来电而中断。

3、优化硬件特征: 您可以查询音频会话,以发现运行应用程序的设备的特性,例如硬件采样率,硬件通道数以及音频输入是否可用。

两个用于处理音频会话的接口
  • AVAudioSession : 一个简化的Objective-C接口,可以访问核心音频会话功能。
  • AudioSession : 一个基于C的接口,可提供对所有基本和高级音频会话功能的全面访问

在具体的使用过程中,你完全可以混用AVAudioSession和AudioSession,因为他们完全兼容。

音频会话带有一些默认行为,可用于开始开发。但是,在某些特殊情况下,默认行为不再适合当前音频的开发需求,你可以去更改默认行为。

例如: 在使用默认音频会话时,当“自动锁定”时间段超时且屏幕锁定时,应用程序中的音频会停止。为了确保在锁定屏幕的情况下继续播放,你需要以下代码段:

NSError *setCategoryErr = nil;
NSError *activationErr  = nil;
[[AVAudioSession sharedInstance]
             setCategory: AVAudioSessionCategoryPlayback
                   error: &setCategoryErr];
[[AVAudioSession sharedInstance]
               setActive: YES
                   error: &activationErr];
音频技术 中断如何运行
AV Foundation framework AVAudioPlayerAVAudioRecorder类提供了中断的开始和结束的委托方法。实现这些方法以更新用户界面,并有选择地在中断结束后恢复暂停的播放。系统会在中断时自动暂停播放或录制,并在您继续播放或录制时重新激活音频会话。 如果要在应用程序启动之间保存和还原播放位置,请在中断以及应用程序退出时保存播放位置。
Audio Queue Services, I/O audio unit 这些技术使您的应用程序可以控制中断的处理。您有责任保存播放或录制位置,并在中断结束后重新激活音频会话。实现AVAudioSession中断委托方法或编写中断侦听器回调函数。
OpenAL 使用OpenAL进行播放时,请实现AVAudioSession中断委托方法或编写中断侦听器回调函数,就像使用音频队列服务时一样。但是,委托或回调必须另外管理OpenAL上下文。
System Sound Services 中断开始时,使用系统声音服务播放的声音会静音。如果中断结束,它们可以自动再次使用。应用程序无法影响使用此播放技术的声音的中断行为。

如何处理由打来的电话或时钟或日历警报引起的中断,取决于所使用的音频技术。

处理音频中断

使用AVAudioSessionCategoryPlayback可确保在屏幕锁定时继续播放。激活音频会话会使指定的类别生效。

音频播放

使用iPod库访问、System Sound Services、Audio Queue Services、AVFoundation框架和OpenAL框架 播放音频。

通过iPod Library访问播放音频项目

从iOS 3.0开始,使用iPod库访问权限,您的应用程序可以播放用户的歌曲,有声读物和音频播客。API设计使基本播放非常简单,同时还支持高级搜索和播放控制。但是这个我们使用得不多。

音频播放

使用iPod库访问、System Sound Services、Audio Queue Services、AVFoundation框架和OpenAL框架 播放音频。

通过iPod Library访问播放音频项目

从iOS 3.0开始,使用iPod库访问权限,您的应用程序可以播放用户的歌曲,有声读物和音频播客。API设计使基本播放非常简单,同时还支持高级搜索和播放控制。但是这个我们使用得不多。

1、通过MPMediaPickerController来调起系统播放器

[self presentViewController:[MPMediaPickerController new] animated:YES completion:nil];

2、通过MPMoviePlayerController创建一个音乐播放器

// 获取资源路径
NSString * path = [[NSBundle mainBundle] pathForResource:@"多幸运" ofType:@"mp3"];
// 初始化播放器
self.playController = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL fileURLWithPath:path]];
// 开始播放
[_playController play];

使用系统声音服务播放UI声音效果或调用振动

播放UI互动音效,或者需要调用振动,需要使用 System Sound Services。

注意: 使用系统声音服务播放的声音不会通过音频会话进行配置。因此,您不能使系统声音服务音频的行为与应用程序中的其他音频行为保持一致。这是避免将系统声音服务用于其预期用途以外的任何音频的最重要原因。

播放音效的示例代码:

//获取资源路径 
CFBundleRef mainBundleRef = CFBundleGetMainBundle();
CFURLRef soundFileURLRef = CFBundleCopyResourceURL(mainBundleRef, CFSTR("tag"), CFSTR("mp3"), nil);

SystemSoundID soundFileObject;

// 创建代表声音文件的系统声音对象
AudioServicesCreateSystemSoundID(soundFileURLRef,&soundFileObject);

 // 播放声音
 AudioServicesPlaySystemSound(soundFileObject);

使用AudioServicesPlaySystemSound可以非常简单地播放短声音文件。但是它有一些限制。您的声音文件必须是:

  • 持续时间不超过30秒
  • 线性PCM或IMA4(IMA/ADPCM)格式
  • 封装在一个.caf,.aif或.wav 文件

另外,在使用 AudioServicesPlaySystemSound时:

  • 声音以当前系统音频音量播放,没有可编程的音量控制
  • 声音立即播放
  • 循环和立体声定位不可用
  • 无法同时播放:一次只能播放一个声音

AudioServicesPlayAlertSound是播放音效的另外一个接口,它的功能是发出短促的声音作为警报。如果用户已将其设备配置为在“铃声设置”中振动,则调用此功能除了播放声音文件外,还会引起振动。

触发振动的示例代码:

// 振动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

使用AVAudioPlayer类播放音频

AVAudioPlayer类提供了一个简单的用于播放声音接口。如果您的应用程序不需要立体声定位或精确同步,并且您没有播放从网络流捕获的音频。

使用AVAudioPlayer,您可以:

  • 播放任何持续时间的声音
  • 播放文件或者内存缓存区中的声音
  • 循环声音
  • 同时播放多个声音(尽管不能精确同步)
  • 控制正在播放的每个声音的相对的播放级别
  • 在声音文件中寻找特定点,该文件支持诸如快进和快退之类的应用程序功能
  • 获取可用于音频电平表的音频功率数据

AVAudioPlayer类可以播放任何可用的音频格式的声音。以下是配置播放器的步骤:

1、将音频文件分配给音频播放器

2、准备音频播放器进行播放,以获取所需的硬件资源

3、指定一个音频播放器委托对象,该对象处理中断以及播放完成的事件

AVAudioPlayer使用示例:

// 初始化AudioPlayer播放器
-(void)initAudioPlayer{
    
    NSString * path = [[NSBundle mainBundle] pathForResource:@"多幸运" ofType:@"mp3"];
    
    AVAudioPlayer * audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:nil];
    // 设置代理
    audioPlayer.delegate = self;
 
    // 设置音量
    [audioPlayer setVolume:0.5];
  
    // 进入准备状态
    [audioPlayer prepareToPlay];
    
    // 开始播放
    [audioPlayer play];
    
    //播放暂停
    [audioPlayer pause];
}

// 播放完成
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    
}
// 播放中断
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error{
    
}

使用 Audio Queue Services 实现音频播放

Audio Queue Services 增加了播放功能,功能比AVAudioPlayer 的功能更加强大。

功能点:

  • 精确安排声音播放的时间,允许同步。
  • 逐个缓冲区精确控制音量
  • 使用Audio File Stream Services 从网络流中捕获音频。

Audio Queue Services 可以播放IOS系统中任何可用的音频格式的音频。

创建音频队列对象

步骤:

1、创建一个数据结构来管理音频队列所需的信息,例如要播放的数据的音频格式。

2、义用于管理音频队列缓冲区的回调函数。回调使用音频文件服务读取您要播放的文件。

3、使用AudioQueueNewOutput实例化播放音频队列

示例代码:

控制播放级别

音频队列对象为您提供了两种控制播放级别的方法:

1、要直接设置播放级别,请将该AudioQueueSetParameter函数与kAudioQueueParam_Volume参数一起使用,级别更改立即生效。

2、使用该AudioQueueEnqueueBufferWithParameters功能设置音频队列缓冲区的播放级别。这使您可以分配音频队列设置,该设置实际上是在排队时由音频队列缓冲区承载的。这些变化在缓冲区开始播放时生效。

示例代码:

获取播放级别

获取当前的播放级别方式:

1、将音频队列对象的kAudioQueueProperty_EnableLevelMetering属性设置为true。

2、调用音频队列对象的kAudioQueueProperty_CurrentLevelMeter属性,此属性的值是一个AudioQueueLevelMeterState结构数组,每个通道一个。

示例代码:

同时播放多种声音

同时播放多个声音,需要为每个声音都创建一个播放音频队列对象。每一个队列都设置该AudioQueueEnqueueBufferWithParameters属性,让每一个音频缓冲区都在在同一时间开始。

从iOS 3.0开始,几乎所有受支持的音频格式都可以用于同时播放,即所有可以使用软件解码播放的音频格式,如果你要获得处理器效率最高的多重播放,请使用线性PCM(未压缩)或IMA4(压缩)音频。

使用OpenAL播放声音

开源的OpenAL音频API(在OpenAL 框架的 iOS中可用)提供了优化的接口,用于在播放过程中将声音定位在立体声场中。播放、定位和移动声音的方式与在其他平台上一样。OpenAL还可以让您混合声音。OpenAL使用I / O单元进行回放,从而使延迟最小。

由于所有这些原因,OpenAL是在基于iOS的设备上的游戏应用程序中播放声音的最佳选择。但是,对于一般的iOS应用程序音频播放需求,OpenAL也是一个不错的选择。

录音

iOS支持使用AVAudioRecorder类和音频队列服务进行音频录制。这些接口负责连接音频硬件,管理内存以及根据需要使用编解码器的工作。

记录在iOS中以系统定义的输入级别进行。系统从用户选择的音频源(内置麦克风或耳机麦克风或其他输入源,如果已连接)中获取输入。

使用AVAudioRecorder类进行录制

在iOS中录制声音的最简单方法是使用AVAudioRecorder类,可轻松提供复杂的功能,例如暂停/恢复记录和处理音频中断。同时,您可以完全控制录制格式。

录制步骤:

1、指定声音文件的URL

2、设置音频会话

3、配置录音机的初始状态

示例代码:

- (void) viewDidLoad {
 
    [super viewDidLoad];
 		// 配置路径
    NSString *tempDir = NSTemporaryDirectory ();
    NSString *soundFilePath =
                [tempDir stringByAppendingString: @"sound.caf"];
 
    NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
    self.soundFileURL = newURL;
 		// 设置AudioSession 
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    audioSession.delegate = self;
    [audioSession setActive: YES error: nil];
 
    recording = NO;
    playing = NO;
}
使用Audio Queue Services 录制

要设置使用Audio Queue Services进行音频录制,您的应用程序将实例化录制音频队列对象并提供回调函数。回调将传入的音频数据存储在内存中以供立即使用,或将其写入文件以进行长期存储。

与播放一样,您可以通过查询其kAudioQueueProperty_CurrentLevelMeter属性来从音频队列对象获取当前的录音音频级别。

解析流音频

若要播放流式音频内容(例如通过网络连接),请与“Audio File Stream Services ”配合使用“Audio Queue Services”。音频文件流服务从网络比特流中解析常见音频文件容器格式的音频数据包和元数据。您也可以使用它来解析磁盘文件中的数据包和元数据。

在IOS中,你可以解析与MacOSX中相同的音频文件和比特流格式:

  • MPEG-1 Audio Layer 3, 用于.mp3文件
  • MPEG-2 ADTS, 用于.aac 音频数据格式
  • AIFC
  • AIFF
  • CAF
  • MPEG-4, 用于.m4a, .mp4, 和.3gp 文件
  • NeXT
  • WAVE

检索到音频数据包后,您可以使用iOS支持的任何格式播放恢复的声音。

要连接到网络流,请使用Core Foundation中的接口,例如CFHTTPMessage Reference中描述的接口。使用音频文件流服务解析网络数据包以恢复音频数据包。然后缓冲音频数据包,并将其发送到回放音频队列对象。

音频文件流服务依赖于音频文件服务的接口,例如AudioFramePacketTranslation结构和AudioFilePacketTableInfo结构。

IOS中的音频单元支持

iOS提供了一组音频处理插件,称为音频单元,您可以在任何应用程序中使用它们。音频单元框架中的接口使您可以打开,连接和使用这些音频单元。

系统提供的音频单元

音响单元 描述
iPod Equalizer unit iPod均衡器单元:类型的iPod EQ单元kAudioUnitSubType_AUiPodEQ提供了一个简单的,基于预设的均衡器,您可以在应用程序中使用它。有关如何使用此音频单元的演示。
3D Mixer unit 3D调音台:类型为的3D混合器单元kAudioUnitSubType_AU3DMixerEmbedded可让您混合多个音频流,指定立体声输出声像,操纵播放速率等等。OpenAL建立在此音频单元的顶部,并提供了非常适合游戏应用程序的高级API。
Multichannel Mixer unit 多通道调音台:类型为的多声道混音器单元kAudioUnitSubType_MultiChannelMixer可让您将多个单声道或立体声音频流混合到一个立体声流中。它还支持每个输入的左右平移。
Remote I/O unit 远程I / O单元:类型为的远程I / O单元kAudioUnitSubType_RemoteIO连接到音频输入和输出硬件,并支持实时I / O。
Voice Processing I/O unit 语音处理I / O单元:类型的语音处理I / O单元kAudioUnitSubType_VoiceProcessingIO具有I / O单元的特性,并增加了回声抑制和其他双向通信功能。
Generic Output unit 通用输出单元:类型的通用输出单元kAudioUnitSubType_GenericOutput支持与线性PCM格式之间的转换;可用于启动和停止图形。
Converter unit 转换单元:类型为Converter的Converter单元kAudioUnitSubType_AUConverter可让您将音频数据从一种格式转换为另一种格式。通常,您可以通过使用包含转换器单元的远程I / O单元来获得此音频单元的功能。

IOS 音频最佳做法

列出了在iOS中使用音频的一些重要技巧,并介绍了各种用途的最佳音频数据格式。

使用音频时要记住的重要提示:

提示 具体实现
适当使用压缩音频 对于AAC,MP3和ALAC(Apple无损)音频,可以使用硬件辅助编解码器进行解码。虽然有效,但一次只限于一个音频流。如果您需要同时播放多个声音,请使用IMA4(压缩)或线性PCM(未压缩)格式存储这些声音。
转换为所需的数据格式和文件格式 afconvertMac OS X中的工具可让您转换为各种音频数据格式和文件类型。
评估音频内存问题 使用“音频队列服务”播放声音时,您编写了一个回调,该回调将音频数据的短片段发送到音频队列缓冲区。在某些情况下,最好将整个声音文件加载到内存中进行播放,以最大程度地减少磁盘访问。在其他情况下,最好一次加载仅足够的数据以保持缓冲区已满。测试和评估哪种策略最适合您的应用程序。
通过限制采样率,位深和通道来减小音频文件的大小 采样率和每个采样的位数直接影响音频文件的大小。如果您需要播放许多此类声音或长时间的声音,请考虑减少这些值以减少音频数据的内存占用量。例如,您可以使用32 kHz(或更低)的采样率,而不是使用44.1 kHz的采样率获得声音效果,但仍可以提供合理的质量。 使用单声道(单声道)音频而不是立体声(两声道)可减小文件大小。对于每种声音资产,请考虑单声道是否可以满足您的需求。
选择合适的技术 当您需要方便的高级界面将声音定位在立体声场中或需要低延迟播放时,请使用OpenAL。要解析来自文件或网络流的音频数据包,请使用音频文件流服务。要简单地播放单个或多个声音,请使用AVAudioPlayer该类。要记录到文件中,请使用AVAudioRecorder类。要进行音频聊天,请使用语音处理I / O单元。要播放从用户的iTunes库同步的音频资源,请使用iPod Library Access。当您唯一需要播放警报和用户界面声音效果的音频时,请使用Core Audio的系统声音服务。对于其他音频应用程序,包括流音频的回放,精确同步以及对传入音频包的访问,请使用音频队列服务。
低延迟代码 为了获得尽可能低的播放延迟,请使用OpenAL或直接使用I / O单元。

IOS中首选的音频格式

对于未压缩(最高质量)的音频,请使用打包在CAF文件中的16位,低端线性线性PCM音频数据。

对于一次播放一种声音时的压缩音频,以及不需要与iPod应用程序同时播放音频的情况,请使用CAF或m4a文件中打包的AAC格式。

当需要同时播放多个声音时,为了减少内存使用量,请使用IMA4(IMA / ADPCM)压缩。这样可以减小文件大小,但在解压缩期间对CPU的影响最小。与线性PCM数据一样,将IMA4数据打包在CAF文件中。

参考资料: 音频开发官方文档

 

如需转载请标注来处: CoderMrWu

点赞