了解iPhone游戏开发中声音处理流播放文件是本文介绍的内容,流播放文件即用AudioStream 和 AudioQueue 来播放文件。好处是可以快速的开始播放,减少读文件的过程,适合大文件特别是背景音乐的播放。坏处是一次只能播放一个文件,如果要换播放文件,中间需要一定的时间。但是因为iPhone的文件读取时间只有10秒,对于资源较大的文件,只能考虑这个方式了。
下面我将分享一下我在这方面的一点经验:1. 单个文件播放2. 在线文件播放
1. 单个文件播放
- BOOL isPlaying;
- /*-------------------USED FOR LOCAL FILE--------------------*/
- AudioFileID audioFile;
- AudioStreamBasicDescription dataFormat;
- AudioStreamPacketDescription *packetDescs;
- UInt64 packetIndex;
- UInt32 numPacketsToRead;
- BOOL repeat;
- BOOL trackClosed;
- /*--------------------USED FOR PUBLIC------------------------*/
- BOOL trackEnded;
- AudioQueueRef queue;
- AudioQueueBufferRef buffers[NUM_QUEUE_BUFFERS];
以上是需要定义的为单独文件播放的所需要的元素。可以定义在类里面。
2. 在线文件播放
- NSURL *url;
- AudioFileStreamID audioFileStream; // the audio file stream parser
- AudioStreamPacketDescription packetDescsQueue[kAQMaxPacketDescs]; // packet descriptions for enqueuing audio
- CFReadStreamRef stream;
- unsigned int fillBufferIndex; // the index of the audioQueueBuffer that is being filled
- size_t bytesFilled; // how many bytes have been filled
- size_t packetsFilled; // how many packets have been filled
- bool inuse[kNumAQBufs]; // flags to indicate that a buffer is still in use
- bool started; // flag to indicate that the queue has been started
- bool failed; // flag to indicate an error occurred
- bool discontinuous; // flag to trigger bug-avoidance
- pthread_mutex_t mutex; // a mutex to protect the inuse flags
- pthread_cond_t cond; // a condition varable for handling the inuse flags
- pthread_mutex_t mutex2; // a mutex to protect the AudioQueue buffer
- BOOL trackEnded;
- AudioQueueRef queue;
- AudioQueueBufferRef buffers[NUM_QUEUE_BUFFERS];
利用http1.1协议播放在线文件。以上是在线文件播放所需要的参数。
- #define NUM_QUEUE_BUFFERS 3
- #define kNumAQBufs 6 // number of audio queue buffers we allocate
- #define kAQBufSize 32 * 1024 // number of bytes in each audio queue buffer
- #define kAQMaxPacketDescs 512 // number of packet descriptions in our array
这里是定义的一些参数,NUM_QUEUE_BUFFERS 用于播放本地文件,而 kNumAQBufs 用于播放在线文件。
3. 本地文件初始化
- - (id)initWithPath:(NSString*)path
- {
- UInt32 size, maxPacketSize;
- char *cookie;
- int i;
- if (kxxxTrackActive)
- {
- NSLog(@"Other music is playing.");
- return nil;
- }
- if (path == nil) return nil;
- if(!(self = [super init])) return nil;
- // try to open up the file using the specified path
- if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x01, 0, &audioFile))
- {
- NSLog(@"File can not be opened!");
- return nil;
- }
- // get the data format of the file
- size = sizeof(dataFormat);
- AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &size, &dataFormat);
- // create a new playback queue using the specified data format and buffer callback
- AudioQueueNewOutput(&dataFormat, BufferCallback, self, nil, nil, 0, &queue);
- // calculate number of packets to read and allocate space for packet descriptions if needed
- if (dataFormat.mBytesPerPacket == 0 || dataFormat.mFramesPerPacket == 0)
- {
- // Ask Core Audio to give us a conservative estimate of the largest packet
- size = sizeof(maxPacketSize);
- AudioFileGetProperty(audioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
- if (maxPacketSize > kxxxBufferSizeBytes)
- {
- /*Limitation for the maximum buffer size*/
- maxPacketSize = kxxxBufferSizeBytes;
- NSLog(@"Size out of bounds!");
- }
- // calculate how many packs to read
- numPacketsToRead = kxxxBufferSizeBytes / maxPacketSize;
- // will need a packet description for each packet to allocate space accordingly
- packetDescs = malloc(sizeof(AudioStreamPacketDescription) * numPacketsToRead);
- }
- else
- {
- // constant bitrate
- numPacketsToRead = kxxxBufferSizeBytes / dataFormat.mBytesPerPacket;
- // don't need packet descriptions for CBR data
- packetDescs = nil;
- }
- // see if file uses a magic cookie (a magic cookie is meta data which some formats use)
- AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyMagicCookieData, &size, nil);
- if (size > 0)
- {
- // copy the cookie data from the file into the audio queue
- cookie = malloc(sizeof(char) * size);
- AudioFileGetProperty(audioFile, kAudioFilePropertyMagicCookieData, &size, cookie);
- AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, cookie, size);
- free(cookie);
- }
- // we want to know when the playing state changes so we can properly dispose of the audio queue when it's done
- AudioQueueAddPropertyListener(queue, kAudioQueueProperty_IsRunning, propertyListenerCallback, self);
- // allocate and prime buffers with some data
- packetIndex = 0;
- for (i = 0; i < NUM_QUEUE_BUFFERS; i++)
- {
- AudioQueueAllocateBuffer(queue, kxxxBufferSizeBytes, &buffers);
- if ([self readPacketsIntoBuffer:buffers] == 0)
- {
- // this might happen if the file was so short that it needed less buffers than we planned on using
- break;
- }
- }
- repeat = NO;
- trackClosed = NO;
- trackEnded = NO;
- kxxxTrackActive = YES;
- return self;
- }
4. 在线文件初始化
- - (id)initWithURL:(NSURL*)newUrl
- {
- self = [super init];
- if (self != nil)
- {
- url = [newUrl retain];
- }
- return self;
- }
算了,废话不多说了,直接上代码,等以后有时间了再逐一解释。
小结了解iPhone游戏开发中声音处理流播放文件的内容介绍完了,希望通过本文的学习能对你有所帮助!