#import 需要引入
//获取document目录的路径
- (nsstring*) documentspath {
if (! _documentspath) {
nsarray *searchpaths =
nssearchpathfordirectoriesindomains
(nsdocumentdirectory, nsuserdomainmask, yes);
_documentspath = [searchpaths objectatindex: 0];
[_documentspath retain];
}
return _documentspath;
}
//(document目录的路径)
nsstring *destinationstring = [[self documentspath]
stringbyappendingpathcomponent:filenamefield.text];
nsurl *destinationurl = [nsurl fileurlwithpath: destinationstring];
//初始化avaudiorecorder
nserror *recordersetuperror = nil;
avaudiorecorder audiorecorder = [[avaudiorecorder alloc] initwithurl:destinationurl
settings:recordsettings error:&recordersetuperror];
[recordsettings release];
第二个参数 settings是一个容纳键值对的nsdictionary有四种一般的键
1:一般的音频设置
2:线性pcm设置
3:编码器设置
4:采样率转换设置
nsmutabledictionary 需要加入五个设置值(线性pcm)
nsmutabledictionary *recordsettings =
[[nsmutabledictionary alloc] initwithcapacity:10];
//1 id号
[recordsettings setobject:
[nsnumber numberwithint: kaudioformatlinearpcm] forkey: avformatidkey];
float samplerate =
[pcmsettingsviewcontroller.sampleratefield.text floatvalue];
//2 采样率
[nsnumber numberwithfloat:samplerate] forkey: avsampleratekey];
//3 通道的数目
[nsnumber numberwithint:
(pcmsettingsviewcontroller.stereoswitch.on ? 2 : 1)]
forkey:avnumberofchannelskey];
int bitdepth =
[pcmsettingsviewcontroller.sampledepthfield.text intvalue];
//4 采样位数 默认 16
[nsnumber numberwithint:bitdepth] forkey:avlinearpcmbitdepthkey];
//5
[nsnumber numberwithbool:
pcmsettingsviewcontroller.bigendianswitch.on]
forkey:avlinearpcmisbigendiankey];
//6 采样信号是整数还是浮点数
pcmsettingsviewcontroller.floatingsamplesswitch.on]
forkey:avlinearpcmisfloatkey];
avaudiorecorder成功创建后,使用他非常直接.它的三个基本方法如下
-(void) startrecording {
[audiorecorder record];
-(void) pauserecording {
[audiorecorder pause];
recordpausebutton.selected = no;
-(void) stoprecording {
[audiorecorder stop];
这里ios的录音功能主要依靠avfoundation.framework与coreaudio.framework来实现
在工程内添加这两个framework
我这里给工程命名audio_text
在生成的audio_textviewcontroller.h里的代码如下
#import
@interface audio_textviewcontroller : uiviewcontroller {
iboutlet uibutton *bthstart;
iboutlet uibutton *bthplay;
iboutlet uitextfield *freq;
iboutlet uitextfield *value;
iboutlet uiactivityindicatorview *actspinner;
bool toggle;
//variable setup for access in the class
nsurl *recordedtmpfile;
avaudiorecorder *recorder;
nserror *error;
}
@property (nonatomic,retain)iboutlet uiactivityindicatorview *actspinner;
@property (nonatomic,retain)iboutlet uibutton *bthstart;
@property (nonatomic,retain)iboutlet uibutton *bthplay;
-(ibaction)start_button_pressed;
-(ibaction)play_button_pressed;
@end
audio_textviewcontroller.m
#import "audio_textviewcontroller.h"
@implementation audio_textviewcontroller
- (void)viewdidload {
[super viewdidload];
//start the toggle in true mode.
toggle = yes;
bthplay.hidden = yes;
//instanciate an instance of the avaudiosession object.
avaudiosession * audiosession = [avaudiosession sharedinstance];
//setup the audiosession for playback and record.
//we could just use record and then switch it to playback leter, but
//since we are going to do both lets set it up once.
[audiosession setcategory:avaudiosessioncategoryplayandrecord error: &error];
//activate the session
[audiosession setactive:yes error: &error];
- (ibaction) start_button_pressed{
if(toggle)
{
toggle = no;
[actspinner startanimating];
[bthstart settitle:@"停" forstate: uicontrolstatenormal ];
bthplay.enabled = toggle;
bthplay.hidden = !toggle;
//begin the recording session.
//error handling removed. please add to your own code.
//setup the dictionary object with all the recording settings that this
//recording sessoin will use
//its not clear to me which of these are required and which are the bare minimum.
//this is a good resource: http://www.totodotnet.net/tag/avaudiorecorder/
nsmutabledictionary* recordsetting = [[nsmutabledictionary alloc] init];
[recordsetting setvalue :[nsnumber numberwithint:kaudioformatappleima4] forkey:avformatidkey];
[recordsetting setvalue:[nsnumber numberwithfloat:[freq.text floatvalue]] forkey:avsampleratekey];
[recordsetting setvalue:[nsnumber numberwithint: [value.text intvalue]] forkey:avnumberofchannelskey];
//now that we have our settings we are going to instanciate an instance of our recorder instance.
//generate a temp file for use by the recording.
//this sample was one i found online and seems to be a good choice for making a tmp file that
//will not overwrite an existing one.
//i know this is a mess of collapsed things into 1 call. i can break it out if need be.
recordedtmpfile = [nsurl fileurlwithpath:[nstemporarydirectory() stringbyappendingpathcomponent: [nsstring stringwithformat: @"%.0f.%@", [nsdate timeintervalsincereferencedate] * 1000.0, @"caf"]]];
nslog(@"using file called: %@",recordedtmpfile);
//setup the recorder to use this file and record to it.
recorder = [[ avaudiorecorder alloc] initwithurl:recordedtmpfile settings:recordsetting error:&error];
//use the recorder to start the recording.
//im not sure why we set the delegate to self yet.
//found this in antother example, but im fuzzy on this still.
[recorder setdelegate:self];
//we call this to start the recording process and initialize
//the subsstems so that when we actually say "record" it starts right away.
[recorder preparetorecord];
//start the actual recording
[recorder record];
//there is an optional method for doing the recording for a limited time see
//[recorder recordforduration:(nstimeinterval) 10]
}
else
toggle = yes;
[actspinner stopanimating];
[bthstart settitle:@"开始录音" forstate:uicontrolstatenormal ];
//stop the recorder.
[recorder stop];
- (void)didreceivememorywarning {
// releases the view if it doesn't have a superview.
[super didreceivememorywarning];
// release any cached data, images, etc that aren't in use.
-(ibaction) play_button_pressed{
//the play button was pressed...
//setup the avaudioplayer to play the file that we just recorded.
avaudioplayer * avplayer = [[avaudioplayer alloc] initwithcontentsofurl:recordedtmpfile error:&error];
[avplayer preparetoplay];
[avplayer play];
- (void)viewdidunload {
// release any retained subviews of the main view.
// e.g. self.myoutlet = nil;
//clean up the temp file.
nsfilemanager * fm = [nsfilemanager defaultmanager];
[fm removeitematpath:[recordedtmpfile path] error:&error];
//call the dealloc on the remaining objects.
[recorder dealloc];
recorder = nil;
recordedtmpfile = nil;
- (void)dealloc {
[super dealloc];
最后在interface builder里面绘制好界面,如
设置下按键的属性
基本就ok了,可以开始录音了。
bug解决
但是大家要注意一个貌似是ios5.0之后引入的bug,就是当你录制音频的时候启动时间往往会比较慢,大概需要3--5秒的时间吧,这种现象尤其在播放的时候立刻切换到录制的时候非常明显。
具体的原因我也不是很清楚,感觉应该是更底层的一些bug。目前我的解决方案是这样的。
1.在音频队列的初始化方法中加入代码
osstatus error = audiosessioninitialize(null, null, null, null);
uint32 category
= kaudiosessioncategory_playandrecord;
error = audiosessionsetproperty(kaudiosessionproperty_audiocategory, sizeof(category),
&category);
audiosessionaddpropertylistener(kaudiosessionproperty_audioroutechange, null, self);
uint32 inputavailable = 0;
uint32 size = sizeof(inputavailable);
audiosessiongetproperty(kaudiosessionproperty_audioinputavailable, &size, &inputavailable);
audiosessionaddpropertylistener(kaudiosessionproperty_audioinputavailable, null, self);
audiosessionsetactive(true);
2.在录制声音开始的时候先把播放声音stop,加入
uint32 category
audiosessionsetproperty(kaudiosessionproperty_audiocategory, sizeof(category),
这样做应该会让你的录制启动速度显著加快的。