YMRecordSoundView.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. //
  2. // YMRecordSoundView.m
  3. // MSYOUPAI
  4. //
  5. // Created by YoMi on 2024/2/25.
  6. // Copyright © 2024 MS. All rights reserved.
  7. //
  8. #import "YMRecordSoundView.h"
  9. #import "NSURL+TransferFileFormat.h"
  10. #import "YMCircleView.h"
  11. @interface YMRecordSoundView ()<AVAudioPlayerDelegate,AVAudioRecorderDelegate>
  12. /// 是否需要提交按钮
  13. @property (nonatomic, assign) BOOL isNeedSubmitButton;
  14. /// 操作按钮尺寸
  15. @property (nonatomic, assign) CGSize operationSize;
  16. /// 录音状态
  17. @property (nonatomic, assign) YMRecordSoundStatusType recordSoundStatusType;
  18. /// 录制时长标签
  19. @property (nonatomic, strong) UILabel *recordDurationLb;
  20. /// 圆形视图
  21. @property (nonatomic, strong) YMCircleView *circleView;
  22. /// 录制按钮
  23. @property (nonatomic, strong) UIButton *recordBtn;
  24. /// 描述标签
  25. @property (nonatomic, strong) UILabel *descLb;
  26. /// 重录按钮
  27. @property (nonatomic, strong) UIButton *rerecordBtn;
  28. /// 提交按钮
  29. @property (nonatomic, strong) UIButton *submitBtn;
  30. /// 音频播放器
  31. @property (nonatomic, strong) AVAudioPlayer *audioPlayer;
  32. /// 音频录制器
  33. @property (nonatomic, strong) AVAudioRecorder *audioRecorder;
  34. /// 录制音频链接
  35. @property (nonatomic, strong) NSURL *recordAudioUrl;
  36. /// 录音时间
  37. @property (nonatomic, assign) NSInteger audioTime;
  38. /// 播放时间
  39. @property (nonatomic, assign) NSInteger playTime;
  40. @property (nonatomic, strong) NSTimer *recordTimer;
  41. @end
  42. @implementation YMRecordSoundView
  43. - (instancetype)initWithIsNeedSubmitButton:(BOOL)isNeedSubmitButton OperationSize:(CGSize)operationSize{
  44. if (self = [super init]) {
  45. self.isNeedSubmitButton = isNeedSubmitButton;
  46. self.operationSize = operationSize;
  47. [self setupViews];
  48. }
  49. return self;
  50. }
  51. - (void)setupViews{
  52. self.minDuration = 2;
  53. self.maxDuration = 8;
  54. self.rerecordBgColor = HexColorFromRGB(0xF5F5F5);
  55. self.submitBgColor = HexColorFromRGB(0xF888E7);
  56. self.rerecordTitleColor = HexColorFromRGB(0x555555);
  57. self.submitTitleColor = HexColorFromRGB(0xFFFFFF);
  58. self.rerecordFont = LCFont(14);
  59. self.submitFont = LCFont(14);
  60. self.rerecordTitle = @"重录";
  61. self.submitTitle = @"确定";
  62. self.rerecordRadius = adapt(10);
  63. self.submitRadius = adapt(10);
  64. self.rerecordBorderColor = HexColorFromRGB(0xF5F5F5);
  65. self.submitBorderColor = HexColorFromRGB(0xF888E7);
  66. self.rerecordBorderWidth = adapt(0.5);
  67. self.submitBorderWidth = adapt(0.5);
  68. self.exportType = YMRecordSoundExportTypePM3;
  69. self.recordSoundStatusType = YMRecordSoundStatusTypeNone;
  70. [self addSubview:self.recordDurationLb];
  71. [self addSubview:self.circleView];
  72. [self addSubview:self.recordBtn];
  73. [self addSubview:self.descLb];
  74. [self addSubview:self.rerecordBtn];
  75. [self addSubview:self.submitBtn];
  76. [self setNeedsUpdateConstraints];
  77. [self updateConstraintsIfNeeded];
  78. }
  79. - (void)updateConstraints{
  80. [self.recordDurationLb mas_makeConstraints:^(MASConstraintMaker *make) {
  81. make.centerX.equalTo(self.mas_centerX);
  82. make.top.equalTo(self).offset(adapt(10));
  83. }];
  84. [self.circleView mas_makeConstraints:^(MASConstraintMaker *make) {
  85. make.centerX.equalTo(self.mas_centerX);
  86. make.top.equalTo(self.recordDurationLb.mas_bottom).offset(adapt(15));
  87. make.width.height.mas_equalTo(adapt(75));
  88. }];
  89. [self.recordBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  90. make.centerX.equalTo(self.circleView.mas_centerX);
  91. make.centerY.equalTo(self.circleView.mas_centerY);
  92. make.width.height.mas_equalTo(adapt(65));
  93. }];
  94. if (self.isNeedSubmitButton) {
  95. [self.descLb mas_makeConstraints:^(MASConstraintMaker *make) {
  96. make.centerX.equalTo(self.mas_centerX);
  97. make.top.equalTo(self.recordBtn.mas_bottom).offset(adapt(15));
  98. make.bottom.equalTo(self).offset(adapt(-10)).priorityHigh();
  99. }];
  100. [self.rerecordBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  101. make.centerY.equalTo(self.recordBtn.mas_centerY);
  102. make.right.equalTo(self.recordBtn.mas_left).offset(adapt(-30));
  103. make.size.mas_equalTo(self.operationSize);
  104. }];
  105. [self.submitBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  106. make.centerY.equalTo(self.recordBtn.mas_centerY);
  107. make.left.equalTo(self.recordBtn.mas_right).offset(adapt(30));
  108. make.size.mas_equalTo(self.operationSize);
  109. }];
  110. } else {
  111. [self.descLb mas_makeConstraints:^(MASConstraintMaker *make) {
  112. make.centerX.equalTo(self.mas_centerX);
  113. make.top.equalTo(self.recordBtn.mas_bottom).offset(adapt(15));
  114. }];
  115. [self.rerecordBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  116. make.centerX.equalTo(self.mas_centerX);
  117. make.top.equalTo(self.descLb.mas_bottom).offset(adapt(20));
  118. make.bottom.equalTo(self).offset(adapt(-10)).priorityHigh();
  119. make.size.mas_equalTo(self.operationSize);
  120. }];
  121. [self.submitBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  122. make.centerX.equalTo(self.mas_centerX);
  123. make.top.equalTo(self.descLb.mas_bottom).offset(adapt(20));
  124. make.bottom.equalTo(self).offset(adapt(-10)).priorityHigh();
  125. make.size.mas_equalTo(self.operationSize);
  126. }];
  127. }
  128. [super updateConstraints];
  129. }
  130. /// 录制事件
  131. - (void)recordAction{
  132. if(self.recordSoundStatusType == YMRecordSoundStatusTypeNone){
  133. self.recordSoundStatusType = YMRecordSoundStatusTypeStart;
  134. //创建录音通道
  135. AVAudioSession *session = [AVAudioSession sharedInstance];
  136. NSError *sessionError;
  137. [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
  138. if(session == nil){
  139. NSLog(@"Error creating session: %@", [sessionError description]);
  140. }else{
  141. [session setActive:YES error:nil];
  142. }
  143. // 开始录音
  144. [self.audioRecorder record];
  145. self.audioTime = 0;
  146. [self startTimer];
  147. }else if(self.recordSoundStatusType == YMRecordSoundStatusTypeFinish){
  148. self.recordSoundStatusType = YMRecordSoundStatusTypePlay;
  149. UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
  150. AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
  151. AVAudioSession * session = [AVAudioSession sharedInstance];
  152. [session setActive:YES error:nil];
  153. [session setCategory:AVAudioSessionCategoryPlayback error:nil];
  154. NSError *error;
  155. self.audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:self.recordAudioUrl error:&error];
  156. if (error) {
  157. NSLog(@"%@",error);
  158. }
  159. self.audioPlayer.delegate = self;
  160. /// 播放
  161. [self.audioPlayer play];
  162. self.playTime = self.audioTime;
  163. [self startTimer];
  164. }else if (self.recordSoundStatusType == YMRecordSoundStatusTypePlay){
  165. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  166. /// 停止播放
  167. [self.audioPlayer stop];
  168. self.audioPlayer = nil;
  169. [self stopTimer];
  170. }else if (self.recordSoundStatusType == YMRecordSoundStatusTypeStart){
  171. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  172. /// 停止录制
  173. [self.audioRecorder stop];
  174. self.audioRecorder = nil;
  175. [self stopTimer];
  176. if (self.audioTime < self.minDuration) {
  177. [ZCHUDHelper showTitle:stringFormat(@"录音不可少于%ld秒",self.minDuration)];
  178. [self rerecordAction];
  179. }
  180. }
  181. }
  182. /// 重录事件
  183. - (void)rerecordAction{
  184. [self stopTimer];
  185. self.recordSoundStatusType = YMRecordSoundStatusTypeNone;
  186. [self.audioPlayer stop];
  187. self.audioPlayer = nil;
  188. self.audioRecorder = nil;
  189. self.recordAudioUrl = nil;
  190. if (self.exportUrlBlock) {
  191. self.exportUrlBlock(nil,0);
  192. }
  193. }
  194. /// 提交事件
  195. - (void)submitAction{
  196. if (self.exportUrlBlock) {
  197. self.exportUrlBlock([self getSubmitSoundUrl], self.audioTime);
  198. }
  199. }
  200. - (void)setMinDuration:(NSInteger)minDuration{
  201. _minDuration = minDuration;
  202. }
  203. - (void)setMaxDuration:(NSInteger)maxDuration{
  204. _maxDuration = maxDuration;
  205. }
  206. - (void)setRerecordBgColor:(UIColor *)rerecordBgColor{
  207. _rerecordBgColor = rerecordBgColor;
  208. _rerecordBtn.backgroundColor = rerecordBgColor;
  209. }
  210. - (void)setSubmitBgColor:(UIColor *)submitBgColor{
  211. _submitBgColor = submitBgColor;
  212. self.submitBtn.backgroundColor = submitBgColor;
  213. }
  214. - (void)setRerecordTitleColor:(UIColor *)rerecordTitleColor{
  215. _rerecordTitleColor = rerecordTitleColor;
  216. [self.rerecordBtn setTitleColor:rerecordTitleColor forState:UIControlStateNormal];
  217. }
  218. - (void)setSubmitTitleColor:(UIColor *)submitTitleColor{
  219. _submitTitleColor = submitTitleColor;
  220. [self.submitBtn setTitleColor:submitTitleColor forState:UIControlStateNormal];
  221. }
  222. - (void)setRerecordFont:(UIFont *)rerecordFont{
  223. _rerecordFont = rerecordFont;
  224. self.rerecordBtn.titleLabel.font = rerecordFont;
  225. }
  226. - (void)setSubmitFont:(UIFont *)submitFont{
  227. _submitFont = submitFont;
  228. self.submitBtn.titleLabel.font = submitFont;
  229. }
  230. - (void)setRerecordTitle:(NSString *)rerecordTitle{
  231. _rerecordTitle = rerecordTitle;
  232. [self.rerecordBtn setTitle:rerecordTitle forState:UIControlStateNormal];
  233. }
  234. - (void)setSubmitTitle:(NSString *)submitTitle{
  235. _submitTitle = submitTitle;
  236. [self.submitBtn setTitle:submitTitle forState:UIControlStateNormal];
  237. }
  238. - (void)setRerecordadius:(CGFloat)rerecordRadius{
  239. _rerecordRadius = rerecordRadius;
  240. self.rerecordBtn.layer.cornerRadius = rerecordRadius;
  241. }
  242. - (void)setSubmitRadius:(CGFloat)submitRadius{
  243. _submitRadius = submitRadius;
  244. self.submitBtn.layer.cornerRadius = submitRadius;
  245. }
  246. - (void)setRerecordBorderColor:(UIColor *)rerecordBorderColor{
  247. _rerecordBorderColor = rerecordBorderColor;
  248. self.rerecordBtn.layer.borderColor = rerecordBorderColor.CGColor;
  249. }
  250. - (void)setSubmitBorderColor:(UIColor *)submitBorderColor{
  251. _submitBorderColor = submitBorderColor;
  252. self.submitBtn.layer.borderColor = submitBorderColor.CGColor;
  253. }
  254. - (void)setRerecordBorderWidth:(CGFloat)rerecordBorderWidth{
  255. _rerecordBorderWidth = rerecordBorderWidth;
  256. self.rerecordBtn.layer.borderWidth = rerecordBorderWidth;
  257. }
  258. - (void)setSubmitBorderWidth:(CGFloat)submitBorderWidth{
  259. _submitBorderWidth = submitBorderWidth;
  260. self.submitBtn.layer.borderWidth = submitBorderWidth;
  261. }
  262. - (void)setRerecordImageStr:(NSString *)rerecordImageStr{
  263. _rerecordImageStr = rerecordImageStr;
  264. [self.rerecordBtn ym_imageLocationStyle:YMImageLocationStyleTop spacing:adapt(5) imageLocationBlock:^(UIButton * _Nonnull button) {
  265. [button setTitle:self.rerecordTitle forState:UIControlStateNormal];
  266. [button setImage:ImageByName(rerecordImageStr) forState:UIControlStateNormal];
  267. }];
  268. }
  269. - (void)setSubmitImageStr:(NSString *)submitImageStr{
  270. _submitImageStr = submitImageStr;
  271. [self.submitBtn ym_imageLocationStyle:YMImageLocationStyleTop spacing:adapt(5) imageLocationBlock:^(UIButton * _Nonnull button) {
  272. [button setTitle:self.submitTitle forState:UIControlStateNormal];
  273. [button setImage:ImageByName(submitImageStr) forState:UIControlStateNormal];
  274. }];
  275. }
  276. - (void)setRecordSoundStatusType:(YMRecordSoundStatusType)recordSoundStatusType{
  277. _recordSoundStatusType = recordSoundStatusType;
  278. NSString *recordDuration = @"";
  279. NSString *desc = @"";
  280. self.circleView.progress = 0.0f;
  281. self.circleView.hidden = YES;
  282. self.rerecordBtn.hidden = YES;
  283. self.submitBtn.hidden = YES;
  284. UIImage *recordImage = nil;
  285. switch (recordSoundStatusType) {
  286. case YMRecordSoundStatusTypeNone:
  287. {
  288. recordDuration = @"0s";
  289. desc = stringFormat(@"录制一段%ld~%ld秒的语音",self.minDuration,self.maxDuration);
  290. recordImage = ImageByName(@"ym_common_record_sound_none");
  291. }
  292. break;
  293. case YMRecordSoundStatusTypeStart:
  294. {
  295. recordDuration = @"0s";
  296. desc = @"点击结束录音";
  297. recordImage = ImageByName(@"ym_common_record_sound_start");
  298. self.circleView.hidden = NO;
  299. [self progressAnimation];
  300. }
  301. break;
  302. case YMRecordSoundStatusTypeFinish:
  303. {
  304. recordDuration = stringFormat(@"%lds",self.audioTime);
  305. desc = @"点击试听";
  306. recordImage = ImageByName(@"ym_common_record_sound_finish");
  307. self.rerecordBtn.hidden = NO;
  308. if (self.isNeedSubmitButton) {
  309. self.submitBtn.hidden = NO;
  310. } else {
  311. self.submitBtn.hidden = YES;
  312. }
  313. }
  314. break;
  315. case YMRecordSoundStatusTypePlay:
  316. {
  317. recordDuration = [NSString stringWithFormat:@"%@s",@(self.audioTime)];
  318. desc = @"播放中";
  319. recordImage = ImageByName(@"ym_common_record_sound_play");
  320. self.rerecordBtn.hidden = NO;
  321. if (self.isNeedSubmitButton) {
  322. self.submitBtn.hidden = NO;
  323. } else {
  324. self.submitBtn.hidden = YES;
  325. }
  326. }
  327. break;
  328. case YMRecordSoundStatusTypeSubmit:
  329. {
  330. }
  331. break;
  332. default:
  333. break;
  334. }
  335. self.recordDurationLb.text = recordDuration;
  336. self.descLb.text = desc;
  337. [self.recordBtn setBackgroundImage:recordImage forState:UIControlStateNormal];
  338. }
  339. #pragma mark - AVAudioPlayerDelegate
  340. - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
  341. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  342. // 停止播放
  343. [self.audioPlayer stop];
  344. self.audioPlayer = nil;
  345. [self stopTimer];
  346. }
  347. - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error{
  348. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  349. // 停止播放
  350. [self.audioPlayer stop];
  351. self.audioPlayer = nil;
  352. [self stopTimer];
  353. }
  354. - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{
  355. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  356. // 停止播放
  357. [self.audioPlayer stop];
  358. self.audioPlayer = nil;
  359. [self stopTimer];
  360. }
  361. #pragma mark - AVAudioRecorderDelegate
  362. - (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
  363. if (!self.isNeedSubmitButton) {
  364. [self submitAction];
  365. }
  366. }
  367. - (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * _Nullable)error{
  368. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  369. // 停止录制
  370. [self.audioRecorder stop];
  371. self.audioRecorder = nil;
  372. [self stopTimer];
  373. }
  374. - (void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder{
  375. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  376. // 停止录制
  377. [self.audioRecorder stop];
  378. self.audioRecorder = nil;
  379. [self stopTimer];
  380. }
  381. // 开始计时
  382. - (void)startTimer{
  383. self.recordTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
  384. [[NSRunLoop currentRunLoop] addTimer:self.recordTimer forMode:NSRunLoopCommonModes];
  385. }
  386. // 结束计时
  387. - (void)stopTimer{
  388. [self.recordTimer invalidate];
  389. self.recordTimer = nil;
  390. self.recordDurationLb.text = stringFormat(@"%lds",self.audioTime);
  391. }
  392. // 进度动画
  393. - (void)progressAnimation{
  394. __block CGFloat timeout = 0.0f;
  395. dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  396. dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
  397. dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 0.025f * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
  398. //3.设置定时器要执行的任务
  399. dispatch_source_set_event_handler(_timer, ^{
  400. if(timeout >= 1.0f){
  401. dispatch_source_cancel(_timer);
  402. dispatch_async(dispatch_get_main_queue(), ^{
  403. });
  404. }else{
  405. timeout += 0.025f;
  406. CGFloat currentTime = (CGFloat)self.audioTime + timeout;
  407. dispatch_async(dispatch_get_main_queue(), ^{
  408. self.circleView.progress = currentTime / (CGFloat)self.maxDuration;
  409. });
  410. }
  411. });
  412. dispatch_resume(_timer);
  413. }
  414. - (void)timerAction{
  415. if (self.recordSoundStatusType == YMRecordSoundStatusTypeStart) {
  416. self.audioTime++;
  417. self.recordDurationLb.text = stringFormat(@"%lds",self.audioTime);
  418. [self progressAnimation];
  419. if (self.audioTime >= self.maxDuration) {
  420. self.recordSoundStatusType = YMRecordSoundStatusTypeFinish;
  421. // 停止录制
  422. [self.audioRecorder stop];
  423. self.audioRecorder = nil;
  424. [self stopTimer];
  425. }
  426. }else if (self.recordSoundStatusType == YMRecordSoundStatusTypePlay){
  427. self.playTime--;
  428. self.recordDurationLb.text = stringFormat(@"%lds",self.playTime);
  429. }
  430. }
  431. - (NSURL *)recordAudioUrl{
  432. if (!_recordAudioUrl) {
  433. NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) lastObject];
  434. NSString *fileName;
  435. if (self.exportType == YMRecordSoundExportTypeAAC) {
  436. fileName = @"audioVerify.aac";
  437. }else{
  438. fileName = @"audioVerify.caf";
  439. }
  440. _recordAudioUrl = [NSURL fileURLWithPath:[path stringByAppendingPathComponent:fileName]];
  441. if ([[NSFileManager defaultManager] fileExistsAtPath:_recordAudioUrl.resourceSpecifier]){
  442. [[NSFileManager defaultManager] removeItemAtPath:_recordAudioUrl.resourceSpecifier error:nil];
  443. }
  444. }
  445. return _recordAudioUrl;
  446. }
  447. - (NSURL*)getSubmitSoundUrl{
  448. [self stopTimer];
  449. // 停止播放
  450. [self.audioPlayer stop];
  451. if (_recordSoundStatusType < YMRecordSoundStatusTypeFinish){
  452. return nil;
  453. }
  454. NSURL *url = nil;
  455. switch (self.exportType) {
  456. case YMRecordSoundExportTypePM3:
  457. url = [self.recordAudioUrl transformCAFToMP3];
  458. break;
  459. case YMRecordSoundExportTypeAAC:{
  460. url = self.recordAudioUrl;
  461. }
  462. break;
  463. default:
  464. break;
  465. }
  466. return url;
  467. }
  468. - (void)stopRecord{
  469. [self stopTimer];
  470. // 停止播放
  471. [self.audioPlayer stop];
  472. self.audioPlayer = nil;
  473. self.audioRecorder = nil;
  474. self.recordAudioUrl = nil;
  475. }
  476. - (void)dealloc{
  477. [self stopRecord];
  478. }
  479. - (UILabel *)recordDurationLb{
  480. if (!_recordDurationLb) {
  481. _recordDurationLb = [[UILabel alloc]init];
  482. _recordDurationLb.font = LCFont(12);
  483. _recordDurationLb.textColor = UIColor.blackColor;
  484. _recordDurationLb.textAlignment = NSTextAlignmentCenter;
  485. _recordDurationLb.text = @"0s";
  486. }
  487. return _recordDurationLb;
  488. }
  489. - (YMCircleView *)circleView{
  490. if (!_circleView) {
  491. _circleView = [[YMCircleView alloc]init];
  492. _circleView.progress = 0.0f;
  493. _circleView.progerssColor = HexColorFromRGB(0xFDD45E);
  494. _circleView.progerssBackgroundColor = [UIColor.whiteColor colorWithAlphaComponent:0.13f];
  495. _circleView.progerWidth = 2.5f;
  496. _circleView.progerBackgroundWidth = 1.0f;
  497. _circleView.hidden = YES;
  498. }
  499. return _circleView;
  500. }
  501. - (UIButton *)recordBtn{
  502. if (!_recordBtn) {
  503. _recordBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  504. WS(weakSelf)
  505. [[[_recordBtn rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {
  506. // 检查权限
  507. [UCAuthorityManager microPhoneAuthority:^{
  508. [weakSelf recordAction];
  509. } denied:^{
  510. YMTipsPopupView *customView = [[YMTipsPopupView alloc]init];
  511. [customView configutationWithTips:@"请在iphone的“设置-隐私-麦克风”选项中,允许APP访问您的麦克风。" TipsAlignment:NSTextAlignmentCenter IsHideTitle:NO IsHideSingleButton:NO];
  512. YMPopupView *popupView = [YMPopupView initWithCustomView:customView parentView:[YMGlobalUtils getCurrentVC].view popStyle:YMPopupStyleFade dismissStyle:YMDismissStyleFade];
  513. popupView.priority = 999;
  514. popupView.cornerRadius = adapt(10);
  515. popupView.rectCorners = UIRectCornerAllCorners;
  516. popupView.positionStyle = YMPositionStyleCenter;
  517. popupView.isHideBg = NO;
  518. popupView.bgAlpha = 0.3;
  519. @weakify(popupView)
  520. customView.buttonBlock = ^(BOOL issubmit) {
  521. @strongify(popupView)
  522. if (issubmit) {
  523. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
  524. }
  525. [popupView dismissWithStyle:YMDismissStyleFade duration:2.0];
  526. };
  527. [popupView pop];
  528. }];
  529. }];
  530. }
  531. return _recordBtn;
  532. }
  533. - (UILabel *)descLb{
  534. if (!_descLb) {
  535. _descLb = [[UILabel alloc]init];
  536. _descLb.font = LCFont(12);
  537. _descLb.textColor = HexColorFromRGB(0x9d9d9d);
  538. _descLb.textAlignment = NSTextAlignmentCenter;
  539. _descLb.text = stringFormat(@"录制一段%ld~%ld秒的语音",self.minDuration,self.maxDuration);
  540. }
  541. return _descLb;
  542. }
  543. - (UIButton *)rerecordBtn{
  544. if (!_rerecordBtn) {
  545. _rerecordBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  546. _rerecordBtn.backgroundColor = self.rerecordBgColor;
  547. _rerecordBtn.titleLabel.font = self.rerecordFont;
  548. [_rerecordBtn setTitleColor:self.rerecordTitleColor forState:UIControlStateNormal];
  549. [_rerecordBtn setTitle:self.rerecordTitle forState:UIControlStateNormal];
  550. _rerecordBtn.layer.cornerRadius = self.rerecordRadius;
  551. _rerecordBtn.layer.masksToBounds = YES;
  552. _rerecordBtn.hidden = YES;
  553. WS(weakSelf)
  554. [[[_rerecordBtn rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {
  555. [weakSelf rerecordAction];
  556. }];
  557. }
  558. return _rerecordBtn;
  559. }
  560. - (UIButton *)submitBtn{
  561. if (!_submitBtn) {
  562. _submitBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  563. _submitBtn.backgroundColor = self.submitBgColor;
  564. _submitBtn.titleLabel.font = self.submitFont;
  565. [_submitBtn setTitleColor:self.submitTitleColor forState:UIControlStateNormal];
  566. [_submitBtn setTitle:self.submitTitle forState:UIControlStateNormal];
  567. _submitBtn.layer.cornerRadius = self.submitRadius;
  568. _submitBtn.layer.masksToBounds = YES;
  569. _submitBtn.hidden = YES;
  570. WS(weakSelf)
  571. [[[_submitBtn rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {
  572. [weakSelf submitAction];
  573. }];
  574. }
  575. return _submitBtn;
  576. }
  577. - (AVAudioRecorder *)audioRecorder{
  578. if (!_audioRecorder) {
  579. //创建录音机
  580. NSError *error = nil;
  581. _audioRecorder = [[AVAudioRecorder alloc] initWithURL:self.recordAudioUrl settings:[self getAudioSetting] error:&error];
  582. _audioRecorder.delegate = self;
  583. if (error) {
  584. NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);
  585. return nil;
  586. }
  587. }
  588. return _audioRecorder;
  589. }
  590. /**
  591. * 取得录音文件设置
  592. *
  593. * @return 录音设置
  594. */
  595. - (NSDictionary *)getAudioSetting{
  596. if (self.exportType == YMRecordSoundExportTypeAAC) {
  597. NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc]init] ;
  598. //设置录音格式 AVFormatIDKey==kAudioFormatLinearPCM
  599. [recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
  600. //设置录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量)
  601. [recordSetting setValue:[NSNumber numberWithFloat:44100] forKey:AVSampleRateKey];
  602. //录音通道数 1 或 2
  603. [recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
  604. //线性采样位数 8、16、24、32
  605. [recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
  606. //录音的质量
  607. [recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityMedium] forKey:AVEncoderAudioQualityKey];
  608. return recordSetting.copy;
  609. }else{
  610. NSDictionary *recordSetting = @{
  611. AVFormatIDKey : @(kAudioFormatLinearPCM),
  612. AVSampleRateKey : @(44100),
  613. AVNumberOfChannelsKey : @(2),
  614. AVLinearPCMBitDepthKey : @(16),
  615. AVLinearPCMIsNonInterleaved : @NO,
  616. AVLinearPCMIsFloatKey : @NO,
  617. AVLinearPCMIsBigEndianKey : @NO,
  618. };
  619. return recordSetting;
  620. }
  621. }
  622. @end