Core Audio简介

Linear PCM

在介绍Core Audio之前,先介绍一下最常用的非压缩数字音频格式Linear PCM(线性脉冲编码调制)。在计算机录音的过程中,他会每隔一定的时间会来抽样获取现实中的音频信号的强度并且将获取到的数据转换成一个数值。CD音频通常的抽样的频率是44.1kHz(sample rate),每个抽样用一个16bit的整数来表示(bit depth)。

一个抽样代表的是对一个音频通道的数字量化值。

帧(frame)是一系列抽样的集合。例如,一个立体声的声音文件中,每一帧会有2个抽样,一个是左声道的抽样,一个是右声道的。

Package是一系列帧的集合。在Linear PCM中,每个package总是包含一帧。在压缩的音频格式中,一个package可能有更多的帧。Package对已一个给定的音频数据格式来说,是最小的有意义的集合。

在Linear PCM中,一个抽样的大小和他所表示的信号的强度成线性关系。一个16位的标准CD音频可以表示从静音到最高的声音总共65,536种可能的值。相邻的两个数值之间的信号的强度的差别总是相等的。

Core Audio在他的数据结构中可以表示任何采样率和位深的Linear PCM。

Core audio

Core audio是ios系统中用于处理和音频相关的框架。下图是Core audio的架构。


Audio Queue Service主要负责声音的录制播放。

System sounds使用来播放系统的声音和用户界面的声音效果

AVAudioPlayer提供了一个简单的OC接口的音频播放器。

Audio File

Services主要负责来读取和写入音频数据和文件。

Audio Session

Services主要是用来管理你的app在移动设备中的声音的行为

Audio units包含一系列的底层的音频处理插件,可以处理混音、均衡、实时的录音和播放等

Audio File

Stream Services主要负责处理流媒体的音频文件的播放

OpenAL主要是游戏开发中使用的比较多,主要是根据标准实现了位置性的音源功能

Codecs主要是对音频文件进行编解码,也就是对ios平台支持的压缩格式的编解码

音频的数据格式

系统使用AudioStreamBasicDescription和AudioStreamPacketDescription描述音频的格式。他们的结构如下所示:

struct AudioStreamBasicDescription {

Float64 mSampleRate;

UInt32mFormatID;

UInt32mFormatFlags;

UInt32mBytesPerPacket;

UInt32mFramesPerPacket;

UInt32mBytesPerFrame;

UInt32mChannelsPerFrame;

UInt32mBitsPerChannel;

UInt32mReserved;

};

typedef structAudioStreamBasicDescriptionAudioStreamBasicDescription;

structAudioStreamPacketDescription {

SInt64mStartOffset;

UInt32mVariableFramesInPacket;

UInt32mDataByteSize;

};

typedef struct AudioStreamPacketDescriptionAudioStreamPacketDescription;

获取文件的数据格式

你可以手动的填充音频格式这个数据结构,也可以从系统中获取。

- (void) openPlaybackFile: (CFURLRef)soundFile {

AudioFileOpenURL (

(CFURLRef) self.audioFileURL,

0x01,// readonly

kAudioFileCAFType,

&audioFileID

);

UInt32 sizeOfPlaybackFormatASBDStruct =sizeof ([self audioFormat]);

AudioFileGetProperty (

[self audioFileID],

kAudioFilePropertyDataFormat,

&sizeOfPlaybackFormatASBDStruct,

&audioFormat// thesound file's ASBD is returned here

);

}

标准音频数据格式

对于不同的平台,Core

Audio有一两个标准的音频格式,这种格式会:

1.在音频格式转化过程中,被指定为中间格式

2.在Core Audio中被特殊优化过

3.当你没有设置音频格式的时候,会作为默认的格式

CoreAudio的标准格式是:

[if !supportLists]1.[endif]ios输入输出Linear PCM格式,并且位深是16bit

[if !supportLists]2.[endif]iOS audio units和其他的音频处理使用linear PCM,并且使用8.24-bit定点数采样

下面是一个双声道,标准的iPhone audio unit格式,采样频率是44.1 kHz的音频格式结构

