ios播放PCM数据

  1. //  
  2. //  MainViewController.h  
  3. //  RawAudioDataPlayer  
  4. //  
  5. //  Created by SamYou on 12-8-18.  
  6. //  Copyright (c) 2012年 SamYou. All rights reserved.  
  7. //  
  8.   
  9. #import <UIKit/UIKit.h>  
  10. #import <AudioToolbox/AudioToolbox.h>  
  11.   
  12. #define QUEUE_BUFFER_SIZE 4 //队列缓冲个数  
  13. #define EVERY_READ_LENGTH 1000 //每次从文件读取的长度  
  14. #define MIN_SIZE_PER_FRAME 2000 //每侦最小数据长度  
  15.   
  16. @interface MainViewController : UIViewController  
  17. {  
  18.     AudioStreamBasicDescription audioDescription;///音频参数  
  19.     AudioQueueRef audioQueue;//音频播放队列  
  20.     AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_SIZE];//音频缓存  
  21.     NSLock *synlock ;///同步控制  
  22.     Byte *pcmDataBuffer;//pcm的读文件数据区  
  23.     FILE *file;//pcm源文件  
  24. }  
  25.   
  26. static void AudioPlayerAQInputCallback(void *input, AudioQueueRef inQ, AudioQueueBufferRef outQB);  
  27.   
  28. -(void)onbutton1clicked;  
  29. -(void)onbutton2clicked;  
  30. -(void)initAudio;  
  31. -(void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB;  
  32. -(void)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf;  
  33.   
  34. @end  



  1. //  
  2. //  MainViewController.m  
  3. //  RawAudioDataPlayer  
  4. //  
  5. //  Created by SamYou on 12-8-18.  
  6. //  Copyright (c) 2012年 SamYou. All rights reserved.  
  7. //  
  8.   
  9. #import "MainViewController.h"  
  10.   
  11. @interface MainViewController ()  
  12.   
  13. @end  
  14.   
  15. @implementation MainViewController  
  16.   
  17. #pragma mark -  
  18. #pragma mark life cycle  
  19.   
  20. - (id)init  
  21. {  
  22.     self = [super init];  
  23.     if (self) {  
  24.         NSString *filepath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"audio.raw"];  
  25.         NSLog(@"filepath = %@",filepath);  
  26.         NSFileManager *manager = [NSFileManager defaultManager];  
  27.         NSLog(@"file exist = %d",[manager fileExistsAtPath:filepath]);  
  28.         NSLog(@"file size = %lld",[[manager attributesOfItemAtPath:filepath error:nil] fileSize]) ;  
  29.         file  = fopen([filepath UTF8String], "r");  
  30.         if(file)  
  31.         {  
  32.             fseek(file, 0, SEEK_SET);  
  33.             pcmDataBuffer = malloc(EVERY_READ_LENGTH);  
  34.         }  
  35.         else{  
  36.             NSLog(@"!!!!!!!!!!!!!!!!");  
  37.         }  
  38.         synlock = [[NSLock alloc] init];  
  39.     }  
  40.     return self;  
  41. }  
  42.   
  43. -(void)loadView  
  44. {  
  45.     [super loadView];  
  46.     self.view.backgroundColor = [UIColor grayColor];  
  47.       
  48.     UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];  
  49.     button1.frame = CGRectMake(10, 10, 300, 50);  
  50.     [button1 setTitle:@"button1" forState:UIControlStateNormal];  
  51.     [button1 setTitle:@"button1" forState:UIControlStateHighlighted];  
  52.     [button1 addTarget:self action:@selector(onbutton1clicked) forControlEvents:UIControlEventTouchUpInside];  
  53.     [self.view addSubview:button1];  
  54.       
  55.     UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];  
  56.     button2.frame = CGRectMake(10, 70, 300, 50);  
  57.     [button2 setTitle:@"button2" forState:UIControlStateNormal];  
  58.     [button2 setTitle:@"button2" forState:UIControlStateHighlighted];  
  59.     [button2 addTarget:self action:@selector(onbutton2clicked) forControlEvents:UIControlEventTouchUpInside];  
  60.     [self.view addSubview:button2];  
  61.       
  62. }  
  63. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation  
  64. {  
  65.     return (interfaceOrientation == UIInterfaceOrientationPortrait);  
  66. }  
  67.   
  68. -(void)onbutton1clicked  
  69. {  
  70.     [self initAudio];  
  71.     NSLog(@"onbutton1clicked");  
  72.     AudioQueueStart(audioQueue, NULL);  
  73.     for(int i=0;i<QUEUE_BUFFER_SIZE;i++)  
  74.     {  
  75.         [self readPCMAndPlay:audioQueue buffer:audioQueueBuffers[i]];  
  76.     }  
  77.     /* 
  78.      audioQueue使用的是驱动回调方式,即通过AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);传入一个buff去播放,播放完buffer区后通过回调通知用户, 
  79.      用户得到通知后再重新初始化buff去播放,周而复始,当然,可以使用多个buff提高效率(测试发现使用单个buff会小卡) 
  80.      */  
  81. }  
  82.   
  83. -(void)onbutton2clicked  
  84. {  
  85.     NSLog(@"onbutton2clicked");  
  86. }  
  87.   
  88. #pragma mark -  
  89. #pragma mark player call back  
  90. /* 
  91.  试了下其实可以不用静态函数,但是c写法的函数内是无法调用[self ***]这种格式的写法,所以还是用静态函数通过void *input来获取原类指针 
  92.  这个回调存在的意义是为了重用缓冲buffer区,当通过AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);函数放入queue里面的音频文件播放完以后,通过这个函数通知 
  93.  调用者,这样可以重新再使用回调传回的AudioQueueBufferRef 
  94.  */  
  95. static void AudioPlayerAQInputCallback(void *input, AudioQueueRef outQ, AudioQueueBufferRef outQB)  
  96. {  
  97.     NSLog(@"AudioPlayerAQInputCallback");  
  98.     MainViewController *mainviewcontroller = (MainViewController *)input;  
  99.     [mainviewcontroller checkUsedQueueBuffer:outQB];  
  100.     [mainviewcontroller readPCMAndPlay:outQ buffer:outQB];  
  101. }  
  102.   
  103.   
  104.   
  105. -(void)initAudio  
  106. {  
  107.     ///设置音频参数  
  108.     audioDescription.mSampleRate = 8000;//采样率  
  109.     audioDescription.mFormatID = kAudioFormatLinearPCM;  
  110.     audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;  
  111.     audioDescription.mChannelsPerFrame = 1;///单声道  
  112.     audioDescription.mFramesPerPacket = 1;//每一个packet一侦数据  
  113.     audioDescription.mBitsPerChannel = 16;//每个采样点16bit量化      
  114.     audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/8) * audioDescription.mChannelsPerFrame;  
  115.     audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ;  
  116.     ///创建一个新的从audioqueue到硬件层的通道  
  117. //  AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &audioQueue);///使用当前线程播  
  118.     AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, nil, nil, 0, &audioQueue);//使用player的内部线程播  
  119.     添加buffer区  
  120.     for(int i=0;i<QUEUE_BUFFER_SIZE;i++)  
  121.     {  
  122.         int result =  AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);///创建buffer区,MIN_SIZE_PER_FRAME为每一侦所需要的最小的大小,该大小应该比每次往buffer里写的最大的一次还大  
  123.         NSLog(@"AudioQueueAllocateBuffer i = %d,result = %d",i,result);  
  124.     }  
  125. }  
  126.   
  127. -(void)readPCMAndPlay:(AudioQueueRef)outQ buffer:(AudioQueueBufferRef)outQB  
  128. {  
  129.     [synlock lock];  
  130.     int readLength = fread(pcmDataBuffer, 1, EVERY_READ_LENGTH, file);//读取文件  
  131.     NSLog(@"read raw data size = %d",readLength);  
  132.     outQB->mAudioDataByteSize = readLength;  
  133.     Byte *audiodata = (Byte *)outQB->mAudioData;  
  134.     for(int i=0;i<readLength;i++)  
  135.     {  
  136.         audiodata[i] = pcmDataBuffer[i];  
  137.     }  
  138.     /* 
  139.      将创建的buffer区添加到audioqueue里播放 
  140.      AudioQueueBufferRef用来缓存待播放的数据区,AudioQueueBufferRef有两个比较重要的参数,AudioQueueBufferRef->mAudioDataByteSize用来指示数据区大小,AudioQueueBufferRef->mAudioData用来保存数据区 
  141.      */  
  142.     AudioQueueEnqueueBuffer(outQ, outQB, 0, NULL);  
  143.     [synlock unlock];  
  144. }  
  145.   
  146. -(void)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf  
  147. {  
  148.     if(qbuf == audioQueueBuffers[0])  
  149.     {  
  150.         NSLog(@"AudioPlayerAQInputCallback,bufferindex = 0");  
  151.     }  
  152.     if(qbuf == audioQueueBuffers[1])  
  153.     {  
  154.         NSLog(@"AudioPlayerAQInputCallback,bufferindex = 1");  
  155.     }  
  156.     if(qbuf == audioQueueBuffers[2])  
  157.     {  
  158.         NSLog(@"AudioPlayerAQInputCallback,bufferindex = 2");  
  159.     }  
  160.     if(qbuf == audioQueueBuffers[3])  
  161.     {  
  162.         NSLog(@"AudioPlayerAQInputCallback,bufferindex = 3");  
  163.     }  
  164. }  
  165.   
  166.   
  167.   
  168.   
  169.   
  170.   
  171. @end  


哥的源代码下载地址      http://download.csdn.net/detail/samguoyi/4509544
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值