iOS录音方法实用详解(配Demo下载)
?
iOS錄音播放Demo下載地址:http://download.csdn.net/detail/lovechris00/9587214
?
本文將涉及到以下內(nèi)容:
一、搭建長按錄音UI效果;
二、使用AVAudioRecorder錄音;
三、使用AVAudioPlayer播放,并添加播放動(dòng)畫;
四、使用lame將caf音頻轉(zhuǎn)化為mp3;
五、將mp3 轉(zhuǎn)化為 base64編碼;
六、查看錄音文件大小;
七、刪除語音文件;
八、獲取錄音時(shí)長
?
一、搭建長按錄音UI效果;
頁面樣式效果如下:
其中:
1、錄音按鈕是由兩個(gè)UIImageView實(shí)現(xiàn),監(jiān)聽手勢(shì)方法,長按第一層UIImageView時(shí),第二層開始旋轉(zhuǎn)動(dòng)畫;
?? 這里我想過用UIButton來實(shí)現(xiàn)點(diǎn)擊錄音效果,其中UIControlEventTouchDown可以檢測(cè)點(diǎn)擊下去的效果,UIControlEventTouchUpInside可以檢測(cè)點(diǎn)擊后起來的效果,但是測(cè)試點(diǎn)擊下去后,沒有直接起來,而是將手指移動(dòng)到其他位置,導(dǎo)致錄音無法關(guān)閉,所以,還是使用了長按手勢(shì)來監(jiān)聽。
?
2、其他控件比較簡單。
?
核心代碼
1、長按啟動(dòng)錄音;
- (UIImageView *)recordBtn {if (!_recordBtn) {_recordBtn = [[UIImageView alloc]init];_recordBtn.backgroundColor = [UIColor clearColor];[_recordBtn setImage:[UIImage imageNamed:@"record_norm"]];_recordBtn.userInteractionEnabled = YES;//方便添加長按手勢(shì)}return _recordBtn; }?
self.recordBtn.frame = CGRectMake((kSCREEN_WIDTH - btnH)*0.5, CGRectGetMaxY(self.timeLabel.frame) + margin, btnH, btnH);self.recordBtn.layer.cornerRadius = self.recordBtn.frame.size.width * 0.5;[self.recordBtn.layer setMasksToBounds:YES];// [self.recordBtn addTarget:self action:@selector(recordNotice) forControlEvents:UIControlEventTouchDown];// [self.recordBtn addTarget:self action:@selector(stopNotice) forControlEvents:UIControlEventTouchUpInside];//實(shí)例化長按手勢(shì)監(jiān)聽UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTableviewCellLongPressed:)];//代理longPress.delegate = self;longPress.minimumPressDuration = 0.5;[self.recordBtn addGestureRecognizer:longPress];?
//長按事件的實(shí)現(xiàn)方法- (void) handleTableviewCellLongPressed:(UILongPressGestureRecognizer *)gestureRecognizer {if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {NSLog(@"UIGestureRecognizerStateBegan");[self startRecordNotice];}if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {}if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {NSLog(@"UIGestureRecognizerStateEnded");[self stopRecordNotice];}} </span>?
2、錄音過程中,錄音外圈旋轉(zhuǎn)效果
1)初始化
-(UIImageView *)rotateImgView {if (!_rotateImgView) {_rotateImgView = [[UIImageView alloc]init];_rotateImgView.image = [UIImage imageNamed:@"rcirle_norm"];_rotateImgView.frame = CGRectMake(0, 0, btnH, btnH);_rotateImgView.center = self.recordBtn.center;}return _rotateImgView; }?
2)動(dòng)畫設(shè)置
// 執(zhí)行動(dòng)畫 - (void)starAnimalWithTime:(CFTimeInterval)time //time為旋轉(zhuǎn)一周的時(shí)間 {self.rotateImgView.image = [UIImage imageNamed:@"rcirle_high"];self.rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];self.rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 ];self.rotationAnimation.duration = time;self.rotationAnimation.cumulative = YES;self.rotationAnimation.repeatCount = HUGE_VALF;[self.rotateImgView.layer addAnimation:self.rotationAnimation forKey:@"rotationAnimation"]; }?
3、播放時(shí)的動(dòng)畫效果
1)動(dòng)畫設(shè)置
#pragma mark - 動(dòng)畫效果- (void)pictureChangeAnimationSetting {NSArray *picArray = @[[UIImage imageNamed:@"voice1"],[UIImage imageNamed:@"voice2"],[UIImage imageNamed:@"voice3"],];// self.imageView.image = [UIImage imageNamed:@"voice1"];//imageView的動(dòng)畫圖片是數(shù)組imagesself.voiceView.animationImages = picArray;//按照原始比例縮放圖片,保持縱橫比self.voiceView.contentMode = UIViewContentModeScaleAspectFit;//切換動(dòng)作的時(shí)間3秒,來控制圖像顯示的速度有多快,self.voiceView.animationDuration = 1;//動(dòng)畫的重復(fù)次數(shù),想讓它無限循環(huán)就賦成0self.voiceView.animationRepeatCount = 0;}?
2)開啟動(dòng)畫
[self.voiceView startAnimating];</span>?
3)關(guān)閉動(dòng)畫
[self.voiceView.layer removeAllAnimations];self.voiceView.image = [UIImage imageNamed:@"voice3"];</span>?
二、使用AVAudioRecorder錄音;
#pragma mark - Getter /*** 獲得錄音機(jī)對(duì)象** @return 錄音機(jī)對(duì)象*/ -(AVAudioRecorder *)audioRecorder{if (!_audioRecorder) {//創(chuàng)建錄音文件保存路徑NSURL *url=[NSURL URLWithString:self.cafPathStr];//創(chuàng)建錄音格式設(shè)置NSDictionary *setting=[self getAudioSetting];//創(chuàng)建錄音機(jī)NSError *error=nil;_audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];_audioRecorder.delegate=self;_audioRecorder.meteringEnabled=YES;//如果要監(jiān)控聲波則必須設(shè)置為YESif (error) {NSLog(@"創(chuàng)建錄音機(jī)對(duì)象時(shí)發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);return nil;}}return _audioRecorder; }?
/*** 取得錄音文件設(shè)置** @return 錄音設(shè)置*/ -(NSDictionary *)getAudioSetting{//LinearPCM 是iOS的一種無損編碼格式,但是體積較為龐大//錄音設(shè)置NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];//錄音格式 無法使用[recordSettings setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey: AVFormatIDKey];//采樣率[recordSettings setValue :[NSNumber numberWithFloat:11025.0] forKey: AVSampleRateKey];//44100.0//通道數(shù)[recordSettings setValue :[NSNumber numberWithInt:2] forKey: AVNumberOfChannelsKey];//線性采樣位數(shù)//[recordSettings setValue :[NSNumber numberWithInt:16] forKey: AVLinearPCMBitDepthKey];//音頻質(zhì)量,采樣質(zhì)量[recordSettings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];return recordSettings; }?
- (void)startRecordNotice{if ([self.audioRecorder isRecording]) {[self.audioRecorder stop];}[self deleteOldRecordFile]; //如果不刪掉,會(huì)在原文件基礎(chǔ)上錄制;雖然不會(huì)播放原來的聲音,但是音頻長度會(huì)是錄制的最大長度。AVAudioSession *audioSession=[AVAudioSession sharedInstance];[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];if (![self.audioRecorder isRecording]) {//0--停止、暫停,1-錄制中[self.audioRecorder record];//首次使用應(yīng)用時(shí)如果調(diào)用record方法會(huì)詢問用戶是否允許使用麥克風(fēng)self.countNum = 0;NSTimeInterval timeInterval =1 ; //0.1sself.timer1 = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(changeRecordTime) userInfo:nil repeats:YES];[self.timer1 fire];}[self starAnimalWithTime:2.0]; }?
- (void)stopRecordNotice {NSLog(@"----------結(jié)束錄音----------");[self.audioRecorder stop];[self.timer1 invalidate];}三、使用AVAudioPlayer播放;
這段代碼寫的不好,暫不分享,歡迎大家分享給我
?
四、使用lame將caf音頻轉(zhuǎn)化為mp3;
lame 源碼下載地址:https://lame.sourceforge.io/download.php
導(dǎo)入lame框架,import進(jìn)來頭文件即可使用,如果導(dǎo)出后是噪音,需要檢查錄音的設(shè)置
#pragma mark - caf轉(zhuǎn)mp3 - (void)audio_PCMtoMP3 {@try {int read, write;FILE *pcm = fopen([self.cafPathStr cStringUsingEncoding:1], "rb"); //source 被轉(zhuǎn)換的音頻文件位置fseek(pcm, 4*1024, SEEK_CUR); //skip file headerFILE *mp3 = fopen([self.mp3PathStr cStringUsingEncoding:1], "wb"); //output 輸出生成的Mp3文件位置const int PCM_SIZE = 8192;const int MP3_SIZE = 8192;short int pcm_buffer[PCM_SIZE*2];unsigned char mp3_buffer[MP3_SIZE];lame_t lame = lame_init();lame_set_in_samplerate(lame, 11025.0);lame_set_VBR(lame, vbr_default);lame_init_params(lame);do {read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);if (read == 0)write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);elsewrite = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);fwrite(mp3_buffer, write, 1, mp3);} while (read != 0);lame_close(lame);fclose(mp3);fclose(pcm);}@catch (NSException *exception) {NSLog(@"%@",[exception description]);}@finally {NSLog(@"MP3生成成功: %@",self.mp3PathStr);}}?
使用上述lame轉(zhuǎn)碼可能會(huì)出現(xiàn)獲取時(shí)長不準(zhǔn)確,最近(18年1月11日)發(fā)現(xiàn)是lame轉(zhuǎn)碼的問題。由于上傳資源不能修改,所以這里補(bǔ)充 lame的轉(zhuǎn)碼方法:
http://blog.csdn.net/lovechris00/article/details/79034036
?
五、將mp3 轉(zhuǎn)化為 base64編碼;
#pragma mark - 文件轉(zhuǎn)換 // 二進(jìn)制文件轉(zhuǎn)為base64的字符串 - (NSString *)Base64StrWithMp3Data:(NSData *)data{if (!data) {NSLog(@"Mp3Data 不能為空");return nil;}// NSString *str = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];NSString *str = [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];return str; }// base64的字符串轉(zhuǎn)化為二進(jìn)制文件 - (NSData *)Mp3DataWithBase64Str:(NSString *)str{if (str.length ==0) {NSLog(@"Mp3DataWithBase64Str:Base64Str 不能為空");return nil;}NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];NSLog(@"Mp3DataWithBase64Str:轉(zhuǎn)換成功");return data; }?
六、查看錄音文件大小;
//單個(gè)文件的大小,返回單位為K - (long long) fileSizeAtPath:(NSString*)filePath{NSFileManager* manager = [NSFileManager defaultManager];if ([manager fileExistsAtPath:filePath]){return [[manager attributesOfItemAtPath:filePath error:nil] fileSize];}return 0; }?
調(diào)用
//計(jì)算文件大小long long fileSize = [self fileSizeAtPath:self.mp3PathStr]/1024.0;NSString *fileSizeStr = [NSString stringWithFormat:@"%lld",fileSize];七、刪除(語音)文件;
-(void)deleteOldRecordFileAtPath:(NSString *)pathStr{NSFileManager* fileManager=[NSFileManager defaultManager];BOOL blHave=[[NSFileManager defaultManager] fileExistsAtPath:pathStr];if (!blHave) {NSLog(@"不存在");return ;}else {NSLog(@"存在");BOOL blDele= [fileManager removeItemAtPath:self.cafPathStr error:nil];if (blDele) {NSLog(@"刪除成功");}else {NSLog(@"刪除失敗");}} }?
?
八、獲取錄音時(shí)長
#pragma mark 獲取mp3時(shí)長(秒) //返回mp3音頻的時(shí)間長(n秒,字符串) - (NSString *)getMp3DataDuration:(NSData *)mp3Data{NSError *error = nil;AVAudioPlayer *tempPlayer = [[AVAudioPlayer alloc]initWithData:mp3Data error:&error];int duration = ceilf(tempPlayer.duration);NSString *durationStr = [NSString stringWithFormat:@"%d",duration];NSLog(@"durationStr : %@ ,duration : %d ,error : %@ ",durationStr,duration,error);return durationStr; }?
使用上述lame轉(zhuǎn)碼可能會(huì)出現(xiàn)獲取時(shí)長不準(zhǔn)確,最近(18年1月11日)發(fā)現(xiàn)是lame轉(zhuǎn)碼的問題。由于上傳資源不能修改,所以這里補(bǔ)充 lame的轉(zhuǎn)碼方法:
http://blog.csdn.net/lovechris00/article/details/79034036
?
?
iOS錄音播放Demo下載地址:http://download.csdn.net/detail/lovechris00/9587214
?
?
總結(jié)
以上是生活随笔為你收集整理的iOS录音方法实用详解(配Demo下载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 将新项目上传到svn
- 下一篇: 状态空间描述的概念