博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈游戏的声音处理-流播放文件 source
阅读量:7224 次
发布时间:2019-06-29

本文共 13950 字,大约阅读时间需要 46 分钟。

.h文件 #ifdef TARGET_OS_IPHONE #import 
#else #import
#endif TARGET_OS_IPHONE #import
#import
#include
#include
#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 @interface xxxxx : NSObject { /*-----------------USED FOR HTTP STREAM------------------*/ NSURL *url; BOOL isPlaying; @public 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 /*-------------------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]; } @property BOOL isPlaying; @property BOOL trackClosed; - (id) initWithURL:(NSURL*) newURL; - (id) initWithPath:(NSString*) path; - (void) setGain:(Float32)gain; - (void) setRepeat:(BOOL)yn; - (void) setPlayingWhenAutoLock; - (void) play; - (void) playURL; - (void) pause; - (void) stopURL; - (void) close; extern NSString *xxxTrackFinishedPlayingNotification; @end .m文件 #import "xxxxx.h" #import
static UInt32 kxxxBufferSizeBytes = 0x10000; // 64k static BOOL kxxxTrackActive = NO; NSString *xxxTrackFinishedPlayingNotification = @"xxxTrackFinishedPlayingNotification"; #pragma mark - #pragma mark CFReadStream Callback Function Prototypes void ReadStreamCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void* dataIn); #pragma mark - #pragma mark Audio Callback Function Prototypes void MyAudioQueueOutputCallback(void* inClientData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer); void MyAudioQueueIsRunningCallback(void *inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID); void MyPropertyListenerProc(void *inClientData, AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags); void MyPacketsProc(void *inClientData, UInt32 inNumberBytes, UInt32 inNumberPackets, const void *inInputData, AudioStreamPacketDescription *inPacketDescriptions); OSStatus MyEnqueueBuffer(xxxxx* myData); #ifdef TARGET_OS_IPHONE void MyAudioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState); #endif #pragma mark - #pragma mark Audio Callback Function Implementations // // MyPropertyListenerProc // // Receives notification when the AudioFileStream has audio packets to be // played. In response, this function creates the AudioQueue, getting it // ready to begin playback (playback won't begin until audio packets are // sent to the queue in MyEnqueueBuffer). // // This function is adapted from Apple's example in AudioFileStreamExample with // kAudioQueueProperty_IsRunning listening added. // void MyPropertyListenerProc(void *inClientData, AudioFileStreamID inAudioFileStream, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags) { // this is called by audio file stream when it finds property values xxxxx* myData = (xxxxx*)inClientData; OSStatus err = noErr; switch (inPropertyID) { case kAudioFileStreamProperty_ReadyToProducePackets : { myData->discontinuous = true; // the file stream parser is now ready to produce audio packets. // get the stream format. AudioStreamBasicDescription asbd; UInt32 asbdSize = sizeof(asbd); err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd); if (err) { NSLog(@"get kAudioFileStreamProperty_DataFormat"); myData->failed = true; break; } // create the audio queue err = AudioQueueNewOutput(&asbd, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &myData->queue); if (err) { NSLog(@"AudioQueueNewOutput"); myData->failed = true; break; } // listen to the "isRunning" property err = AudioQueueAddPropertyListener(myData->queue, kAudioQueueProperty_IsRunning, MyAudioQueueIsRunningCallback, myData); if (err) { NSLog(@"AudioQueueAddPropertyListener"); myData->failed = true; break; } // allocate audio queue buffers for (unsigned int i = 0; i < kNumAQBufs; ++i) { err = AudioQueueAllocateBuffer(myData->queue, kAQBufSize, &myData->buffers); if (err) { NSLog(@"AudioQueueAllocateBuffer"); myData->failed = true; break; } } // get the cookie size UInt32 cookieSize; Boolean writable; err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable); if (err) { NSLog(@"info kAudioFileStreamProperty_MagicCookieData"); break; } // get the cookie data void* cookieData = calloc(1, cookieSize); err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData); if (err) { NSLog(@"get kAudioFileStreamProperty_MagicCookieData"); free(cookieData); break; } // set the cookie on the queue. err = AudioQueueSetProperty(myData->queue, kAudioQueueProperty_MagicCookie, cookieData, cookieSize); free(cookieData); if (err) { NSLog(@"set kAudioQueueProperty_MagicCookie"); break; } break; } } }

 

