服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS多媒体音频(下)-录音及其播放的实例

iOS多媒体音频(下)-录音及其播放的实例

2021-02-28 14:24程序员小强 IOS

本篇文章主要介绍了iOS多媒体音频(下)-录音及其播放的实例,非常具有实用价值,需要的朋友可以参考下。

上一篇中总结了ios中音效和音频播放的最基本使用方法,其中音频的播放控制是使用avfoundation.framework框架中的avaudioplayer播放器对象来实现的,而这里音频的录制则是使用了同样框架下的一个叫avaudiorecorder的录音机对象来实现,这两个类的用法流程非常类似,类的属性和方法也类似,例如:播放器中需要获取音频文件的url,而录音机要在沙盒中docuemnt目录下创建一个音频文件路径url;

播放器有isplaying变量判断是否正在播放,录音机中有isrecording变量表示是否正在录制;currenttime在播放器中表示播放时间,在录音机中则表示录音时间;播放器通过preparetoplay方法加载文件到缓冲区,录音机通过preparetorecord创建缓冲区;播放音频有play方法,音频录制有record方法,另外都有pause暂停方法和stop停止方法等等,具体可直接打开两个类的头文件详细了解。

这里实现最基本的录音流程以及录音过程的控制,并通过之前使用的avaudioplayer来播放录制好的音频。注意ios录制的音频为caf格式,如果需要通用化可以通过lame等插件将caf格式音频转成mp3格式。

iOS多媒体音频(下)-录音及其播放的实例

录音

这里实现开始录音,暂停,继续以及停止录音。

创建文件目录

ios沙盒内胡要有三个目录:documents目录,tmp目录以及library目录,其中documents目录用来存放用户的应用程序数据,需要定期备份的数据要放在这里,和plist文件存储一样,我们要找到存放文件的路径,然后在该路径下放一个我们的文件,因此要自定义一个带后缀的文件名,将获得的路径和文件名拼在一起记得到我们的文件的绝对路径:

?
1
2
3
4
5
6
7
8
9
// 文件名
#define filename_caf @"demorecord.caf"
// 录音文件绝对路径
@property (nonatomic, copy) nsstring *filepathcaf;
 
// 获取沙盒document文件路径
nsstring *sandboxpath = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];
// 拼接录音文件绝对路径
_filepathcaf = [sandboxpath stringbyappendingpathcomponent:filename_caf];

创建音频会话

录音前要创建一个音频会话,同时要设置录音类型,提供的类型有以下几种:

  • avf_export nsstring *const avaudiosessioncategoryambient; // 用于录制背景声音,像雨声、汽车引擎发动噪音等,可和其他音乐混合
  • avf_export nsstring *const avaudiosessioncategorysoloambient; // 也是背景声音,但其他音乐会被强制停止
  • avf_export nsstring *const avaudiosessioncategoryplayback; // 音轨
  • avf_export nsstring *const avaudiosessioncategoryrecord; // 录音
  • avf_export nsstring *const avaudiosessioncategoryplayandrecord; // 录音和回放
  • avf_export nsstring *const avaudiosessioncategoryaudioprocessing; // 用于底层硬件编码信号处理等
  • avf_export nsstring *const avaudiosessioncategorymultiroute; // 内置硬件相关,ios 6.0以上可用

常用的是avaudiosessioncategoryplayandrecord类型,便于录音后播放。

?
1
2
3
4
5
// 创建音频会话
avaudiosession *audiosession=[avaudiosession sharedinstance];
// 设置录音类别(这里选用录音后可回放录音类型)
[audiosession setcategory:avaudiosessioncategoryplayandrecord error:nil];
[audiosession setactive:yes error:nil];

录音设置

录音前要根据需要对录音进行一些相应的基本设置,例如录音格式(linearpcm)、采样率、通道数等等,设置保存在一个字典内并作为初始化录音机的一个参数。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 录音设置
-(nsdictionary *)getaudiosetting{
  // linearpcm 是ios的一种无损编码格式,但是体积较为庞大
  // 录音设置信息字典
  nsmutabledictionary *recordsettings = [[nsmutabledictionary alloc] init];
  // 录音格式
  [recordsettings setvalue :@(kaudioformatlinearpcm) forkey: avformatidkey];
  // 采样率
  [recordsettings setvalue :@11025.0 forkey: avsampleratekey];
  // 通道数(双通道)
  [recordsettings setvalue :@2 forkey: avnumberofchannelskey];
  // 每个采样点位数(有8、16、24、32)
  [recordsettings setvalue :@16 forkey: avlinearpcmbitdepthkey];
  // 采用浮点采样
  [recordsettings setvalue:@yes forkey:avlinearpcmisfloatkey];
  // 音频质量
  [recordsettings setvalue:@(avaudioqualitymedium) forkey:avencoderaudioqualitykey];
  // 其他可选的设置
  // ... ...
 
  return recordsettings;
}

创建录音机对象

