Audio player duration changes while playing
Asked Answered
R

3

5

When I take the duration of an audio file before playing it with:

audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
...
[audioPlayer prepareToPlay];
duration = audioPlayer.duration;

I get a duration of for example 16.71s. Then when taking samples every 0.2s while playing, the duration changes. It changes every 1.2 to 1.6 seconds to: 16.71s, 17.02s, 17.23s, 17.33s, 17.38s, 17.43s, 17.38s, 17.29s, 17.31s, then stays at 17.51s for the last 2.5 seconds. So it goes up and down.

I sample in a method that updates a slider position, and also shows the elapsed time and total duration. You can imagine it looks really weird to see the duration (which is int-truncated) go from 16 to 17 while playing. Additionally, the slider position will be off with all this drifting.

Does anyone have an idea why this is?

Now that we're talking about duration: Does anyone know why audio player.duration can return values that are about twice the actual duration when [audioPlayer prepareToPlay] is omitted?

Raffo answered 26/4, 2013 at 22:21 Comment(4)
If you run it multiple times, are these the same numbers you get each time? Or do they change?Musgrave
The first value taken is always the same: 16,71s. The values after that are different each time played with a fresh AVAudioPlayer. The final value is also always the same: 17.51s. But when I replay with the same audio player all values are 17.51s.Raffo
What type of audiofile is it? If it's encoded with VBR (variable bitrate) it could be that the audioplayer is trying the estimate the length of the file.Rakel
I record these files with AVAudioRecorder using settings @{ AVEncoderAudioQualityKey : @(AVAudioQualityMedium), AVNumberOfChannelsKey : @(1), AVFormatIDKey : @(kAudioFormatMPEG4AAC) }. Would be surprised if the true/correct duration of AAC is not in the format.Raffo
R
6

The duration returned by avaudioplayer's duration method is a best estimate of the total duration of the file based on how much of the file has been decoded so far. That's why the duration continues to get refined as you check it over time.

In order to get a better time, I use AVAsset's duration method. It explains what is going on a bit better here:

https://developer.apple.com/library/mac/documentation/AVFoundation/Reference/AVAsset_Class/Reference/Reference.html#//apple_ref/occ/instp/AVAsset/duration

If you specify providesPreciseDurationAndTiming = YES, then AVAsset will decode the file if needed to determine its duration with accuracy. If the decode time is too long for your use, you can disable it.

In my situation, I use the AVURLAsset subclass:

            AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:localURL options:[NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], AVURLAssetPreferPreciseDurationAndTimingKey, nil]];
            float t = CMTimeGetSeconds(asset.duration);
Rhetoric answered 14/7, 2014 at 15:37 Comment(1)
This works perfectly. For example my audioPlayer's duration was 8.02 but when I added the audioPlayer's url to the AVURLAsset using [AVURLAssetPreferPreciseDurationAndTimingKey: true] the actual time was 8.0143333333. The audioPlayer's duration was incorrectTaunton
T
2

@AndyKorth's answer is the best! Here it is in Swift

guard let audioPlayer = audioPlayer, let url = audioPlayer.url else { return }

let assetOpts = [AVURLAssetPreferPreciseDurationAndTimingKey: true]
let asset = AVURLAsset(url: url, options: assetOpts)

let assetDuration: Float64 = CMTimeGetSeconds(asset.duration)

// compare both
print("assetDuration: ", assetDuration)

print("audioPlayerDuration: ", Float(audioPlayer.duration))
Taunton answered 4/12, 2021 at 11:8 Comment(0)
P
0

If you record the audio from your side, you can put your audio file duration in your network params, which can be used in Audio Playing when download audio file from network.

Posterior answered 25/10, 2023 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.