Audio File Stream
Audio File Stream提供了解析音频流文件的接口。
音频流文件本质上是不允许随机访问的。当你从音频流中请求数据的时候,早期的数据可能还没能被访问而后面的数据可能还没被接收。另外,你所获取的数据(将要提高那个给解析器的)可能会含有部分帧(Packets)。为了解析流音频数据,解析器必须记住部分满足请求命令的数据,也必须能够等待该数据的剩下的其他数据。换句话说,就是解析器必须能够按照需求暂停解析然后从暂停的地方继续开始。
要使用解析器的话,你需要将流音频文件中的数据传递给解析器(当你获取时也是一样)。当解析器接收到一个完整的音频数据帧或者完整的特性时,会调用回调函数。然后你的回调函数会开始进行已解析数据的处理,比如说播放或者写入硬盘。
一般情况下的使用步骤:
- 调用AudioFileStreamOpen函数创建一个新的音频文件流解析器。给音频数据和metadata传递回调函数的指针(AudioFileStream_PacketsProc和AudioFileStream_PropertyListenerProc)。AudioFileStreamOpen会给出一个新的解析器的引用。
- 获取流数据。当有数据要传递给解析器时调用AudioFileStreamParseBytes,如果可以的话就无间隙的将数据继续传入。
- 当解析器获取到可以使用的音频数据缓冲时,会调用音频数据回调。然后回调函数会执行播放,写入等操作
- 当解析器获取到metadata时,会调用属性回调。可以通过调用AudioFileStreamGetPropertyInfo和AudioFileStreamGetProperty函数获取
3.结束解析时,调用AudioFileStreamClose函数关闭并且释放解析器
Audio File Stream所支持的音频数据格式有:AIFF, AIFC, WAVE, CAF, NeXT, ADTS, MP3, AAC
函数
打开音频文件流
OSStatus AudioFileStreamOpen ( void *inClientData, // 要传递给回调函数的值或者结构的指针,可以理解为上下文对象
AudioFileStream_PropertyListenerProc inPropertyListenerProc, // property-listener回调,当解析器发现数据流中的属性值,会调用属性监听的回调并将该值匹配到一个属性ID上。然后可以通过AudioFileStreamGetPropertyInfo和AudioFileStreamGetProperty来获取该属性
AudioFileStream_PacketsProc inPacketsProc, // 音频数据回调。当解析器发现数据流中的数据帧时进行调用
AudioFileTypeID inFileTypeHint, // 音频文件类型提示。如果无法从数据中轻易判断出音频文件的类型时可传入该提示帮助解析。如果不清楚文件类型时,可以传入0
AudioFileStreamID *outAudioFileStream ); // 在输出时,代表了音频文件流解析器的对象。该对象作为音频流文件的解析器的ID,在之后的API中需要用到
返回值参考结果代码
传递音频流数据给解析器
OSStatus AudioFileStreamParseBytes ( AudioFileStreamID inAudioFileStream, // 想要传递数据的解析器ID,在上面的函数中给出
UInt32 inDataByteSize, // 将要解析的字节数
const void *inData, // 要解析的数据
UInt32 inFlags ); // 音频文件标志。如果所传递的最后的数据与前一次的数据是中断的,则传入kAudioFileStreamParseFlag_Discontinuity
返回值参考结果代码
在音频文件中出现的流音频文件数据一般是在同个序列中传递给解析器的,也就是从开始传递到结束中间没有中断。但是,如果你调用了AudioFileStreamSeek函数,解析器则会假定传递给AudioFileStreamParseBytes的数据是从AudioFileStreamSeek函数返回的字节偏移开始传入的。
当提供数据给解析器时,解析器会寻找属性数据和音频数据帧。在准备开始解析时,调用AudioFileStream_PropertyListenerProc和AudioFileStream_PacketsProc回调函数来处理数据。你需要提供至少多于一个的音频文件数据帧,但是通常来说在较短的时间内只提供一丁点的数据帧会比较好。
在数据流中寻找帧(跳转,理解为快进或快退行为)
OSStatus AudioFileStreamSeek ( AudioFileStreamID inAudioFileStream, // 解析器ID,在AudioFileStreamOpen中给出
SInt64 inPacketOffset, // 要seek的帧的偏移
SInt64 *outDataByteOffset, // 在seek到的帧中字节偏移。在不包含帧的音频文件中会返回一个估计值
UInt32 *ioFlags ); // 在输出时,如果上面的参数返回的是估计值,则这个参数返回的是常量kAudioFileStreamSeekFlag_OffsetIsEstimated
返回值参照结果代码
调用这个函数后,AudioFileStreamParseBytes会假定从outDataByteOffset返回的字节偏移的位置上开始解析
获取属性值的信息
OSStatus AudioFileStreamGetPropertyInfo ( AudioFileStreamID inAudioFileStream, // 解析器ID,在AudioFileStreamOpen中给出
AudioFileStreamPropertyID inPropertyID, // 一个四个字节的ID, 在下面中会有介绍
UInt32 *outPropertyDataSize, // 在输出时,指定属性的值的size(字节)
Boolean *outWritable ); // 在输出时,true表明允许写。但是目前没有可以写的音频文件流属性
获取指定属性值
OSStatus AudioFileStreamGetProperty ( AudioFileStreamID inAudioFileStream, // 解析器ID,在AudioFileStreamOpen中给出
AudioFileStreamPropertyID inPropertyID, // 4字节的ID
UInt32 *ioPropertyDataSize, // 作为输入时,为outPropertyData中的缓冲大小,调用AudioFileStreamGetPropertyInfo获取大小。作为输出时,表示属性值返回的字节数
void *outPropertyData ); // 作为输出时,为指定属性的值
有的Core Audio属性是C语言类型的,有的是Core Foundation
设置特定属性的值
OSStatus AudioFileStreamSetProperty ( AudioFileStreamID inAudioFileStream, // 解析器ID,在AudioFileStreamOpen中给出
AudioFileStreamPropertyID inPropertyID, // 4字节的ID
UInt32 inPropertyDataSize, // 属性数据的大小
const void *inPropertyData ); // 属性数据
目前没有可以设定的属性!!!
关闭并释放指定的音频文件流解析器
OSStatus AudioFileStreamClose ( AudioFileStreamID inAudioFileStream ); // 解析器ID
回调函数
处理属性值
typedef void (*AudioFileStream_PropertyListenerProc) ( void *inClientData, // 调用AudioFileStreamOpen时所提供的值,理解为上下文对象
AudioFileStreamID inAudioFileStream, // 调用此回调函数的解析器ID。在AudioFileStreamOpen中返回
AudioFileStreamPropertyID inPropertyID, // 4字节的ID
UInt32 *ioFlags ); // 作为输入时,如果设置了kAudioFileStreamPropertyFlag_PropertyIsCached,则解析器会缓存属性值。如没有的话,则在输出时可以设定kAudioFileStreamPropertyFlag_CacheProperty来缓存
当你在属性监听中调用AudioFileStreamGetProperty时,由于输入数据的边界,解析器会返回结果代码kAudioFileStreamError_DataUnavailable表明无法接受该值。当属性监听方法的范围内请求了无法被接受的数据时,解析会开始缓存属性值并且在属性值可接受时重新调用属性监听。
处理音频文件流数据的帧
typedef void (*AudioFileStream_PacketsProc) ( void *inClientData, // 同上
UInt32 inNumberBytes, // inInputData缓冲的数据的字节数
UInt32 inNumberPackets, // inInputData缓冲的数据的帧数
const void *inInputData, // 音频数据
AudioStreamPacketDescription *inPacketDescriptions ); // 描述了数据的音频文件流帧的描述结构的对象数组
对于CBR音频数据来说,调用回调函数的次数与传递给AudioFileStreamParseBytes函数的数据的数量一致。但是,事实上由于输入数据的边界,可能只会有一帧会被传递。对于VBR音频数据来说,在每次调用AudioFileStreamParseBytes函数时可能会多次调用此回调函数
数据类型
typedef UInt32 AudioFileStreamPropertyID;
音频文件流的唯一识别码
typedef struct OpaqueAudioFileStreamID *AudioFileStreamID
代表音频文件流对象解析器的对象
常量
属性监听回调和AudioFileStreamParseBytes
enum {
kAudioFileStreamPropertyFlag_PropertyIsCached = 1,
kAudioFileStreamPropertyFlag_CacheProperty = 2,
kAudioFileStreamParseFlag_Discontinuity = 1,
kAudioFileStreamSeekFlag_OffsetIsEstimated = 1
};
音频文件流属性
enum {
kAudioFileStreamProperty_ReadyToProducePackets = 'redy',
kAudioFileStreamProperty_FileFormat = 'ffmt',
kAudioFileStreamProperty_DataFormat = 'dfmt',
kAudioFileStreamProperty_FormatList = 'flst',
kAudioFileStreamProperty_MagicCookieData = 'mgic', //
kAudioFileStreamProperty_AudioDataByteCount = 'bcnt', // 字节的数目
kAudioFileStreamProperty_AudioDataPacketCount = 'pcnt', // 数据中帧的数目
kAudioFileStreamProperty_MaximumPacketSize = 'psze', // 数据中帧的最大值
kAudioFileStreamProperty_DataOffset = 'doff', // 字节偏移量
kAudioFileStreamProperty_ChannelLayout = 'cmap',
kAudioFileStreamProperty_PacketToFrame = 'pkfr',
kAudioFileStreamProperty_FrameToPacket = 'frpk',
kAudioFileStreamProperty_PacketToByte = 'pkby', //
kAudioFileStreamProperty_ByteToPacket = 'bypk', //
kAudioFileStreamProperty_PacketTableInfo = 'pnfo', // AudioFilePacketTableInfo
kAudioFileStreamProperty_PacketSizeUpperBound = 'pkub', // 理论上的帧的最大值
kAudioFileStreamProperty_AverageBytesPerPacket = 'abpp', // 帧的平均字节数
kAudioFileStreamProperty_BitRate = 'brat' // 比特率
};
结果代码
kAudioFileStreamError_UnsupportedFileType
= 'typ?'
不支持该类型
kAudioFileStreamError_UnsupportedDataFormat
= 'fmt?'
不支持指定文件的数据格式
kAudioFileStreamError_UnsupportedProperty
= 'pty?'
不支持的属性
kAudioFileStreamError_BadPropertySize
= '!siz'
提供给属性数据的缓冲大小不合适
kAudioFileStreamError_NotOptimized
= 'optm'
因为帧表格或者其他信息不存在,所以无法产生输出帧
kAudioFileStreamError_InvalidPacketOffset
= 'pck?'
帧的偏移量小于0,或者已经到达文件结尾,又或者是读取到一个坏的帧
kAudioFileStreamError_InvalidFile
= 'dta?'
文件异常
kAudioFileStreamError_ValueUnknown
= 'unk?'
在音频数据之前并没有出现该值
kAudioFileStreamError_DataUnavailable
= 'more' 提供给解析器的数据量不足
kAudioFileStreamError_IllegalOperation
= 'nope'
试图进行非法操作
kAudioFileStreamError_UnspecifiedError
= 'wht?'
出现未指定的错误
kAudioFileStreamError_DiscontinuityCantRecover
= 'dsc!'
音频数据出现无法修复的断点