// // AudioRecorder.m // mask // // Created by 翟玉磊 on 2019/1/3. // Copyright © 2019 翟玉磊. All rights reserved. // #import "AudioRecorder.h" // 导入录音头文件(注意添加framework:AVFoundation.framework、AudioToolbox.framework) #import #import #import "NSTimer+Weak.h" @interface AudioRecorder () @property (nonatomic, strong) NSTimer *audioRecorderTimer; // 录音音量计时器 @property (nonatomic, strong) NSMutableDictionary *audioRecorderSetting; // 录音设置 @property (nonatomic, strong) AVAudioRecorder *audioRecorder; // 录音 @property (nonatomic, strong) AVAudioPlayer *audioPlayer; // 播放 @property (nonatomic, assign) double audioRecorderTime; // 录音时长 @end @implementation AudioRecorder /// 录音文件保存路径 NSString *GetFilePathWithDate() { NSDate *currentDate = [NSDate date]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"YYYYMMddHHmmss"]; NSString *filePath = [dateFormatter stringFromDate:currentDate]; filePath = [NSString stringWithFormat:@"%@.aac", filePath]; NSString *tmpPath = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"]; filePath = [tmpPath stringByAppendingFormat:@"/%@",filePath]; return filePath; } /// 获取文件名(包含后缀,如:xxx.acc;不包含文件类型,如xxx) NSString *GetFileNameWithFilePath(NSString *filePath, BOOL hasFileType) { NSString *fileName = [filePath stringByDeletingLastPathComponent]; if (hasFileType) { fileName = [filePath lastPathComponent]; } return fileName; } /// 获取文件大小 long long GetFileSizeWithFilePath(NSString *filePath) { BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath]; if (isExist) { NSDictionary *fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; long long fileSize = fileDict.fileSize; return fileSize; } return 0.0; } /// 删除文件 void DeleteFileWithFilePath(NSString *filePath) { BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath]; if (isExist) { [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; } } #pragma mark - 实例化 - (instancetype)init { self = [super init]; if (self) { // 参数设置 格式、采样率、录音通道、线性采样位数、录音质量 self.audioRecorderSetting = [NSMutableDictionary dictionary]; [self.audioRecorderSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey]; [self.audioRecorderSetting setValue:[NSNumber numberWithInt:11025] forKey:AVSampleRateKey]; [self.audioRecorderSetting setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey]; [self.audioRecorderSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey]; [self.audioRecorderSetting setValue:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey]; } return self; } /// 录音单例 + (AudioRecorder *)shareManager { static AudioRecorder *staticAudioRecorde; static dispatch_once_t once; dispatch_once(&once, ^{ staticAudioRecorde = [[self alloc] init]; }); return staticAudioRecorde; } // 内存释放 - (void)dealloc { // 内存释放前先停止录音,或音频播放 [self audioStop]; [self audioRecorderStop]; // 内存释放 if (self.audioRecorderTime) { [self.audioRecorderTimer invalidate]; self.audioRecorderTimer = nil; } if (self.audioRecorderSetting) { self.audioRecorderSetting = nil; } if (self.audioRecorder) { self.audioRecorder = nil; } if (self.audioPlayer) { self.audioPlayer = nil; } } #pragma mark - 音频处理-录音 /// 开始录音 - (void)audioRecorderStartWithFilePath:(NSString *)filePath { // 生成录音文件 NSURL *urlAudioRecorder = [NSURL fileURLWithPath:filePath]; self.audioRecorder = [[AVAudioRecorder alloc] initWithURL:urlAudioRecorder settings:self.audioRecorderSetting error:nil]; // 开启音量检测 [self.audioRecorder setMeteringEnabled:YES]; [self.audioRecorder setDelegate:self]; if (self.audioRecorder) { // 录音时设置audioSession属性,否则不兼容Ios7 AVAudioSession *recordSession = [AVAudioSession sharedInstance]; [recordSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; [recordSession setActive:YES error:nil]; if ([self.audioRecorder prepareToRecord]) { [self.audioRecorder record]; // 设置定时检测 WeakSelf self.audioRecorderTimer = [NSTimer scheduledTimerWithTimeInterval:0 event:^(NSTimer * _Nonnull timer) { [weakSelf detectionVoice]; }]; } } } /// 录音音量显示 - (void)detectionVoice { // 刷新音量数据 [self.audioRecorder updateMeters]; // // 获取音量的平均值 // [self.audioRecorder averagePowerForChannel:0]; // // 音量的最大值 // [self.audioRecorder peakPowerForChannel:0]; double lowPassResults = pow(10, (0.05 * [self.audioRecorder peakPowerForChannel:0])); double currentTime = self.audioRecorder.currentTime; // NSLog(@"lowPassResults:%.2f", lowPassResults); if (self.detectionVoiceBlock) { self.detectionVoiceBlock(lowPassResults, currentTime); } } /// 停止录音 - (void)audioRecorderStop { if (self.audioRecorder) { if ([self.audioRecorder isRecording]) { // 获取录音时长 self.audioRecorderTime = [self.audioRecorder currentTime]; [self.audioRecorder stop]; // 停止录音后释放掉 self.audioRecorder = nil; } } // 释放计时器 [self.audioRecorderTimer invalidate]; self.audioRecorderTimer = nil; } /// 根据录音文件获取录音时长 - (NSTimeInterval)durationAudioRecorderWithFilePath:(NSString *)filePath { NSURL *urlFile = [NSURL fileURLWithPath:filePath]; self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:urlFile error:nil]; NSTimeInterval time = self.audioPlayer.duration; self.audioPlayer = nil; return time; } #pragma mark - 音频处理-播放/停止 /// 音频开始播放或停止 - (void)audioPlayWithFilePath:(NSString *)filePath { if (self.audioPlayer) { // 判断当前与下一个是否相同 // 相同时,点击时要么播放,要么停止 // 不相同时,点击时停止播放当前的,开始播放下一个 NSString *currentStr = [self.audioPlayer.url relativeString]; // currentStr包含字符"file://location/",通过判断filePath是否为currentPath的子串,是则相同,否则不同 NSRange range = [currentStr rangeOfString:filePath]; if (range.location != NSNotFound) { if ([self.audioPlayer isPlaying]) { [self.audioPlayer stop]; self.audioPlayer = nil; } else { self.audioPlayer = nil; [self audioPlayerPlay:filePath]; } } else { [self audioPlayerStop]; [self audioPlayerPlay:filePath]; } } else { [self audioPlayerPlay:filePath]; } } /// 音频播放停止 - (void)audioStop { [self audioPlayerStop]; } - (BOOL)playing { return self.audioPlayer.playing; } /// 音频播放器开始播放 - (void)audioPlayerPlay:(NSString *)filePath { // 判断将要播放文件是否存在 BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath]; if (!isExist) { return; } NSURL *urlFile = [NSURL fileURLWithPath:filePath]; self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:urlFile error:nil]; self.audioPlayer.delegate = self; if (self.audioPlayer) { if ([self.audioPlayer prepareToPlay]) { // 播放时,设置喇叭播放否则音量很小 AVAudioSession *playSession = [AVAudioSession sharedInstance]; [playSession setCategory:AVAudioSessionCategoryPlayback error:nil]; [playSession setActive:YES error:nil]; [self.audioPlayer play]; } } } /// 音频播放器停止播放 - (void)audioPlayerStop { if (self.audioPlayer) { if ([self.audioPlayer isPlaying]) { [self.audioPlayer stop]; } self.audioPlayer = nil; } if (self.playerFinished) { self.playerFinished(); } } - (void)clear { if (_audioRecorderTimer) { [_audioRecorderTimer invalidate]; _audioRecorderTimer = nil; } if (_audioRecorder) { [_audioRecorder stop]; _audioRecorder = nil; } if (_audioPlayer) { [_audioPlayer stop]; _audioPlayer = nil; } } #pragma mark - AVAudioPlayerDelegate /// 播放完成时调用的方法 (代理里的方法),需要设置代理才可以调用 - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { [self audioPlayerStop]; } @end