structAudioStreamBasicDescription {

mSampleRate= 44100.0;

mFormatID= kAudioFormatLinearPCM;

mFormatFlags= kAudioFormatFlagsAudioUnitCanonical;

mBitsPerChannel= 8 * sizeof (AudioUnitSampleType);// 32 bits

mChannelsPerFrame = 2;

mBytesPerFrame= mChannelsPerFrame * sizeof(AudioUnitSampleType);// 8 bytes

mFramesPerPacket= 1;

mBytesPerPacket= mFramesPerPacket * mBytesPerFrame;// 8 bytes

mReserved= 0;

};

Magic Cookies

在Core Audio的实现中,magic

cookie是对于压缩音频数据的一个不透明元数据。这个元数据给解码器足够的信息让他来对音频文件进行解码。你可以把magic

cookie当作一个黑盒子,依靠Core Audio的函数来复制读取和使用它。

下面是一个例子:

- (void) copyMagicCookieToQueue:(AudioQueueRef) queue fromFile: (AudioFileID) file {

UInt32 propertySize = sizeof (UInt32);

OSStatus result = AudioFileGetPropertyInfo (

file,

kAudioFilePropertyMagicCookieData,

&propertySize,

NULL

);

if (!result && propertySize) {

char *cookie = (char *) malloc (propertySize);

AudioFileGetProperty (

file,

kAudioFilePropertyMagicCookieData,

&propertySize,

cookie

);

AudioQueueSetProperty (

queue,

kAudioQueueProperty_MagicCookie,

cookie,

propertySize

);

free (cookie);

}

}

音频数据包

Package是一系列帧的集合。对于音频数据来说,他是最小的有意义的单元。因此他是最好的表示一个音频文件中某一个时间内的数据集合。Core Audio中的同步就是通过数package来实现的。你可以使用package来计算音频数据的缓存大小。

对于不同的数据类型有三种包:

[if !supportLists]1.[endif]CBR(固定比特率),例如linear PCM和IMA/ADPCM,所有的package的大小都一样

[if !supportLists]2.[endif]VBR(浮动比特率),例如AAC, Apple Lossless,和MP3,所有的package包含的frame的数量一样,但是每个frame的大小可能不同

[if !supportLists]3.[endif]VFR(浮动帧率),package有不同的数量的帧。这种类型少见

如果要使用VBR或者VFR你需要使用stream packet description结构体,每一个结构体表示一个package。如果要播放或者录制,你需要一个这个结构体的数字来表示其中的每一个package。

Audio File Services和Audio File

Stream会让你使用package来进行文件操作。AudioFileReadPackets从文件中读取一个package到内存中。同时,他会给你一个AudioStreamPacketDescription的数组,来表示package。

对于CBR and VBR,每秒钟读取的package的数目是不一定的。下面的方法可以帮助你计算出音频文件缓存的大小:

- (void) calculateSizesFor: (Float64) seconds {

UInt32 maxPacketSize;

UInt32 propertySize =sizeof (maxPacketSize);

AudioFileGetProperty (

audioFileID,

kAudioFilePropertyPacketSizeUpperBound,

&propertySize,

&maxPacketSize

);

static const intmaxBufferSize = 0x10000;// limitmaximum size to 64K

static const intminBufferSize = 0x4000;// limitminimum size to 16K

if (audioFormat.mFramesPerPacket){

Float64numPacketsForTime =

audioFormat.mSampleRate / audioFormat.mFramesPerPacket * seconds;

[selfsetBufferByteSize: numPacketsForTime * maxPacketSize];

} else {

// if frames perpacket is zero, then the codec doesn't know the

// relationshipbetween packets and time. Return a default buffer size

[selfsetBufferByteSize:

maxBufferSize >maxPacketSize ? maxBufferSize : maxPacketSize];

}

// clamp buffer size to ourspecified range

if (bufferByteSize >maxBufferSize && bufferByteSize > maxPacketSize) {

[selfsetBufferByteSize: maxBufferSize];

} else {

if (bufferByteSize< minBufferSize) {

[selfsetBufferByteSize: minBufferSize];

}

}

[self setNumPacketsToRead:self.bufferByteSize / maxPacketSize];

}

