iOS audio playback audioqueue (a): Play local music

Source: Internet
Author: User

  • Audioqueue Introduction
  • Audiostreamer description
  • Audioqueue detailed
    • Audioqueue Working principle
    • Audioqueue Main interface
      • Audioqueuenewoutput
      • Audioqueueallocatebuffer
      • Audioqueueenqueuebuffer
      • Audioqueuestart Pause Stop Flush Reset Dispose
      • Audioqueuefreebuffer
      • Audioqueuegetproperty Audioqueuesetproperty
  • Audio playback Localaudioplayer
    • Initialization of the player
    • Play Audio
      • Localaudioplayer related properties
      • Read and start parsing audio
      • Parsing Audio Information
        • Kaudiofilestreamproperty_dataformat
        • Kaudiofilestreamproperty_fileformat
        • Kaudiofilestreamproperty_audiodatabytecount
        • Kaudiofilestreamproperty_bitrate
        • Kaudiofilestreamproperty_dataoffset
        • Kaudiofilestreamproperty_audiodatapacketcount
        • Kaudiofilestreamproperty_readytoproducepackets
      • Parsing Audio Frames
      • Play audio data
      • Clean up Related resources
  • End

iOS to play local music, there are many ways, such as Avaudioplayer, these can be very good, some people wonder, why go back to the second, using more complex audioqueue to play local music? Please keep looking down.

Audioqueue Introduction

Audioqueue, that's what Apple's developer documentation says.

"Audio Queue Services provides a straightforward, low overhead way to record and play audio in iOS and Mac OS X."

Audioqueue Official documents

The Audioqueue service provides a direct, low-overhead way to record and play music on iOS and Mac OS x.

The advantage of using Audioqueue to play music is that the overhead is very small and support streaming (side-to-bottom broadcast), but the disadvantage is that the development is difficult, so there is network Audio library Audiostreamer, there are many audioqueue on the internet, but there are examples of code, it is very little , just as the company project has audio requirements, although the project is not the use of my own Write audio playback function, but afterwards still want to study, this in my opinion is more magical and more interesting audioqueue.

Audiostreamer description

A more famous streaming audio player on iOS is Audiostreamer, which uses audioqueue, but the audio library does not support local music playback, and I feel strange why the author does not support it. And in the use of the process, I found that the library is still a bit of a problem, although I do not know much about audio knowledge, and can not be comparable with the master, but I also hope that through their own study, the final completion of a similar Audiostreamer network music library, is perhaps just a vision, In the end, whether or not they have that ability, at least I have tried, but the work is relatively busy recently, coupled with their lack of knowledge, I do not know when to achieve. This time first to make up Audiostreamer no support, use Audioqueue play local music.

Audioqueue detailed Audioqueue Working principle

I truncated the following image from Apple's Official document:

This diagram is a good illustration of how Audioqueue works, as explained below:
1. The user calls the appropriate method, reads the audio data from the hard disk into the audioqueue buffer, and feeds the buffer into the audio queue.
2. User app through the interface provided by Audioqueue, tell the speaker device, the buffer is already have data, can be taken to play.
3. When the audio data in a buffer is played, Audioqueue tells the user that there is currently an empty buffer that can be used to populate the data for you.
4. Repeat the above steps until the data has finished playing.

Here, there must be a lot of students found that Audioqueue is actually the producer-consumer model of the typical application.

Audioqueue Main interface Audioqueuenewoutput
OSStatus AudioQueueNewOutput(const AudioStreamBasicDescription *ininCallbackProc, void *ininininFlags, AudioQueueRef  _Nullable *outAQ);

This method is used to create a audioqueue for outputting audio

The parameters and return instructions are as follows:
1. Informat: This parameter indicates the data format of the audio that will be played
2. Incallbackproc: This callback is used to notify the user when Audioqueue has finished using a buffer, and the user can continue to populate the audio data
3. inuserdata: Data pointer passed by the user for passing to the callback function
4. Incallbackrunloop: Indicates which runloop the callback event occurred in, and if NULL is passed, the callback event is executed on the thread where the Audioqueue is located, and in general, NULL is passed.
5. Incallbackrunloopmode: Indicates the runloop pattern of the callback event, passing null equivalent to kcfrunloopcommonmodes, typically passing null
6. Outaq: The reference instance of the Audioqueue,

Returns Osstatus, if the value is Noerr, indicates that there is no error, Audioqueue created successfully.

Audioqueueallocatebuffer
ininBufferByteSize, AudioQueueBufferRef  _Nullable *outBuffer);

The function of this method is to open up space for the buffer that holds the audio data.

The parameters and return instructions are as follows:
1. Inaq: reference instance of Audioqueue
2. inbufferbytesize: The size of the buffer that needs to be opened
3. Outbuffer: A reference instance of the open buffer

Returns Osstatus if the value is Noerr, which indicates a successful buffer opening.

Audioqueueenqueuebuffer
inininNumPacketDescs, const AudioStreamPacketDescription *inPacketDescs);

