使用 audioqueue 播放PCM數據

    //  
    //  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緩存

相關文章
相關標籤/搜索