Swift: AudioToolbox 开发 C 程序本地播放器

iOS 的本地播放器,使用 AVAudioPlayer 很简单,

拿音频资源文件路径,创建 AVAudioPlayer,

然后 prepareToPlay, 就可以 play


使用 AudioToolbox, 开发 C 程序本地播放器,套路也很简单

播放分 3 步:

1, 拿到音频文件, 新建音频输出队列

给定一个本地资源路径 url, 使用 AudioFileOpenURL, 获取音频文件 AudioFileID

使用 AudioQueueNewOutput, 创建音频输出队列 AudioQueueRef

AudioToolbox 中, 输出就是播放, AudioQueueNewOutput

输入就是录音, AudioQueueNewInput

2,想要播放,一般分配 3 个缓冲 AudioQueueBufferRef,就可以开始了

使用 AudioQueueAllocateBuffer,分配 3 个音频数据缓冲 AudioQueueBufferRef

一个缓冲用于播放,一个缓冲用于注入音频数据,

还有一个缓冲,用于准备,防止滞后

使用 AudioQueueStart,音频队列输出,

输出就是播放

3, 输出队列回调处理中,给输出队列,注入音频文件的数据

主要通过下面两个方法:

取出数据

AudioFileReadPacketData

将数据,注入给输出队列

AudioQueueEnqueueBuffer

停止播放,一步就好

AudioQueueStop


重点:

1, AudioToolbox 开发的 C 程序播放器,就是一个简单的结构体

struct Player {
    //  对应音频文件
    var playbackFile: AudioFileID?                                    
    
    // 这一轮,使用音频包的起始位置, start position
    var packetPosition: Int64 = 0                                          
    
    
    // 这一轮使用几个音频包, length
    var numPacketsToRead: UInt32 = 0                                     
    
    // 可能用到 ASPD
    var packetDescs: UnsafeMutablePointer?   
    

    // 播放完结了,没有
    var isDone = false                                                   
}
  • 第一个属性,很好理解,代表音频资源文件

音频文件开启后,就用 AudioFileID 代表

  • 最后一个属性,很好理解,文件播放完结了没有。
  • 倒数第二个属性,ASPD, 可能用到,

音频的数据格式,也就是音频的编码格式,主要分为压缩和非压缩,

非压缩数据,使用 ASBD, 计算比较简单,

压缩数据,ASBD 不够用,还要加上 ASPD

如果 ASPD 还不够,还要加上 magic cookie

  • 剩下两个属性,主要用在播放的回调中,

也就是输出队列的回调方法中

packetPosition,代表当前播放到哪里了

numPacketsToRead, 代表此时要注入几个数据


2, 输出队列的回调方法

在这里,拿音频文件的数据,

给分配的 3 个空白 buffer ,注入数据,

交给播放队列去播放

这里使用的指针多

指针,想用就用,苹果加上 Unsafe,真无聊

要留意的是,

取数据,有 start position ( packetPosition ), 和 length ( numPacketsToRead ),

注入队列后, start position 发生了改变, 前进了 nPackets ( player.pointee.numPacketsToRead )

没数据了, nPackets 为 0 ,就是播放完结了

func outputCallback(userData: UnsafeMutableRawPointer?, queue: OpaquePointer, bufferToFill: UnsafeMutablePointer) {

    guard let user = userData else {
        return
    }
    
    
    let player = user.assumingMemoryBound(to: Player.self)
        
        
    if player.pointee.isDone { return }
        
       
    var numBytes: UInt32 = bufferToFill.pointee.mAudioDataBytesCapacity
    var nPackets = player.pointee.numPacketsToRead
        
    Utility.check(error: AudioFileReadPacketData(player.pointee.playbackFile!,             
                                                false,                                     
                                                &numBytes,                               
                                                player.pointee.packetDescs,              
                                                player.pointee.packetPosition,             
                                                &nPackets,                               
                                                bufferToFill.pointee.mAudioData),         
                      operation: "AudioFileReadPacketData failed")

        
        if nPackets > 0 {
            bufferToFill.pointee.mAudioDataByteSize = numBytes
            
            Utility.check(error: AudioQueueEnqueueBuffer(queue,                                                 // queue
                                                         bufferToFill,                                          // buffer to enqueue
                                                         (player.pointee.packetDescs == nil ? 0 : nPackets),    // number of packet descriptions
                                                         player.pointee.packetDescs),                           // pointer to a PacketDescriptions array
                          operation: "AudioQueueEnqueueBuffer failed")
            
            player.pointee.packetPosition += Int64(nPackets)
            
        } else {
            
            Utility.check(error: AudioQueueStop(queue, false),
                          operation: "AudioQueueStop failed")
            
            player.pointee.isDone = true
        }
    
}


可以看出,苹果的播放器 AVAudioPlayer ,不过是简单的状态封装,

主要还是使用 AudioToolbox

github repo

你可能感兴趣的:(ios)