#import “VoiceInputCell.h”
#import <AVFoundation/AVFoundation.h>
#define kRecordAudioFile @“myRecord.wav”
@interface VoiceInputCell ()<AVAudioRecorderDelegate,AVAudioPlayerDelegate>
@property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音频录音机
@property (nonatomic,strong) NSTimer *timer;///录音时长
///录音时长
@property (nonatomic,assign) NSInteger record_time;
///提示文字
@property (nonatomic,strong) UILabel *placeholder_normal;
///右侧图标
@property (nonatomic,strong) UIImageView *imageView_normal;
///删除
@property (nonatomic,strong) UIButton *delete_button;
///有录音时灰色背景
@property (nonatomic,strong) UIView *backView_small;
///底部白色背景
@property (nonatomic,strong) UIView *backView_normal;
#pragma mark—播放
///本地文件播放
@property (nonatomic,strong) AVAudioPlayer *player;
#pragma mark—回显 以及播放在线音频文件
#pragma mark—回显 以及播放在线音频文件
#pragma mark—回显 以及播放在线音频文件
@property (nonatomic, strong) AVPlayer *avPlayer;
///是否是详情
@property (nonatomic,assign) BOOL isDetailView;
@end
@implementation VoiceInputCell
-
(void)awakeFromNib {
[super awakeFromNib];
// Initialization code
} -
(void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];// Configure the view for the selected state
}
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.backgroundColor = [UIColor clearColor];
self.contentView.backgroundColor = [UIColor clearColor];
if ([reuseIdentifier isEqualToString:@“VoiceInputCell_Detail”]){
self.isDetailView = YES;
}
[self createView];
}
return self;
}
-(void)createView{
//正常状态-未录入语音
self.backView_normal = [[UIView alloc] init];
[self.contentView addSubview:self.backView_normal];
[self.backView_normal mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(0);
make.height.mas_equalTo(WMAKENEW(68));
make.bottom.mas_equalTo(0);
make.top.mas_equalTo(Cell_Spacing);
}];
self.backView_normal.backgroundColor = UIColor.whiteColor;
self.backView_normal.layer.cornerRadius = WMAKENEW(4);
UITapGestureRecognizer *tapOne = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapClickAction)];
[self.backView_normal addGestureRecognizer:tapOne];
//有录音时灰色背景
self.backView_small = [[UIView alloc] init];
[self.backView_normal addSubview:self.backView_small];
[self.backView_small mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(-WMAKENEW(16));
make.top.mas_equalTo(WMAKENEW(12));
make.bottom.mas_equalTo(-WMAKENEW(12));
make.width.mas_equalTo(WMAKENEW(80));
}];
self.backView_small.backgroundColor = rgba(244, 246, 248, 1);
self.backView_small.layer.cornerRadius = WMAKENEW(4);
self.backView_small.hidden = YES;
//右侧图标
self.imageView_normal = [[UIImageView alloc] init];
[self.backView_normal addSubview:self.imageView_normal];
[self.imageView_normal mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(-WMAKENEW(16));
make.width.height.mas_equalTo(20);
make.centerY.equalTo(self.backView_normal);
}];
//时长、提示语
self.placeholder_normal = [Support_ControlSet createLabelTextColor:rgba(151, 151, 151, 0.44) textFont:12 textAligment:NSTextAlignmentLeft addToView:self.backView_normal];
self.placeholder_normal.font = FONT_SizeAndWight(12, UIFontWeightMedium);
[self.placeholder_normal mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.imageView_normal.mas_left).mas_offset(-WMAKENEW(10));
make.centerY.equalTo(self.backView_normal);
}];
self.placeholder_normal.userInteractionEnabled = NO;
self.imageView_normal.userInteractionEnabled = NO;
self.backView_normal.userInteractionEnabled = YES;
//删除
self.delete_button = [[UIButton alloc] init];
[self.backView_normal addSubview:self.delete_button];
[self.delete_button setImage:ImageName(@"delete") forState:UIControlStateNormal];
[self.delete_button mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.backView_small.mas_left);
make.top.bottom.mas_equalTo(0);
make.width.mas_equalTo(16+WMAKENEW(24));
}];
[self.delete_button addTarget:self action:@selector(deleteButtonClick) forControlEvents:UIControlEventTouchUpInside];
self.delete_button.userInteractionEnabled = YES;
UILabel *leftLabel = [Support_ControlSet createLabelTextColor:[Support_Color rebuildColor_Left_withType:ViewShowTypeAdd] textFont:14 textAligment:NSTextAlignmentLeft addToView:self.contentView];
[leftLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(WMAKENEW(20));
make.width.mas_equalTo(WMAKENEW(90));
make.centerY.equalTo(self.backView_normal);
}];
if (self.isDetailView){
leftLabel.text = @"语音";
self.delete_button.hidden = YES;
self.backView_small.hidden = NO;
self.placeholder_normal.text = @"点击开始播放";
self.placeholder_normal.textColor = rgba(151, 151, 151, 1);
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@"\U0000E66B", 20)];
[self.imageView_normal mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(-WMAKENEW(32));
}];
}else{
leftLabel.text = @"上传语音";
[self deleteButtonClick];
}
}
#pragma mark—创建
/**
- 设置音频会话
*/
-(void)setAudioSession:(BOOL)isRecord{
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
//设置为 录音状态
[audioSession setCategory:isRecord ? AVAudioSessionCategoryRecord:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
}
/**
- 取得录音文件保存路径
- @return 录音文件路径
*/
-(NSURL *)getSavePath{
NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
urlStr=[urlStr stringByAppendingPathComponent:kRecordAudioFile];
NSURL *url=[NSURL fileURLWithPath:urlStr];
return url;
}
/**
- 取得录音文件设置
- @return 录音设置
*/
-(NSDictionary *)getAudioSetting{
NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
//设置录音格式
[dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
//设置录音采样率,8000是电话采样率,对于一般录音已经够了
[dicM setObject:@(8000) forKey:AVSampleRateKey];
//设置通道,这里采用单声道
[dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
//每个采样点位数,分为8、16、24、32
[dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
//是否使用浮点数采样
[dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
//…其他设置等
return dicM;
}
/**
- 获得录音机对象
- @return 录音机对象
*/
-(AVAudioRecorder *)audioRecorder{
if (!_audioRecorder) {
//创建录音文件保存路径
NSURL *url=[self getSavePath];
//创建录音格式设置
NSDictionary *setting=[self getAudioSetting];
//创建录音机
NSError *error=nil;
_audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
_audioRecorder.delegate=self;
_audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES
if (error) {
NSLog(@“创建录音机对象时发生错误,错误信息:%@”,error.localizedDescription);
return nil;
}
}
return _audioRecorder;
}
/**
- 录音声波监控定制器
- @return 定时器
*/
-(NSTimer *)timer{
if (!_timer) {
_timer=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}
return _timer;
}
-(void)timerAction{
self.record_time ++;
self.placeholder_normal.text = NSIntegerToString(self.record_time);
if (self.record_time == 2){
self.backView_normal.userInteractionEnabled = YES;
}
if(self.record_time >= 60){
[self record_Stop];
}
}
#pragma mark—删除录音
-(void)deleteButtonClick{
self.record_time = 0;
self.delete_button.hidden = self.backView_small.hidden = YES;
self.placeholder_normal.text = @“点击开始录音”;
self.placeholder_normal.textColor = rgba(151, 151, 151, 0.44);
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E63E”, 20)];
[self.imageView_normal mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(-WMAKENEW(16));
}];
if (_player){
[_player stop];
}
_record_info = nil;
}
#pragma mark—录音
///录音 开始
- (void)tapClickAction{
NSLog(@“tapClickAction”);
if(self.isDetailView){
[self playNetRecord];
return;
}
if ([self.audioRecorder isRecording]) {
//停止录音 录音最少大于2秒
[self record_Stop];
}else{
if (self.record_time != 0){
//有录音
if ([self.player isPlaying]){
//停止播放
[self.player stop];
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E66B”, 20)];
}else{
//播放录音
[self playVoiceAction];
}
}else{
NSInteger havePower = [[Support_PowerCheck shareCheckPower] checkIsHavePower_Microphone:^(bool IsAllow) {
if (IsAllow){
[self record_Start];
}
}];
if (havePower == PowerStateAllow) {
[self record_Start];
}
}
}
}
-(void)record_Start{
self.backView_normal.userInteractionEnabled = NO;
[self setAudioSession:YES];
#warning 模拟首次使用
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E632”, 20)];
self.placeholder_normal.textColor = rgba(151, 151, 151, 1);
self.record_time = 0;
self.placeholder_normal.text = NSIntegerToString(self.record_time);
[self.audioRecorder record];//首次使用应用时如果调用record方法会询问用户是否允许使用麦克风
self.timer.fireDate=[NSDate distantPast];
}
///录音 结束 - (void)record_Stop{
if(self.isDetailView){
[self.avPlayer pause];
return;
}
[self.audioRecorder stop];
self.timer.fireDate = [NSDate distantFuture];
[self.timer invalidate];
_timer = nil;
}
#pragma mark - 录音机代理方法
/**
-
录音完成,录音完成后播放录音
-
@param recorder 录音机对象
-
@param flag 是否成功
*/
-(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
NSLog(@“录音完成!”);self.backView_small.hidden = NO;
self.delete_button.hidden = NO;
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E66B”, 20)];
self.backView_normal.userInteractionEnabled = YES;
[self.imageView_normal mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(-WMAKENEW(32));
}];self.record_info = [NSMutableDictionary new];
NSData *ddd = [NSData dataWithContentsOfURL:[self getSavePath]];
[self.record_info setValue:ddd forKey:@“fileData”];
[Support_Function getUploadFileName:@“record” fileType:@“.wav”];
[self.record_info setValue:[Support_Function getUploadFileName:@“record” fileType:@“.wav”] forKey:@“fileName”];
[self.record_info setValue:self.record_info[@“fileName”] forKey:@“name”];
}
#pragma mark—已经录音,播放还是停止播放
///播放本地录音
-(void)playVoiceAction{
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E632”, 20)];
[self setAudioSession:NO];
NSErrorerror;
self.player= [[AVAudioPlayer alloc] initWithContentsOfURL:[self getSavePath] error:&error];
//设置播放循环次数
[self.player setNumberOfLoops:0];
[self.player setVolume:1];//音量,0-1之间
//分配播放所需的资源,并将其加入内部播放队列
[self.player setDelegate:self];
[self.player prepareToPlay];
[self.player play];
}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer)player successfully:(BOOL)flag{
NSLog(@“播放完成”);
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E66B”, 20)];
}
#pragma mark—回显 以及播放在线音频文件
#pragma mark—回显 以及播放在线音频文件
#pragma mark—回显 以及播放在线音频文件
///播放在线文件
-(void)playNetRecord{
[self setAudioSession:NO];
if (self.avPlayer.timeControlStatus == 2){
[self.avPlayer pause];
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E66B”, 20)];
}else{
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E632”, 20)];
[self.avPlayer seekToTime:CMTimeMakeWithSeconds(0, 1.0)];//设置开始播放时间
[self.avPlayer play];
}
}
///设置音频文件路径
-(void)setRecord_net_name:(NSString *)record_net_name{
_record_net_name = record_net_name;
//获取音频时长
NSURL *url= [Support_Special returnImageUrlStr:record_net_name];
NSDictionary *dic = @{AVURLAssetPreferPreciseDurationAndTimingKey:@(YES)};
AVURLAsset *audioAsset = [AVURLAsset URLAssetWithURL:url options:dic];
CMTime audioDuration = audioAsset.duration;
Float64 audioDurationSeconds = CMTimeGetSeconds(audioDuration);
self.placeholder_normal.text = [NSString stringWithFormat:@"%0.f",audioDurationSeconds];
self.avPlayer=[[AVPlayer alloc] initWithURL:url];
self.avPlayer.volume = 1;
// //监控状态属性,注意AVPlayer也有一个status属性,通过监控它的status也可以获得播放状态
// [self.avPlayer.currentItem addObserver:self forKeyPath:@“status” options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:nil];
//监控播放完成通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayer.currentItem];
}
-(void)playbackFinished{
//监控播放完成通知
NSLog(@“播放完成”);
self.imageView_normal.image = [UIImage iconWithInfo:TBCityIconInfoMakeNoColor(@“\U0000E66B”, 20)];
}
//-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
// NSLog(@“监控状态属性”);
// if([keyPath isEqualToString:@“status”]){
// AVPlayerItemStatus status = [change[@“new”] integerValue];
// switch (status) {
// case AVPlayerItemStatusReadyToPlay:
// {
// // 开始播放
// NSLog(@“开始播放”);
// }
// break;
// case AVPlayerItemStatusFailed:
// {
// NSLog(@“加载失败”);
// }
// break;
// case AVPlayerItemStatusUnknown:
// {
// NSLog(@“未知资源”);
// }
// break;
// default:
// break;
// }
// }else if ([keyPath isEqualToString:@“loadedTimeRanges”]){
AVPlayerItem *playerItem = object;
NSArray *array=playerItem.loadedTimeRanges;
//本次缓冲时间范围
CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
//缓冲总长度
NSTimeInterval totalBuffer = startSeconds + durationSeconds;
NSLog(@“共缓冲:%.2f”,totalBuffer);
// }
//}
@end
.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VoiceInputCell : UITableViewCell
///录音 结束
- (void)record_Stop;
///录音信息
@property (nonatomic,strong) NSMutableDictionary *record_info;
///回显时的 录音文件
@property (nonatomic,strong) NSString *record_net_name;
///播放在线文件
-(void)playNetRecord;
@end
NS_ASSUME_NONNULL_END