//
// 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, , 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(, , , );
[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(, , , );
[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=;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 = ;//采样率
audioDescription.mFormatID = kAudioFormatLinearPCM;
audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioDescription.mChannelsPerFrame = ;///单声道
audioDescription.mFramesPerPacket = ;//每一个packet一侦数据
audioDescription.mBitsPerChannel = ;//每个采样点16bit量化
audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/) * audioDescription.mChannelsPerFrame;
audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ;
///创建一个新的从audioqueue到硬件层的通道
// AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &audioQueue);///使用当前线程播
AudioQueueNewOutput(&audioDescription, AudioPlayerAQInputCallback, self, nil, nil, , &audioQueue);//使用player的内部线程播
////添加buffer区
for(int i=;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, , EVERY_READ_LENGTH, file);//读取文件
NSLog(@"read raw data size = %d",readLength);
outQB->mAudioDataByteSize = readLength;
Byte *audiodata = (Byte *)outQB->mAudioData;
for(int i=;i<readLength;i++)
{
audiodata[i] = pcmDataBuffer[i];
}
/*
将创建的buffer区添加到audioqueue里播放
AudioQueueBufferRef用来缓存待播放的数据区,AudioQueueBufferRef有两个比较重要的参数,AudioQueueBufferRef->mAudioDataByteSize用来指示数据区大小,AudioQueueBufferRef->mAudioData用来保存数据区
*/
AudioQueueEnqueueBuffer(outQ, outQB, , NULL);
[synlock unlock];
} -(void)checkUsedQueueBuffer:(AudioQueueBufferRef) qbuf
{
if(qbuf == audioQueueBuffers[])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 0");
}
if(qbuf == audioQueueBuffers[])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 1");
}
if(qbuf == audioQueueBuffers[])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 2");
}
if(qbuf == audioQueueBuffers[])
{
NSLog(@"AudioPlayerAQInputCallback,bufferindex = 3");
}
} @end

源代码下载地址      http://download.csdn.net/detail/samguoyi/4509544

使用 audioqueue 播放PCM数据的更多相关文章

  1. ffplay代码播放pcm数据

    摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...

  2. FFMPEG学习----使用SDL播放PCM数据

    参考雷神的代码: /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * Simplest Audio Play SDL2 (SDL2 play PCM) * * 本程序使用SDL2播放 ...

  3. Android OpenSL ES 开发:使用 OpenSL 播放 PCM 数据

    OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,通过使用它能够做到标准化, 高性能,低响应时间的音频功能实现方法. 这次是使用OpenSL ES来做一个音乐播放器,它能够播放m ...

  4. DirectSound播放PCM(可播放实时采集的音频数据)

    前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的 ...

  5. 使用AudioTrack播放PCM音频数据(android)

    众所周知,Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的.MediaPl ...

  6. 音频 PCM 数据的采集和播放

    PCM(Pulse Code Modulation)脉冲编码调制 —— 音频的采集与量化过程. PCM数据是最原始的音频数据完全无损,所以PCM数据虽然音质优秀但体积庞大. 为了解决这个问题先后诞生了 ...

  7. 最简单的视音频播放示例9:SDL2播放PCM

    本文记录SDL播放音频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API ...

  8. 最简单的视音频播放示例8:DirectSound播放PCM

    本文记录DirectSound播放音频的技术.DirectSound是Windows下最常见的音频播放技术.目前大部分的音频播放应用都是通过DirectSound来播放的.本文记录一个使用Direct ...

  9. 最简单的视音频播放演示样例8:DirectSound播放PCM

    ===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...

随机推荐

  1. LiveCD 修复Grub引导

    /usr/sbin/grub-probe: error: failed to get canonical path of /cow 如果你是从这句报错search过来的,恭喜您!看来你也是一个调皮的孩 ...

  2. Spark无法读取hive 3.x的表数据

    通过Ambari2.7.3安装HDP3.1.0成功之后,通过spark sql去查询hive表的数据发现竟然无法查询 HDP3.0 集成了hive 3.0和 spark 2.3,然而spark却读取不 ...

  3. Java学习-054-Mybatis IN查询,通过 foreach 获取列表数据

    通过如下语句查询商品订单信息: ,,,) 在 Mapper.java 中定义如下接口: List<GoodsOrder> findGoodsOrderByIds(String ids); ...

  4. MathML

    MathML https://developer.mozilla.org/en-US/docs/Web/MathML/Examples/MathML_Pythagorean_Theorem Mathe ...

  5. weixin-js-sdk

    场景:在h5移动端,实现分享朋友,分享朋友圈. 插曲:一开始我认为是不能做到分享的,主要是我从微信小程序的角度出发的,想着微信小程序都做不到分享朋友圈功能,那h5就更不能实现了,导致出现了错误的判断. ...

  6. gitlib配置push后自动触发jenkins构建sonar扫描

    jenkins所用到的插件: Gitlab Hook Plugin 配置步骤 1.先进入gitlab的个人设置,生成api token 2.复制生成的访问令牌,打开jenkins的凭据,添加选择类型是 ...

  7. IDEA中提示配置jdk1.8

    问题描述:运行Java Web项目时,IDEA中提示:Warning:java: 源值1.5已过时, 将在未来所有发行版中删除 解决方法:1. 打开[File]—[Project Structure] ...

  8. [UE4] Adding a custom shading model

    转自:https://blog.felixkate.net/2016/05/22/adding-a-custom-shading-model-1/ This was written in Februa ...

  9. spring boot2.x中集成H2数据库

    H2数据库介绍  查看 在spring boot中集成 1.添加依赖 <dependency> <groupId>org.springframework.boot</gr ...

  10. “无法从节点xx检索exectask的版本” 原因分析

    客户有一套部署在Window 2008 R2 sp环境下的12.1.0.2 RAC环境,该RAC基于策略管理.因为业务需要,现在需要更换部分设备——踢出两台2路的服务器(节点名称分别为racnode2 ...