swift 录音 AVAudioRecorder
2018年05月16日 15:22:44 msmwncx阅读数:548
https://blog.csdn.net/msmwncx/article/details/80336973
版权声明:本文为博主原创文章,未经博主允许不得转载。如有问题,请联系QQ547394765 https://blog.csdn.net/msmwncx/article/details/80336973
距离上次写博客已经好久好久了ZZZzzzzzzz。
首先交代下用处,做的IM项目,需要语音聊天,研究了下AVAudioRecorder。
其实挺简单的,主要步骤就是 创建一个recorder -> recorder.record() -> recorder.stop()
不多说 上代码
func createRecord(path: String) {
if self.recorder != nil {
self.resetRecorder()
}
let url = URL(fileURLWithPath: path)
self.cafPathStr = path
self.mp3PathStr = self.recordFileCaf2Mp3(cafPath: path)
let setting = self.recordSetting()
do {
self.recorder = try AVAudioRecorder(url: url, settings: setting)
self.recorder?.delegate = self
self.recorder?.isMeteringEnabled = true
} catch {
XMPPAudioLog("create recorder error:")
}
}
func startRecord(path: String) {
guard self.recorder == nil else {
EdoAssertionFailure("should reset recorder before start record")
return
}
if self.recorder == nil {
self.createRecord(path: path)
}
guard let _ = self.recorder else {
assertionFailure("ChatAudio: recorder could not be nil")
return
}
//if isRecording, should stop first
if let _ = self.recorder?.isRecording {
self.recorder?.stop()
}
//stop all player
self.stopAllMusic()
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
if let isRecorder = self.recorder?.isRecording, isRecorder == false {
self.recorder?.record()
}
} catch {
}
}
这里的mp3PathStr是转换成MP3格式的路径
这里是一些配置还有大小以及mp3路径的转换方法
func recordSetting() -> [String: Any] {
var recordSetting = [String: Any]()
//format of record
/****
kAudioFormatMPEG4AAC压缩格式能在显著减小文件的同时,保证音频的质量。
****/
recordSetting[AVFormatIDKey] = NSNumber(value: kAudioFormatLinearPCM)
//sampling rate of record
/******
采样率越高,文件越大,质量越好,反之,文件小,质量相对差一些,但是低于普通的音频,人耳并不能明显的分辨出好坏。最终选取哪一种采样率,由我们的耳朵来判断。建议使用标准的采样率,8000、16000、22050、44100。
*****/
recordSetting[AVSampleRateKey] = NSNumber(value: 8000)
//The quality of record
recordSetting[AVEncoderAudioQualityKey] = NSNumber(value: AVAudioQuality.high.rawValue)
//线性采样位数 8、16、24、32
recordSetting[AVLinearPCMBitDepthKey] = NSNumber(value: 8)
//录音通道数 1 或2
/****
AVNumberOfChannelsKey用于指定记录音频的通道数。1为单声道,2为立体声。
***/
recordSetting[AVNumberOfChannelsKey] = NSNumber(value: 2)
return recordSetting
}
func fileSizeAtPath(path: String) -> String {
if FileManager.default.fileExists(atPath: path) {
let attributes = try? FileManager.default.attributesOfItem(atPath: path)
if let attrs = attributes, let size = attrs[FileAttributeKey(rawValue:"NSFileSize")] as? Int64 {
return ByteCountFormatter.string(fromByteCount: size, countStyle: ByteCountFormatter.CountStyle.file)
}
}
return "0 KB"
}
func recordFileCaf2Mp3(cafPath: String) -> String {
var mp3Path = cafPath
if cafPath.hasSuffix(".caf") {
mp3Path = cafPath.replacingOccurrences(of: "caf", with: "mp3", options: NSString.CompareOptions.caseInsensitive, range: Range(cafPath.index(cafPath.startIndex, offsetBy: cafPath.count - 3)..<cafPath.endIndex))
}
return mp3Path
}
由于我这边是要做语音聊天,所以每次结束都会把recorder销毁掉
func deleteRecording() {
guard let recorder = self.recorder, recorder.isRecording == false else {
assertionFailure("ChatAudio: recorder must be stopped")
return
}
self.recorder?.deleteRecording()
self.resetRecorder()
}
func resetRecorder() {
self.recorder?.stop()
self.recorder = nil
self.mp3PathStr = ""
self.cafPathStr = ""
}
emmmm 好像就这么多了 具体一些缘由 为什么这么写什么的 可以参考一下apple的官方资料
然后就是转MP3
转mp3我是用的lame.h 和 libmp3lame.a 然后遇到一个什么 libmp3lame.a 不支持bitcode什么的问题 于是用以下解决
1.http://sourceforge.net/projects/lame/files/lame/3.99/ 下载lame的最新版本并解压
2.https://github.com/kewlbear/lame-ios-build 下载build的脚本 下载之后得到lame-build.sh拷贝到刚才解压后的文件夹
3.用一些编辑器按照注释修改lame-build.sh 如下图
4.cd 到1解压的目录下 执行脚本 chmod 777 lame-build.sh 等待1分钟左右就编译完成了
5.里边生成fat-lame目录和thin-lame目录,分别存放合并所有指令集的静态库,以及各指令集的静态库. 具体用哪个里边的lame.h和libmp3lame.a 我就忘记了。。。试一下吧。
然后就是转MP3文件了
我查了下资料,前人大部分都是用的OC写的 于是我用了一个OC文件转译了一下
+ (BOOL)audio_PCMtoMP3:(NSString *)cafPath mp3Path:(NSString *)mp3Path {
@try {
int read, write;
FILE *pcm = fopen([cafPath cStringUsingEncoding:1], "rb"); //source 被转换的音频文件位置
fseek(pcm, 4*1024, SEEK_CUR); //skip file header
FILE *mp3 = fopen([mp3Path cStringUsingEncoding:1], "wb"); //output 输出生成的Mp3文件位置
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
//should be equle with AVSampleRateKey
lame_set_in_samplerate(lame, 8000.0);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
lame_close(lame);
fclose(mp3);
fclose(pcm);
}
@catch (NSException *exception) {
NSLog(@"%@",[exception description]);
return NO;
}
@finally {
NSLog(@"MP3生成成功: %@",mp3Path);
return YES;
}
}
注意里边有一句
lame_set_in_samplerate(lame, 8000.0);
这里的8000要与recorder设置里的采样率一致,否则会变声。(我感觉一些app的变音就是这么来的,有兴趣可以试试,开始我设置的采样率是8000,这里写的是44100,然后声音特别细)
swift 录音 AVAudioRecorder的更多相关文章
- iOS开发简记(4):录音AVAudioRecorder
录音,声音的采集,一般有两种实现办法,一是使用AVAudioRecorder,一是使用AudioUnit.如果只是简单的录音,使用AVAudioRecorder就可以了,如果想更灵活地处理刚录到的声音 ...
- iOS开发(4):录音AVAudioRecorder
录音,声音的采集,一般有两种实现办法,一是使用AVAudioRecorder,一是使用AudioUnit.如果只是简单的录音,使用AVAudioRecorder就可以了,如果想更灵活地处理刚录到的声音 ...
- Domain=NSOSStatusErrorDomain Code=1937337955 关于iOS录音AVAudioRecorder与音频播放AVAudioPlayer真机调试录音不能播放的问题
error:Domain=NSOSStatusErrorDomain Code=1937337955 ,这个错误很常见, 原因是因为我们需要调用另外一个AVAudioPlayer 的初始化方法,来确定 ...
- ios录音Demo
<AudioToolbox/AudioToolbox.h> :这个库是C的接口,偏向于底层,主要用于在线流媒体的播放 <AVFoundation/AVFoundation.h> ...
- Audio/Movie/Image
Audio 1. 引入AVFoundation 库,此库用于处理音频的播放. > 使用AVAudioPlayer 播放音频,此类只能播放本地音频文件.对于流媒体(边下边播)的播放使用第三方框架实 ...
- 用swift实现自动录音器
基本介绍 自动录音与一般录音区别在:不用像微信那样按下录音-松手结束,而是根据说话声音的大小自动判断该录音和该停止的点,然后可以做到结束录音之后马上播放出来.类似于达到会说话的汤姆猫那样的效果. 在自 ...
- Swift实现iOS录音与播放音频功能
作用AVPLayer:可以用来播放在线及本地音视频AVAudioSession:音频会话,主要用来管理音频设置与硬件交互使用时需要导入 #import <AVFoundation/AVFound ...
- iOS AVAudioRecorder 录音频率、声道、位数配置 wav格式
iOS AVAudioRecorder 录音频率.声道.位数配置 #pragma mark 录音设置 - (void)setUP_VOICE_RECOARDER { NSError *error = ...
- iOS开发-解决AVAudioRecorder录音文件无法保存的问题
我们在开发iOS客户端APP时,有时候会用到录音的功能,一般会使 AVAudioRecorder 这个类.如下面这样: @interface MyViewController : UIViewCont ...
随机推荐
- php 打印格式化显示利器 <pre>
当我们PHP调试的时候,用var_dump 或 print_r打印json数据或array数组时,html页面没有换行显示,看到的内容一大堆,不好定位. 输出前添加 <pre>,便可以自动 ...
- POJ 3669 Meteor Shower BFS求最小时间
Meteor Shower Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 31358 Accepted: 8064 De ...
- java 搭积木
搭积木 小明最近喜欢搭数字积木, 一共有10块积木,每个积木上有一个数字,0~9. 搭积木规则: 每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小. 最后搭成4层的金字塔形,必须用完所有 ...
- 洛谷P2296 寻找道路
\(\Large\textbf{Description:} \large {在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:}\) \ ...
- Redis详解(七)——集群
Redis详解(七)--集群 Redis3.0版本之前,可以通过Redis Sentinel(哨兵)来实现高可用 ( HA ),从3.0版本之后,官方推出了Redis Cluster,它的主要用途是 ...
- Redis详解(五)——主从复制
Redis详解(五)--主从复制 面临问题 机器故障.我们部署到一台 Redis 服务器,当发生机器故障时,需要迁移到另外一台服务器并且要保证数据是同步的.而数据是最重要的,如果你不在乎,基本上也就不 ...
- Java 解决Emoji表情过滤问题
Emoji表情从三方数据中获取没有过滤,导致存入DB的时候报错. 原因: UTF-8编码有可能是两个.三个.四个字节.Emoji表情是4个字节,而Mysql的utf8编码最多3个字节,所以数据插不进去 ...
- Django(十三)状态保持 —— cookie与session+ajax异步请求+session记住登录状态+cookie记住登录名密码
一.状态保持的概述 http协议是无状态的.下一次去访问一个页面时并不知道上一次对这个页面做了什么.因此引入了cookie.session两种方式来配合解决此问题. Duplicate entry:重 ...
- IIC协议解析
(1)概述 I2C(Inter-Integrated Circuit BUS) 集成电路总线,该总线由NXP(原PHILIPS)公司设计,多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距 ...
- TBLASTN
TBLASTN search translated nucleotide databases using a protein query