AVAudioRecorder currentTime 给出错误值

Posted

技术标签:

【中文标题】AVAudioRecorder currentTime 给出错误值【英文标题】:AVAudioRecorder currentTime giving bad values 【发布时间】:2017-04-11 16:50:23 【问题描述】:

我有如下设置,在装有 ios 10.3 的 iPhone 5s 上进行测试,包括调试内外。

AVAudioRecorder 触发 record(forDuration: 5.0) CADisplayLink 监视记录器的级别(记录器是 meteringEnabled),同步动画,并跟踪 recorder.currentTime(但可以通过在显示链接中最小限度地跟踪时间来重现问题) recorder.currentTime 的报告始终达到 > 5 的值(通常为 5.2 到 5.5)。结果与recorder.deviceTimeCFAbsoluteTimeGetCurrent的值基本一致 我初始化了一个AVAudioPlayer 并验证了声音资产的持续时间是否正好为 5.0 秒。

据我了解,录音机的currentTime 以秒为单位,当recorder.isRecording 恢复为false 时会重置为0.0,这会在录音机停止时立即发生(这与我在audioRecorderDidFinishRecording 中看到的一致)。 .. 所以用CADisplayLink 观察应该产生的 currentTime 值严格小于 5.0?

问题是:这里可能出了什么问题?记录器在 5 秒后按原样停止,但在内部它认为它记录了超过 5 秒?我正在听我所有的录音,它们听起来不错。

我不确定它是否相关,但我的AVAudioSessionAVAudioSessionCategoryPlayAndRecord 类型,我的音频设置如下(除采样率之外的所有这些都是以后分析所必需的):

audioSettings = [
    AVFormatIDKey: Int(kAudioFormatLinearPCM),
    AVSampleRateKey: 44100,
    AVNumberOfChannelsKey: 2,
    AVLinearPCMIsBigEndianKey: 0,
    AVLinearPCMIsFloatKey: 0,
    AVLinearPCMBitDepthKey: 16,
    AVLinearPCMIsNonInterleaved: 0
]

我已经尝试摆弄所有这些,但没有看到任何更改行为。

CADisplayLink 是通过主线程添加的

recorderDisplayLink?.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)

我可以在堆栈交换中找到的唯一类似问题是 this,但该问题未详细说明,答案也无济于事(至少对我而言)。 起初我认为问题可能在于主队列超载,因此记录器的时间感不知何故变得臃肿(我认为 仍然会构成不良行为),但是在禁用动画后(并且还尝试使用 Timer 而不是 CADisplayLink),问题仍然存在!!!也许它仍然是一个线程问题,但我不明白为什么会这样。如果我确实需要多线程,我可以在理解和实现方面使用一些帮助:) 任何想法表示赞赏。

【问题讨论】:

那么问题来了,为什么您比recordForDuration: 请求的持续时间多出 0.2 到 0.5 秒? 问题是,以下两个语句如何同时兼容: (1) record(forDuration: 5.0) 产生正好 5.0 秒的有效记录 (2) 观察记录器的 currentTime 属性的计时器在行动报告值显着 > 5.0 TL;DR AVAudioRecorder 不是很好,更换它。请参阅我的答案以获得更细致入微的版本。 您不能拥有装有 iOS 10.3 的 iphone 4,此设备上最后支持的版本是 iOS 7.1.2。即使您的意思是 4s 仍然会将最高版本设置为 iOS 9.3.5 哈哈谢谢!你是对的。更正了问题。 【参考方案1】:

在我使用AVAudioRecorder 的所有时间中,我最终不得不更换它。 AVAudioRecorder 是一个通用的录音类,所以一旦你的要求变得有点专业,它会让你失望。

但是,它确实可以计量,这也是吸引很多人的原因。所以也许情况可以挽救。

可能性:

一个。如果currentTime 不可信,请不要观察!您已经获得了 5 秒的文件,因此也许可以找到其他方式在您的应用中标记该时间的流逝。

b.属性currentTime,头文件说:

  only valid while recording

您是否仅在录制时对currentTime 进行采样?如果是这样,那可能就是问题所在。在这种情况下,您可以使用始终有效的deviceCurrentTime 属性,尽管您必须减去初始的deviceCurrentTime

如果情况无法挽救,您可以很快将AVAudioRecorder 替换为AVAudioEngineAVAudioFile,但这是另一天的问题。

【讨论】:

是的,我正在考虑更换它,但如果可能的话,我不想这样做......吸引我的是计量。基本上,我正在观察记录器的平均功率来提供动画和测量静音。这是我需要 currentTime 属性的第二部分。但我需要这些时间与AVAudioPlayerAVReader对时间的感知保持一致。 哦,我还要澄清一下:当isRecording 为真时,我只报告currentTime 的值。这意味着当currentTime 超过实际音频持续时间时,录音机仍在录音,或者isRecording 实际上并未指示录音机正在做什么。但也许标题说明了一切。 "Only valid while recording (but don't bet on it)" 我确实尝试使用记录器的deviceCurrentTime 属性,但发现它的行为同样奇怪。也许我应该在记录器之外使用不同的设备时间度量? 是的,其他一些标记时间的方式不是AVAudioRecorder 实际上我尝试用CFAbsoluteTimeGetCurrent 标记时间,我也看到了同样的问题。 isRecording 标志读取为 true 的系统时间量确实比 duration【参考方案2】:

我在 Timer 上更新 UILabel 时遇到了同样的问题,但能够通过检查计时器触发器之间的间隙是否太大并将增量记忆为 currentRecordTimeOffset 来解决该问题。

     if ( self.recorder.recording ) 
         float adjustedRecordTime = self.recorder.currentTime;
         if(self.currentRecordTimeOffset == 0)
             if(self.recorder.currentTime - self.lastRecordedTime > 1.0)    // current time should be updated every 0.1 so a 1 Sec delta indicates offset needed
                 self.currentRecordTimeOffset = self.recorder.currentTime;
                 adjustedRecordTime = self.recorder.currentTime - self.currentRecordTimeOffset;
             
         
         else
             adjustedRecordTime = self.recorder.currentTime - self.currentRecordTimeOffset;     // get rid of the unusual offset
         
         self.lastRecordedTime = self.recorder.currentTime;
         self.durationLabel.text = [NSString stringWithFormat:@"%.2f", adjustedRecordTime];

【讨论】:

以上是关于AVAudioRecorder currentTime 给出错误值的主要内容,如果未能解决你的问题,请参考以下文章

AVAudioRecorder 不保留

iOS开发简记:录音AVAudioRecorder

释放 AVAudioRecorder 会话后恢复录制

AVAudioRecorder 不保存文件

AVAudioRecorder 的有效“设置”键/值是啥?

AVAudioRecorder:峰值和平均功率