// // MyPacketsProc // // When the AudioStream has packets to be played, this function gets an // idle audio buffer and copies the audio packets into it. The calls to // MyEnqueueBuffer won't return until there are buffers available (or the // playback has been stopped). // // This function is adapted from Apple's example in AudioFileStreamExample with // CBR functionality added. // void MyPacketsProc(void *inClientData, UInt32 inNumberBytes, UInt32 inNumberPackets, const void *inInputData, AudioStreamPacketDescription *inPacketDescriptions) {
// this is called by audio file stream when it finds packets of audio xxxxx* myData = (xxxxx*)inClientData; // we have successfully read the first packests from the audio stream, so // clear the "discontinuous" flag myData->discontinuous = false; // the following code assumes we're streaming VBR data. for CBR data, the second branch is used. if (inPacketDescriptions) {
for (int i = 0; i < inNumberPackets; ++i) {
SInt64 packetOffset = inPacketDescriptions.mStartOffset; SInt64 packetSize = inPacketDescriptions.mDataByteSize; // If the audio was terminated before this point, then // exit. if (myData->trackEnded) {
return; } // if the space remaining in the buffer is not enough for this packet, then enqueue the buffer. size_t bufSpaceRemaining = kAQBufSize - myData->bytesFilled; if (bufSpaceRemaining < packetSize) {
MyEnqueueBuffer(myData); } pthread_mutex_lock(&myData->mutex2); // If the audio was terminated while waiting for a buffer, then // exit. if (myData->trackEnded) {
pthread_mutex_unlock(&myData->mutex2); return; } // copy data to the audio queue buffer AudioQueueBufferRef fillBuf = myData->buffers[myData->fillBufferIndex]; memcpy((char*)fillBuf->mAudioData + myData->bytesFilled, (const char*)inInputData + packetOffset, packetSize); pthread_mutex_unlock(&myData->mutex2); // fill out packet description myData->packetDescsQueue[myData->packetsFilled] = inPacketDescriptions; myData->packetDescsQueue[myData->packetsFilled].mStartOffset = myData->bytesFilled; // keep track of bytes filled and packets filled myData->bytesFilled += packetSize; myData->packetsFilled += 1; // if that was the last free packet description, then enqueue the buffer. size_t packetsDescsRemaining = kAQMaxPacketDescs - myData->packetsFilled; if (packetsDescsRemaining == 0) {
MyEnqueueBuffer(myData); } } } else {
size_t offset = 0; while (inNumberBytes) {
// if the space remaining in the buffer is not enough for this packet, then enqueue the buffer. size_t bufSpaceRemaining = kAQBufSize - myData->bytesFilled; if (bufSpaceRemaining < inNumberBytes) {
MyEnqueueBuffer(myData); } pthread_mutex_lock(&myData->mutex2); // If the audio was terminated while waiting for a buffer, then // exit. if (myData->trackEnded) {
pthread_mutex_unlock(&myData->mutex2); return; } // copy data to the audio queue buffer AudioQueueBufferRef fillBuf = myData->buffers[myData->fillBufferIndex]; bufSpaceRemaining = kAQBufSize - myData->bytesFilled; size_t copySize; if (bufSpaceRemaining < inNumberBytes) {
copySize = bufSpaceRemaining; } else {
copySize = inNumberBytes; } memcpy((char*)fillBuf->mAudioData + myData->bytesFilled, (const char*)(inInputData + offset), copySize); pthread_mutex_unlock(&myData->mutex2); // keep track of bytes filled and packets filled myData->bytesFilled += copySize; myData->packetsFilled = 0; inNumberBytes -= copySize; offset += copySize; } } } // // MyEnqueueBuffer // // Called from MyPacketsProc and connectionDidFinishLoading to pass filled audio // bufffers (filled by MyPacketsProc) to the AudioQueue for playback. This // function does not return until a buffer is idle for further filling or // the AudioQueue is stopped. // // This function is adapted from Apple's example in AudioFileStreamExample with // CBR functionality added. // OSStatus MyEnqueueBuffer(xxxxx* myData) {
OSStatus err = noErr; myData->inuse[myData->fillBufferIndex] = true; // set in use flag // enqueue buffer AudioQueueBufferRef fillBuf = myData->buffers[myData->fillBufferIndex]; fillBuf->mAudioDataByteSize = myData->bytesFilled; if (myData->packetsFilled) {
err = AudioQueueEnqueueBuffer(myData->queue, fillBuf, myData->packetsFilled, myData->packetDescsQueue); } else {
err = AudioQueueEnqueueBuffer(myData->queue, fillBuf, 0, NULL); } if (err) { NSLog(@"AudioQueueEnqueueBuffer"); myData->failed = true; return err; } if (!myData->started) { // start the queue if it has not been started already err = AudioQueueStart(myData->queue, NULL); if (err) { NSLog(@"AudioQueueStart"); myData->failed = true; return err; } myData->started = true; } // go to next buffer if (++myData->fillBufferIndex >= kNumAQBufs) myData->fillBufferIndex = 0; myData->bytesFilled = 0; // reset bytes filled myData->packetsFilled = 0; // reset packets filled // wait until next buffer is not in use pthread_mutex_lock(&myData->mutex); while (myData->inuse[myData->fillBufferIndex] && !myData->trackEnded) {
pthread_cond_wait(&myData->cond, &myData->mutex); } pthread_mutex_unlock(&myData->mutex); return err; } // // MyFindQueueBuffer // // Returns the index of the specified buffer in the audioQueueBuffer array. // // This function is unchanged from Apple's example in AudioFileStreamExample. // int MyFindQueueBuffer(xxxxx* myData, AudioQueueBufferRef inBuffer) {
for (unsigned int i = 0; i < kNumAQBufs; ++i) {
if (inBuffer == myData->buffers) return i; } return -1; } // // MyAudioQueueOutputCallback // // Called from the AudioQueue when playback of specific buffers completes. This // function signals from the AudioQueue thread to the AudioStream thread that // the buffer is idle and available for copying data. // // This function is unchanged from Apple's example in AudioFileStreamExample. // void MyAudioQueueOutputCallback(void* inClientData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
// this is called by the audio queue when it has finished decoding our data. // The buffer is now free to be reused. xxxxx* myData = (xxxxx*)inClientData; unsigned int bufIndex = MyFindQueueBuffer(myData, inBuffer); // signal waiting thread that the buffer is free. pthread_mutex_lock(&myData->mutex); myData->inuse[bufIndex] = false; pthread_cond_signal(&myData->cond); pthread_mutex_unlock(&myData->mutex); } // // MyAudioQueueIsRunningCallback // // Called from the AudioQueue when playback is started or stopped. This // information is used to toggle the observable "isPlaying" property and // set the "finished" flag. // void MyAudioQueueIsRunningCallback(void *inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID) {
xxxxx *myData = (xxxxx *)inUserData; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if (myData.isPlaying) {
myData->trackEnded = true; myData.isPlaying = false; #ifdef TARGET_OS_IPHONE AudioSessionSetActive(false); #endif } else {
myData.isPlaying = true; if (myData->trackEnded) {
myData.isPlaying = false; } // // Note about this bug avoidance quirk: // // On cleanup of the AudioQueue thread, on rare occasions, there would // be a crash in CFSetContainsValue as a CFRunLoopObserver was getting // removed from the CFRunLoop. // // After lots of testing, it appeared that the audio thread was // attempting to remove CFRunLoop observers from the CFRunLoop after the // thread had already deallocated the run loop. // // By creating an NSRunLoop for the AudioQueue thread, it changes the // thread destruction order and seems to avoid this crash bug -- or // at least I haven't had it since (nasty hard to reproduce error!) // [NSRunLoop currentRunLoop]; } [pool release]; } #ifdef TARGET_OS_IPHONE // // MyAudioSessionInterruptionListener // // Invoked if the audio session is interrupted (like when the phone rings) // void MyAudioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState) {
} #endif

