ios播放PCM数据

ios播放PCM数据


[cpp] 
// 
//  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 


[cpp] 
// 
//  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
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值