了解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];
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
以上是需要定义的为单独文件播放的所需要的元素。可以定义在类里面。
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];
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
利用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
- 1.
- 2.
- 3.
- 4.
这里是定义的一些参数,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;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
4. 在线文件初始化
- (id)initWithURL:(NSURL*)newUrl
{
self = [super init];
if (self != nil)
{
url = [newUrl retain];
}
return self;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
算了,废话不多说了,直接上代码,等以后有时间了再逐一解释。
小结了解iPhone游戏开发中声音处理流播放文件的内容介绍完了,希望通过本文的学习能对你有所帮助!