ios 音频录音、上传至7牛、播放及其与android兼容的问题

2017-09-12 19:34:09来源:CSDN作者:ZQ_timor人点击

分享

iOS录音使用AVAudioRecorder,播放用 AVPlayer 就可以很好的解决,网上也有很多的教程。这里就不细讲,后面会附上代码。

先说一下demo内容,现在项目要求做一个录音、上传、播放的功能。细节:录音前需要提示音,录音时会有一个根据声音强度来展示的相应动态效果,还有个计时功能。

我们来说一下我在制作此功能时所遇到的坑!!

这里先呈现音频录制的代码,这里面引用了SpectrumView,点击打开链接。这是一个根据声强来显示声音录制的效果,如果不需要可以去除。

录制音频代码:

1.首先说一下录制音频的格式。

   经验证,这里博主建议各位使用AAC的录制格式。AAC(Advanced Audio Coding),中文称为“高级音频编码”,所占内存小,音质也不错,最重要的是可以与android兼容。


2.这里用的是7牛云的上传。这里我遇到的大问题就是上传音频到7牛云后,发现格式不能识别,显示为application/octet-stream。我最开始用.mp4的格式,的确上传上去后,能够识别为video/mp4,并且能正常播放。 但是后来发现不能播放android的录音。于是就想办法解决,经过一下午的各种博客浏览,。。。无果!! 好吧,最后想到先本地存储,再来播放的方式,解决问题。(这里的录音文件都比较小,不超过30s)


这里附上部分demo片段,有需要自取。

