iOS录音使用AVAudioRecorder,播放用 AVPlayer 就可以很好的解决,网上也有很多的教程。这里就不细讲,后面会附上代码。
先说一下demo内容,现在项目要求做一个录音、上传、播放的功能。细节:录音前需要提示音,录音时会有一个根据声音强度来展示的相应动态效果,还有个计时功能。
我们来说一下我在制作此功能时所遇到的坑!!
这里先呈现音频录制的代码,这里面引用了SpectrumView,点击打开链接。这是一个根据声强来显示声音录制的效果,如果不需要可以去除。
录制音频代码:
1.首先说一下录制音频的格式。
经验证,这里博主建议各位使用AAC的录制格式。AAC(Advanced Audio Coding),中文称为“高级音频编码”,所占内存小,音质也不错,最重要的是可以与android兼容。
2.这里用的是7牛云的上传。这里我遇到的大问题就是上传音频到7牛云后,发现格式不能识别,显示为application/octet-stream。我最开始用.mp4的格式,的确上传上去后,能够识别为video/mp4,并且能正常播放。 但是后来发现不能播放android的录音。于是就想办法解决,经过一下午的各种博客浏览,。。。无果!! 好吧,最后想到先本地存储,再来播放的方式,解决问题。(这里的录音文件都比较小,不超过30s)
这里附上部分demo片段,有需要自取。
录音部分:#import "AudioRecorderVC.h"
#import <AVFoundation/AVFoundation.h>
#define kRecordAudioFile @"myRecord.aac"
@interface AudioRecorderVC ()<AVAudioRecorderDelegate>
@property (strong,nonatomic) SpectrumView *spectrumView;
@property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音频录音机
@property (nonatomic, strong) AVAudioPlayer *bellplayer;
@property (nonatomic, assign) int sCountup;
@property (nonatomic, strong) NSTimer *mTimer;
@end
@implementation AudioRecorderVC
#pragma mark - 控制器视图方法
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.naView setHidden:YES];
[self.statusTip setHidden:YES];
[self.view createBordersWithColor:[UIColor clearColor] withCornerRadius:6 andWidth:1];
[self.labReminder createBordersWithColor:[UIColor clearColor] withCornerRadius:4 andWidth:1];
[self.labReminder setTextColor:MCOLOR_FFFFFF];
[self addTapGesture];
[self addSpectrumView];
[self labToSize];
}
-(void)addSpectrumView{
if (!self.spectrumView) {
__weak AudioRecorderVC *weakSelf = self;
self.spectrumView = [[SpectrumView alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.view.bounds)-150,240,300, 60.0)];
self.spectrumView.hidden = YES;
self.spectrumView.text = [NSString stringWithFormat:@"%d",0];
__weak SpectrumView * weakSpectrum = self.spectrumView;
self.spectrumView.itemLevelCallback = ^() {
[weakSelf.audioRecorder updateMeters];
//取得第一个通道的音频,音频强度范围是-160到0
float power= [weakSelf.audioRecorder averagePowerForChannel:0];
weakSpectrum.level = power;
};
[self.view addSubview:self.spectrumView];
}
}
-(void)addTapGesture{
//添加手势
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickPop)];
//将手势添加到需要相应的view中去
[self.view addGestureRecognizer:tapGesture];
}
-(void)clickPop{
if (_Block) {
_Block(nil);
}
}
#pragma mark - getter 懒加载
- (UIButton *)btnRecorder {
// 开始
[_btnRecorder addTarget:self action:@selector(recordStart:) forControlEvents:UIControlEventTouchDown];
// 取消
// [_btnRecorder addTarget:self action:@selector(recordCancel:) forControlEvents: UIControlEventTouchUpOutside];
//完成
[_btnRecorder addTarget:self action:@selector(recordFinish:) forControlEvents:UIControlEventTouchUpInside];
/*
//移出
[_btnRecorder addTarget:self action:@selector(recordTouchDragExit:) forControlEvents:UIControlEventTouchDragExit];
//移入
[_btnRecorder addTarget:self action:@selector(recordTouchDragEnter:) forControlEvents:UIControlEventTouchDragEnter];
*/
return _btnRecorder;
}
/**
* 获得录音机对象
*
* @return 录音机对象
*/
- (AVAudioRecorder *)audioRecorder {
if (!_audioRecorder) {
[self setAudioSession];
//创建录音文件保存路径
NSURL *url=[self getSavePath];
//创建录音格式设置
NSDictionary *setting=[self getAudioSetting];
//创建录音机
NSError *error=nil;
_audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
_audioRecorder.delegate= self;
_audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES
if (error) {
NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);
return nil;
}
}
return _audioRecorder;
}
#pragma mark - layout
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat width = self.view.bounds.size.width;
CGFloat height = self.view.bounds.size.height;
self.btnRecorder.frame = CGRectMake(width / 2.f - 50.f, height - 180.f, 100.f, 100.f);
[self.audioRecorder record];
[self.audioRecorder stop];
[self removeFile];
}
#pragma mark - ControlEvents
/*
- (void)recordCancel:(UIButton *)button {
if ([self.audioRecorder isRecording]) {
NSLog(@"取消");
[self.audioRecorder stop];
self.spectrumView.hidden = NO;
}
}
*/
- (void)recordStart:(UIButton *)button {
if (![self.audioRecorder isRecording]) {
NSLog(@"录音开始");
[self startScount];
[self playthebell];
[self.audioRecorder record];
[self startAnimate];
self.labReminder.hidden = YES;
self.spectrumView.hidden = NO;
}
}
- (void)recordFinish:(UIButton *)button {
if ([self.audioRecorder isRecording]) {
NSLog(@"完成");
[self.audioRecorder stop];
[self stopAnimate];
self.spectrumView.hidden = NO;
[self judgePushAudio];
}
}
/*
- (void)recordTouchDragExit:(UIButton *)button {
if([self.audioRecorder isRecording]) {
[self stopAnimate];
}
}
- (void)recordTouchDragEnter:(UIButton *)button {
if([self.audioRecorder isRecording]) {
[self startAnimate];
}
}
*/
- (void)startAnimate {
[self.spectrumView start];
}
- (void)stopAnimate {
[self.spectrumView stop];
[self.mTimer invalidate];
self.mTimer = nil;
}
- (void)setAudioSession {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *sessionError;
//AVAudioSessionCategoryPlayAndRecord用于录音和播放
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
if(session == nil)
NSLog(@"Error creating session: %@", [sessionError description]);
else
[session setActive:YES error:nil];
}
/**
* 取得录音文件设置
*
* @return 录音设置
*/
- (NSDictionary *)getAudioSetting {
NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
//设置录音格式
[dicM setObject:@(kAudioFormatMPEG4AAC) forKey:AVFormatIDKey];
//设置录音采样率,8000是电话采样率,对于一般录音已经够了
[dicM setObject:@(8000) forKey:AVSampleRateKey];
//设置通道,这里采用单声道
[dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
//每个采样点位数,分为8、16、24、32
[dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
//是否使用浮点数采样
[dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
//....其他设置等
return dicM;
}
/**
* 取得录音文件保存路径
*
* @return 录音文件路径
*/
- (NSURL *)getSavePath {
// 在Documents目录下创建一个名为FileData的文件夹
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioData"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir = FALSE;
BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
if(!(isDirExist && isDir)) {
BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
if(!bCreateDir){
NSLog(@"创建文件夹失败!");
}
NSLog(@"创建文件夹成功,文件路径%@",path);
}
path = [path stringByAppendingPathComponent:kRecordAudioFile];
NSLog(@"file path:%@",path);
NSURL *url=[NSURL fileURLWithPath:path];
return url;
}
- (void)removeFile{
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioData"];
NSFileManager *fileManager = [NSFileManager defaultManager];
path = [path stringByAppendingPathComponent:kRecordAudioFile];
NSError *error;
if ([fileManager removeItemAtPath:path error:&error] != YES)
NSLog(@"Unable to delete file: %@", [error localizedDescription]);
}
- (void)judgePushAudio{
if (_sCountup < 1) {
[self showToast:@"录音时间太短,请重试!"];
[self removeFile];
}else if(_sCountup >= 1 && _sCountup <= 30){
if (_Block) {
_Block([self getSavePath]);
}
}
}
- (void)labToSize{
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.labReminder.text];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:20.0f];//调整行间距
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [self.labReminder.text length])];
self.labReminder.attributedText = attributedString;
[self.labReminder sizeToFit];
}
#pragma --提示音
- (void)playthebell{
NSString *mp3Str;
mp3Str = @"talkroom_begin";
NSString *filePath = [[NSBundle mainBundle] pathForResource:mp3Str ofType:@"mp3"];
self.bellplayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:nil];
self.bellplayer.volume = 1.0;
self.bellplayer.numberOfLoops = -1;
[self.bellplayer prepareToPlay];
[self.bellplayer play];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ( 0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.bellplayer stop];
});
}
#pragma --计时器
- (void)startScount{
self.sCountup = 0;
[UIView animateWithDuration:0.5 animations:^{
self.mTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(startCountUp) userInfo:nil repeats:YES];
}];
}
- (void)startCountUp{
_sCountup++;
self.spectrumView.timeLabel.text = [NSString stringWithFormat:@"%ds", _sCountup];
if (_sCountup == 30) {
[self recordFinish:nil];
}
}
@end
3
#pragma --播放录音
- (void)addVoiceButton:(DoorVoucherCell *)cell{
UIButton *voiceBtn = [[UIButton alloc]initWithFrame:CGRectMake(cell.contentValue.left, 0, 150, 50)];
[voiceBtn addTarget:self action:@selector(playRecoderVoice) forControlEvents:UIControlEventTouchUpInside];
voice = [[UIImageView alloc]initWithFrame:CGRectMake(0, 12, 25, 25)];
//动画未开始前的图片
voice.image = [UIImage imageNamed:@"chat_animation_white3"];
//进行动画效果的3张图片(按照播放顺序放置)
voice.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:@"chat_animation_white1"],
[UIImage imageNamed:@"chat_animation_white2"],
[UIImage imageNamed:@"chat_animation_white3"],nil];
//设置动画间隔
voice.animationDuration = 1;
voice.animationRepeatCount = 0;
voice.userInteractionEnabled = NO;
voice.backgroundColor = [UIColor clearColor];
[voiceBtn addSubview:voice];
[cell addSubview:voiceBtn];
}
- (NSURL *)writeRecoderToFile{
//播放
NSURL *url = [NSURL URLWithString:self.dataModel.voice];
//把音频文件保存到本地
NSData *audioData = [NSData dataWithContentsOfURL:url];
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioData"];
path = [path stringByAppendingPathComponent:@"myRecord.aac"];
// DDLogWarn(@" 从网络拿到的音频数据写入的本地路径 %@",filePath);
[audioData writeToFile:path atomically:YES];
NSURL *fileURL = [NSURL fileURLWithPath:path];
return fileURL;
}
- (void)playRecoderVoice{
[self setAudioPlayer];
[self.audioPlayer play];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[voice startAnimating];
});
}
- (void)playerItemDidReachEnd{
[self playthebell];
[voice stopAnimating];
voice.image = [UIImage imageNamed:@"chat_animation_white3"];
}
- (AVPlayer *)setAudioPlayer{
NSError *error=nil;
AVPlayerItem * songItem = [[AVPlayerItem alloc]initWithURL:[self writeRecoderToFile]];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
_audioPlayer = [[AVPlayer alloc] initWithPlayerItem:songItem];
// 监听音乐是否播放完成
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd)
name:AVPlayerItemDidPlayToEndTimeNotification
object:nil];
if (error) {
NSLog(@"创建播放器过程中发生错误,错误信息:%@",error.localizedDescription);
return nil;
}
return _audioPlayer;
}
#pragma --提示音
- (void)playthebell{
NSString *mp3Str;
mp3Str = @"talkroom_up";
NSString *filePath = [[NSBundle mainBundle] pathForResource:mp3Str ofType:@"mp3"];
self.bellplayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:nil];
self.bellplayer.volume = 1.0;
self.bellplayer.numberOfLoops = -1;
[self.bellplayer prepareToPlay];
[self.bellplayer play];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ( 0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.bellplayer stop];
});
}
有问题欢迎提问,喜欢请点赞,Star。谢谢。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)