#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),
這樣做應該會讓你的錄制啟動速度顯著加快的。