[TOC]
录音 AVAudioRecorder
初始化方法
/* The file type to create can be set through the corresponding settings key. If not set, it will be inferred from the file extension. Will overwrite a file at the specified url if a file exists. */
- (nullable instancetype)initWithURL:(NSURL *)url settings:(NSDictionary *)settings error:(NSError **)outError;
// 录音文件的url
@property(readonly) NSURL *url; /* URL of the recorded file */
// 录音文件的设置信息
/* these settings are fully valid only when prepareToRecord has been called */
@property(readonly) NSDictionary *settings;
-
url
: 录音文件保存的位置,一般都是保存到沙盒中
注意:
url
一般使用[NSURL fileURLWithPath:_filePath]
进行初始化,使用URLWithString:
方法初始化会初始化失败;原因就是URL
的格式,需要scheme
,fileURLWithPath
会添加file://
,但是URLWithString
不会做任何处理
-
settings
: 录音的配置信息,取值如下:
例子:
设置:
_settings = @{
AVFormatIDKey: @(kAudioFormatMPEG4AAC),
AVSampleRateKey: @(_sampleRate),
AVNumberOfChannelsKey: @2,
AVLinearPCMBitDepthKey: @16,
AVEncoderAudioQualityKey: @(AVAudioQualityHigh)
};
// 打印结果:
_audioRecorder.settings: {
AVAudioFileTypeKey = 1633973363;
AVEncoderBitDepthHintKey = 0; // 默认的
AVEncoderBitRateKey = 40000; // 默认的
AVEncoderQualityKey = 96;
AVFormatIDKey = 1633772320;
AVNumberOfChannelsKey = 2;
AVSampleRateKey = 11025;
}
注意,对于录音音量比较小的问题,需要添加下面的代码
// 音量控制,否则声音很小
NSError *volumError = nil;
[[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&volumError];
if (volumError) {
NSLog(@"音量控制失败 --- ");
NSLog(@"%@", volumError);
}
AVFormatIDKey
录音的文件格式
CF_ENUM(AudioFormatID)
{
kAudioFormatLinearPCM = 'lpcm',
kAudioFormatAC3 = 'ac-3',
kAudioFormat60958AC3 = 'cac3',
kAudioFormatAppleIMA4 = 'ima4',
kAudioFormatMPEG4AAC = 'aac ',
kAudioFormatMPEG4CELP = 'celp',
kAudioFormatMPEG4HVXC = 'hvxc',
kAudioFormatMPEG4TwinVQ = 'twvq',
kAudioFormatMACE3 = 'MAC3',
kAudioFormatMACE6 = 'MAC6',
kAudioFormatULaw = 'ulaw',
kAudioFormatALaw = 'alaw',
kAudioFormatQDesign = 'QDMC',
kAudioFormatQDesign2 = 'QDM2',
kAudioFormatQUALCOMM = 'Qclp',
kAudioFormatMPEGLayer1 = '.mp1',
kAudioFormatMPEGLayer2 = '.mp2',
kAudioFormatMPEGLayer3 = '.mp3',
kAudioFormatTimeCode = 'time',
kAudioFormatMIDIStream = 'midi',
kAudioFormatParameterValueStream = 'apvs',
kAudioFormatAppleLossless = 'alac',
kAudioFormatMPEG4AAC_HE = 'aach',
kAudioFormatMPEG4AAC_LD = 'aacl',
kAudioFormatMPEG4AAC_ELD = 'aace',
kAudioFormatMPEG4AAC_ELD_SBR = 'aacf',
kAudioFormatMPEG4AAC_ELD_V2 = 'aacg',
kAudioFormatMPEG4AAC_HE_V2 = 'aacp',
kAudioFormatMPEG4AAC_Spatial = 'aacs',
kAudioFormatAMR = 'samr',
kAudioFormatAMR_WB = 'sawb',
kAudioFormatAudible = 'AUDB',
kAudioFormatiLBC = 'ilbc',
kAudioFormatDVIIntelIMA = 0x6D730011,
kAudioFormatMicrosoftGSM = 0x6D730031,
kAudioFormatAES3 = 'aes3',
kAudioFormatEnhancedAC3 = 'ec-3',
kAudioFormatFLAC = 'flac',
kAudioFormatOpus = 'opus'
};
-
kAudioFormatLinearPCM
: 音频的原始文件(caf
) -
kAudioFormatMPEG4AAC
:aac
文件格式的音频
注意
文件格式不可以直接.mp3
格式,会报错
AVSampleRateKey
采用率(赫兹)``
常用的有
-
8,000 Hz
: 电话所用采样率, 对于人的说话已经足够 -
11,025 Hz
: 说话
参考文章:
https://baike.baidu.com/item/%E9%9F%B3%E9%A2%91%E9%87%87%E6%A0%B7%E7%8E%87/9023551
AVNumberOfChannelsKey
采用通道数,一般有:
-
1
: 单声道 -
2
: 双声道
linear PCM keys
AVLinearPCMBitDepthKey
采样深度,影响声音质量,比如从caf
转mp3
,如果设置为8
的话,声音可能会失真,需要设置更高一点(比如16
)
取值有: 8, 16, 24, 32
AVLinearPCMIsBigEndianKey
-
YES
: 大端模式 -
NO
: 小端模式
参考文章:
https://blog.csdn.net/chivalrousli/article/details/38419995
AVLinearPCMIsFloatKey
是否支持浮点处理
AVLinearPCMIsNonInterleaved
交叉的
audio file type key
11.0 之后
AVAudioFileTypeKey
AudioFile.h
文件中可以查看具体的
encoder property keys
编码属性
AVEncoderAudioQualityKey
编码质量
取值有:
typedef NS_ENUM(NSInteger, AVAudioQuality) {
AVAudioQualityMin = 0,
AVAudioQualityLow = 0x20,
AVAudioQualityMedium = 0x40,
AVAudioQualityHigh = 0x60,
AVAudioQualityMax = 0x7F
};
AVEncoderAudioQualityForVBRKey
动态比特率,取值是 AVAudioQuality
,只和AVAudioBitRateStrategy_Variable
有关
AVEncoderBitRateKey
编码比特率
注意
AVEncoderBitRateKey
和AVEncoderBitRatePerChannelKey
只需要设置一个 ;only one of AVEncoderBitRateKey and AVEncoderBitRatePerChannelKey should be provided.
AVEncoderBitRatePerChannelKey
每个声道的比特率
AVEncoderBitRateStrategyKey
编码比特率的策略
取值有:
/* values for AVEncoderBitRateStrategyKey */
AVF_EXPORT NSString *const AVAudioBitRateStrategy_Constant NS_AVAILABLE(10_9, 7_0);
AVF_EXPORT NSString *const AVAudioBitRateStrategy_LongTermAverage NS_AVAILABLE(10_9, 7_0);
AVF_EXPORT NSString *const AVAudioBitRateStrategy_VariableConstrained NS_AVAILABLE(10_9, 7_0);
AVF_EXPORT NSString *const AVAudioBitRateStrategy_Variable NS_AVAILABLE(10_9, 7_0);
AVEncoderBitDepthHintKey
取值 8 to 32
控制方法
// 准备录音
- (BOOL)prepareToRecord; /* creates the file and gets ready to record. happens automatically on record. */
// 开始录音
- (BOOL)record; /* start or resume recording to file. */
// 在设定的时间time开始录音
- (BOOL)recordAtTime:(NSTimeInterval)time NS_AVAILABLE_IOS(6_0); /* start recording at specified time in the future. time is an absolute time based on and greater than deviceCurrentTime. */
// 录音时间为 duration 秒,超过会自动停止
- (BOOL)recordForDuration:(NSTimeInterval) duration; /* record a file of a specified duration. the recorder will stop when it has recorded this length of audio */
// 在设定的时间time开始录音,录音最大时间长为 duration
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval) duration NS_AVAILABLE_IOS(6_0); /* record a file of a specified duration starting at specified time. time is an absolute time based on and greater than deviceCurrentTime. */
// 暂停
- (void)pause; /* pause recording */
// 停止
- (void)stop; /* stops recording. closes the file. */
// 删除录音
- (BOOL)deleteRecording; /* delete the recorded file. recorder must be stopped. returns NO on failure. */
// 是否正在录音中
@property(readonly, getter=isRecording) BOOL recording; /* is it recording or not? */
代理
/* the delegate will be sent messages from the AVAudioRecorderDelegate protocol */
@property(assign, nullable) id delegate;
@protocol AVAudioRecorderDelegate
@optional
/* audioRecorderDidFinishRecording:successfully: is called when a recording has been finished or stopped. This method is NOT called if the recorder is stopped due to an interruption. */
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag;
/* if an error occurs while encoding it will be reported to the delegate. */
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * __nullable)error;
#if TARGET_OS_IPHONE
/* AVAudioRecorder INTERRUPTION NOTIFICATIONS ARE DEPRECATED - Use AVAudioSession instead. */
/* audioRecorderBeginInterruption: is called when the audio session has been interrupted while the recorder was recording. The recorded file will be closed. */
- (void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder NS_DEPRECATED_IOS(2_2, 8_0);
/* audioRecorderEndInterruption:withOptions: is called when the audio session interruption has ended and this recorder had been interrupted while recording. */
/* Currently the only flag is AVAudioSessionInterruptionFlags_ShouldResume. */
- (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder withOptions:(NSUInteger)flags NS_DEPRECATED_IOS(6_0, 8_0);
- (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder withFlags:(NSUInteger)flags NS_DEPRECATED_IOS(4_0, 6_0);
/* audioRecorderEndInterruption: is called when the preferred method, audioRecorderEndInterruption:withFlags:, is not implemented. */
- (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder NS_DEPRECATED_IOS(2_2, 6_0);
#endif // TARGET_OS_IPHONE
@end
录音时间
/* get the current time of the recording - only valid while recording */
@property(readonly) NSTimeInterval currentTime;
/* get the device current time - always valid */
@property(readonly) NSTimeInterval deviceCurrentTime NS_AVAILABLE_IOS(6_0);
-
currentTime
: 当前的录音时间,录音时有效;停止录音的时候为0
-
deviceCurrentTime
: 当前的设备时间
录音时间的处理:
-
record
时记录deviceCurrentTime
为_recorderBeginTime
- 录音完成的代理方法
audioRecorderDidFinishRecording
记录结束时间为_recorderEndTime
-
_recorderEndTime
减去_recorderBeginTime
就得到了录音时间长,不过这只是一个大概的,不是很准确,aac
格式会有误差;
注意
1、使用caf
格式录音时,时间是准确的,设置recordForDuration:
方法也是有效的、准确的;
2、使用aac
格式录音时,设置recordForDuration:
方法也是不
准确的,有误差1秒多
录音最大时间的处理:
- 1、设置最大时间的方法:
BOOL result = [_audioRecorder recordAtTime:_audioRecorder.deviceCurrentTime forDuration:_maxDuration]
- 2、开启定时器进行处理
注:在定时器方法中也需要处理最大时间,aac
文件格式录音时间是不准确的
- (void)timerFire {
// 主线程执行
dispatch_async(dispatch_get_main_queue(), ^{
BOOL result = _audioRecorder.isRecording;
NSTimeInterval time = result ? _audioRecorder.currentTime : _audioPlayer.currentTime;
NSLog(@"currentTime: %f", _audioRecorder.currentTime);
NSLog(@"deviceCurrentTime: %f", _audioRecorder.deviceCurrentTime);
NSLog(@"_recorderBeginTime: %f", _recorderBeginTime);
NSLog(@"duration: %f", _audioRecorder.deviceCurrentTime - _recorderBeginTime);
// 录音的最大时间处理: (aac格式时间不准确,caf准确)
if (result) {
if (time > _maxDuration) {
[self stop];
return;
}
}
[self notifyToDelegateDidRecordingOrPalying:result currentTime:time];
});
}
补充
/* get the current time of the recording - only valid while recording */
@property(readonly) NSTimeInterval currentTime;
/* get the device current time - always valid */
@property(readonly) NSTimeInterval deviceCurrentTime NS_AVAILABLE_IOS(6_0);
-
currentTime
: 当前时间,录音时有效,停止录音的时候为0
-
deviceCurrentTime
: 一直有效,有值
代码:
NSLog(@"_audioRecorder 初始化完成");
[self _logRecordTime];
/// ------
- (BOOL)record {
NSLog(@"_audioRecorder 准备");
[self _logRecordTime];
BOOL result = [_audioRecorder recordAtTime:_audioRecorder.deviceCurrentTime forDuration:_maxDuration];
if (result) {
NSLog(@"_audioRecorder 开始");
[self _logRecordTime];
_recorderBeginTime = _audioRecorder.deviceCurrentTime;
} else {
[self notifyToDelegateRecorderInitFailed];
}
return result;
}
2018-08-22 18:06:38.177723+0800 HaiZiGuoParents[42414:12224854] _audioRecorder 初始化完成
2018-08-22 18:06:38.177745+0800 HaiZiGuoParents[42414:12224854] _audioRecorder.deviceCurrentTime: 1388447.325438
2018-08-22 18:06:38.177769+0800 HaiZiGuoParents[42414:12224854] _audioRecorder.currentTime: 0.000000
2018-08-22 18:06:38.177798+0800 HaiZiGuoParents[42414:12224854] _audioRecorder 准备
2018-08-22 18:06:38.177950+0800 HaiZiGuoParents[42414:12224854] _audioRecorder.deviceCurrentTime: 1388447.325647
2018-08-22 18:06:38.177971+0800 HaiZiGuoParents[42414:12224854] _audioRecorder.currentTime: 0.000000
2018-08-22 18:06:38.394655+0800 HaiZiGuoParents[42414:12224854] _audioRecorder 开始
2018-08-22 18:06:38.394743+0800 HaiZiGuoParents[42414:12224854] _audioRecorder.deviceCurrentTime: 1388447.542438
2018-08-22 18:06:38.394961+0800 HaiZiGuoParents[42414:12224854] _audioRecorder.currentTime: 0.026122
1388447.542438 - 1388447.325647 = 0.216791
可以看到以录音deviceCurrentTime
作为标准计算时间为 0.216791
,实际上currentTime
为0.026122
,差了一些
分贝
// 是否开启分贝检测
@property(getter=isMeteringEnabled) BOOL meteringEnabled; /* turns level metering on or off. default is off. */
// 更新,在调用下面两个方法之前需要先调用这个方法
- (void)updateMeters; /* call to refresh meter values */
// 当前分贝
- (float)peakPowerForChannel:(NSUInteger)channelNumber; /* returns peak power in decibels for a given channel */
// 平均分贝
- (float)averagePowerForChannel:(NSUInteger)channelNumber; /* returns average power in decibels for a given channel */
备注
采样率:
-
11025.0
: 5分钟1.5M