iOS录音和播放

一、录音

//Recorder.h

#import <Foundation/Foundation.h>

#import <AudioToolbox/AudioToolbox.h>

#import <CoreAudio/CoreAudioTypes.h>

//设置录音的数据的结构体

typedef struct AQCallbackStruct{

AudioStreamBasicDescription       mDataFormat; //音频的格式

AudioQueueRef                            queue; //音频队列对象AudioQueueRef

AudioQueueBufferRef                  mBuffers[3];//缓冲区

AudioFileID                                 outputFile;

unsigned long                             frameSize;//音频的长度

int                                              run; //是否正在录音

} AQCallbackStruct;

@interfaceRecorder :NSObject{

long _audioDataLength;//录音数据的长度

Byte _audioByte[999999];

long _audioDataIndex; //录音数据的起始位置

}

@property(nonatomic,assign)AQCallbackStruct aqc;

- (id)init;

- (void)start;

- (void)stop;

- (void)pause;

- (Byte*)getBytes;

- (long)getLength;

- (void)processAudioBuffer:(AudioQueueBufferRef)buffer withQueue:(AudioQueueRef)queue;

@end

//Recorder.m

//录音回调

static void AQInputCallback (void* inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inBuffer, const AudioTimeStamp* inStartTime, unsigned long inNumPackets, const AudioStreamPacketDescription* inPacketDesc){

Recorder*engine = (__bridge Recorder *)inUserData;

if(inNumPackets >0) {

[engine processAudioBuffer:inBuffer withQueue:inAudioQueue];

}

if(engine.aqc.run) {

AudioQueueEnqueueBuffer(engine.aqc.queue, inBuffer,0,NULL);

}

}

- (id)init{

self = [super init];

if(self){

_aqc.mDataFormat.mSampleRate = 48000; //设置采样率为48000

_aqc.mDataFormat.mFormateID = kAudioFormatLinearPCM;//设置采样格式为PCM格式

_aqc.mDataFormat.mFormateFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;

_aqc.mDataFormat.mFramePerPacket = 1;

_aqc.mDataFormat.mChannelsPerFrame = 1;//单声道

_aqc.mDataFormat.mBitsPerChannel=16;//语音采样点占用的位数

_aqc.mDataFormat.mBytesPerFrame=2;//每帧的Byte数

_aqc.mDataFormat.mBytesPerPacket=2;//每个数据包bytes总数 = 每个数据包的帧数 * 每帧的Bytes总数

_aqc.frameSize=1024*8;

AudioQueueNewInput(&_aqc.mDataFormat, (AudioQueueInputCallback)AQInputCallback, (__bridgevoid*)self,NULL,kCFRunLoopCommonModes,0, &_aqc.queue);

for(inti=0;i

{

AudioQueueAllocateBuffer(_aqc.queue,_aqc.frameSize, &_aqc.mBuffers[i]);

AudioQueueEnqueueBuffer(_aqc.queue,_aqc.mBuffers[i],0,NULL);

}

_aqc.recPtr=0;

_aqc.run=1;

}

return self;

}

- (void) dealloc{

AudioQueueStop(_aqc.queue,true);

_aqc.run=0;

AudioQueueDispose(_aqc.queue,true);

}

- (void)start{

AudioQueueStart(_aqc.queue,NULL);

}

- (void)stop{

AudioQueueStop(_aqc.queue,true);

}

- (void)pause{

AudioQueuePause(_aqc.queue);

}

- (Byte*)getBytes{

return _audioByte;

}

- (long)getLength{

return _audioDataLength;

}

- (void)processAudioBuffer:(AudioQueueBufferRef)buffer withQueue:(AudioQueueRef)queue{

NSLog(@"processAudioData :%u",(unsignedint)buffer->mAudioDataByteSize);

memcpy(_audioByte+_audioDataIndex, buffer->mAudioData, buffer->mAudioDataByteSize);

_audioDataIndex+= buffer->mAudioDataByteSize;

_audioDataLength=_audioDataIndex;

}

@end

二、播放

//Player.h

#import <AudioToolbox/AudioToolbox.h>

#define EVERY_READ_LENGTH20

typedefstructplayState

{

AudioStreamBasicDescriptiondataFormat;//输出音频的格式

AudioQueueRefqueue;//音频队列的对象AudioQueueRef

AudioQueueBufferRefbuffer[3];//缓冲区

UInt32bufferByteSize;//缓冲区大小

BOOLplaying;//是否正在播放

}PlayState;

@interfacePlayer :NSObject{

PlayState_playState;

}

- (BOOL)playData:(NSData*)data;

@end


#import"Player.h"

#import <AudioToolbox/AudioQueue.h>

#import <MediaPlayer/MediaPlayer.h>

#import <AVFoundation/AVAudioSession.h>

static UInt32 gBufferSizeBytes =0x100000;

@interfacePlayer(){

Byte*_audioByte;

long _audioDataIndex;

long _audioDataLenth;

}

@end

@implementationPlayer

static void BufferCallback(void* inUserData,AudioQueueRef inAQ,AudioQueueBufferRef buffer){

Player* player=(__bridgePlayer*)inUserData;

AudioQueueStop(player->_playState.queue,NO);

for(inti =0; i <3; i++)

{

AudioQueueFreeBuffer(player->_playState.queue, player->_playState.buffer[i]);

}

AudioQueueDispose(player->_playState.queue,YES);

}

- (instancetype)init

{

self= [super init];

if(self) {

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

}

return self;

}

- (BOOL)playData:(NSData*)data{

if(data ==nil|| [dataisKindOfClass:[NSNullclass]] || data.length<=0) {

return NO;

}


_playState.dataFormat.mSampleRate=44100;

_playState.dataFormat.mFormatID=kAudioFormatLinearPCM;

_playState.dataFormat.mFormatFlags=kAudioFormatFlagIsSignedInteger|kLinearPCMFormatFlagIsPacked;

_playState.dataFormat.mBytesPerPacket=2;

_playState.dataFormat.mFramesPerPacket=1;

_playState.dataFormat.mBytesPerFrame=2;

_playState.dataFormat.mChannelsPerFrame=1;

_playState.dataFormat.mBitsPerChannel=16;

_playState.dataFormat.mReserved=0;

OSStatusstatus =AudioQueueNewOutput(&_playState.dataFormat, (AudioQueueOutputCallback)BufferCallback, (__bridgevoid*)self,nil,nil,0, &_playState.queue);

if(status !=noErr) {

return NO;

}

status =AudioQueueAllocateBuffer(_playState.queue,gBufferSizeBytes, &_playState.buffer[0]);

if(status !=noErr) {

return NO;

}

_playState.buffer[0]->mAudioDataByteSize= (int)[datalength];

memcpy(_playState.buffer[0]->mAudioData, [databytes], [datalength]);

status = AudioQueueEnqueueBuffer(_playState.queue,_playState.buffer[0],0,nil);

if(status !=noErr) {

return NO;

}

float value;

AudioQueueGetParameter(_playState.queue,kAudioQueueParam_Volume, &value);

AudioQueueSetParameter(_playState.queue,kAudioQueueParam_Volume,1.0);

status = AudioQueueStart(_playState.queue,nil);

if(status !=noErr) {

return NO;

}

return YES;

}

@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容