Fork me on GitHub

浅谈游戏的声音处理-流播放文件

转自:http://hi.baidu.com/%B0%D9ii%D6%AAi%B5%C0/blog/item/f13304aa580f49a7ca130c58.html

流播放文件即用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 == nilreturn nil;
if(!(self = [super init])) return nil;

// try to open up the file using the specified path
if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x010, &audioFile))
{
NSLog(@"File can not be opened!");
return nil;
}

// get the data format of the file
size = sizeof(dataFormat);
AudioFileGetProperty(audioFilekAudioFilePropertyDataFormat, &size, &dataFormat);

// create a new playback queue using the specified data format and buffer callback
AudioQueueNewOutput(&dataFormat, BufferCallback, selfnilnil0, &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(audioFilekAudioFilePropertyPacketSizeUpperBound, &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(audioFilekAudioFilePropertyMagicCookieData, &size, nil);
if (size > 0)
{
// copy the cookie data from the file into the audio queue
cookie = malloc(sizeof(char) * size);
AudioFileGetProperty(audioFilekAudioFilePropertyMagicCookieData, &size, cookie);
AudioQueueSetProperty(queuekAudioQueueProperty_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(queuekAudioQueueProperty_IsRunning, propertyListenerCallback, self);

// allocate and prime buffers with some data
packetIndex = 0;
for (i = 0; i < NUM_QUEUE_BUFFERS; i++)
{
AudioQueueAllocateBuffer(queuekxxxBufferSizeBytes, &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;
}


算了,废话不多说了,直接上代码,等以后有时间了再逐一解释。


代码中对指针形式和数组形式2种各写了不同的代码,大家可以根据个人爱好使用,而且还将url和文件path2种播放方式写在了一起。这个类是xxxxx.h 

posted on 2012-03-25 12:02  pengyingh  阅读(428)  评论(0)    收藏  举报

导航