I have a setup as follows, testing on an iPhone 5s with iOS 10.3, both in and out of debug.
AVAudioRecorder
fires record(forDuration: 5.0)
CADisplayLink
watches the levels of the recorder (the recorder is meteringEnabled
), synchronizing an animation, and keeping track of recorder.currentTime
(but the problem can be reproduced by minimally keeping track of time in the display link)recorder.currentTime
consistently reach values > 5 (often 5.2 to 5.5). The results are essentially consistent with the values of recorder.deviceTime
and CFAbsoluteTimeGetCurrent
AVAudioPlayer
and verify that the sound asset does have a duration of precisely 5.0 seconds. From my understanding, the recorder's currentTime
is measured in seconds, and resets to 0.0 when recorder.isRecording reverts to false, which happens immediately when the recorder stops (this is consistent with what i see in audioRecorderDidFinishRecording
)... so observing with a CADisplayLink
should produce currentTime values strictly less than 5.0?
The question is: what could be going wrong here? The recorder is stopping as it should after exactly 5 seconds, but internally it thinks it recorded for more than 5 seconds? I'm listening to all my recordings and they sound fine.
I'm not sure if it's relevant, but my AVAudioSession
is of type AVAudioSessionCategoryPlayAndRecord
, and my audio settings are as follows (all of these excepting sample rate are necessary for later analysis):
audioSettings = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVLinearPCMIsBigEndianKey: 0,
AVLinearPCMIsFloatKey: 0,
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsNonInterleaved: 0
]
I already tried fiddling with all of these and didn't see any change behavior.
The CADisplayLink
is added from the main thread via
recorderDisplayLink?.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)
The only similar question I can find on stack exchange is this, but the question is underspecified and the answer unhelpful (for me at least).
At first I thought maybe the issue is with overloading the main queue, so that somehow the recorder's sense of time becomes bloated (which I think
would still constitute bad behavior), but after disabling the animation (and also experimenting with a Timer instead of a CADisplayLink), the problem persists!!! Perhaps it is still a threading problem, but I don't see why that would be the case. And if i do need to multi-thread, I could use some help both with understanding and implementing :)
Any ideas appreciated.
Of all the times I've used AVAudioRecorder
, I've eventually had to replace it. AVAudioRecorder
is a general purpose recording class, so once your requirements get a little specialised, it will disappoint you.
However, it does do metering, which is what attracts many people to it. So maybe the situation can be salvaged.
Possibilities:
a. if currentTime
isn't trustworthy, then don't observe it! You've got your 5 second files, so maybe find some other way to mark that passage of time in your app.
b. of the the property currentTime
, the header file says:
only valid while recording
Are you sampling currentTime
only while recording? If so that could be the problem. In which case you could use the deviceCurrentTime
property, which is always valid, although you will have to subtract off the initial deviceCurrentTime
.
If the situation can't be salvaged, you could pretty quickly replace AVAudioRecorder
with AVAudioEngine
and AVAudioFile
, but that's a question for another day.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With