// // MainViewController.h // RawAudioDataPlayer // // Created by SamYou on 12-8-18. // Copyright (c) 2012年 SamYou. All rights reserved. // #import <UIKit/UIKit.h> #import <AudioToolbox/AudioToolbox.h> #define QUEUE_BUFFER_SIZE 4 //队列缓冲个数 #define EVERY_READ_LENGTH 1000 //每次从文件读取的长度 #define MIN_SIZE_PER_FRAME 2000 //每侦最小数据长度 @interface MainViewController : UIViewController { AudioStreamBasicDescription audioDescription;///音频参数 AudioQueueRef audioQueue;//音频播放队列 AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_SIZE];//音频缓存 NSLock *synlock ;///同步控制 Byte *pcmDataBuffer;//pcm的读文件数据区 FILE *file;//pcm源文件 } static void AudioPlayerAQInputCallback(void *input, AudioQueueRef inQ, AudioQueueBufferRef outQB); -(void)onbutton1clicked; -(void)onbutton2clicked; -(void)initAudio; -(void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB; -(void)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf; @end
// // MainViewController.m // RawAudioDataPlayer // // Created by SamYou on 12-8-18. // Copyright (c) 2012年 SamYou. All rights reserved. // #import "MainViewController.h" @interface MainViewController () @end @implementation MainViewController #pragma mark - #pragma mark life cycle - (id)init { self = [super init]; if (self) { NSString *filepath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"audio.raw"]; NSLog(@"filepath = %@",filepath); NSFileManager *manager = [NSFileManager defaultManager]; NSLog(@"file exist = %d",[manager fileExistsAtPath:filepath]); NSLog(@"file size = %lld",[[manager attributesOfItemAtPath:filepath error:nil] fileSize]) ; file = fopen([filepath UTF8String], "r"); if(file) { fseek(file, 0, SEEK_SET); pcmDataBuffer = malloc(EVERY_READ_LENGTH); } else{ NSLog(@"!!!!!!!!!!!!!!!!"); } synlock = [[NSLock alloc] init]; } return self; } -(void)loadView { [super loadView]; self.view.backgroundColor = [UIColor grayColor]; UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; button1.frame = CGRectMake(10, 10, 300, 50); [button1 setTitle:@"button1" forState:UIControlStateNormal]; [button1 setTitle:@"button1" forState:UIControlStateHighlighted]; [button1 addTarget:self action:@selector(onbutton1clicked) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button1]; UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; button2.frame = CGRectMake(10, 70, 300, 50); [button2 setTitle:@"button2" forState:UIControlStateNormal]; [button2 setTitle:@"button2" forState:UIControlStateHighlighted]; [button2 addTarget:self action:@selector(onbutton2clicked) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button2]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation == UIInterfaceOrientationPortrait); } -(void)onbutton1clicked { [self initAudio]; NSLog(@"onbutton1clicked"); AudioQueueStart(audioQueue, NULL); for(int i=0;i<QUEUE_BUFFER_SIZE;i++) { [self readPCMAndPlay:audioQueue buffer:audioQueueBuffers[i]]; } /* audioQueue使用的是驱动回调方式,即通过AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);传入一个buff去播放,播放完buffer区后通过回调通知用户, 用户得到通知后再重新初始化buff去播放,周而复始,当然,可以使用多个buff提高效率(测试发现使用单个buff会小卡) */ } -(void)onbutton2clicked { NSLog(@"onbutton2clicked"); } #pragma mark - #pragma mark player call back /* 试了下其实可以不用静态函数,但是c写法的函数内是无法调用[self ***]这种格式的写法,所以还是用静态函数通过void *input来获取原类指针 这个回调存在的意义是为了重用缓冲buffer区,当通过AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);函数放入queue里面的音频文件播放完以后,通过这个函数通知 调用者,这样可以重新再使用回调传回的AudioQueueBufferRef */ static void AudioPlayerAQInputCallback(void *input, AudioQueueRef outQ, AudioQueueBufferRef outQB) { NSLog(@"AudioPlayerAQInputCallback"); MainViewController *mainviewcontroller = (MainViewController *)input; [mainviewcontroller checkUsedQueueBuffer:outQB]; [mainviewcontroller readPCMAndPlay:outQ buffer:outQB]; } -(void)initAudio { ///设置音频参数 audioDescription.mSampleRate = 8000;//采样率 audioDescription.mFormatID = kAudioFormatLinearPCM; audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audioDescription.mChannelsPerFrame = 1;///单声道 audioDescription.mFramesPerPacket = 1;//每一个packet一侦数据 audioDescription.mBitsPerChannel = 16;//每个采样点16bit量化 audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/8) * audioDescription.mChannelsPerFrame; audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ; ///创建一个新的从audioqueue到硬件层的通道 // AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &audioQueue);///使用当前线程播 AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, nil, nil, 0, &audioQueue);//使用player的内部线程播 ////添加buffer区 for(int i=0;i<QUEUE_BUFFER_SIZE;i++) { int result = AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);///创建buffer区,MIN_SIZE_PER_FRAME为每一侦所需要的最小的大小,该大小应该比每次往buffer里写的最大的一次还大 NSLog(@"AudioQueueAllocateBuffer i = %d,result = %d",i,result); } } -(void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB { [synlock lock]; int readLength = fread(pcmDataBuffer, 1, EVERY_READ_LENGTH, file);//读取文件 NSLog(@"read raw data size = %d",readLength); outQB->mAudioDataByteSize = readLength; Byte *audiodata = (Byte *)outQB->mAudioData; for(int i=0;i<readLength;i++) { audiodata[i] = pcmDataBuffer[i]; } /* 将创建的buffer区添加到audioqueue里播放 AudioQueueBufferRef用来缓存待播放的数据区,AudioQueueBufferRef有两个比较重要的参数,AudioQueueBufferRef->mAudioDataByteSize用来指示数据区大小,AudioQueueBufferRef->mAudioData用来保存数据区 */ AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL); [synlock unlock]; } -(void)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf { if(qbuf == audioQueueBuffers[0]) { NSLog(@"AudioPlayerAQInputCallback,bufferindex = 0"); } if(qbuf == audioQueueBuffers[1]) { NSLog(@"AudioPlayerAQInputCallback,bufferindex = 1"); } if(qbuf == audioQueueBuffers[2]) { NSLog(@"AudioPlayerAQInputCallback,bufferindex = 2"); } if(qbuf == audioQueueBuffers[3]) { NSLog(@"AudioPlayerAQInputCallback,bufferindex = 3"); } } @end
源代码下载地址 http://download.csdn.net/detail/samguoyi/4509544
时间: 2024-10-09 03:31:40