將錄音及播放等功能封裝到View中(真機(jī)過(guò)不去的看這里)

有一些人喜歡用第三方,我還是比較喜歡用自己封裝的,每次更改內(nèi)部什么的都熟悉!

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

共包含兩個(gè)文件JPRecordToolRecorderView,前者是個(gè)工具類,為后者服務(wù),如果有其他需求只用前者來(lái)完成自己的特殊需求,如果只是簡(jiǎn)單的需求,只用控制后者即可,代碼如下:

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;
/** 錄音對(duì)象 */
@property (nonatomic, strong) AVAudioRecorder *recorder;
/** 更新圖片的代理 */
@property (nonatomic, assign) iddelegate;
@end

JPRecordTool.m

#import "JPRecordTool.h"
#define LVRecordFielName @"JPVRecord.caf"
@interface JPRecordTool ()
/** 播放器對(duì)象 */
@property (nonatomic, retain) AVAudioPlayer *player;
/** 錄音文件地址 */
@property (nonatomic, copy) NSURL *recordFileUrl;
/** 定時(shí)器 */
@property (nonatomic, retain) NSTimer *timer;
@property (nonatomic, retain) AVAudioSession *session;
@end
@implementation JPRecordTool
- (void)startRecording {
// 錄音時(shí)停止播放 刪除曾經(jīng)生成的文件
[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 {
// 播放時(shí)停止錄音
[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.設(shè)置錄音的一些參數(shù)
NSMutableDictionary *setting = [NSMutableDictionary dictionary];
// 音頻格式
setting[AVFormatIDKey] = @(kAudioFormatAppleIMA4);
// 錄音采樣率(Hz) 如:AVSampleRateKey==8000/44100/96000(影響音頻的質(zhì)量)
setting[AVSampleRateKey] = @(44100);
// 音頻通道數(shù) 1 或 2
setting[AVNumberOfChannelsKey] = @(1);
// 線性音頻的位深度  8、16、24徐伐、32
setting[AVLinearPCMBitDepthKey] = @(8);
//錄音的質(zhì)量
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;//添加播放麥克風(fēng)圖片(點(diǎn)擊后依然可以錄音)
@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中可以完成自己的特殊需求,那三個(gè)按鈕的擺放位置什么的都是自己定義的,筆者不說(shuō)
recordView.recordTool = [JPRecordTool sharedRecordTool];
// 初始化監(jiān)聽事件
[recordView setup];
return recordView;
}
- (void)setup {
self.recorderButton.layer.cornerRadius = 10;
self.playButton.layer.cornerRadius = 10;
[self.recorderButton setTitle:@"按住 說(shuō)話" forState:UIControlStateNormal];
[self.recorderButton setTitle:@"松開 結(jié)束" 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];
}
// 點(diǎn)擊
- (void)recordBtnDidTouchUpInside:(UIButton *)recordBtn {
double currentTime = self.recordTool.recorder.currentTime;
if (currentTime < 1) {
[self.imageView setImage:[UIImage imageNamed:@"mic_0"] forState:UIControlStateNormal];
[self alertWithMessage:@"說(shuō)話時(shí)間太短"];
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

之所以封裝成一個(gè)View,原因有很多,畢竟這只是個(gè)簡(jiǎn)單的錄音,太分散不利于與App協(xié)調(diào),最主要解決了模擬器可以錄音播放通過(guò)真機(jī)不行的問(wèn)題!希望對(duì)大家有用吧!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末研侣,一起剝皮案震驚了整個(gè)濱河市童漩,隨后出現(xiàn)的幾起案子翘悉,更是在濱河造成了極大的恐慌春贸,老刑警劉巖唯欣,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘹吨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡境氢,警方通過(guò)查閱死者的電腦和手機(jī)躺苦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)产还,“玉大人匹厘,你說(shuō)我怎么就攤上這事∑昵” “怎么了愈诚?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)牛隅。 經(jīng)常有香客問(wèn)我炕柔,道長(zhǎng),這世上最難降的妖魔是什么媒佣? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任匕累,我火速辦了婚禮,結(jié)果婚禮上默伍,老公的妹妹穿的比我還像新娘欢嘿。我一直安慰自己,他們只是感情好也糊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布炼蹦。 她就那樣靜靜地躺著,像睡著了一般狸剃。 火紅的嫁衣襯著肌膚如雪掐隐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天钞馁,我揣著相機(jī)與錄音虑省,去河邊找鬼。 笑死僧凰,一個(gè)胖子當(dāng)著我的面吹牛探颈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播允悦,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼膝擂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼虑啤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起架馋,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤狞山,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后叉寂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萍启,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年屏鳍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勘纯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钓瞭,死狀恐怖驳遵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情山涡,我是刑警寧澤堤结,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鸭丛,受9級(jí)特大地震影響竞穷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳞溉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一瘾带、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧熟菲,春花似錦看政、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)菜皂。三九已至贞绵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恍飘,已是汗流浹背榨崩。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留章母,地道東北人母蛛。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乳怎,于是被迫代替她去往敵國(guó)和親彩郊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容