使用 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, , 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数据的更多相关文章
- ffplay代码播放pcm数据
摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...
- FFMPEG学习----使用SDL播放PCM数据
参考雷神的代码: /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * Simplest Audio Play SDL2 (SDL2 play PCM) * * 本程序使用SDL2播放 ...
- Android OpenSL ES 开发:使用 OpenSL 播放 PCM 数据
OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,通过使用它能够做到标准化, 高性能,低响应时间的音频功能实现方法. 这次是使用OpenSL ES来做一个音乐播放器,它能够播放m ...
- DirectSound播放PCM(可播放实时采集的音频数据)
前言 该篇整理的原始来源为http://blog.csdn.net/leixiaohua1020/article/details/40540147.非常感谢该博主的无私奉献,写了不少关于不同多媒体库的 ...
- 使用AudioTrack播放PCM音频数据(android)
众所周知,Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的.MediaPl ...
- 音频 PCM 数据的采集和播放
PCM(Pulse Code Modulation)脉冲编码调制 —— 音频的采集与量化过程. PCM数据是最原始的音频数据完全无损,所以PCM数据虽然音质优秀但体积庞大. 为了解决这个问题先后诞生了 ...
- 最简单的视音频播放示例9:SDL2播放PCM
本文记录SDL播放音频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API ...
- 最简单的视音频播放示例8:DirectSound播放PCM
本文记录DirectSound播放音频的技术.DirectSound是Windows下最常见的音频播放技术.目前大部分的音频播放应用都是通过DirectSound来播放的.本文记录一个使用Direct ...
- 最简单的视音频播放演示样例8:DirectSound播放PCM
===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...
随机推荐
- springboot响应消息(http)的编码设置
一.方式一 在单个REST接口上设置 @ResponseBody @RequestMapping(value = "sys/getTree1",method = RequestMe ...
- ES6----拓展运算符 三个点【...】
[...]拓展运算符是什么? es6中引入扩展运算符(...),它用于把一个数组转化为用逗号分隔的参数序列,它常用在不定参数个数时的函数调用,数组合并等情形.因为typeScript是es6的超集,所 ...
- 如何在本地使用scala或python运行Spark程序
如何在本地使用scala或python运行Spark程序 包含两个部分: 本地scala语言编写程序,并编译打包成jar,在本地运行. 本地使用python语言编写程序,直接调用spark的接口, ...
- angular7post提交的例子
postDemo() { const params = new HttpParams(); '); '); this._httpClient.post('http://127.0.0.1:12345/ ...
- Ubuntu 上编译opencv_contrib模块for Android
https://blog.csdn.net/ipfpm/article/details/81132144 [ubuntu]Ubuntu中Android SDK下载跟配置 android24的版本 (1 ...
- mysql删除唯一索引
在项目中用spring data jpa指定了一个唯一索引: @Entity @Table(name = "t_product") @Getter @Setter @AllArgs ...
- 使用Python读写文件进行图片复制(文件复制)
发现Python在读二进制文件时,可以生成一个新的文件,操作还很简单,如下:对一个jpeg的文件进行复制 fp1=open("e:\\1.jpeg","rb") ...
- springboot redis 示例代码
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...
- Oracle树形结构查询(递归)
引用:https://blog.csdn.net/u012615705/article/details/78321022 文章转自上述地址,内部有稍许改动,如有需要请查看原文. oracle树状结构 ...
- Mobaxterm使用(类似xshell)
先来看看SSH是什么,定义如下:SSH是一种可以保证用户远程登录到系统的协议.实际上,SSH是一个网络协议,允许通过网络连接到Linux和Unix服务器.SSH使用公钥加密来认证远程的计算机.通常有多 ...