Fading audio with AVPlayer
AVPlayer doesn’t provide a built-in way to fade in or out. I previously described how you achieve a video fade-in (or out) using general CoreAnimation layer animation, as part of making a macOS screen saver. Now let’s tackle the audio.
extension AVPlayer {
func fadeAudio(from startVolume: Float, to endVolume: Float, duration: Double) {
let audioMix = AVMutableAudioMix()
audioMix.inputParameters = (player.currentItem?.tracks ?? [])
.compactMap(\.assetTrack)
.filter({ $0.mediaType == .audio })
.map { track in
let currentTime = player.currentTime()
let parameters = AVMutableAudioMixInputParameters(track: track)
parameters.setVolumeRamp(fromStartVolume: startVolume,
toEndVolume: endVolume,
timeRange: CMTimeRange(start: currentTime,
duration: CMTime(seconds: duration,
preferredTimescale: currentTime.timeScale)))
return parameters
}
player.currentItem?.audioMix = audioMix
}
}I’m not certain what curve this implements, but to my ears it doesn’t sound quite as harsh as a naive linear ramp, so perhaps it’s an S-curve or similar.
Edge cases not handled
Where there’s less than duration time left in the track(s).
How you want to handle that might vary depending on context. e.g. you could clamp the duration to the remaining duration (but you have to think about whether your individual tracks all have the same duration, whether they match the duration of the overall playback item, and whether they’re all aligned within the playback sequence), or wrap it around to the beginning (if you’re looping), or carry the fade through to the next item (if you’re playing a sequence…