数据格式转换

你可以使用格式转换器来进行数据的格式转换。你可以进行PCM的采样率的转换或者将压缩格式和PCM直接任意转换。一共有三种转化:

[if !supportLists]1.[endif]将一个音频格式解码为linear PCM

[if !supportLists]2.[endif]将linear PCM转换为另外一个音频格式

[if !supportLists]3.[endif]linear PCM之间的转化

当你使用了AudioQueue Services,你会自动的获取到相应的编码器。

声音文件

你可以使用Audio File Services来和app中的音频文件交互。它对获取音频文件和创建音频文件有很有用的抽象。

你可以使用Audio File Services来获取系统参数。AudioFileGetGlobalInfoSize来让你分配足够的内存空间来保存数据,AudioFileGetGlobalInfo来获取真正的数据。你可以在AudioFile.h文件中查看,你可以获取到那些信息:

[if !supportLists]1.[endif]可读的文件类型

[if !supportLists]2.[endif]可写的文件类型

[if !supportLists]3.[endif]对于每一种可写的类型,你可以写入的音频数据的格式

另外还有其他的两种技术:

[if !supportLists]1.[endif]Audio

File Stream Services让可以读取硬盘或者流中的文件数据

[if !supportLists]2.[endif]Extended

Audio File Services他封装了file和stream接口,让你使用的更容易

创建一个新的声音文件

为了创建一个新的声音文件,你需要:

[if !supportLists]1.[endif]这个文件的系统路径,以CFURL或者NSURL对象类型

[if !supportLists]2.[endif]你想要创建的文件的类型,例如CAF文件你需要设定为kAudioFileCAFType

[if !supportLists]3.[endif]你将要写入到文件中的音频数据的audio stream basic description。在很多情况下,你可以设置一部分,然后让系统帮你决定另一部分。

你将这三个参数给AudioFileCreateWithURL,它会创建一个文件,并返回AudioFileID对象。你可以使用它来作为后面进一步交互的对象。

AudioFileCreateWithURL(

audioFileURL,

kAudioFileCAFType,

&audioFormat,

kAudioFileFlags_EraseFile,

&audioFileID// the function provides the new file objecthere

);

打开一个音频文件

你可以使用AudioFileOpenURL来打开一个文件。你可以给他一个URL,一个文件类型的提示还有一个你想使用的文件权限,然后他就会返回一个ID。

你可以使用这个ID和AudioFileGetPropertyInfo和AudioFileGetProperty来获取文件的各种信息。通常你需要知道的信息包括:kAudioFilePropertyFileFormat,kAudioFilePropertyDataFormat,kAudioFilePropertyMagicCookieData,kAudioFilePropertyChannelLayout。

对于一个VBR的长文件,你读取所有的package可能需要很长时间,这两个参数有帮助kAudioFilePropertyPacketSizeUpperBound和kAudioFilePropertyEstimatedDuration。他可以预估出package的大小和时长。

读写一个音频文件

Ios中通常使用Audio File Services来读和写文件。除非必要都使用package来读和写。因为,对于VBR你只能使用package来读写,并且使用基于package的读写也更加简单。

iPhone可以支持的音频文件格式

Format nameFormat filename extensions

AIFF.aif,.aiff

CAF.caf

MPEG-1, layer 3.mp3

MPEG-2 or MPEG-4 ADTS.aac

MPEG-4.m4a,.mp4

WAV.wav

AC-3 (Dolby Digital).ac3

Enhanced AC-3 (Dolby Digital  Plus).ec3

CAF文件

Ios和osx有自己的音频文件格式叫做Core Audio Format (或者CAF)。他可以包含平台支持的所有的音频数据格式。

音频流

Audio File Stream Services主要用来对音频流进行解析。你创建一个audio file stream的对象AudioFileStreamID。他作为你和音频流相互的代理。因为audio file stream Services主要负责对音频流进行解析,那么你的app就需要解析后的各种信息和数据进行交互和反馈。你通过两个回调函数来对这些信息最反馈。