录音机对象的创建主要是利用上面的保存路径和录音设置进行初始化得到:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 懒加载录音机对象get方法
- (avaudiorecorder *)audiorecorder {
  if (!_audiorecorder) {
    // 保存录音文件的路径url
    nsurl *url = [nsurl urlwithstring:_filepathcaf];
    // 创建录音格式设置setting
    nsdictionary *setting = [self getaudiosetting];
    // error
    nserror *error=nil;
 
    _audiorecorder = [[avaudiorecorder alloc]initwithurl:url settings:setting error:&error];
    _audiorecorder.delegate = self;
    _audiorecorder.meteringenabled = yes;// 监控声波
    if (error) {
      nslog(@"创建录音机对象时发生错误,错误信息:%@",error.localizeddescription);
      return nil;
    }
  }
  return _audiorecorder;
}

录音控制方法

录音过程控制主要是开始录音、暂停、继续和停止录音,其中开始录音和继续录音都是record方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 开始录音或者继续录音
- (ibaction)startorresumerecord {
  // 注意调用audiorecorder的get方法
  if (![self.audiorecorder isrecording]) {
    // 如果该路径下的音频文件录制过则删除
    [self deleterecord];
    // 开始录音,会取得用户使用麦克风的同意
    [_audiorecorder record];
  }
}
 
// 录音暂停
- (ibaction)pauserecord {
  if (_audiorecorder) {
    [_audiorecorder pause];
  }
}
 
// 结束录音
- (ibaction)stoprecord {
  [_audiorecorder stop];
}

录音播放

录音的播放很简单,就是之前avaudioplayer音频播放的简单应用,播放的路径即我们录音时创建好的音频路径。但这里注意为了保证每次都播放最新录制的音频,播放器的get方法要每次重新创建初始化。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// audioplayer懒加载getter方法
- (avaudioplayer *)audioplayer {
  _audiorecorder = null; // 每次都创建新的播放器,删除旧的
 
  // 资源路径
  nsurl *url = [nsurl fileurlwithpath:_filepathcaf];
 
  // 初始化播放器,注意这里的url参数只能为本地文件路径,不支持http url
  nserror *error = nil;
  _audioplayer = [[avaudioplayer alloc]initwithcontentsofurl:url error:&error];
 
  //设置播放器属性
  _audioplayer.numberofloops = 0;// 不循环
  _audioplayer.delegate = self;
  _audioplayer.volume = 0.5; // 音量
  [_audioplayer preparetoplay];// 加载音频文件到缓存【这个函数在调用play函数时会自动调用】
 
  if(error){
    nslog(@"初始化播放器过程发生错误,错误信息:%@",error.localizeddescription);
    return nil;
  }
 
  return _audioplayer;
}
 
// 播放录制好的音频
- (ibaction)playrecordedaudio {
  // 没有文件不播放
  if (![[nsfilemanager defaultmanager] fileexistsatpath:self.filepathcaf]) return;
  // 播放最新的录音
  [self.audioplayer play];
}

完整源码和demo下载

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//
// viewcontroller.m
// iosrecorderdemo
//
// created by xinhou jiang on 29/12/16.
// copyright © 2016年 xinhou jiang. all rights reserved.
//
 
#import "viewcontroller.h"
#import <avfoundation/avfoundation.h>
 
// 文件名
#define filename_caf @"demorecord.caf"
 
@interface viewcontroller ()
 
// 录音文件绝对路径
@property (nonatomic, copy) nsstring *filepathcaf;
// 录音机对象
@property (nonatomic, strong) avaudiorecorder *audiorecorder;
// 播放器对象,和上一章音频播放的方法相同,只不过这里简单播放即可
@property (nonatomic, strong) avaudioplayer *audioplayer;
// 用一个processview显示声波波动情况
@property (nonatomic, weak) iboutlet uiprogressview *processview;
// 用一个label显示录制时间
@property (nonatomic, weak) iboutlet uilabel *recordtime;
// ui刷新监听器
@property (nonatomic, strong) nstimer *timer;
 
@end
 
@implementation viewcontroller
 
- (void)viewdidload {
  [super viewdidload];
  // 初始化工作
  [self initdata];
}
 
// 初始化
- (void)initdata {
  // 获取沙盒document文件路径
  nsstring *sandboxpath = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];
  // 拼接录音文件绝对路径
  _filepathcaf = [sandboxpath stringbyappendingpathcomponent:filename_caf];
 
  // 1.创建音频会话
  avaudiosession *audiosession=[avaudiosession sharedinstance];
  // 设置录音类别(这里选用录音后可回放录音类型)
  [audiosession setcategory:avaudiosessioncategoryplayandrecord error:nil];
  [audiosession setactive:yes error:nil];
 
  // 2.开启定时器
  [self timer];
}
 