This method is used to queue audioqueuebuffer that have already populated the data to Audioqueue

The parameters and return instructions are as follows:
1. Inaq: reference instance of Audioqueue
2. inbuffer: A buffer instance that needs to be queued
3. Innumpacketdescs: How many frames of audio data exist in the buffer
4. Inpacketdescs: Information about each frame in the buffer, the user needs to indicate the offset value of each frame in the buffer, and the field Mstartoffset to specify

Returns Osstatus if the value is Noerr, indicating that the buffer has been successfully queued. Wait for playback

Audioqueuestart Pause Stop Flush Reset Dispose
inAQ, const AudioTimeStamp *ininininininininImmediate);

As the name implies, the first three methods are used for audio playback, pause and stop. The latter two methods are used to clean and reset the audio queue at last, cleaning to ensure that the data in the queue is fully output. Audioqueudispose is used to clean up audioqueue resources.

The parameters and return instructions are as follows:
1. Inaq: reference instance of Audioqueue
2. instarttime: Indicates the time to start playing audio, and if you want to start now, pass NULL
3. Inimmediate: Indicates whether to stop audio playback immediately, if so, pass True

Returns a osstatus indicating whether the related operation was executed successfully.

Audioqueuefreebuffer
ininBuffer);

This method is used when the scavenging buffer is released at the end of playback

Audioqueuegetproperty Audioqueuesetproperty
ininininID, const void *ininDataSize);

This get/set method, which is used to set the related properties for getting audioqueue, see the instructions in the AudioQueue.h header file.

Audio Playback (Localaudioplayer)

Use Audioqueue play music, generally need to cooperate with Audiofilestream, Audiofilestream is responsible for parsing audio data, Audioqueue is responsible for playing the audio data resolved to.

This time, only the most basic local audio playback function is designed to lay the groundwork for the future, not to deal with any related state (such as pause, stop, SEEK), errors, etc. Playback is similar to streaming, except that audio data originates from a local file rather than a network, and takes several steps:
1. Continuously read part of the data from the file until the end of all data read
2. Submit the data read in the file to Audiofilestream for data parsing
3. Create Audioqueue when data is put into Audioqueuebuffer
4. Place the buffer in the Audioqueue to start playing the audio
5. Play audio end, clean up related resources

Initialization of the player

The init of the player is used primarily to specify the audio file to play, as follows:

The read file operation, using the Nsfilehandle class, Audioinuselock, is a nslock* type that is used to mark when Audioqueue notifies us that an empty buffer can be used.

We initialize the player when the user taps the play button and call the Play method to play

Play Audio

Playing audio is divided into the following steps:
1. Read and start parsing audio
2. Parsing Audio Information
3. Parsing Audio Frames
4. Play Audio data
5. Cleanup of related resources

Let's first define a few macros to specify the size of some buffers

#define kNumberOfBuffers 3              //AudioQueueBuffer数量,一般指明为3#define kAQBufSize 128 * 1024           //每个AudioQueueBuffer的大小#define kAudioFileBufferSize 2048       //文件读取数据的缓冲区大小#define kMaxPacketDesc 512              //最大的AudioStreamPacketDescription个数
Localaudioplayer related properties

The properties defined in Localaudioplayer are as follows:

Read and start parsing audio

We use Audiofilestream to parse the audio information, and after the user calls the play method, first call Audiofilestreamopen and open the Audiofilestream as follows:

extern OSStatus AudioFileStreamOpen (void *inClientData, AudioFileStream_PropertyListenerProc   inPropertyListenerProc, AudioFileStream_PacketsProc             inPacketsProc, AudioFileTypeID                          inFileTypeHint, AudioFileStreamID * outAudioFileStream);

The parameters of the Audiofilestreamopen are described below:
1. inclientdata: User-specified data for passing to the callback function, where we specify (__bridge localaudioplayer*) Self
2. Inpropertylistenerproc: When parsing to an audio message, the method is recalled
3. Inpacketsproc: When parsing to an audio frame, the method is recalled
4. infiletypehint: Specify the format of the audio data, if you do not know the format of audio data, you can pass 0
5. Outaudiofilestream: audiofilestreamid instance, to be saved for subsequent use

After reading the data, call Audiofilestreamparsebytes to parse the data, which is prototyped as follows:

ininininFlags);

The parameters are described as follows:
1. Inaudiofilestream: audiofilestreamid instance, opened by Audiofilestreamopen
2. indatabytesize: The size of the data bytes parsed
3. InData: The data size of this resolution
4. inflags: Data parsing flag, where only one value kaudiofilestreamparseflag_discontinuity = 1, indicating whether the parsed data is discontinuous, we can now pass 0.

When the file data is read at the end of the collection, you can close the file.

Parsing Audio Information

If the audio information is resolved, the previously specified callback function is called, as follows:

Each related property can be called Audiofilestreamgetproperty to get the corresponding value, and the prototype is as follows:

