//
// 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. input file上传文件弹出框的默认格式设置

    我们使用html的input 标签type="flie"时,如何设置默认可选的文件格式 <input id="doc_file" type="f ...

  2. MYSQL定时任务-定时清除备份数据

    背景 由于项目需要,每个月的历史存量数据需要进行一个归档和备份操作,以及一些日志表需要进行一个明细字段清除,让mysql数据库磁盘节省空间.则需要一些定时任务来定时清理这些数据. 技术选型 Java ...

  3. CentOS7静默安装Oracle 18g数据库(无图形化界面)

    说明: 因为是静默安装,所以我们不需要安装图形界面 准备:下载Oracle软件 官方网站:http://www.oracle.com/technetwork/database/enterprise-e ...

  4. [转]sql server 分页

    转自 https://www.cnblogs.com/fengxiaojiu/p/7994124.html 第一种:ROW_NUMBER() OVER()方式 select * from ( sele ...

  5. EasyNVR网页摄像机无插件H5、谷歌Chrome直播方案安装使用常见问题的分析

    EasyNVR对于互联网的视频直播还是有着一定的贡献的.为了方便用户的体验使用,我们也在互联网上放置了对应的试用版本,并且也会随着功能是更新也会定期的更新上去.软件包也会配置对应的使用文档和说明. 许 ...

  6. maven更改本地的maven私服

    1.今天想升级一个服务的jar包,更改后 使用命令 mvn deploy -e 一直报错, 看错误信息是  私服地址不是公司现在的地址. 想了半天,原来是电脑一直配置的上家公司的私服地址.. 但是在哪 ...

  7. Django框架 + Djiango安装 + First Djiango + 常用命令

    一.Django框架 MVC框架和MTV框架 参考:https://www.cnblogs.com/taosiyu/p/11260016.html MVC,全名是Model View Controll ...

  8. [LeetCode] 641.Design Circular Deque 设计环形双向队列

    Design your implementation of the circular double-ended queue (deque). Your implementation should su ...

  9. 深入玩转K8S之利用Label控制Pod位置

    首先介绍下什么是Label? Label是Kubernetes系列中一个核心概念.是一组绑定到K8s资源对象上的key/value对.同一个对象的labels属性的key必须唯一.label可以附加到 ...

  10. mysql新建用户host使用%但使用localhost无法连接

    今天新建了一个用户,权限也给了,host设置的为% 但是使用该用户连接时出现如下错误 查看用户 mysql> select host,user,password from mysql.user; ...