有一些人喜欢用第三方,我还是比较喜欢用自己封装的,每次更改内部什么的都熟悉!
共包含两个文件
JPRecordTool
和RecorderView
,前者是个工具类,为后者服务,如果有其他需求只用前者来完成自己的特殊需求,如果只是简单的需求,只用控制后者即可,代码如下:
JPRecordTool.h
@class JPRecordTool;
@protocol JPRecordToolDelegate
@optional
- (void) recordTool:(JPRecordTool *)recordTool didstartRecoring:(int)no;
@end
@interface JPRecordTool : NSObject
/** 录音工具单例 */
+ (instancetype) sharedRecordTool;
+ (instancetype)allocWithZone:(struct _NSZone *)zone;
/** 开始录音 */
- (void) startRecording;
/** 停止录音*/
- (void) stopRecording;
/** 播放录音文件 */
- (void) playRecordingFile;
/** 停止播放录音文件 *
/- (void) stopPlaying;
/** 销毁录音文件*/
- (void)destructionRecordingFile;
/** 录音对象 */
@property (nonatomic, strong) AVAudioRecorder *recorder;
/** 更新图片的代理 */
@property (nonatomic, assign) iddelegate;
@end
JPRecordTool.m
#import "JPRecordTool.h"
#define LVRecordFielName @"JPVRecord.caf"
@interface JPRecordTool ()
/** 播放器对象 */
@property (nonatomic, retain) AVAudioPlayer *player;
/** 录音文件地址 */
@property (nonatomic, copy) NSURL *recordFileUrl;
/** 定时器 */
@property (nonatomic, retain) NSTimer *timer;
@property (nonatomic, retain) AVAudioSession *session;
@end
@implementation JPRecordTool
- (void)startRecording {
// 录音时停止播放 删除曾经生成的文件
[self stopPlaying];
[self destructionRecordingFile];
[self setUp];
[self.recorder record];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(updateImage) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[timer fire];
self.timer = timer;
}
- (void)updateImage {
[self.recorder updateMeters];
double lowPassResults = pow(10, (0.05 * [self.recorder peakPowerForChannel:0]));
float result = 10 * (float)lowPassResults;
NSLog(@"%f", result);
int no = 0;
if (result > 0 && result <= 1.3) {
no = 1;
} else if (result > 1.3 && result <= 2) {
no = 2;
} else if (result > 2 && result <= 3.0) {
no = 3;
} else if (result > 3.0 && result <= 5.0) {
no = 4;
} else if (result > 5.0 && result <= 10) {
no = 5;
} else if (result > 10 && result <= 40) {
no = 6;
} else if (result > 40) {
no = 7;
}
if ([self.delegate respondsToSelector:@selector(recordTool:didstartRecoring:)]) {
[self.delegate recordTool:self didstartRecoring: no];
}
}
- (void)stopRecording {
[self.recorder stop];
[self.timer invalidate];
}
- (void)playRecordingFile {
// 播放时停止录音
[self.recorder stop];
// 正在播放就返回
if ([self.player isPlaying]) return;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:self.recordFileUrl error:NULL];
[self.player play];
}
- (void)stopPlaying {
[self.player stop];
}
static id instance;
#pragma mark - 单例
+ (instancetype)sharedRecordTool {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == nil) {
instance = [[self alloc] init];
}
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == nil) {
instance = [super allocWithZone:zone];
}
});
return instance;
}
- (void)creatRecorder:(NSMutableDictionary*)dic
{
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:self.recordFileUrl settings:dic error:NULL];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
self.recorder = recorder;
}
- (void) setUp
{
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *sessionError;
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
if(session == nil)
NSLog(@"Error creating session: %@", [sessionError description]);
else
[session setActive:YES error:nil];
self.session = session;
// 1.获取沙盒地址
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [path stringByAppendingPathComponent:LVRecordFielName];
self.recordFileUrl = [NSURL fileURLWithPath:filePath];
NSLog(@"%@", filePath);
// 3.设置录音的一些参数
NSMutableDictionary *setting = [NSMutableDictionary dictionary];
// 音频格式
setting[AVFormatIDKey] = @(kAudioFormatAppleIMA4);
// 录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量)
setting[AVSampleRateKey] = @(44100);
// 音频通道数 1 或 2
setting[AVNumberOfChannelsKey] = @(1);
// 线性音频的位深度 8、16、24、32
setting[AVLinearPCMBitDepthKey] = @(8);
//录音的质量
setting[AVEncoderAudioQualityKey] = [NSNumber numberWithInt:AVAudioQualityHigh];
[self creatRecorder:setting];
}
- (void)destructionRecordingFile {
NSFileManager *fileManager = [NSFileManager defaultManager];
if (self.recordFileUrl) {
[fileManager removeItemAtURL:self.recordFileUrl error:NULL];
}
}
#pragma mark - AVAudioRecorderDelegate
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
if (flag) {
NSLog(@"录音成功");
NSError *sessionError;
[self.session setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
}
}
@end
RecorderView.h
@interface RecorderView : UIView
+ (instancetype)recordView;
@end
RecorderView.m
#import "RecorderView.h"
#import "JPRecordTool.h"
@interface RecorderView ()@property (weak, nonatomic) IBOutlet UIButton *imageView;//添加播放麦克风图片(点击后依然可以录音)
@property (weak, nonatomic) IBOutlet UIButton *recorderButton;//录音按钮
@property (weak, nonatomic) IBOutlet UIButton *playButton;//播放按钮
@property (strong, nonatomic) JPRecordTool *recordTool;
@end
@implementation RecorderView
+ (instancetype)recordView {
RecorderView *recordView = [[[NSBundle mainBundle] loadNibNamed:@"RecorderView" owner:nil options:nil] lastObject];//此xib中可以完成自己的特殊需求,那三个按钮的摆放位置什么的都是自己定义的,笔者不说
recordView.recordTool = [JPRecordTool sharedRecordTool];
// 初始化监听事件
[recordView setup];
return recordView;
}
- (void)setup {
self.recorderButton.layer.cornerRadius = 10;
self.playButton.layer.cornerRadius = 10;
[self.recorderButton setTitle:@"按住 说话" forState:UIControlStateNormal];
[self.recorderButton setTitle:@"松开 结束" forState:UIControlStateHighlighted];
self.recordTool.delegate = self;
// 录音按钮
[self.recorderButton addTarget:self action:@selector(recordBtnDidTouchDown:) forControlEvents:UIControlEventTouchDown];
[self.recorderButton addTarget:self action:@selector(recordBtnDidTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
[self.recorderButton addTarget:self action:@selector(recordBtnDidTouchDragExit:) forControlEvents:UIControlEventTouchDragExit];
[self.imageView addTarget:self action:@selector(recordBtnDidTouchDown:) forControlEvents:UIControlEventTouchDown];
[self.imageView addTarget:self action:@selector(recordBtnDidTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
[self.imageView addTarget:self action:@selector(recordBtnDidTouchDragExit:) forControlEvents:UIControlEventTouchDragExit];
// 播放按钮
[self.playButton addTarget:self action:@selector(play) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark - 录音按钮事件
// 按下
- (void)recordBtnDidTouchDown:(UIButton *)recordBtn {
[self.recordTool startRecording];
}
// 点击
- (void)recordBtnDidTouchUpInside:(UIButton *)recordBtn {
double currentTime = self.recordTool.recorder.currentTime;
if (currentTime < 1) {
[self.imageView setImage:[UIImage imageNamed:@"mic_0"] forState:UIControlStateNormal];
[self alertWithMessage:@"说话时间太短"];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.recordTool stopRecording];
[self.recordTool destructionRecordingFile];
});
} else {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.recordTool stopRecording];
dispatch_async(dispatch_get_main_queue(), ^{
[self.imageView setImage:[UIImage imageNamed:@"mic_0"] forState:UIControlStateNormal]; });
});
// 已成功录音
NSLog(@"已成功录音");
}
}
// 手指从按钮上移除
- (void)recordBtnDidTouchDragExit:(UIButton *)recordBtn {
[self.imageView setImage:[UIImage imageNamed:@"mic_0"] forState:UIControlStateNormal]; dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self.recordTool stopRecording];
[self.recordTool destructionRecordingFile];
dispatch_async(dispatch_get_main_queue(), ^{
[self alertWithMessage:@"已取消录音"];
});
});
}
#pragma mark - 弹窗提示
- (void)alertWithMessage:(NSString *)message {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil];
[alert show];
}
#pragma mark - 播放录音
- (void)play {
[self.recordTool playRecordingFile];
}
#pragma mark - JPRecordToolDelegate
- (void)recordTool:(JPRecordTool *)recordTool didstartRecoring:(int)no {
NSString *imageName = [NSString stringWithFormat:@"mic_%d", no];
[self.imageView setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
}
@end
之所以封装成一个View,原因有很多,毕竟这只是个简单的录音,太分散不利于与App协调,最主要解决了模拟器可以录音播放通过真机不行的问题!希望对大家有用吧!