将录音及播放等功能封装到View中(真机过不去的看这里)

有一些人喜欢用第三方,我还是比较喜欢用自己封装的,每次更改内部什么的都熟悉!

55225BC9-A8C8-40B2-A01C-E20E396874B8.png

共包含两个文件JPRecordToolRecorderView,前者是个工具类,为后者服务,如果有其他需求只用前者来完成自己的特殊需求,如果只是简单的需求,只用控制后者即可,代码如下:

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协调,最主要解决了模拟器可以录音播放通过真机不行的问题!希望对大家有用吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容