音视频学习笔记一——iOS端PCM播放(补充)

566 阅读3分钟

题记:对上一节的补充,iOS端PCM音频的播放,后续有统一的SDL音频播放,本节可跳过。

PCM简易播放

流程简介

AudioToolbox是一个用于音频处理的框架,提供了录制、播放和流解析的接口。AudioToolbox支持多种音频播放,如短时音效(AudioServices)、本地音乐(AVAudioPlayer)、音频会话(AVAudioSession)、音频队列(AudioQueue)。

本文主要播放上一章的音频流,简单介绍数据流播放,播放流程如图(官网) 音频播放.jpg 简单来说

  • AudioQueue播放Buffer队列中的数据
  • 队列中Buffer播放完时,会通过callback通知补充数据

代码解析

AudioQueue可以播放各种音频格式,包括AAC数据,Demo主要播放PCM数据。

设置音频数据格式

在使用Audio Queue之前,需要配置音频数据的格式,使用AudioStreamBasicDescription结构体来描述,包括采样率、位深度、声道数量等。具体参数:

  • mSampleRate:采样率,每秒的样本数。常见的采样率有16000Hz、32000Hz、44100Hz等。
  • mFormatID:数据格式,AAC、PCM等
  • mFormatFlags:音频数据的方式的说明,如可以根据大端字节序或小端字节序,浮点数或整数以及不同体位去保存数据
  • mBytesPerPacket:每个数据包的字节数。对于固定比特率的音频数据mFramesPerPacket * mBytesPerFrame;对于可变比特率的音频数据,这个值应设为0
  • mFramesPerPacket:每个数据包中的帧数。对于线性PCM格式,这个值通常为1;对于压缩格式,这个值可能大于1。
  • mBytesPerFrame:每帧的字节数声道数*位深度。当一帧中不包含一个采样通道时(如压缩格式),这个值为0。
  • mChannelsPerFrame:声道数。单声道音频1;立体声音频为2
  • mBitsPerChannel:每个声道的位深度,常见的位深度有8位、16位、24位等。
  • mReserved:保留字段

初始化Audio Queue

使用AudioQueueNewOutput函数创建音频输出队列,指定音频数据的格式、回调函数以及用户数据等。参数:

  • inFormat:上文中的格式描述
  • inCallbackProc:当AudioQueue已使用完一个缓冲区时通知用户的回调函数,用户填充音频数据
  • inUserData:传入的数据指针,用于callback中传递对象 callback会透传这个void *(C风格)
  • inCallbackRunLoop:指明回调事件发生在哪个RunLoop之中,假设传递NULL,表示在AudioQueue所在的线程上运行该回调事件。
  • inCallbackRunLoopMode:指明回调事件发生的RunLoop的模式,传递NULL相当于kCFRunLoopCommonModes
  • outAQ:创建的AudioQueue的实例,传入指针地址

分配音频缓冲区

AudioQueueAllocateBuffer为音频队列缓冲区分配内存,即图中的红色区域(一般3个buffer)

  • inAQ:AudioQueue实例,上文中创建的对象
  • inBufferByteSize:开辟的缓冲区的大小,这个大小需要用户指定,过小会造成播放不连贯,过大会造成缓冲时间较大
  • outBuffer:开辟的缓冲区 bufferalloc.jpg

控制Audio Queue

  • AudioQueueStart 启动音频。启动后,音频队列将开始读取数据进行播放
  • AudioQueuePause 暂停播放
  • AudioQueueStop 停止播放
  • AudioQueueSetParameter 设置参数,如音量

返回OSStatus结果,为noErr(0)表示成功

实现回调函数

AudioQueueNewOutput中设置的inCallbackProc回调函数,参数解析:

  • inUserData AudioQueueNewOutput中传入void *指针,因为函数是全局的,一般用于传递对象。
  • audioQueueRef 是操作AudioQueue的句柄或引用
  • audioQueueBufferRef 需要填充的buffer地址

当音频数据播放完成时,回调函数会被触发,此时可以在回调函数中执行相应的处理逻辑,如更新播放状态、释放缓冲区等。Demo中

pcm播放.jpg

注意 AudioQueue可以直接播放AAC数据,Demo中是为了展示播放流程,后续有SDL的播放

其他

此外,如果需要更精细地控制音频队列的运行状态,可以使用AudioQueueAddPropertyListener函数为音频队列添加属性监听器。当音频队列的某些属性(如播放状态、缓冲区数量等)发生变化时,会触发监听器回调函数。