Loading

IOS开发:录音功能,播放功能的完整实现demo

我是在别人的demo基础上继续做的,百度cui ios ,博客园的那个,那人博客写的相当仔细,大家想学的更多可以去他博客看看

原demo只有录音界面,然后录音结束自动播放的功能。

录音界面我稍微改了下,本身是录音结束就自动播放,我是选择了在别的界面播放。然后是取路径命名的问题,我改为了用当前时间命名。原demo是用myRecord.caf作为结尾命名,因为原demo录完就播放嘛。

录音界面有个列表按钮,跳到第二个界面,可看到具体的录音栏目。然后点击右侧的按钮,进入第三个页面自动播放,然后是暂停继续等等

第三个页面自动播放,其实就是把创建音频播放器对象写在了load里,然后调用下音频会话,跟第一个界面的东西基本一样的思路。

然后还有一个关键点是第二个界面点按钮跳转的时候,你必须知道你点的是第几行,也就是你点的是哪个录音,把这个路径送到第三个界面给音频对象用,这个采用单例模式实现跨界面传值。

还有就是页面间的跳转,一种直接拉线,一种是用代码,我的随笔里也写了用代码的。

 

界面设计

 

 

录音界面代码

  1 #import "ViewController.h"
  2 #import <AVFoundation/AVFoundation.h>
  3 
  4 @interface ViewController ()<AVAudioRecorderDelegate>
  5 
  6 @property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音频录音机
  7 @property (nonatomic,strong) AVAudioPlayer *audioPlayer;//音频播放器,用于播放录音文件
  8 @property (nonatomic,strong) NSTimer *timer;//录音声波监控(注意这里暂时不对播放进行监控)
  9 
 10 @property (weak, nonatomic) IBOutlet UIButton *record;//开始录音
 11 @property (weak, nonatomic) IBOutlet UIButton *pause;//暂停录音
 12 @property (weak, nonatomic) IBOutlet UIButton *resume;//恢复录音
 13 @property (weak, nonatomic) IBOutlet UIButton *stop;//停止录音
 14 @property (weak, nonatomic) IBOutlet UIProgressView *audioPower;//音频波动
 15 @property (weak, nonatomic) IBOutlet UIButton *exit;//退出
 16 
 17 @end
 18 
 19 @implementation ViewController
 20 
 21 #pragma mark - 控制器视图方法
 22 - (void)viewDidLoad {
 23     //f改变progressview的长宽
 24     _audioPower.transform=CGAffineTransformMakeScale(1.0f,4.0f);
 25     [super viewDidLoad];
 26     //自动播放的
 27     [self setAudioSession];
 28 }
 29 
 30 #pragma mark - 私有方法
 31 
 32 
 33 
 34 /**
 35  *  取得录音文件保存路径
 36  *
 37  *  @return 录音文件路径
 38  */
 39 -(NSURL *)getSavePath{
 40     //获取文件路径
 41     NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
 42     NSLog(@"%@",urlStr);
 43     NSDate *date=[NSDate date];
 44     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
 45     [dateFormatter setDateFormat:@"yyyy-MM-dd-HH:mm:ss"];
 46     //NSDate转NSString
 47     NSString *sss = [dateFormatter stringFromDate:date];
 48     NSString *ccc=[sss stringByAppendingString:@".caf"];
 49     urlStr=[urlStr stringByAppendingPathComponent:ccc];
 50     NSURL *url=[NSURL fileURLWithPath:urlStr];
 51    // NSLog(@"第一个页面的路径",url);
 52     return url;
 53 }
 54 
 55 /**
 56  *  取得录音文件设置
 57  *
 58  *  @return 录音设置
 59  */
 60 -(NSDictionary *)getAudioSetting{
 61     NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
 62     //设置录音格式
 63     [dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
 64     //设置录音采样率,8000是电话采样率,对于一般录音已经够了
 65     [dicM setObject:@(8000) forKey:AVSampleRateKey];
 66     //设置通道,这里采用单声道
 67     [dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
 68     //每个采样点位数,分为8、16、24、32
 69     [dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
 70     //是否使用浮点数采样
 71     [dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
 72     //....其他设置等
 73     return dicM;
 74 }
 75 
 76 /**
 77  *  获得录音机对象
 78  *
 79  *  @return 录音机对象
 80  */
 81 -(AVAudioRecorder *)audioRecorder{
 82     if (!_audioRecorder) {
 83         //创建录音文件保存路径
 84         NSURL *url=[self getSavePath];
 85         //创建录音格式设置
 86         NSDictionary *setting=[self getAudioSetting];
 87         //创建录音机
 88         NSError *error=nil;
 89         _audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
 90         _audioRecorder.delegate=self;
 91         _audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES
 92         if (error) {
 93             NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);
 94             return nil;
 95         }
 96     }
 97     return _audioRecorder;
 98 }
 99 -(void)setAudioSession{
100     AVAudioSession *audioSession=[AVAudioSession sharedInstance];
101     //设置为录音状态
102     [audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
103     [audioSession setActive:YES error:nil];
104 }/**
105  *  录音声波监控定制器
106  *
107  *  @return 定时器
108  */
109 -(NSTimer *)timer{
110     if (!_timer) {
111         //创建一个定时器
112         _timer=[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(audioPowerChange) userInfo:nil repeats:YES];
113     }
114     return _timer;
115 };
116 
117 /**
118  *  录音声波状态设置
119  */
120 -(void)audioPowerChange{
121     [self.audioRecorder updateMeters];//更新测量值
122     float power= [self.audioRecorder averagePowerForChannel:0];//取得第一个通道的音频,注意音频强度范围时-160到0
123     CGFloat progress=(1.0/160.0)*(power+160.0);
124     [self.audioPower setProgress:progress];
125 };
126 #pragma mark - UI事件
127 /**
128  *  点击录音按钮
129  *
130  *  @param sender 录音按钮
131  */
132 - (IBAction)recordBu:(UIButton *)sender {
133     if (![self.audioRecorder isRecording]) {
134         [self.audioRecorder record];//首次使用应用时如果调用record方法会询问用户是否允许使用麦克风,需要在info.plist加权限
135        //创建一个定时器
136         self.timer.fireDate=[NSDate distantPast];
137     }
138 };
139 
140 /**
141  *  点击暂定按钮
142  *
143  *  @param sender 暂停按钮
144  */
145 - (IBAction)pauseBu:(UIButton *)sender {
146     if ([self.audioRecorder isRecording]) {
147         [self.audioRecorder pause];
148         self.timer.fireDate=[NSDate distantFuture];
149         NSLog(@"录音暂停");
150     }
151 };
152 
153 /**
154  *  点击恢复按钮
155  *  恢复录音只需要再次调用record,AVAudioSession会帮助你记录上次录音位置并追加录音
156  *
157  *  @param sender 恢复按钮
158  */
159 - (IBAction)resumeBu:(UIButton *)sender {
160     [self recordBu:sender];
161     NSLog(@"录音继续");
162 };
163 
164 /**
165  *  点击停止按钮
166  *
167  *  @param sender 停止按钮
168  */
169 - (IBAction)stopBu:(UIButton *)sender {
170     [self.audioRecorder stop];
171     self.timer.fireDate=[NSDate distantFuture];
172     self.audioPower.progress=0.0;
173     NSLog(@"录音文件路径%@",[self getSavePath]);
174 };
175 /**
176  
177     退出
178  */
179 -(IBAction)exitBu:(UIButton *)sender{
180     exit(0);
181 };
182 #pragma mark - 录音机代理方法
183 /**
184  *  录音完成,录音完成后播放录音
185  *
186  *  @param recorder 录音机对象
187  *  @param flag     是否成功
188  */
189 /*
190 -(void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
191     if (![self.audioPlayer isPlaying]) {
192         [self.audioPlayer play];
193     }
194     NSLog(@"录音完成!");
195 };
196 */
197 @end

列表界面代码

  9 #import "ViewController2.h"
 10 #import <Foundation/Foundation.h>
 11 #import <AVFoundation/AVFoundation.h>
 12 #import "ViewController3.h"
 13 #import "Single.h"
 14 @interface ViewController2 () <AVAudioRecorderDelegate,UITableViewDelegate,UITableViewDataSource>
 15 //,UITableViewDelegate, UITableViewDataSource>
 16 //tableView
 17 @property (strong, nonatomic) IBOutlet UITableView *recoderTableView;
 18 
 19 @property (strong,nonatomic ) IBOutlet UIButton  *remove;
 20 
 21 
 22 
 23 
 24 @end
 25 
 26 
 27 @implementation ViewController2
 28 
 29 - (void)viewDidLoad {
 30     [super viewDidLoad];
 31     self.recoderTableView.dataSource=self;
 32     
 33 }
 34 
 35 //返回数组共下面的方法调用
 36 -(NSMutableArray *)getFileList{
 37     NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
 38     NSFileManager *fileManager = [NSFileManager defaultManager];
 39     //将doc下面的文件,以caf为后缀的全部存入数组
 40     //  NSMutableArray *ss=[fileManager enumeratorAtPath:urlStr];
 41     NSMutableArray *ss=[fileManager contentsOfDirectoryAtPath:urlStr error:nil];
 42      return  ss;
 43     // NSString *file;
 44 /* for(int i=0;i<[ss count];i++)
 45     while(file=[ss indexOfObject:i])
 46     {
 47         if([[file pathExtension] isEqual:@".caf"])
 48         {
 49             [fileList addObject:file];
 50             //看file是否有信息
 51             NSLog(@"%@",file);
 52         }
 53     }*/
 54 }
 55 //tableView 的相关方法
 56 //告诉控件分为几组
 57 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 58 {
 59     return  1;
 60 }
 61 //告诉UI每组显示几行数据,section参数表示第几组,只有1组,那么section为0
 62 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 63 {
 64     //一组数据,返回存储文件名称的数组长度
 65     return [[self getFileList]count];
 66 }
 67 //告诉控件每组的每行显示什么单元格内容
 68 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
 69 {
 70     UITableViewCell  *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
 71  //右侧的按钮
 72     cell.accessoryType=UITableViewCellAccessoryDetailButton;
 73     
 74     //获取存了文件信息的数组然后遍历赋值到cell文本中
 75    NSMutableArray *ss=[self getFileList];
 76     for(int i=0;i<[tableView numberOfRowsInSection:0];i++)
 77     {
 78      //   indexPath.section==0
 79     //控制每行的
 80       if( indexPath.row==i)
 81         cell.textLabel.text=[ss objectAtIndex:i];
 82     }
 83     return cell;
 84     
 85 }
 86 #pragma  ui控件操作
 87 -(IBAction)deleteBU:(UIButton *)sender{
 88     //setedit animate让tableView进入可编辑模式
 89     [_recoderTableView setEditing:!_recoderTableView.isEditing animated:true];
 90 }
 91 //对tableView自带删除功能的方法实现
 92 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
 93 {
 94     
 95     if (editingStyle == UITableViewCellEditingStyleDelete) {//删除
 96         NSFileManager *fileM=[NSFileManager new];
 97         NSString *newUrl2=[self cellItemPath:indexPath];
 98         [fileM removeItemAtPath:newUrl2 error:nil];
 99        // sing.singleCase=toUrl;
100         [self.recoderTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];//删除刷新
101     }
102     
103 }
104 //tableView右侧的点击跳转,需要将URL通过单例对象送到第三个页面
105 - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
106 {
107     NSString *newUrl2=[self cellItemPath:indexPath];
108     NSURL *toUrl=[[NSURL alloc]initFileURLWithPath:newUrl2];
109     NSLog(@"页面二准备复制给单例对象的URL是%@",toUrl);
110     [Single sharedInstance].value=toUrl;
111     //跳转代码
112     UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:@"ViewController3"];
113     [self presentModalViewController:next animated:NO];
114 
115 }
116 //cell中拿到每行文件的信息,并且拼装成完整的路径,供删除当前行方法,和点击当前行跳转方法使用
117 -(NSString  *)cellItemPath:(NSIndexPath *)indexPath{
118     NSFileManager *fileM=[NSFileManager new];
119     NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
120     //     NSString *newStr=urlStr+indexPath.row;
121     NSArray *newArr=[fileM contentsOfDirectoryAtPath:urlStr error:nil];
122     //行数
123     int i=indexPath.row;
124     //接收要删除的元素
125     NSString *newPro;
126     for(int j=0;j<[newArr count];j++)
127     {
128         if(j==i)
129         {
130             newPro= [newArr objectAtIndex:i];
131         }
132     }
133     //重新拼接路径,路径文件夹名+/+要删除  的文件名
134     NSString *newUrl=[urlStr stringByAppendingString:@"/"];
135     NSString *newUrl2=[newUrl stringByAppendingString:newPro];
136     return  newUrl2;
137 }
138 
139 
140 
141 @end

播放界面代码

#import "ViewController3.h"
#import <AVFoundation/AVFoundation.h>
#import "ViewController.h"
#import "ViewController2.h"
#import "Single.h"
@interface ViewController3 ()<AVAudioRecorderDelegate>
@property (nonatomic,strong) NSTimer *timer;  //声波监控,对播放进行监控
@property (weak, nonatomic) IBOutlet UIProgressView *audioPower;//音频波动
@property (nonatomic,strong) AVAudioPlayer *audioPlayer;//音频播放器,用于播放录音文件
@property (weak,nonatomic ) IBOutlet UIButton *pause;//暂停
@property (weak,nonatomic ) IBOutlet UIButton *conti;//继续
@property (weak,nonatomic ) IBOutlet UIButton *back;//返回
//通过单例对象拿到第二个控制器的cell对象传的URL
@property (nonatomic,copy) NSURL *url;

@property (weak, nonatomic) IBOutlet UIButton *exit0;

@end

@implementation ViewController3

- (void)viewDidLoad {
    [super viewDidLoad];
    _url=[Single sharedInstance].value;
    
    NSLog(@"页面三%@",_url);
    if(!_audioPlayer){
    _audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:_url error:nil];
    _audioPlayer.numberOfLoops=0;
    [_audioPlayer prepareToPlay];
    
    //开启定时器
    self.timer.fireDate=[NSDate distantPast];
    }
     
    [self setAudioSession];
[self.audioPlayer play]; }
/** * 设置音频会话 */ -(void)setAudioSession{ AVAudioSession *audioSession=[AVAudioSession sharedInstance]; //设置为播放状态 [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; [audioSession setActive:YES error:nil]; } /** * 录音声波监控定制器 * * @return 定时器 */ -(NSTimer *)timer{ if (!_timer) { //创建一个定时器 _timer=[NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(audioPowerChange) userInfo:nil repeats:YES]; } return _timer; }; /** * 播放声波状态设置 */ -(void)audioPowerChange{ float progress= self.audioPlayer.currentTime /self.audioPlayer.duration; [self.audioPower setProgress:progress animated:true]; }; #pragma UI操作 //退出 -(IBAction)exitBu:(UIButton *)sender{ exit(0); }; //返回 -(IBAction)backBu:(UIButton *)sender{ UIViewController *next = [[self storyboard] instantiateViewControllerWithIdentifier:@"ViewController2"]; [self presentModalViewController:next animated:NO]; }; //暂停 -(IBAction)pauseBu:(UIButton *)sender { [self.audioPlayer pause]; self.timer.fireDate=[NSDate distantFuture]; }; //继续 -(IBAction)contiBu:(UIButton *)sender{ [self.audioPlayer play]; self.timer.fireDate=[NSDate distantPast]; } @end

还有个单例类存URL的代码,这个我写过了,在随笔里

 

posted @ 2020-06-19 13:56  DDD-SagerKing  阅读(1403)  评论(0编辑  收藏  举报