首先你需要有一个回调来对音频流的属性变化做反馈。至少你需要对属性kAudioFileStreamProperty_ReadyToProducePackets的变化有反馈。通常使用这个属性的场景如下:

[if !supportLists]1.[endif]用户按下开始播放按钮,或者请求这个音频流来播放

[if !supportLists]2.[endif]Audio

File Stream Services开始解析音频流

[if !supportLists]3.[endif]当足够多的package被解析并发送到你的app中,Audio File

Stream Services会将属相kAudioFileStreamProperty_ReadyToProducePackets的值设置为1

[if !supportLists]4.[endif]Audio

File Stream Services会回调你的回调函数,并且回调的属性ID是kAudioFileStreamProperty_ReadyToProducePackets

[if !supportLists]5.[endif]你的回调开始负责做后续的操作,例如建立一个audio queue对象来负责播放这个音频流

其次,你需要一个回调来处理音频数据。每当Audio File Stream Services获取到一系列完整的音频package,他就会回调你的函数。你的回调需要处理收到的数据。通常,你需要立即将他们发送给Audio Queue Services来播放。

Audio Sessions:与Core Audio相互合作

audio

session是你的appios系统的中间人。每个app都只有一个audio session,你通过他来表达你的app的音频的用处。你必须首先回答几个关于你的app如何表现的问题:

[if !supportLists]1.[endif]你的app如何对打断作反应,例如一个电话?

[if !supportLists]2.[endif]你想要你的app的声音和其他声音混合播放吗,或者你想要让别的app静音?

[if !supportLists]3.[endif]你的app对音频通道的变化如何反应,当用户插入或者拔出他的二级

当你想好了答案,你可以使用audio session的接口来设置你的接口和应用。下面提供了三种特性,你可以通过变成来设置他们.

Audio session featureDescription

CategoriesA category is a key that  identifies a set of audio behaviors for your application. By setting a  category, you indicate your audio intentions to iOS, such as whether your  audio should continue when the screen locks.

Interruptions and route  changesYour audio session posts  notifications when your audio is interrupted, when an interruption ends, and  when the hardware audio route changes. These notifications let you respond to  changes in the larger audio environment—such as an interruption due to in an  incoming phone call—gracefully.

Hardware characteristicsYou can query the audio session  to discover characteristics of the device your application is running on,  such as hardware sample rate, number of hardware channels, and whether audio  input is available.

Audio Sessiond的默认行为

[if !supportLists]1.[endif]当用户通过静音按钮来静音,你的声音将会被静音

[if !supportLists]2.[endif]当设备进入锁屏或者待机状态,你的声音将被静音。

[if !supportLists]3.[endif]当你的声音开始,其他的声音将会被停止

这些行为是由它的默认类别kAudioSessionCategory_SoloAmbientSound所决定的。Ios提供了很多类别来满足你的需求,你可以在应用启动或者在你的app运行的时候来设置

Audio session的默认行为对于ios的音频开发足够了。除非你有自己的特殊需求,下面会讨论。

打断:激活和非激活

一个audio session的默认行为中缺少他在打断结束后重新激活自己的能力。audio session主要有两个状态:激活和非激活。你只有在激活状态下,才能对你的音频进行操作。

在启动时,你的默认的audio

session就被激活。但是,如果电话来了,你的audio session会成为非激活状态,并且声音被打断。这叫做打断,如果用户选择忽略这个电话,你的应用会继续运行,但是你的audio session已经处于非激活状态,他不能继续播放了。

如果你的app中使用OpenAL,

I/O audio unit,或者Audio Queue Services,你必须写一个打断的回调函数,并且在打断结束的时候,显式的重新激活你的audio session。

如果你使用AVAudioPlayer类,他自己会帮你处理好。

判断你的音频输入是否有效

在你录音前,你必须首先知道你的ios音频录入设备是否有效,因为在ipod

touch(2代)中,他只有当其他的输入设备接入的时候,才能进行语音的输入。你可以使用kAudioSessionProperty_AudioInputAvailable属性来判断。下面是一个例子:

UInt32 audioInputIsAvailable;

UInt32 propertySize = sizeof (audioInputIsAvailable);

AudioSessionGetProperty (

kAudioSessionProperty_AudioInputAvailable,

&propertySize,

&audioInputIsAvailable // A nonzero value on output means that

// audio input isavailable

);

使用你的Audio Session

在同一时刻,你的app只能有一个audio

session的类别。你的所有的音频特性都遵守这个类别的特性。(除了System Sound Services,她总是使用最低优先级的audio

session列别)。

你必须在真机上测试你的audio session的行为。

使用AVAudioPlayer类播放声音

AVAudioPlayer提供了一个简单的oc的类来播放音频。如果你的app不需要立体声或者准确的同步,并且不是从网络上获取音频来播放。苹果推荐你使用这个类来播放音乐。

使用它来播放音乐你可以:

[if !supportLists]1.[endif]播放任何时长的声音

[if !supportLists]2.[endif]从文件或者内存中播放声音

[if !supportLists]3.[endif]循环播放

[if !supportLists]4.[endif]同时播放多个声音

[if !supportLists]5.[endif]控制你播放的每个声音的音量

[if !supportLists]6.[endif]获取文件的某一个特定的点,这个可以支持快进或者快退

[if !supportLists]7.[endif]获取声音的音量数据

AVAudioPlayer不需要你使用Audio Session Services,但是他的默认行为不符合你的要求,你可以使用默认的audio session。

为了使用AVAudioPlayer,你首先给他一个音频文件,准备播放,并且设置一个代理,例子如下:

NSString*soundFilePath =

[[NSBundle mainBundle]pathForResource: @"sound"

ofType: @"wav"];

NSURL *fileURL =[[NSURL alloc] initFileURLWithPath: soundFilePath];

AVAudioPlayer*newPlayer =

[[AVAudioPlayer alloc]initWithContentsOfURL: fileURL

error: nil];

[fileURLrelease];

self.player =newPlayer;

[newPlayerrelease];

[self.playerprepareToPlay];

[self.playersetDelegate: self];

你使用一个代理来处理打断和更新用户界面当声音播放结束。下面实现了一个简单代理方法的实现,这个嗲吗更新了开始和暂停按钮的标题,当声音完成播放。

- (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *) player

successfully: (BOOL)flag {

if(flag == YES) {

[self.button setTitle: @"Play" forState:UIControlStateNormal];

}

}

为了播放、暂停或者停止一个AVAudioPlayer对象,调用他的播放控制方法。你可以使用playing属性来获取声音是否在播放。下面是简单的一个实现了点击播放暂停按钮来更新按钮的标题:

- (IBAction) playOrPause: (id) sender {

// ifalready playing, then pause

if(self.player.playing) {

[self.button setTitle: @"Play" forState:UIControlStateHighlighted];

[self.button setTitle: @"Play" forState:UIControlStateNormal];

[self.player pause];

// ifstopped or paused, start playing

} else{

[self.button setTitle: @"Pause" forState: UIControlStateHighlighted];

[self.button setTitle: @"Pause" forState:UIControlStateNormal];

[self.player play];

}

}

AVAudioPlayer使用oc的方式声明一个属性并且管理声音。你可以使用下面的方法来设置音频的声音:

[self.player setVolume: 1.0];// available range is 0.0 through 1.0

使用Audio Queue Services来录制或者播放音频

AudioQueue Services使用了一个很直接的并且足够低层的方式来录制或者播放声音。他可以使你的app使用硬件来录制或者播放声音(例如麦克风或者音像)而不用知道硬件的细节。他可以让你使用复杂的编码而不用知道编码是如何工作的。

尽管他是一个高层的接口,Audio

Queue Services支持一些高级特性。他提供细粒度的时间控制来支持定时播放和同步。你可以使用它来同步多个audio queue的播放来使这些声音同步播放,来单独控制多个声音的声音大小,并且来重复播放。Audio Queue Services和AVAudioPlayer是唯一的两种方式来播放压缩的音频。