#pragma mark -录音设置工具函数
// 懒加载录音机对象get方法
- (avaudiorecorder *)audiorecorder {
  if (!_audiorecorder) {
    // 保存录音文件的路径url
    nsurl *url = [nsurl urlwithstring:_filepathcaf];
    // 创建录音格式设置setting
    nsdictionary *setting = [self getaudiosetting];
    // error
    nserror *error=nil;
 
    _audiorecorder = [[avaudiorecorder alloc]initwithurl:url settings:setting error:&error];
    _audiorecorder.delegate = self;
    _audiorecorder.meteringenabled = yes;// 监控声波
    if (error) {
      nslog(@"创建录音机对象时发生错误,错误信息:%@",error.localizeddescription);
      return nil;
    }
  }
  return _audiorecorder;
}
 
// audioplayer懒加载getter方法
- (avaudioplayer *)audioplayer {
  _audiorecorder = null; // 每次都创建新的播放器,删除旧的
 
  // 资源路径
  nsurl *url = [nsurl fileurlwithpath:_filepathcaf];
 
  // 初始化播放器,注意这里的url参数只能为本地文件路径,不支持http url
  nserror *error = nil;
  _audioplayer = [[avaudioplayer alloc]initwithcontentsofurl:url error:&error];
 
  //设置播放器属性
  _audioplayer.numberofloops = 0;// 不循环
  _audioplayer.delegate = self;
  _audioplayer.volume = 0.5; // 音量
  [_audioplayer preparetoplay];// 加载音频文件到缓存【这个函数在调用play函数时会自动调用】
 
  if(error){
    nslog(@"初始化播放器过程发生错误,错误信息:%@",error.localizeddescription);
    return nil;
  }
 
  return _audioplayer;
}
 
// 计时器get方法
- (nstimer *)timer {
  if (!_timer) {
    _timer = [nstimer scheduledtimerwithtimeinterval:0.1f repeats:yes block:^(nstimer * _nonnull timer) {
      if(_audiorecorder) {
        // 1.更新录音时间,单位秒
        int curinterval = [_audiorecorder currenttime];
        _recordtime.text = [nsstring stringwithformat:@"%02d:%02d",curinterval/60,curinterval%60];
        // 2.声波显示
        //更新声波值
        [self.audiorecorder updatemeters];
        //第一个通道的音频,音频强度范围:[-160~0],这里调整到0~160
        float power = [self.audiorecorder averagepowerforchannel:0] + 160;
        [_processview setprogress:power/160.0];
      }
    }];
  }
  return _timer;
}
 
// 录音设置
-(nsdictionary *)getaudiosetting{
  // linearpcm 是ios的一种无损编码格式,但是体积较为庞大
  // 录音设置信息字典
  nsmutabledictionary *recordsettings = [[nsmutabledictionary alloc] init];
  // 录音格式
  [recordsettings setvalue :@(kaudioformatlinearpcm) forkey: avformatidkey];
  // 采样率
  [recordsettings setvalue :@11025.0 forkey: avsampleratekey];
  // 通道数(双通道)
  [recordsettings setvalue :@2 forkey: avnumberofchannelskey];
  // 每个采样点位数(有8、16、24、32)
  [recordsettings setvalue :@16 forkey: avlinearpcmbitdepthkey];
  // 采用浮点采样
  [recordsettings setvalue:@yes forkey:avlinearpcmisfloatkey];
  // 音频质量
  [recordsettings setvalue:@(avaudioqualitymedium) forkey:avencoderaudioqualitykey];
  // 其他可选的设置
  // ... ...
 
  return recordsettings;
}
 
// 删除filepathcaf路径下的音频文件
-(void)deleterecord{
  nsfilemanager* filemanager=[nsfilemanager defaultmanager];
  if ([[nsfilemanager defaultmanager] fileexistsatpath:self.filepathcaf]) {
    // 文件已经存在
    if ([filemanager removeitematpath:self.filepathcaf error:nil]) {
      nslog(@"删除成功");
    }else {
      nslog(@"删除失败");
    }
  }else {
    return; // 文件不存在无需删除
  }
}
 
#pragma mark -录音流程控制函数
// 开始录音或者继续录音
- (ibaction)startorresumerecord {
  // 注意调用audiorecorder的get方法
  if (![self.audiorecorder isrecording]) {
    // 如果该路径下的音频文件录制过则删除
    [self deleterecord];
    // 开始录音,会取得用户使用麦克风的同意
    [_audiorecorder record];
  }
}
 
// 录音暂停
- (ibaction)pauserecord {
  if (_audiorecorder) {
    [_audiorecorder pause];
  }
}
 
// 结束录音
- (ibaction)stoprecord {
  [_audiorecorder stop];
}
 
#pragma mark -录音播放
// 播放录制好的音频
- (ibaction)playrecordedaudio {
  // 没有文件不播放
  if (![[nsfilemanager defaultmanager] fileexistsatpath:self.filepathcaf]) return;
  // 播放最新的录音
  [self.audioplayer play];
}
 
@end

demo下载:demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/cordova/article/details/53933160

延伸 · 阅读

精彩推荐
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04