AudioStreamBasicDescription

本文介绍如何使用Core Audio API配置音频播放队列,包括设置采样率、位深、声道等参数,并通过回调函数填充播放缓冲区。
AudioStreamBasicDescription format; // 声音格式设置,这些设置要和采集时的配置一致

memset(&format, 0, sizeof(format));

 

format.mSampleRate = 44100; // 采样率 (立体声 = 8000)

format.mFormatID = kAudioFormatLinearPCM; // PCM 格式

format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;

format.mChannelsPerFrame = 1;  // 1:单声道;2:立体声

format.mBitsPerChannel = 16; // 语音每采样点占用位数

format.mBytesPerFrame = (format.mBitsPerChannel /  * format.mChannelsPerFrame;

format.mFramesPerPacket = 1;

format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;

 

AudioQueueRef queue;

AudioQueueNewOutput(&format,

                AQPlayer::AQOutputCallback,

                this,  // opaque reference to whatever you like

                CFRunLoopGetCurrent(),

                kCFRunLoopCommonModes,

                0,

                &queue);

 

const int bufferSize = 0xA000;  // 48K - around 1/2 sec of 44kHz 16 bit mono PCM

for (int i = 0; i < kNumberBuffers; ++i)

    AudioQueueAllocateBufferWithPacketDescriptions(queue, bufferSize, 0, &mBuffers[i]);

 

AudioQueueSetParameter(queue, kAudioQueueParam_Volume, 1.0);

 

UInt32 category = kAudioSessionCategory_MediaPlayback;

AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);

 

AudioSessionSetActive(true);

 

// prime the queue with some data before starting

for (int i = 0; i < kNumberBuffers; ++i)

    OutputCallback(queue, mBuffers[i]);

 

AudioQueueStart(queue, NULL);

 

在CallBack中填出数据:

 

