zoukankan      html  css  js  c++  java
  • 使用 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

  • 相关阅读:
    Windows下 如何添加开机启动项
    Android在 普通类(非Activity,多数为Adapter) 中 传输数据为空值 解决方法 :在startActivity 用 intent传输数据
    Android 从ImageView中获取Bitmap对象方法
    剑指offer(纪念版)读书笔记【实时更新】
    剑指offer(纪念版) 面试题3:二维数组中的查找
    C++ sizeof 误区 大公司面试题
    51 nod 1521 一维战舰 时间复杂度O(n),同 Codeforces 567D. One-Dimensional Battle Ships 有详细注释
    51nod 1126 求递推序列的第N项 思路:递推模拟,求循环节。详细注释
    51nod 1451 合法三角形 判斜率去重,时间复杂度O(n^2)
    关于JetBrains CLion 激活 (CLion License Activation)的解决办法,带hosts详细修改
  • 原文地址:https://www.cnblogs.com/sunminmin/p/4519039.html
Copyright © 2011-2022 走看看