// // YOUPAILZSoundRecordView.m // MSYOUPAI // // Created by CY on 2022/3/16. // Copyright © 2022 MS. All rights reserved. // #import "YOUPAILZSoundRecordView.h" #import "NSURL+TransferFileFormat.h" #import "LZCircleView.h" @interface YOUPAILZSoundRecordView () @property (nonatomic, weak)UILabel *youpaiptimeL; @property (nonatomic, weak)LZCircleView *youpaipcircleView; /// 录制 @property (nonatomic, strong)AVAudioRecorder *youpaiprecorder; @property (nonatomic, strong)NSURL *youpaiprecordAudioUrl; /// 播放 @property (nonatomic, strong)AVAudioPlayer *youpaipaudioPlayer; @property (nonatomic,strong)NSTimer *youpaiptimer; @property (nonatomic,assign)NSInteger youpaipplayTime; @property (nonatomic,assign) LZSoundRecordState youpaipstate; @end @implementation YOUPAILZSoundRecordView - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { [self youpaifinitValue]; [self youpaifsetupUI]; self.youpaipstate = LZSoundRecordStateNone; } return self; } - (void)youpaifinitValue{ self.youpaipminTimer = 2; self.youpaipmaxTimer = 8; self.youpaiptype = LZAudioTypeWithPM3; } - (void)youpaifsetupUI{ UILabel *timeL = [[UILabel alloc] init]; timeL.font = LCFont12; timeL.textColor = LZ273145Color; timeL.text = @"0s"; [self addSubview:timeL]; self.youpaiptimeL = timeL; [timeL mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); make.top.offset(-10.0f); }]; LZCircleView *circleView = [[LZCircleView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 74.0f, 74.0f)]; circleView.progress = 0.0f; circleView.progerssColor = HexColorFromRGB(0xFDD45E); circleView.progerssBackgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.13f]; circleView.progerWidth = 2.5f; circleView.backgroundProgerWidth = 1.0f; circleView.hidden = YES; [self addSubview:circleView]; self.youpaipcircleView = circleView; [circleView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); make.top.equalTo(timeL.mas_bottom).offset(14.0f); make.size.mas_offset(CGSizeMake(74.0f, 74.0f)); }]; UIButton *centerBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [centerBtn addTarget:self action:@selector(youpaifcenterBtnClick) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:centerBtn]; self.youpaiprecordBtn = centerBtn; [centerBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(circleView); make.size.mas_offset(CGSizeMake(65.0f, 65.0f)); }]; UILabel *descL = [[UILabel alloc] init]; descL.font = LCFont12; descL.textColor = LZA3AABEColor; descL.text = [NSString stringWithFormat:@"录制一段%@~%@秒的语音",@(self.youpaipminTimer),@(self.youpaipmaxTimer)]; [self addSubview:descL]; self.youpaipdescL = descL; [descL mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self); make.top.equalTo(centerBtn.mas_bottom).offset(15.0f); }]; UIButton *leftBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [leftBtn addTarget:self action:@selector(youpaifleftBtnClick) forControlEvents:UIControlEventTouchUpInside]; leftBtn.titleLabel.font = LCFont16; leftBtn.backgroundColor = LZF5F4F7Color; leftBtn.layer.cornerRadius = 24.0f; leftBtn.clipsToBounds = YES; [leftBtn setTitleColor:LZ273145Color forState:UIControlStateNormal]; [leftBtn setTitle:@"重录" forState:UIControlStateNormal]; leftBtn.hidden = YES; [self addSubview:leftBtn]; self.youpaipreRecordBtn = leftBtn; [leftBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(descL.mas_bottom).offset(20.0f); make.size.mas_offset(CGSizeMake(135.0f, 48.0f)); make.centerX.equalTo(self); }]; } - (void)youpaifleftBtnClick{ [self youpaifstopTimer]; self.youpaipstate = LZSoundRecordStateNone; self.youpaiprecordAudioUrl = nil; self.youpaiprecorder = nil; // 停止播放 [self.youpaipaudioPlayer stop]; self.youpaipaudioPlayer = nil; } - (void)youpaifcenterBtnClick{ if(self.youpaipstate == LZSoundRecordStateNone){ self.youpaipstate = LZSoundRecordStateStart; //创建录音通道 [self setAudioSession]; // 开始录音 [self.youpaiprecorder record]; // 检查权限 [self youpaifsetupAuthority]; self.youpaipaudioTime = 0; [self youpaifstartTimer]; }else if(self.youpaipstate == LZSoundRecordStateFinish){ self.youpaipstate = LZSoundRecordStatePlay; // UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback; // AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory); UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker; AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride); AVAudioSession * session = [AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCategory:AVAudioSessionCategoryPlayback error:nil]; NSError *error; self.youpaipaudioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:self.youpaiprecordAudioUrl error:&error]; if (error) { NSLog(@"%@",error); } self.youpaipaudioPlayer.delegate = self; // 播放 [self.youpaipaudioPlayer play]; self.youpaipplayTime = self.youpaipaudioTime; [self youpaifstartTimer]; }else if (self.youpaipstate == LZSoundRecordStatePlay){ self.youpaipstate = LZSoundRecordStateFinish; // 停止播放 [self.youpaipaudioPlayer stop]; self.youpaipaudioPlayer = nil; [self youpaifstopTimer]; }else if (self.youpaipstate == LZSoundRecordStateStart){ self.youpaipstate = LZSoundRecordStateFinish; // 停止录制 [self.youpaiprecorder stop]; self.youpaiprecorder = nil; [self youpaifstopTimer]; if (self.youpaipaudioTime < self.youpaipminTimer) { [ZCHUDHelper showTitle:[NSString stringWithFormat:@"录音不可少于%@秒",@(self.youpaipminTimer)]]; [self youpaifleftBtnClick]; } } } - (NSURL*)getSubmitSound{ [self youpaifstopTimer]; // 停止播放 [self.youpaipaudioPlayer stop]; if (_youpaipstate < LZSoundRecordStateFinish){ return nil; } NSURL *returnurl = nil; switch (self.youpaiptype) { case LZAudioTypeWithPM3: returnurl = [self.youpaiprecordAudioUrl transformCAFToMP3]; break; case LZAudioTypeWithAAC:{ returnurl = self.youpaiprecordAudioUrl; } break; default: break; } return returnurl; } - (void)setYoupaipstate:(LZSoundRecordState)state{ _youpaipstate = state; NSString *time = @""; NSString *desc = @""; self.youpaipreRecordBtn.hidden = YES; // self.youpaiprightBtn.hidden = YES; self.youpaipcircleView.hidden = YES; self.youpaipcircleView.progress = 0.0f; UIImage *centerImg = nil; // UIImage *leftImg = nil; // UIImage *rightImg = nil; switch (state) { case LZSoundRecordStateNone:{ time = @"0s"; desc = [NSString stringWithFormat:@"录制一段%@~%@秒的语音",@(self.youpaipminTimer),@(self.youpaipmaxTimer)]; centerImg = [UIImage imageNamed:@"vqu_images_big_cast_audio_none"]; } break; case LZSoundRecordStateStart:{ time = @"0s"; desc = @"点击结束录音"; centerImg = [UIImage imageNamed:@"vqu_images_big_cast_audio_start"]; self.youpaipcircleView.hidden = NO; [self youpaifprogressAnimation]; } break; case LZSoundRecordStateFinish:{ time = [NSString stringWithFormat:@"%@s",@(self.youpaipaudioTime)]; desc = @"点击试听"; centerImg = [UIImage imageNamed:@"vqu_images_big_cast_audio_finish"]; self.youpaipreRecordBtn.hidden = NO; // leftImg = [UIImage imageNamed:@"vqu_images_big_case_audio_re_record"]; // rightImg = [UIImage imageNamed:@"vqu_images_big_cast_audio_submit"]; // self.youpaipleftBtn.hidden = NO; // self.youpaiprightBtn.hidden = NO; // [self.youpaipleftBtn setTitle:@"重录" forState:UIControlStateNormal]; // [self.youpaiprightBtn setTitle:@"确定" forState:UIControlStateNormal]; } break; case LZSoundRecordStatePlay:{ time = [NSString stringWithFormat:@"%@s",@(self.youpaipaudioTime)]; desc = @"播放中"; centerImg = [UIImage imageNamed:@"vqu_images_big_cast_audio_play1"]; self.youpaipreRecordBtn.hidden = NO; } break; case LZSoundRecordStateSubmit:{ // time = [self timeFormatted:self.audioTime]; // desc = @"已录制"; // centerImg = [UIImage imageNamed:@"vqu_images_game_audio_success"]; } break; default: break; } self.youpaiptimeL.text = time; self.youpaipdescL.text = desc; // [self.youpaipleftBtn setImage:leftImg forState:UIControlStateNormal]; // [self.youpaiprightBtn setImage:rightImg forState:UIControlStateNormal]; [self.youpaiprecordBtn setBackgroundImage:centerImg forState:UIControlStateNormal]; // [self youpaifinitButton:self.youpaipleftBtn]; // [self youpaifinitButton:self.youpaiprightBtn]; } #pragma mark - AVAudioPlayerDelegate - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ self.youpaipstate = LZSoundRecordStateFinish; // 停止播放 [self.youpaipaudioPlayer stop]; self.youpaipaudioPlayer = nil; [self youpaifstopTimer]; } - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error{ self.youpaipstate = LZSoundRecordStateFinish; // 停止播放 [self.youpaipaudioPlayer stop]; self.youpaipaudioPlayer = nil; [self youpaifstopTimer]; } - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{ self.youpaipstate = LZSoundRecordStateFinish; // 停止播放 [self.youpaipaudioPlayer stop]; self.youpaipaudioPlayer = nil; [self youpaifstopTimer]; } #pragma mark - AVAudioRecorderDelegate - (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * _Nullable)error{ self.youpaipstate = LZSoundRecordStateFinish; // 停止录制 [self.youpaiprecorder stop]; self.youpaiprecorder = nil; [self youpaifstopTimer]; } - (void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder{ self.youpaipstate = LZSoundRecordStateFinish; // 停止录制 [self.youpaiprecorder stop]; self.youpaiprecorder = nil; [self youpaifstopTimer]; } // 开始计时 - (void)youpaifstartTimer{ self.youpaiptimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(youpaiftimerAction) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.youpaiptimer forMode:NSRunLoopCommonModes]; } // 结束计时 - (void)youpaifstopTimer{ [self.youpaiptimer invalidate]; self.youpaiptimer = nil; self.youpaiptimeL.text = [NSString stringWithFormat:@"%@s",@(self.youpaipaudioTime)]; } - (void)youpaifprogressAnimation{ __block CGFloat timeout = 0.0f; dispatch_queue_t queue = dispatch_get_global_queue(0, 0); dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 0.025f * NSEC_PER_SEC, 0 * NSEC_PER_SEC); //3.设置定时器要执行的任务 dispatch_source_set_event_handler(_timer, ^{ if(timeout >= 1.0f){ dispatch_source_cancel(_timer); dispatch_async(dispatch_get_main_queue(), ^{ }); }else{ timeout += 0.025f; CGFloat currentTime = (CGFloat)self.youpaipaudioTime + timeout; dispatch_async(dispatch_get_main_queue(), ^{ self.youpaipcircleView.progress = currentTime / (CGFloat)self.youpaipmaxTimer; }); } }); dispatch_resume(_timer); } - (void)youpaiftimerAction{ if (self.youpaipstate == LZSoundRecordStateStart) { self.youpaipaudioTime ++; self.youpaiptimeL.text = [NSString stringWithFormat:@"%@s",@(self.youpaipaudioTime)]; [self youpaifprogressAnimation]; if (self.youpaipaudioTime >= self.youpaipmaxTimer) { self.youpaipstate = LZSoundRecordStateFinish; // 停止录制 [self.youpaiprecorder stop]; self.youpaiprecorder = nil; [self youpaifstopTimer]; } }else if (self.youpaipstate == LZSoundRecordStatePlay){ self.youpaipplayTime --; self.youpaiptimeL.text = [NSString stringWithFormat:@"%@s",@(self.youpaipplayTime)]; } } //- (NSString *)timeFormatted:(NSInteger)totalSeconds{ // NSInteger seconds = totalSeconds % 60; // NSInteger minutes = (totalSeconds / 60); // return [NSString stringWithFormat:@"%02ld:%02ld", minutes, seconds]; //} /// 视频本地url路径 - (NSURL *)youpaiprecordAudioUrl{ if (!_youpaiprecordAudioUrl) { NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) lastObject]; NSString *fileName; if (self.youpaiptype == LZAudioTypeWithAAC) { fileName = @"audioVerify.aac"; }else{ fileName = @"audioVerify.caf"; } _youpaiprecordAudioUrl = [NSURL fileURLWithPath:[path stringByAppendingPathComponent:fileName]]; if ([[NSFileManager defaultManager] fileExistsAtPath:_youpaiprecordAudioUrl.resourceSpecifier]){ [[NSFileManager defaultManager] removeItemAtPath:_youpaiprecordAudioUrl.resourceSpecifier error:nil]; } } return _youpaiprecordAudioUrl; } - (AVAudioRecorder *)youpaiprecorder{ if (_youpaiprecorder == nil) { //创建录音机 NSError *error=nil; _youpaiprecorder = [[AVAudioRecorder alloc] initWithURL:self.youpaiprecordAudioUrl settings:[self getAudioSetting] error:&error]; _youpaiprecorder.delegate = self; if (error) { NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription); return nil; } } return _youpaiprecorder; } /** * 取得录音文件设置 * * @return 录音设置 */ -(NSDictionary *)getAudioSetting{ if (self.youpaiptype == LZAudioTypeWithAAC) { NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc]init] ; //设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey]; //设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量) [recordSetting setValue:[NSNumber numberWithFloat:44100] forKey:AVSampleRateKey]; //录音通道数 1 或 2 [recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey]; //线性采样位数 8、16、24、32 [recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey]; //录音的质量 [recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityMedium] forKey:AVEncoderAudioQualityKey]; return recordSetting.copy; }else{ NSDictionary *recordSetting = @{ AVFormatIDKey : @(kAudioFormatLinearPCM), AVSampleRateKey : @(44100), AVNumberOfChannelsKey : @(2), AVLinearPCMBitDepthKey : @(16), AVLinearPCMIsNonInterleaved : @NO, AVLinearPCMIsFloatKey : @NO, AVLinearPCMIsBigEndianKey : @NO, }; return recordSetting; } } /// 权限 - (void)youpaifsetupAuthority{ [UCAuthorityManager microPhoneAuthority:^{ } denied:^{ [self youpaifshowAlertVCWithTitle:@"请在iphone的“设置-隐私-麦克风”选项中,允许APP访问您的麦克风。"]; }]; } - (void)youpaifshowAlertVCWithTitle:(NSString *)title{ UIAlertController *systemAlert = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"现在去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action){ if ([[UIDevice currentDevice].systemVersion floatValue] < 10.0) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; } else { // 去系统设置页面 if (@available(iOS 10.0, *)) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil]; } else { // Fallback on earlier versions } } }]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; [systemAlert addAction:cancelAction]; [systemAlert addAction:action]; dispatch_async(dispatch_get_main_queue(), ^{ [[LCTools getCurrentVC] presentViewController: systemAlert animated: YES completion: nil]; }); } - (void)setAudioSession{ 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]; } } - (void)youpaifstopSoundRecord{ [self youpaifstopTimer]; self.youpaiprecordAudioUrl = nil; self.youpaiprecorder = nil; // 停止播放 [self.youpaipaudioPlayer stop]; self.youpaipaudioPlayer = nil; } - (void)dealloc{ [self youpaifstopSoundRecord]; } @end