注册
iOS

一个录音项目的开发总结(一)

最近,工作之余,自己做了一个项目,项目的一期主要功能是音频录制和播放,音频格式包含m4a、mp3、wav三种格式,录制过程中要支持变音,还要能获取到metering以绘制录音过程的声音强弱变化图,播放功能包括音频波形图的绘制以及音频播放。


在做之前,我对iOS中的录音方面的知识了解甚少, 以至于走了很多弯路,虽然浪费了很多时间,但是也从中学到了很多知识,最终完成了项目的编码。


以下,主要介绍录音方面开发总结,播放方面后续记录。


在iOS中如果想实现录音功能,那么有四种方式可以实现:



  1. AVAudioRecorder :这是最简单的录音方式,只需要配置好录音格式就能得到相应的文件,但是相应的,这种方式无法得到录音过程中的音频源数据,无法实现变音功能和录制mp3文件。
  2. AVAudioEngine:AVAudioEngine功能强大,能实现录音、播放、混响、变音等功能,当我发现我这个类时,我高兴坏了,看了很多文档,结果做demo时,发现这个类外强中干,譬如你不能改变AudioEngine默认的inputNode、outputNode、mainMixNode的数据format,即使你千辛万苦找方法成功改变了数据格式,输出的数据也会狠狠地扇你一巴掌,告诉你高兴太早了,而且inputNode、outputNode、mainMixNode不会自动转换数据格式......如果想录制m4a、mp3还是需要其他方式才能实现。
  3. AudioQueue & AudioFile:AudioQueue在录音过程中有个回调方法,抛出编码后的音频数据,如果想处理音频数据,譬如变音、转码,可以在这个回调中实现,而且能获取到metering数据; AudioFile用于存储回调方法中抛出的音频数据,这个音频数据要与AudioFile创建时配置的inFormat一致。如果想了解audioqueue,可以看看这个文档
  4. AudioUnit &  ExtAudioFile:AudioUnit在录音过程中也会有回调,AudioUnit只支持pcm录制,所以要辅以ExtAudioFile来实现其他音频格式的录制,ExtAudioFile是个宝藏类,这个类可以实现音频格式的自动转换。

如果只是单纯的录用,那么使用AVAudioRecorder就可以非常简单的实现了,如果想对音频数据做处理,那么对于录音过程中抛出的数据请务必是pcm,只要能拿到pcm源数据,任何能做到的音频处理只要你想,都能实现。


iOS中,系统支持的录音编码格式为:


官方参考文档点击查看



wav文件是无损编码格式pcm,m4a文件编码格式AAC,mp3文件iOS系统不支持录制,系统支持mp3文件播放,有解码器但是无相应编码器,如果想录制mp3 文件只能依托于第三方的编码库,我采用的是lame库。


变音


iOS系统中本身是支持变音功能的,AudioUnit中有一个属性kNewTimePitchParam_Pitch,可以改变声音的音色,但是这个属性是MixerUnit的属性,录音的OutputUnit不支持这个属性,要想将 混音MixerUnit和录音OutputUnit连接到一块,需要AUGraph类去连接,但是AUGraph已弃用。。。系统推荐去使用AVAudioEngine类,这个类也是个坑,我在做demo时无法实现m4a文件的录制,就放弃了。


所以变音我采用的也是三方类SoundTouch,SoundTouch支持pcm编码、音频数据是lettle-endian,所以录音过程中抛出的音频buffer的format必须是pcm的,不然无法实现边录音边变音。


这样看起来AudioUnit貌似更适合这个项目一些,但是AudioUnit无法获取到录音过程中的metering数据,真是个令人悲伤的事情,AudioUnit很强大,如果AUGraph不被弃用,可能我会用它来录音。


最终我的实现方案是:


1、wav文件录制:AudioQueue录音、 AudioFile存储文件,AudioQueue和AudioFile的dataFormat为:


AudioStreamBasicDescription mDataFormat;

mDataFormat.mSampleRate = 44100;
mDataFormat.mChannelsPerFrame = 1;
mDataFormat.mReserved = 0;
mDataFormat.mBitsPerChannel = 16;
mDataFormat.mFramesPerPacket = 1;
mDataFormat.mSampleRate = self.model.sampleRate;
mDataFormat.mBytesPerFrame = mDataFormat.mBytesPerPacket = 2;
mDataFormat.mFormatID = kAudioFormatLinearPCM;
mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;


AudioFile的fileType为kAudioFileCAFType


2、mp3文件:AudioQueue录音, lame转码, FILE文件存储, AudioQueue的编码格式为:


AudioStreamBasicDescription mDataFormat;

mDataFormat.mSampleRate = 44100;
mDataFormat.mChannelsPerFrame = 1;
mDataFormat.mReserved = 0;
mDataFormat.mBitsPerChannel = 16;
mDataFormat.mFramesPerPacket = 1;
mDataFormat.mSampleRate = self.model.sampleRate;
mDataFormat.mBytesPerFrame = mDataFormat.mBytesPerPacket = 2;
mDataFormat.mFormatID = kAudioFormatLinearPCM;
mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
| kLinearPCMFormatFlagIsPacked
|kAudioFormatFlagIsNonInterleaved


3、m4a文件:AudioQueue录音,  ExtAudioFile转码加存储,AudioQueue和ExtAudioFile的kExtAudioFileProperty_ClientDataFormat属性的编码格式为:


AudioStreamBasicDescription mDataFormat;

mDataFormat.mSampleRate = 44100;
mDataFormat.mChannelsPerFrame = 1;
mDataFormat.mReserved = 0;
mDataFormat.mBitsPerChannel = 16;
mDataFormat.mFramesPerPacket = 1;
mDataFormat.mSampleRate = self.model.sampleRate;
mDataFormat.mBytesPerFrame = mDataFormat.mBytesPerPacket = 2;
mDataFormat.mFormatID = kAudioFormatLinearPCM;
mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;


ExtAudioFile文件的音频编码格式为:


AudioStreamBasicDescription outputFormat;outputFormat.mSampleRate = 44100;

outputFormat.mFormatID = kAudioFormatMPEG4AAC;outputFormat.mFormatFlags = 0;outputFormat.mBytesPerPacket = 0;outputFormat.mFramesPerPacket = 1024;

outputFormat.mBytesPerFrame = 0;outputFormat.mChannelsPerFrame = 1;outputFormat.mBitsPerChannel = 0;outputFormat.mReserved = 0;


关于四种录音方式的代码实现后续会更新,音频编辑功能,二期可能会上,到时也会研究、记录,希望到时自己不会太懒......


作者:阿喵同学
链接:https://juejin.cn/post/6936869349546426382

0 个评论

要回复文章请先登录注册