录音部分:#import "AudioRecorderVC.h"#import <AVFoundation/AVFoundation.h>#define kRecordAudioFile @"myRecord.aac"@interface AudioRecorderVC ()<AVAudioRecorderDelegate>@property (strong,nonatomic) SpectrumView *spectrumView;@property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音频录音机@property (nonatomic, strong) AVAudioPlayer *bellplayer;@property (nonatomic, assign) int sCountup;@property (nonatomic, strong) NSTimer *mTimer;@end@implementation AudioRecorderVC#pragma mark - 控制器视图方法- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view from its nib.[self.naView setHidden:YES];[self.statusTip setHidden:YES];[self.view createBordersWithColor:[UIColor clearColor] withCornerRadius:6 andWidth:1];[self.labReminder createBordersWithColor:[UIColor clearColor] withCornerRadius:4 andWidth:1];[self.labReminder setTextColor:MCOLOR_FFFFFF];[self addTapGesture];[self addSpectrumView];[self labToSize];}-(void)addSpectrumView{if (!self.spectrumView) {__weak AudioRecorderVC *weakSelf = self;self.spectrumView = [[SpectrumView alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.view.bounds)-150,240,300, 60.0)];self.spectrumView.hidden = YES;self.spectrumView.text = [NSString stringWithFormat:@"%d",0];__weak SpectrumView * weakSpectrum = self.spectrumView;self.spectrumView.itemLevelCallback = ^() {[weakSelf.audioRecorder updateMeters];//取得第一个通道的音频,音频强度范围是-160到0float power= [weakSelf.audioRecorder averagePowerForChannel:0];weakSpectrum.level = power;};[self.view addSubview:self.spectrumView];}}-(void)addTapGesture{//添加手势UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickPop)];//将手势添加到需要相应的view中去[self.view addGestureRecognizer:tapGesture];}-(void)clickPop{if (_Block) {_Block(nil);}}#pragma mark - getter 懒加载- (UIButton *)btnRecorder {// 开始[_btnRecorder addTarget:self action:@selector(recordStart:) forControlEvents:UIControlEventTouchDown];// 取消// [_btnRecorder addTarget:self action:@selector(recordCancel:) forControlEvents: UIControlEventTouchUpOutside];//完成[_btnRecorder addTarget:self action:@selector(recordFinish:) forControlEvents:UIControlEventTouchUpInside];/*//移出[_btnRecorder addTarget:self action:@selector(recordTouchDragExit:) forControlEvents:UIControlEventTouchDragExit];//移入[_btnRecorder addTarget:self action:@selector(recordTouchDragEnter:) forControlEvents:UIControlEventTouchDragEnter];*/return _btnRecorder;}/*** 获得录音机对象** @return 录音机对象*/- (AVAudioRecorder *)audioRecorder {if (!_audioRecorder) {[self setAudioSession];//创建录音文件保存路径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;//如果要监控声波则必须设置为YESif (error) {NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);return nil;}}return _audioRecorder;}#pragma mark - layout- (void)viewDidLayoutSubviews {[super viewDidLayoutSubviews];CGFloat width = self.view.bounds.size.width;CGFloat height = self.view.bounds.size.height;self.btnRecorder.frame = CGRectMake(width / 2.f - 50.f, height - 180.f, 100.f, 100.f);[self.audioRecorder record];[self.audioRecorder stop];[self removeFile];}#pragma mark - ControlEvents/*- (void)recordCancel:(UIButton *)button {if ([self.audioRecorder isRecording]) {NSLog(@"取消");[self.audioRecorder stop];self.spectrumView.hidden = NO;}}*/- (void)recordStart:(UIButton *)button {if (![self.audioRecorder isRecording]) {NSLog(@"录音开始");[self startScount];[self playthebell];[self.audioRecorder record];[self startAnimate];self.labReminder.hidden = YES;self.spectrumView.hidden = NO;}}- (void)recordFinish:(UIButton *)button {if ([self.audioRecorder isRecording]) {NSLog(@"完成");[self.audioRecorder stop];[self stopAnimate];self.spectrumView.hidden = NO;[self judgePushAudio];}}/*- (void)recordTouchDragExit:(UIButton *)button {if([self.audioRecorder isRecording]) {[self stopAnimate];}}- (void)recordTouchDragEnter:(UIButton *)button {if([self.audioRecorder isRecording]) {[self startAnimate];}}*/- (void)startAnimate {[self.spectrumView start];}- (void)stopAnimate {[self.spectrumView stop];[self.mTimer invalidate];self.mTimer = nil;}- (void)setAudioSession {AVAudioSession *session = [AVAudioSession sharedInstance];NSError *sessionError;//AVAudioSessionCategoryPlayAndRecord用于录音和播放[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];if(session == nil)NSLog(@"Error creating session: %@", [sessionError description]);else[session setActive:YES error:nil];}/*** 取得录音文件设置** @return 录音设置*/- (NSDictionary *)getAudioSetting {NSMutableDictionary *dicM=[NSMutableDictionary dictionary];//设置录音格式[dicM setObject:@(kAudioFormatMPEG4AAC) 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 录音文件路径*/- (NSURL *)getSavePath {// 在Documents目录下创建一个名为FileData的文件夹NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioData"];NSFileManager *fileManager = [NSFileManager defaultManager];BOOL isDir = FALSE;BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];if(!(isDirExist && isDir)) {BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];if(!bCreateDir){NSLog(@"创建文件夹失败!");}NSLog(@"创建文件夹成功,文件路径%@",path);}path = [path stringByAppendingPathComponent:kRecordAudioFile];NSLog(@"file path:%@",path);NSURL *url=[NSURL fileURLWithPath:path];return url;}- (void)removeFile{NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioData"];NSFileManager *fileManager = [NSFileManager defaultManager];path = [path stringByAppendingPathComponent:kRecordAudioFile];NSError *error;if ([fileManager removeItemAtPath:path error:&error] != YES)NSLog(@"Unable to delete file: %@", [error localizedDescription]);}- (void)judgePushAudio{if (_sCountup < 1) {[self showToast:@"录音时间太短,请重试!"];[self removeFile];}else if(_sCountup >= 1 && _sCountup <= 30){if (_Block) {_Block([self getSavePath]);}}}- (void)labToSize{NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.labReminder.text];NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];[paragraphStyle setLineSpacing:20.0f];//调整行间距[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [self.labReminder.text length])];self.labReminder.attributedText = attributedString;[self.labReminder sizeToFit];}#pragma --提示音- (void)playthebell{NSString *mp3Str;mp3Str = @"talkroom_begin";NSString *filePath = [[NSBundle mainBundle] pathForResource:mp3Str ofType:@"mp3"];self.bellplayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:nil];self.bellplayer.volume = 1.0;self.bellplayer.numberOfLoops = -1;[self.bellplayer prepareToPlay];[self.bellplayer play];dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ( 0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{[self.bellplayer stop];});}#pragma --计时器- (void)startScount{self.sCountup = 0;[UIView animateWithDuration:0.5 animations:^{self.mTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(startCountUp) userInfo:nil repeats:YES];}];}- (void)startCountUp{_sCountup++;self.spectrumView.timeLabel.text = [NSString stringWithFormat:@"%ds", _sCountup];if (_sCountup == 30) {[self recordFinish:nil];}}@end

