使用 Audio Toolbox 的 Audio Services 播放 AAC

使用 Audio Toolbox 的 Audio Services 播放 AAC

使用 Audio Toolbox 的 Audio Services 播放 AAC

主要分为 3 步:

  1. 使用 AudioServicesCreateSystemSoundID 创建系统声音。
  2. 使用 AudioServicesAddSystemSoundCompletion 设置回调。
  3. 使用 AudioServicesPlaySystemSound 开始播放。

关于 AudioServicesPlaySystemSound 函数:

此功能播放短声音(持续时间为 30s 或更短)。由于声音可能会播放几秒钟,此功能是异步执行的。要了解声音何时完成播放,调用 AudioServicesAddSystemSoundCompletion 函数来注册回调函数。

在某些 iOS 设备上,可以通过 AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) 来调用振动。在其他 iOS 设备上,使用该常量调用此函数没有任何作用。

以下是该函数能播放的音频文件的限制:

  • No longer than 30 seconds in duration
  • In linear PCM or IMA4 (IMA/ADPCM) format
  • Packaged in a .caf, .aif, or .wav file

但实际上,AAC 文件也是能正常播放的,此外,该函数还有诸多限制:

  • 声音在当前系统音频音量下播放,没有编程音量控制。
  • 声音立即播放。
  • 不支持循环和立体声定位。
  • 无法同时播放,一次只能播放一个声音。
  • 声音在设备扬声器上本地播放,不使用音频路由。

核心代码:

- (void)btnClick:(UIButton *)sender
{
    self.mButton.hidden = YES;
    NSURL *audioUrl = [[NSBundle mainBundle] URLForResource:@"music" withExtension:@"aac"];
    SystemSoundID soundID;
    // create a system sound object
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)audioUrl, &soundID);
    // register a callback function that is invoked when a specified system sound finishes playing
    AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, &playCallback, (__bridge void *_Nullable)(self));
    // play a system sound object
    AudioServicesPlaySystemSound(soundID);
}

void playCallback(SystemSoundID ssID, void  *clientData)
{
    ViewController *vc = (__bridge ViewController *)clientData;
    vc->_mButton.hidden = NO;
}

项目地址:https://github.com/UestcXiye/AudioToolboxSystemSound。

### 使用 AudioToolbox 解码 AAC 流数据并实现音频播放 在 iOS 开发中,使用 `AudioToolbox` 框架解码 AAC 流数据并实现音频播放需要结合多个步骤,包括音频格式解析、流数据解码以及最终的音频输出。以下是完整的流程和技术细节。 #### 音频格式配置 首先,需要定义 AAC 流的原始格式和目标 PCM 格式。AAC 编码的音频通常包含采样率、通道数等信息,这些参数需通过 `AudioStreamBasicDescription` 结构体进行描述。例如: ```cpp AudioStreamBasicDescription sourceFormat = {0}; sourceFormat.mFormatID = kAudioFormatMPEG4AAC; sourceFormat.mSampleRate = 48000; // 采样率为 48kHz sourceFormat.mChannelsPerFrame = 2; // 双声道 AudioStreamBasicDescription destFormat = {0}; destFormat.mFormatID = kAudioFormatLinearPCM; destFormat.mSampleRate = 48000; destFormat.mChannelsPerFrame = 2; destFormat.mBitsPerChannel = 16; destFormat.mBytesPerFrame = destFormat.mChannelsPerFrame * sizeof(short); destFormat.mFramesPerPacket = 1; destFormat.mBytesPerPacket = destFormat.mBytesPerFrame * destFormat.mFramesPerPacket; destFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; ``` 以上代码配置了源数据为 AAC 编码,目标数据为 16-bit 线性 PCM 格式,适用于大多数音频播放需求[^1]。 #### 创建 AudioConverter 实例 使用 `AudioConverterNew` 初始化一个 `AudioConverterRef` 实例,该实例负责将 AAC 数据转换为 PCM 数据: ```cpp OSStatus status = AudioConverterNew(&sourceFormat, &destFormat, &m_decoder); if (status != noErr || !m_decoder) { // Handle error } ``` 此步骤是整个解码流程的核心,确保 AAC 数据能够被正确解析并转换为目标格式[^3]。 #### 解码 AAC 流数据 在实际处理 AAC 流时,数据通常以帧为单位输入到解码器中。通过调用 `AudioConverterFillComplexBuffer` 方法完成解码操作,并通过回调函数提供输入数据: ```cpp static OSStatus MyAudioConverterCallback(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** outDataPacketDescription, void* inUserData) { memcpy(ioData->mBuffers[0].mData, inUserData, *ioNumberDataPackets); *ioNumberDataPackets = 1; return noErr; } OSStatus Decode(const void* inputBuffer, UInt32 inputSize, void* outputBuffer, UInt32* outputSize) { AudioBufferList bufferList; bufferList.mNumberBuffers = 1; bufferList.mBuffers[0].mData = outputBuffer; bufferList.mBuffers[0].mDataByteSize = *outputSize; UInt32 size = inputSize; return AudioConverterFillComplexBuffer(m_decoder, MyAudioConverterCallback, const_cast<void*>(inputBuffer), &size, &bufferList, nullptr); } ``` 上述方法会将 AAC 数据逐帧解码,并存储到指定的输出缓冲区中[^1]。 #### 音频播放 解码后的 PCM 数据可以直接用于播放。iOS 提供了多种音频播放方案,其中 `AudioUnit` 是一种底层且高效的音频处理方式。以下是一个简化的播放流程: - 初始化 `AudioComponentInstance` 并设置音频单元类型(如 RemoteIO)。 - 配置音频流格式(与解码后的 PCM 格式一致)。 - 设置渲染回调函数,在回调中提供解码后的 PCM 数据。 - 启动音频单元并开始播放。 ```objc AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = renderCallback; callbackStruct.inputProcRefCon = self; AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct)); OSStatus status = AudioUnitInitialize(audioUnit); if (status == noErr) { AudioOutputUnitStart(audioUnit); } ``` 在 `renderCallback` 中,可以将之前解码得到的 PCM 数据写入音频输出缓冲区,从而实现连续播放[^4]。 #### 完整流程总结 整体来看,从 AAC 流数据解码到音频播放的过程包括以下几个关键步骤: 1. **打开 AAC 流文件**:读取 AAC 数据流,提取必要的元信息(如采样率、通道数等)。 2. **初始化解码器**:使用 `AudioConverterNew` 创建解码器实例,并配置输入输出格式。 3. **逐帧解码 AAC 数据**:调用 `AudioConverterFillComplexBuffer` 方法解码每一帧 AAC 数据。 4. **将 PCM 数据送入播放器**:通过 `AudioUnit` 或其他音频播放框架将解码后的 PCM 数据实时播放。 5. **循环处理剩余数据**:持续读取和解码 AAC 数据,直到整个流处理完毕。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值