转载于:https://www.cnblogs.com/pengyingh/articles/2416452.html

你可能感兴趣的文章
春运守护者 大陆首批台湾籍乘务长黄佳莹
查看>>
潮汕明代皇封御葬古墓受损追踪:当地相关部门介入
查看>>
“老票证”述时代变迁:从凭“票”买到“任意”购
查看>>
做java该要了解的东西
查看>>
春节出行带个对讲机 旅行实测威诺VR-N65
查看>>
河北旅游发展蓝皮书:借力雄安打造京津冀世界旅游品牌
查看>>
江西一名男婴被弃医院9个月 其父自首其母接回孩子
查看>>
江西去年为企业、居民减税659亿元 发行1082亿元政府债券
查看>>
GitHub发布Python安全警告 识别依赖包的安全漏洞
查看>>
讲好文创的时代故事
查看>>
支持53种语言预训练模型,斯坦福发布全新NLP工具包StanfordNLP
查看>>
翟欣欣微博发声解释“真相”
查看>>
Mac 常用必备软件(GitHub)
查看>>
快速排序就这么简单
查看>>
老腊肉级干货 | OOD面试备战攻略
查看>>
Google 回归中国,你准备好成为 Googler 了吗?
查看>>
util.promisify 的那些事儿
查看>>
vue3.0 尝鲜 -- 摒弃 Object.defineProperty,基于 Proxy 的观察者机制探索
查看>>
PHP 文件操作的各种姿势
查看>>
Linux 探索之旅 | 第一部分第六课:Linux 如何安装在虚拟机中
查看>>