Native player for iOS, using AVAudioPlayer is easy,

Take the audio resource file path, create AVAudioPlayer,

And prepareToPlay, it’s ready to play


Using AudioToolbox to develop local player of C program, the routine is also very simple

Play in 3 steps:

1. Get the audio file and create a new audio output queue

Given a local resource path URL, use AudioFileOpenURL to obtain the audio file AudioFileID

Using AudioQueueNewOutput, create audio output queue AudioQueueRef

With AudioToolbox, output is playback, AudioQueueNewOutput

The input is the recording, AudioQueueNewInput

2, if you want to play, you usually allocate 3 buffers AudioQueueBufferRef, and you’re ready to go

Using the AudioQueueAllocateBuffer, allocate three audio data buffers, AudioQueueBufferRef

One buffer for playback, one buffer for injecting audio data,

There is also a buffer for preparation and to prevent lag

Using AudioQueueStart, the audio queue output,

The output is playing

3. Input audio file data into the output queue during callback processing

Mainly through the following two methods:

Take out the data

AudioFileReadPacketData

Inject the data into the output queue

AudioQueueEnqueueBuffer

Stop playing. One step

AudioQueueStop
Copy the code

Key points:

1. The C program player developed by AudioToolbox is a simple structure
Struct Player {// Corresponding audio file var playbackFile: AudioFileID? Start position var packetPosition: Int64 = 0 start position var packetPosition: Int64 = 0 UInt32 = 0 use ASPD var packetDescs: / / may be UnsafeMutablePointer < AudioStreamPacketDescription >? Var isDone = false}Copy the code
  • The first property, which is easy to understand, represents an audio resource file

When an audio file is opened, it is represented by an AudioFileID

  • And the last property, it’s easy to understand, is the file finished playing.

  • The penultimate property, ASPD, might use,

The data format of audio, that is, the encoding format of audio, is mainly divided into compressed and uncompressed,

Uncompressed data, using ASBD, the calculation is relatively simple,

Compression data, ASBD is not enough, plus ASPD

If ASPD isn’t enough, add magic cookies

  • The remaining two properties, which are mainly used in playback callbacks,

In the callback method of the output queue

PacketPosition, where is the current playing

NumPacketsToRead, which indicates that several data will be injected at this time


2. Output queue callback method

Here, take the data from the audio file,

Inject data into the allocated 3 blank buffers,

Give it to the playback queue to play

There are a lot of Pointers here

Unsafe, even if you want to use a pointer. Apple plus Unsafe, that’s boring

The thing to keep in mind is,

Start Position (packetPosition), length (numPacketsToRead),

After injection of queue, start the position changed, forward nPackets (player. Pointee. NumPacketsToRead)

There is no data, nPackets is 0, it is the end of playing

func outputCallback(userData: UnsafeMutableRawPointer? , queue: OpaquePointer, bufferToFill: UnsafeMutablePointer<AudioQueueBuffer>) { 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 ? Zero: 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 } }Copy the code

As you can see, Apple’s AVAudioPlayer is simply a state wrapper,

We’re still using AudioToolbox

github repo