通常你使用Audio Queue Services时,需要和Audio File Services或者Audio File Stream Services相配合。

Audio Queue录音和播放的回调函数

就和Audio File Stream Services一样,你需要使用回调和属性来和audio queue对象交互。录音时,你实现一个回调来接手音频数据缓存并且写到硬盘中。你的audio queue会在每次新的缓存被写满的时候会调用你的回调。下面是一个简单的示例:


对于播放,你的回调处于一个相反的过程。当你的audio queue需要有一个新的内存数据来播放的时候,会回调你。你的回调读取一定数量的音频package,并且将他们交给audio queue的缓存中。然后audioqueue开始播放,如下图示例:


创建一个Audio Queue对象

为了使用Audio Queue Services,你需要首先创建一个Audio Queue Services。对于播放和录音,创建的方式不同:

[if !supportLists]1.[endif]使用AudioQueueNewInput来创建录音Audio Queue

[if !supportLists]2.[endif]使用AudioQueueNewOutput来创建播放Audio Queue

为了创建一个播放的Audio Queue,你需要实现以下三步:

[if !supportLists]1.[endif]创建一个结构体来管理Audio Queue需要的信息,例如你所播放的数据的音频格式

[if !supportLists]2.[endif]定义一个回调来处理Audio Queue的缓存。回调使用Audio File Services来读取文件播放

[if !supportLists]3.[endif]使用AudioQueueNewOutput来来初始化AudioQueue

示例如下:

static const int kNumberBuffers = 3;

// Create a data structure to manage informationneeded by the audio queue

struct myAQStruct {

AudioFileIDmAudioFile;

CAStreamBasicDescriptionmDataFormat;

AudioQueueRefmQueue;

AudioQueueBufferRefmBuffers[kNumberBuffers];

SInt64mCurrentPacket;

UInt32mNumPacketsToRead;

AudioStreamPacketDescription*mPacketDescs;

boolmDone;

};

// Define a playback audio queue callbackfunction

static void AQTestBufferCallback(

void*inUserData,

AudioQueueRefinAQ,

AudioQueueBufferRefinCompleteAQBuffer

) {

myAQStruct*myInfo = (myAQStruct *)inUserData;

if(myInfo->mDone) return;

UInt32numBytes;

UInt32nPackets = myInfo->mNumPacketsToRead;

AudioFileReadPackets (

myInfo->mAudioFile,

false,

&numBytes,

myInfo->mPacketDescs,

myInfo->mCurrentPacket,

&nPackets,

inCompleteAQBuffer->mAudioData

);

if(nPackets > 0) {

inCompleteAQBuffer->mAudioDataByteSize = numBytes;

AudioQueueEnqueueBuffer (

inAQ,

inCompleteAQBuffer,

(myInfo->mPacketDescs ? nPackets : 0),

myInfo->mPacketDescs

);

myInfo->mCurrentPacket += nPackets;

} else{

AudioQueueStop (

myInfo->mQueue,

false

);

myInfo->mDone = true;

}

}

// Instantiate an audio queue object

AudioQueueNewOutput (

&myInfo.mDataFormat,

AQTestBufferCallback,

&myInfo,

CFRunLoopGetCurrent(),

kCFRunLoopCommonModes,

0,

&myInfo.mQueue

);

控制Audio Queue的播放音量

有两种方式,一种是使用AudioQueueSetParameter直接设置kAudioQueueParam_Volume的参数。音量会立即生效:

Float32 volume = 1;

AudioQueueSetParameter (

myAQstruct.audioQueueObject,

kAudioQueueParam_Volume,

volume

);

你也可以使用AudioQueueEnqueueBufferWithParameters来控制音量。这个绘制在你将这个缓存插入到Audio

Queue中的时候生鲜。在这两种情况下,直到你更改音量之前,audio

queue都会保持你这次设置的音量。

获取Audio Queue播放音量

你可以使用kAudioQueueProperty_CurrentLevelMeterDB来获取当前播放的音量。这个返回是一个包含着AudioQueueLevelMeterState结构体的数组,每一个代表一个声道。如下图所示:

typedef struct AudioQueueLevelMeterState {

Float32mAveragePower;

Float32mPeakPower;

};AudioQueueLevelMeterState

同时播放多个音乐

为了同时播放多个因为,为每一个音乐创建一个audio queue。对于每一个audio queue,让他们的音频的第一个缓存同时播放,使用AudioQueueEnqueueBufferWithParameters。

音频的格式对于同时播放是很重要的。有些压缩的音频格式十分的消耗硬件编码。下面的格式同时只能播放一个实例:

[if !supportLists]·[endif]AAC

[if !supportLists]·[endif]ALAC (Apple Lossless)

[if !supportLists]·[endif]MP3

为了同时播放高音质的音乐,使用PCM or IMA4格式。

1.Linear PCM和IMA/ADPCM (IMA4)音频。你可以同时播放多个PCM或者IMA4格式的音乐而不会产生CPU资源问题.

2.AAC, MP3,和Apple Lossless

(ALAC)音频播放AAC, MP3,和Apple Lossless (ALAC)会很消耗资源,你同时只能播放一个。

使用OpenAL来播放

OpenAL是最适合用来在游戏中播放音乐。

系统声音:提醒和声音效果

如果你播放的声音不需要控制音量,位置,audio session或者其他的控制,使用System Sound Services。这个接口最适合播放一个短的简单的方式来播放声音。在ios中,System Sound Services最多只能播放30秒钟

可以使用AudioServicesPlaySystemSound来立即播放系统声音。AudioServicesPlayAlertSound可以使用它来提醒用户。每一个方法都会在用户静音的时候产生振动。

你可以使用AudioServicesPlaySystemSound并且传入kSystemSoundID_Vibrate参数来直接来触发振动。

使用AudioServicesPlaySystemSound来播放声音,你首先通过创建一个sound ID来注册这个声音效果文件。然后你可以播放这个声音。通常,会播放只播放一次或者重复的播放的情景,你需要持有这个sound ID直到你的app不再使用他。如果你只是使用一次,你可以在它播放完之后,立即释放他。

下面是一个实例:

#include

#include

// Define a callback to be called when the soundis finished

// playing. Useful when you need to free memoryafter playing.

static void MyCompletionCallback (

SystemSoundIDmySSID,

void * myURLRef

) {

AudioServicesDisposeSystemSoundID (mySSID);

CFRelease (myURLRef);

CFRunLoopStop (CFRunLoopGetCurrent());

}

int main (int argc, const char * argv[]) {

// Setup the pieces needed to play a sound.

SystemSoundIDmySSID;

CFURLRefmyURLRef;

myURLRef = CFURLCreateWithFileSystemPath (

kCFAllocatorDefault,

CFSTR ("../../ComedyHorns.aif"),

kCFURLPOSIXPathStyle,

FALSE

);

//create a system sound ID to represent the sound file

OSStatus error = AudioServicesCreateSystemSoundID (myURLRef,&mySSID);

//Register the sound completion callback.

//Again, useful when you need to free memory after playing.

AudioServicesAddSystemSoundCompletion (

mySSID,

NULL,

NULL,

MyCompletionCallback,

(void *) myURLRef

);

// Playthe sound file.

AudioServicesPlaySystemSound (mySSID);

//Invoke a run loop on the current thread to keep the application

// running long enough for the sound to play;the sound completion

//callback later stops this run loop.

CFRunLoopRun ();

return0;

}

Core Audio插件: Audio Units和Codecs

Core Audio有插件的机制来处理音频数据。在ios中,系统提供这些插件。Osx中,有系统内置的,你也可以创建你自己的。

Audio Units

在ios中,audio

units给app提供一个低延时的输入输出方案。他同样提供一些DSP的特性。

iOSaudio units的输入输出使用8.24-bit固定小数的linear PCM音频格式。Ios的audio units是:

[if !supportLists]1.[endif]3D混音

[if !supportLists]2.[endif]多通道混音器

[if !supportLists]3.[endif]转换器

[if !supportLists]4.[endif]I/O器

[if !supportLists]5.[endif]iPod均衡器

�xV��h�

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容