ininPropertyID, UInt32 *ioPropertyDataSize, void *                              outPropertyData);

Parameter description:
1. Inaudiofilestream: audiofilestreamid instance, opened by Audiofilestreamopen
2. Inpropertyid: Name of the property to get, see AudioFileStream.h
3. iopropertydatasize: Indicates the size of the property
4. outpropertydata: space for storing this property value

Kaudiofilestreamproperty_dataformat

This property indicates the format information for the audio data, and the returned data is a audiostreambasicdescription structure. Need to save for use with Audioqueue

Kaudiofilestreamproperty_fileformat

This property indicates the encoding format of the audio data, such as MPEG.

Kaudiofilestreamproperty_audiodatabytecount

This property gets the length of the audio data that can be used to calculate the audio duration, calculated as:
Duration = (audio data byte size * 8)/Sample rate

Kaudiofilestreamproperty_bitrate

This property gets the sample rate to the audio, which can be used to calculate the audio duration

Kaudiofilestreamproperty_dataoffset

This property indicates the offset of the audio data in the entire audio file:
Total audio File size = offset + audio data byte size

Kaudiofilestreamproperty_audiodatapacketcount

This property indicates how many frames are in the audio file

Kaudiofilestreamproperty_readytoproducepackets

This property tells us that the full audio frame data has been parsed, ready to produce an audio frame, and then called to another callback function, where we create the audio queue audioqueue, if there is magic Cookie data in the audio The Audiofilestreamgetpropertyinfo is called first, gets whether the data is writable, if it can be written and then fetches the property value, and writes to Audioqueue. The audio data frame is then parsed.

Parsing Audio Frames

After the audio information is resolved, the audio data frame should be parsed, as shown in the following code:


Here, we use the previously set of Inclientdata, the callback function from the C language form to the form of OBJC, the processing code after parsing to the audio data is as follows:

After parsing to the audio data, we will write the data to Audioqueuebuffer, first of all, the prototype of the callback function is as follows:

typedef void (*AudioFileStream_PacketsProc)(void *              ininNumberBytes,UInt32       inNumberPackets, const void *inInputData,                           AudioStreamPacketDescription *inPacketDescriptions);

Parameter description:
1. inclientdata: User Data set by Audiofilestreamopen
2. innumberbytes: Number of bytes in audio data
3. innumberpackets: The number of audio frames resolved to
4. ininputdata: Data that contains these audio data frames
5. inpacketdescriptions: audiostreampacketdescription array, which contains Mstartoffset, indicating the starting position of the relevant data for the frame, Mdatabytesize indicates the size of the frame data.

At this point we first create an audio queue to play the audio and allocate space for each buffer as follows:

Then we traverse each frame, get the offset position and the data size of each frame, if the current frame data size can not be stored in the current buffer, at this time, we should queue the current buffer, modify the currently used buffer to the next, and reset the relevant data fill information and the data frame information contained.

self.audioQueueCurrentBufferIndex = (++self.audioQueueCurrentBufferIndex) % kNumberOfBuffers;self0;self0;

If you haven't started playing music at this point, you can start playing music

if(self.isPlayingNO) {    NULL);    self.isPlayingYES;}

If the next specified buffer is already in use, that is, all buffers are full and queued, you should wait

while(inuse[self.audioQueueCurrentBufferIndex]);

Finally, if the buffer space can hold a frame of data, we use memcpy to copy the data to the corresponding position in the buffer, save the relevant information for each frame, set the offset of each frame in the buffer (Mstartoffset), set the data size of the current buffer's stored party, And the amount of frames already included.

When a buffer is used, Audioqueue will invoke the callback function set by Audioqueuenewoutput, as follows:


In this callback, we iterate through each buffer, find an empty buffer, and modify the flag of that buffer to be unused.

Play audio data

When processing a data frame, if the buffer is full (the buffer space is not enough to hold the next frame of data), you can start playing audio at this time

if(self.isPlayingNO) {    NULL);    self.isPlayingYES;}

We can also call Audioqueuepause and other related methods to pause and terminate the audio playback as follows:

Clean up Related resources

Finally, we clean up the resources, in front of which we used the Audioqueueaddpropertylistener to set a listener for the Kaudioqueueproperty_isrunning property, This function is called when the Audioqueue is started or terminated:

The callback function is as follows:

In this method, we use Audioqueuereset to reset the play queue, call Audioqueuefreebuffer to free the buffer space, release all audioqueue resources, and turn off Audiofilestream.

However, in the actual use of the process, I found that the data is empty when the Audioqueue does not actively terminate, that is not actively invoke the callback, so I think, it should be to get ourselves to the current playback progress, when the play is finished call Audioqueuestop stop play it, The question remains to be studied later.

End

Finally finished all the code, the user just click Play, you can hear "distant her" this wonderful music. Since there is only one play button on the interface, do not put on the demo, put on headphones, quietly enjoy their achievements with this wonderful music.

iOS audio playback audioqueue (a): Play local music

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.