You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
12 KiB
323 lines
12 KiB
// |
|
// XHVoiceRecordHelper.m |
|
// MessageDisplayExample |
|
// |
|
// Created by HUAJIE-1 on 14-5-13. |
|
// Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. |
|
// |
|
#import <UIKit/UIKit.h> |
|
|
|
#import "XHVoiceRecordHelper.h" |
|
#import "XHMacro.h" |
|
|
|
//#import "SVProgressHUD.h" |
|
|
|
#import "JLAuthorizationManager.h" |
|
#import "myHelper.h" |
|
|
|
@interface XHVoiceRecordHelper () <AVAudioRecorderDelegate> { |
|
NSTimer *_timer; |
|
|
|
BOOL _isPause; |
|
|
|
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE |
|
UIBackgroundTaskIdentifier _backgroundIdentifier; |
|
#endif |
|
} |
|
|
|
@property (nonatomic, copy, readwrite) NSString *recordPath; |
|
@property (nonatomic, readwrite) NSTimeInterval currentTimeInterval; |
|
|
|
|
|
@end |
|
|
|
@implementation XHVoiceRecordHelper |
|
|
|
- (id)init { |
|
self = [super init]; |
|
if (self) { |
|
self.maxRecordTime = kVoiceRecorderTotalTime; |
|
self.recordDuration = @(0); |
|
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE |
|
_backgroundIdentifier = UIBackgroundTaskInvalid; |
|
#endif |
|
} |
|
return self; |
|
} |
|
|
|
- (void)dealloc { |
|
[self stopRecord]; |
|
self.recordPath = nil; |
|
[self stopBackgroundTask]; |
|
} |
|
|
|
- (void)startBackgroundTask { |
|
[self stopBackgroundTask]; |
|
|
|
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE |
|
_backgroundIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ |
|
[self stopBackgroundTask]; |
|
}]; |
|
#endif |
|
} |
|
|
|
- (void)stopBackgroundTask { |
|
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE |
|
if (_backgroundIdentifier != UIBackgroundTaskInvalid) { |
|
[[UIApplication sharedApplication] endBackgroundTask:_backgroundIdentifier]; |
|
_backgroundIdentifier = UIBackgroundTaskInvalid; |
|
} |
|
#endif |
|
} |
|
|
|
- (void)resetTimer { |
|
if (!_timer) |
|
return; |
|
|
|
if (_timer) { |
|
[_timer invalidate]; |
|
_timer = nil; |
|
} |
|
|
|
} |
|
|
|
- (void)cancelRecording { |
|
if (!_recorder) |
|
return; |
|
|
|
if (self.recorder.isRecording) { |
|
[self.recorder stop]; |
|
} |
|
|
|
self.recorder = nil; |
|
} |
|
|
|
- (void)stopRecord { |
|
[self cancelRecording]; |
|
[self resetTimer]; |
|
} |
|
|
|
- (BOOL)canRecord |
|
{ |
|
__block BOOL bCanRecord = NO; |
|
JLAuthorizationManager *jlManager = [JLAuthorizationManager defaultManager]; |
|
[jlManager JL_requestAuthorizationWithAuthorizationType:JLAuthorizationTypeAudio |
|
authorizedHandler:^{ |
|
bCanRecord = YES; |
|
} |
|
unAuthorizedHandler:^{}]; |
|
|
|
return bCanRecord; |
|
} |
|
|
|
- (void)prepareRecordingWithPath:(NSString *)path prepareRecorderCompletion:(XHPrepareRecorderCompletion)prepareRecorderCompletion { |
|
|
|
WEAKSELF |
|
JLAuthorizationManager *jlManager = [JLAuthorizationManager defaultManager]; |
|
[jlManager JL_requestAuthorizationWithAuthorizationType:JLAuthorizationTypeAudio |
|
authorizedHandler:nil |
|
unAuthorizedHandler:^{ |
|
LGAlertView *alertView = [[LGAlertView alloc] initWithTitle:[NSString stringWithFormat:@"请为%@打开麦克风权限",APPName] message:nil style:LGAlertViewStyleAlert buttonTitles:@[@"确定"] cancelButtonTitle:@"取消" destructiveButtonTitle:nil actionHandler:^(LGAlertView *alertView, NSString *title, NSUInteger index) { |
|
|
|
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; |
|
|
|
} cancelHandler:^(LGAlertView *alertView) { |
|
|
|
} destructiveHandler:nil]; |
|
[alertView showAnimated:YES completionHandler:nil]; |
|
}]; |
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
|
_isPause = NO; |
|
|
|
NSError *error = nil; |
|
AVAudioSession *audioSession = [AVAudioSession sharedInstance]; |
|
[audioSession setCategory :AVAudioSessionCategoryPlayAndRecord error:&error]; |
|
if(error) { |
|
DLog(@"audioSession: %@ %ld %@", [error domain], (long)[error code], [[error userInfo] description]); |
|
return; |
|
} |
|
|
|
error = nil; |
|
[audioSession setActive:YES error:&error]; |
|
if(error) { |
|
DLog(@"audioSession: %@ %ld %@", [error domain], (long)[error code], [[error userInfo] description]); |
|
return; |
|
} |
|
|
|
//MARK: 设置录音设置 |
|
NSDictionary * recordSetting = @{ |
|
AVSampleRateKey:[NSNumber numberWithFloat:8000.0], //采样率 |
|
AVFormatIDKey:[NSNumber numberWithInt:kAudioFormatLinearPCM], |
|
AVLinearPCMBitDepthKey:[NSNumber numberWithInt:16],//采样位数 默认 16 |
|
AVNumberOfChannelsKey:[NSNumber numberWithInt:2],//通道的数目 |
|
AVEncoderBitRateKey:[NSNumber numberWithFloat:128000], |
|
// [recordSetting setValue :[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey]; |
|
// [recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey]; |
|
// [recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey]; |
|
// AVEncoderAudioQualityKey: [NSNumber numberWithInt: AVAudioQualityMax],//音频编码质量 |
|
AVEncoderAudioQualityKey: [NSNumber numberWithInt: AVAudioQualityHigh],//音频编码质量 |
|
}; |
|
|
|
// MARK: 乐家守护录音设置参数 |
|
NSDictionary *recordSetting2 = [[NSDictionary alloc] initWithObjectsAndKeys: |
|
[NSNumber numberWithFloat: 8000.0],AVSampleRateKey, //采样率 |
|
[NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey, |
|
[NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//采样位数 默认 16 |
|
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,//通道的数目 |
|
// [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,//大端还是小端 是内存的组织方式 |
|
// [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,//采样信号是整数还是浮点数 |
|
// [NSNumber numberWithInt: AVAudioQualityMedium],AVEncoderAudioQualityKey,//音频编码质量 |
|
nil]; |
|
|
|
if (weakSelf) { |
|
STRONGSELF |
|
strongSelf.recordPath = path; |
|
error = nil; |
|
|
|
if (strongSelf.recorder) { |
|
[strongSelf cancelRecording]; |
|
} else { |
|
strongSelf.recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:strongSelf.recordPath] settings:recordSetting2 error:&error]; |
|
strongSelf.recorder.delegate = strongSelf; |
|
[strongSelf.recorder prepareToRecord]; |
|
strongSelf.recorder.meteringEnabled = YES; |
|
[strongSelf.recorder recordForDuration:(NSTimeInterval) 160]; |
|
[strongSelf startBackgroundTask]; |
|
} |
|
|
|
if(error) { |
|
DLog(@"audioSession: %@ %ld %@", [error domain], (long)[error code], [[error userInfo] description]); |
|
return; |
|
} |
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
|
|
//上層如果傳會來說已經取消了, 那這邊就做原先取消的動作 |
|
if (!prepareRecorderCompletion()) { |
|
[strongSelf cancelledDeleteWithCompletion:^{ |
|
}]; |
|
} |
|
}); |
|
} |
|
}); |
|
} |
|
|
|
- (void)startRecordingWithStartRecorderCompletion:(XHStartRecorderCompletion)startRecorderCompletion { |
|
if ([_recorder record]) { |
|
[self resetTimer]; |
|
_timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateMeters) userInfo:nil repeats:YES]; |
|
if (startRecorderCompletion) |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
startRecorderCompletion(); |
|
}); |
|
} |
|
} |
|
|
|
- (void)resumeRecordingWithResumeRecorderCompletion:(XHResumeRecorderCompletion)resumeRecorderCompletion { |
|
_isPause = NO; |
|
if (_recorder) { |
|
if ([_recorder record]) { |
|
dispatch_async(dispatch_get_main_queue(), resumeRecorderCompletion); |
|
} |
|
} |
|
} |
|
|
|
- (void)pauseRecordingWithPauseRecorderCompletion:(XHPauseRecorderCompletion)pauseRecorderCompletion { |
|
_isPause = YES; |
|
if (_recorder) { |
|
[_recorder pause]; |
|
} |
|
if (!_recorder.isRecording) |
|
dispatch_async(dispatch_get_main_queue(), pauseRecorderCompletion); |
|
} |
|
|
|
- (void)stopRecordingWithStopRecorderCompletion:(XHStopRecorderCompletion)stopRecorderCompletion { |
|
_isPause = NO; |
|
[self stopBackgroundTask]; |
|
[self stopRecord]; |
|
[self getVoiceDuration:_recordPath]; |
|
dispatch_async(dispatch_get_main_queue(), stopRecorderCompletion); |
|
} |
|
|
|
- (void)cancelledDeleteWithCompletion:(XHCancellRecorderDeleteFileCompletion)cancelledDeleteCompletion { |
|
|
|
_isPause = NO; |
|
[self stopBackgroundTask]; |
|
[self stopRecord]; |
|
|
|
if (self.recordPath) { |
|
// 删除目录下的文件 |
|
NSFileManager *fileManeger = [NSFileManager defaultManager]; |
|
if ([fileManeger fileExistsAtPath:self.recordPath]) { |
|
NSError *error = nil; |
|
[fileManeger removeItemAtPath:self.recordPath error:&error]; |
|
if (error) { |
|
DLog(@"error :%@", error.description); |
|
} |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
cancelledDeleteCompletion(error); |
|
}); |
|
} else { |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
cancelledDeleteCompletion(nil); |
|
}); |
|
} |
|
} else { |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
cancelledDeleteCompletion(nil); |
|
}); |
|
} |
|
} |
|
|
|
- (void)updateMeters { |
|
if (!_recorder) |
|
return; |
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
|
[_recorder updateMeters]; |
|
|
|
self.currentTimeInterval = _recorder.currentTime; |
|
|
|
if (!_isPause) { |
|
float progress = self.currentTimeInterval / self.maxRecordTime * 1.0; |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
if (_recordProgress) { |
|
_recordProgress(self.currentTimeInterval); |
|
} |
|
}); |
|
} |
|
|
|
float peakPower = [_recorder averagePowerForChannel:0]; |
|
double ALPHA = 0.015; |
|
double peakPowerForChannel = pow(10, (ALPHA * peakPower)); |
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
// 更新扬声器 |
|
if (_peakPowerForChannel) { |
|
_peakPowerForChannel(peakPowerForChannel); |
|
} |
|
}); |
|
|
|
NSLog(@"----%f",self.currentTimeInterval); |
|
if (self.currentTimeInterval > self.maxRecordTime) { |
|
[self stopRecord]; |
|
dispatch_async(dispatch_get_main_queue(), ^{ |
|
_maxTimeStopRecorderCompletion(); |
|
}); |
|
} |
|
}); |
|
} |
|
|
|
- (void)getVoiceDuration:(NSString*)recordPath { |
|
NSError *error = nil; |
|
AVAudioPlayer *play = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recordPath] error:&error]; |
|
if (error) { |
|
DLog(@"recordPath:%@ error:%@", recordPath, error); |
|
self.recordDuration = @(0); |
|
} else { |
|
DLog(@"时长:%f", play.duration); |
|
self.recordDuration = @(play.duration); |
|
} |
|
} |
|
|
|
@end
|
|
|