void OutputCallback(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inCompleteAQBuffer) {
enum AudioChannelLayout: uint64_t { CH_LAYOUT_UNKNOWN = 0ULL, /** Channel count: 1*/ CH_LAYOUT_MONO = FRONT_CENTER, /** Channel count: 2*/ CH_LAYOUT_STEREO = FRONT_LEFT | FRONT_RIGHT, CH_LAYOUT_STEREO_DOWNMIX = STEREO_LEFT | STEREO_RIGHT, /** Channel count: 3*/ CH_LAYOUT_2POINT1 = CH_LAYOUT_STEREO | LOW_FREQUENCY, CH_LAYOUT_3POINT0 = CH_LAYOUT_STEREO | BACK_CENTER, CH_LAYOUT_SURROUND = CH_LAYOUT_STEREO | FRONT_CENTER, /** Channel count: 4*/ CH_LAYOUT_3POINT1 = CH_LAYOUT_SURROUND | LOW_FREQUENCY, CH_LAYOUT_4POINT0 = CH_LAYOUT_SURROUND | BACK_CENTER, CH_LAYOUT_QUAD_SIDE = CH_LAYOUT_STEREO | SIDE_LEFT | SIDE_RIGHT, CH_LAYOUT_QUAD = CH_LAYOUT_STEREO | BACK_LEFT | BACK_RIGHT, CH_LAYOUT_2POINT0POINT2 = CH_LAYOUT_STEREO | TOP_SIDE_LEFT | TOP_SIDE_RIGHT, /** Channel count: 5*/ CH_LAYOUT_4POINT1 = CH_LAYOUT_4POINT0 | LOW_FREQUENCY, CH_LAYOUT_5POINT0 = CH_LAYOUT_SURROUND | SIDE_LEFT | SIDE_RIGHT, CH_LAYOUT_5POINT0_BACK = CH_LAYOUT_SURROUND | BACK_LEFT | BACK_RIGHT, CH_LAYOUT_2POINT1POINT2 = CH_LAYOUT_2POINT0POINT2 | LOW_FREQUENCY, CH_LAYOUT_3POINT0POINT2 = CH_LAYOUT_2POINT0POINT2 | FRONT_CENTER, /** Channel count: 6*/ CH_LAYOUT_5POINT1 = CH_LAYOUT_5POINT0 | LOW_FREQUENCY, CH_LAYOUT_5POINT1_BACK = CH_LAYOUT_5POINT0_BACK | LOW_FREQUENCY, CH_LAYOUT_6POINT0 = CH_LAYOUT_5POINT0 | BACK_CENTER, CH_LAYOUT_HEXAGONAL = CH_LAYOUT_5POINT0_BACK | BACK_CENTER, CH_LAYOUT_3POINT1POINT2 = CH_LAYOUT_3POINT1 | TOP_FRONT_LEFT | TOP_FRONT_RIGHT, CH_LAYOUT_6POINT0_FRONT = CH_LAYOUT_QUAD_SIDE | FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER, /** Channel count: 7*/ CH_LAYOUT_6POINT1 = CH_LAYOUT_5POINT1 | BACK_CENTER, CH_LAYOUT_6POINT1_BACK = CH_LAYOUT_5POINT1_BACK | BACK_CENTER, CH_LAYOUT_6POINT1_FRONT = CH_LAYOUT_6POINT0_FRONT | LOW_FREQUENCY, CH_LAYOUT_7POINT0 = CH_LAYOUT_5POINT0 | BACK_LEFT | BACK_RIGHT, CH_LAYOUT_7POINT0_FRONT = CH_LAYOUT_5POINT0 | FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER, /** Channel count: 8*/ CH_LAYOUT_7POINT1 = CH_LAYOUT_5POINT1 | BACK_LEFT | BACK_RIGHT, CH_LAYOUT_OCTAGONAL = CH_LAYOUT_5POINT0 | BACK_CENTER | BACK_LEFT | BACK_RIGHT, CH_LAYOUT_5POINT1POINT2 = CH_LAYOUT_5POINT1 | TOP_SIDE_LEFT | TOP_SIDE_RIGHT, CH_LAYOUT_7POINT1_WIDE = CH_LAYOUT_5POINT1 | FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER, CH_LAYOUT_7POINT1_WIDE_BACK = CH_LAYOUT_5POINT1_BACK | FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER, /** Channel count: 10*/ CH_LAYOUT_5POINT1POINT4 = CH_LAYOUT_5POINT1 | TOP_FRONT_LEFT | TOP_FRONT_RIGHT | TOP_BACK_LEFT |TOP_BACK_RIGHT, CH_LAYOUT_7POINT1POINT2 = CH_LAYOUT_7POINT1 | TOP_SIDE_LEFT | TOP_SIDE_RIGHT, /** Channel count: 12*/ CH_LAYOUT_7POINT1POINT4 = CH_LAYOUT_7POINT1 | TOP_FRONT_LEFT | TOP_FRONT_RIGHT | TOP_BACK_LEFT | TOP_BACK_RIGHT, CH_LAYOUT_10POINT2 = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | TOP_FRONT_LEFT | TOP_FRONT_RIGHT | BACK_LEFT | BACK_RIGHT | BACK_CENTER | SIDE_LEFT | SIDE_RIGHT | WIDE_LEFT | WIDE_RIGHT, /** Channel count: 14*/ CH_LAYOUT_9POINT1POINT4 = CH_LAYOUT_7POINT1POINT4 | WIDE_LEFT | WIDE_RIGHT, /** Channel count: 16*/ CH_LAYOUT_9POINT1POINT6 = CH_LAYOUT_9POINT1POINT4 | TOP_SIDE_LEFT | TOP_SIDE_RIGHT, CH_LAYOUT_HEXADECAGONAL = CH_LAYOUT_OCTAGONAL | WIDE_LEFT | WIDE_RIGHT | TOP_BACK_LEFT | TOP_BACK_RIGHT | TOP_BACK_CENTER | TOP_FRONT_CENTER | TOP_FRONT_LEFT | TOP_FRONT_RIGHT, /** HOA: fitst order*/ CH_LAYOUT_HOA_ORDER1_ACN_N3D = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_1 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_ACN << CH_HOA_COMORD_OFFSET) | (HOA_NOR_N3D << CH_HOA_NOR_OFFSET), CH_LAYOUT_HOA_ORDER1_ACN_SN3D = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_1 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_ACN << CH_HOA_COMORD_OFFSET) | (HOA_NOR_SN3D << CH_HOA_NOR_OFFSET), CH_LAYOUT_HOA_ORDER1_FUMA = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_1 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_FUMA << CH_HOA_COMORD_OFFSET), /** HOA: second order*/ CH_LAYOUT_HOA_ORDER2_ACN_N3D = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_2 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_ACN << CH_HOA_COMORD_OFFSET) | (HOA_NOR_N3D << CH_HOA_NOR_OFFSET), CH_LAYOUT_HOA_ORDER2_ACN_SN3D = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_2 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_ACN << CH_HOA_COMORD_OFFSET) | (HOA_NOR_SN3D << CH_HOA_NOR_OFFSET), CH_LAYOUT_HOA_ORDER2_FUMA = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_2 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_FUMA << CH_HOA_COMORD_OFFSET), /** HOA: third order*/ CH_LAYOUT_HOA_ORDER3_ACN_N3D = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_3 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_ACN << CH_HOA_COMORD_OFFSET) | (HOA_NOR_N3D << CH_HOA_NOR_OFFSET), CH_LAYOUT_HOA_ORDER3_ACN_SN3D = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_3 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_ACN << CH_HOA_COMORD_OFFSET) | (HOA_NOR_SN3D << CH_HOA_NOR_OFFSET), CH_LAYOUT_HOA_ORDER3_FUMA = (CHANNEL_MDOE_AMBISONIC << CH_MODE_OFFSET) | (HOA_ORDNUM_3 << CH_HOA_ORDNUM_OFFSET) | (HOA_COMORD_FUMA << CH_HOA_COMORD_OFFSET), };这段代码是啥意思
最新发布
08-19
`AudioChannelLayout` 是在处理音频数据时用于描述音频通道布局的一种枚举类型。其主要作用是定义音频流中各个音频通道的排列和类型,以便音频播放或处理系统能够正确地解释和处理多通道音频数据。 在音频处理中,特别是在涉及多声道音频(如5.1环绕声、7.1声道等)时,`AudioChannelLayout` 提供了一种标准化的方式来描述这些通道的物理布局。例如,它能够明确指定哪些通道对应左前、右前、中置、低音、左环绕和右环绕等声道[^1]。 `AudioChannelLayout` 通常与 `AudioStreamBasicDescription`(ASBD)结构体一起使用,该结构体描述了音频流的基本参数,包括采样率、位深、通道数等。通过在 ASBD 中设置 `mChannelLayout` 字段为特定的 `AudioChannelLayout` 值,可以精确描述音频数据的通道布局,从而确保音频设备或框架能够正确地进行播放或处理。 ### `AudioChannelLayout` 的常见值包括: - `kAudioChannelLayoutTag_Mono`:单声道音频。 - `kAudioChannelLayoutTag_Stereo`:立体声,包含左和右两个通道。 - `kAudioChannelLayoutTag_5_1Audio`:5.1环绕声,通常包括左前、右前、中置、低音、左环绕和右环绕六个通道。 - `kAudioChannelLayoutTag_7_1Audio`:7.1环绕声,扩展了5.1声道,增加了左中置和右中置通道。 ### 使用示例 在设置 `AudioStreamBasicDescription` 时,可以通过如下方式指定通道布局: ```c AudioStreamBasicDescription asbd; memset(&asbd, 0, sizeof(asbd)); asbd.mSampleRate = 44100.0; asbd.mFormatID = kAudioFormatLinearPCM; asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; asbd.mBytesPerPacket = 4; asbd.mFramesPerPacket = 1; asbd.mBytesPerFrame = 4; asbd.mChannelsPerFrame = 2; asbd.mBitsPerChannel = 16; asbd.mChannelLayout = kAudioChannelLayoutTag_Stereo; // 设置立体声布局 ``` 通过这种方式,音频系统可以正确地解析和处理音频数据,以确保在播放或录制时能够按照预期的通道布局进行操作。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值