3
#pragma --播放录音- (void)addVoiceButton:(DoorVoucherCell *)cell{    UIButton *voiceBtn = [[UIButton alloc]initWithFrame:CGRectMake(cell.contentValue.left, 0, 150, 50)];    [voiceBtn addTarget:self action:@selector(playRecoderVoice) forControlEvents:UIControlEventTouchUpInside];    voice = [[UIImageView alloc]initWithFrame:CGRectMake(0, 12, 25, 25)];    //动画未开始前的图片    voice.image = [UIImage imageNamed:@"chat_animation_white3"];    //进行动画效果的3张图片(按照播放顺序放置)    voice.animationImages = [NSArray arrayWithObjects:                             [UIImage imageNamed:@"chat_animation_white1"],                             [UIImage imageNamed:@"chat_animation_white2"],                             [UIImage imageNamed:@"chat_animation_white3"],nil];    //设置动画间隔    voice.animationDuration = 1;    voice.animationRepeatCount = 0;    voice.userInteractionEnabled = NO;    voice.backgroundColor = [UIColor clearColor];    [voiceBtn addSubview:voice];    [cell addSubview:voiceBtn];}- (NSURL *)writeRecoderToFile{    //播放    NSURL *url = [NSURL URLWithString:self.dataModel.voice];    //把音频文件保存到本地    NSData *audioData = [NSData dataWithContentsOfURL:url];    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"AudioData"];    path = [path stringByAppendingPathComponent:@"myRecord.aac"];    //  DDLogWarn(@" 从网络拿到的音频数据写入的本地路径  %@",filePath);    [audioData writeToFile:path atomically:YES];        NSURL *fileURL = [NSURL fileURLWithPath:path];    return fileURL;}- (void)playRecoderVoice{    [self setAudioPlayer];    [self.audioPlayer play];    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        [voice startAnimating];    });}- (void)playerItemDidReachEnd{    [self playthebell];    [voice stopAnimating];    voice.image = [UIImage imageNamed:@"chat_animation_white3"];}- (AVPlayer *)setAudioPlayer{    NSError *error=nil;    AVPlayerItem * songItem = [[AVPlayerItem alloc]initWithURL:[self writeRecoderToFile]];    AVAudioSession *session = [AVAudioSession sharedInstance];    [session setActive:YES error:nil];    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];    [session setCategory:AVAudioSessionCategoryPlayback error:nil];    _audioPlayer = [[AVPlayer alloc] initWithPlayerItem:songItem];    // 监听音乐是否播放完成        [[NSNotificationCenter defaultCenter] addObserver:self                                                  selector:@selector(playerItemDidReachEnd)                                                      name:AVPlayerItemDidPlayToEndTimeNotification                                                    object:nil];    if (error) {        NSLog(@"创建播放器过程中发生错误,错误信息:%@",error.localizedDescription);        return nil;    }    return _audioPlayer;}#pragma --提示音- (void)playthebell{    NSString *mp3Str;    mp3Str = @"talkroom_up";    NSString *filePath = [[NSBundle mainBundle] pathForResource:mp3Str ofType:@"mp3"];    self.bellplayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:nil];    self.bellplayer.volume = 1.0;    self.bellplayer.numberOfLoops = -1;    [self.bellplayer prepareToPlay];    [self.bellplayer play];    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ( 0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        [self.bellplayer stop];    });}






有问题欢迎提问,喜欢请点赞,Star。谢谢。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台