Skip to content
advanced Phase 8 · Media & Hardware

AVFoundation

Work with audio and video: playback, recording, editing, and AVPlayer integration.

1h
3 problems
Topic Progress 0%

Audio Playback

AVAudioSession Setup

Before playing audio, configure the audio session to define how your app interacts with other audio sources.

import AVFAudio

func setupAudioSession() {
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(.playback, mode: .default, options: [.mixWithOthers])
        try session.setActive(true)
    } catch {
        print("Audio session error: \(error.localizedDescription)")
    }
}

Audio Playback with AVAudioPlayer

AVAudioPlayer is the simplest way to play local audio files.

import AVFAudio

class AudioPlayerManager: ObservableObject {
    private var player: AVAudioPlayer?
    @Published var isPlaying = false
    @Published var currentTime: TimeInterval = 0
    @Published var duration: TimeInterval = 0
    
    func loadAudio(named fileName: String) {
        guard let url = Bundle.main.url(forResource: fileName, withExtension: "mp3") else { return }
        do {
            player = try AVAudioPlayer(contentsOf: url)
            player?.delegate = self
            duration = player?.duration ?? 0
            player?.prepareToPlay()
        } catch {
            print("Failed to load audio: \(error)")
        }
    }
    
    func play() { player?.play(); isPlaying = true }
    func pause() { player?.pause(); isPlaying = false }
    func seek(to time: TimeInterval) { player?.currentTime = time }
}

extension AudioPlayerManager: AVAudioPlayerDelegate {
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        isPlaying = false
    }
}

Streaming Audio with AVPlayer

For streaming or advanced playback, use AVPlayer with AVPlayerItem.

import AVKit

class StreamPlayer: ObservableObject {
    private var player: AVPlayer?
    @Published var status: AVPlayer.Status = .unknown
    
    func loadStream(url: URL) {
        let item = AVPlayerItem(url: url)
        player = AVPlayer(playerItem: item)
        item.addObserver(self, forKeyPath: "status", options: [.new], context: nil)
    }
    
    func play() { player?.play() }
    func pause() { player?.pause() }
}

Video Playback

AVPlayerViewController

The simplest way to play video is using AVPlayerViewController which provides a complete playback UI.

import AVKit
import SwiftUI

struct VideoPlayerView: UIViewControllerRepresentable {
    let videoURL: URL
    
    func makeUIViewController(context: Context) -> AVPlayerViewController {
        let controller = AVPlayerViewController()
        controller.player = AVPlayer(url: videoURL)
        return controller
    }
    func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) { }
}

struct VideoScreen: View {
    var body: some View {
        VideoPlayerView(videoURL: URL(string: "https://example.com/video.mp4")!)
            .ignoresSafeArea()
    }
}

Custom Video Player

Build a custom video player with SwiftUI controls for a tailored experience.

struct CustomVideoPlayer: View {
    @State private var player: AVPlayer?
    @State private var isPlaying = false
    @State private var currentTime: Double = 0
    @State private var duration: Double = 0
    let url: URL
    
    var body: some View {
        VStack {
            VideoPlayer(player: player).frame(height: 300)
            Slider(value: $currentTime, in: 0...duration) { editing in
                if !editing {
                    player?.seek(to: CMTime(seconds: currentTime, preferredTimescale: 600))
                }
            }
            HStack {
                Button { player?.seek(to: CMTime(seconds: currentTime - 10, preferredTimescale: 600)) } label: { Image(systemName: "gobackward.10") }
                Button { isPlaying ? player?.pause() : player?.play() } label: { Image(systemName: isPlaying ? "pause.fill" : "play.fill") }
                Button { player?.seek(to: CMTime(seconds: currentTime + 10, preferredTimescale: 600)) } label: { Image(systemName: "goforward.10") }
            }.font(.title)
        }.onAppear { loadPlayer() }
    }
    private func loadPlayer() {
        player = AVPlayer(url: url)
        let interval = CMTime(seconds: 0.5, preferredTimescale: 600)
        player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { time in
            currentTime = time.seconds
            duration = player?.currentItem?.duration.seconds ?? 0
        }
    }
}

Recording & Editing

AVAssetExportSession

AVAssetExportSession handles media trimming, format conversion, and export operations.

import AVFoundation

func trimVideo(sourceURL: URL, startTime: CMTime, endTime: CMTime, completion: @escaping (URL?) -> Void) {
    let asset = AVURLAsset(url: sourceURL)
    guard let exportSession = AVAssetExportSession(
        asset: asset, presetName: AVAssetExportPresetHighestQuality
    ) else {
        completion(nil)
        return
    }
    
    let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("trimmed_\(UUID().uuidString).mp4")
    exportSession.outputURL = outputURL
    exportSession.outputFileType = .mp4
    
    let timeRange = CMTimeRange(start: startTime, end: endTime)
    exportSession.timeRange = timeRange
    
    exportSession.exportAsynchronously {
        switch exportSession.status {
        case .completed:
            DispatchQueue.main.async { completion(outputURL) }
        case .failed:
            DispatchQueue.main.async { completion(nil) }
        default:
            break
        }
    }
}

Audio Recording with AVAudioRecorder

Record audio from the microphone using AVAudioRecorder.

import AVFAudio

class AudioRecorder: ObservableObject {
    private var recorder: AVAudioRecorder?
    @Published var isRecording = false
    
    func startRecording() {
        let settings = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 44100,
            AVNumberOfChannelsKey: 1,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
        ]
        
        let url = FileManager.default.temporaryDirectory.appendingPathComponent("recording.m4a")
        recorder = try? AVAudioRecorder(url: url, settings: settings)
        recorder?.record()
        isRecording = true
    }
    
    func stopRecording() {
        recorder?.stop()
        isRecording = false
    }
}

Compositing and Mixing

Combine multiple audio or video tracks using AVMutableComposition.

func mergeAudio(url1: URL, url2: URL) async throws -> AVComposition {
    let asset1 = AVURLAsset(url: url1)
    let asset2 = AVURLAsset(url: url2)
    
    let composition = AVMutableComposition()
    guard let audioTrack1 = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid),
          let audioTrack2 = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) else {
        throw NSError(domain: "CompositionError", code: 0)
    }
    
    let range1 = CMTimeRange(start: .zero, duration: asset1.duration)
    try audioTrack1.insertTimeRange(range1, of: await asset1.tracks(withMediaType: .audio).first!, at: .zero)
    
    let range2 = CMTimeRange(start: .zero, duration: asset2.duration)
    try audioTrack2.insertTimeRange(range2, of: await asset2.tracks(withMediaType: .audio).first!, at: asset1.duration)
    
    return composition
}

Quiz

1. What must be configured before playing audio in iOS?

Question 1 options

2. Which class is best for playing local audio files?

Question 2 options

3. What does AVAssetExportSession do?

Question 3 options

4. How do you play video in SwiftUI?

Question 4 options

Flashcards

Question

What is AVAudioSession used for?

Answer

It configures how your app interacts with other audio sources and handles audio interruptions.

Question

What is the difference between AVAudioPlayer and AVPlayer?

Answer

AVAudioPlayer plays local audio files. AVPlayer handles both audio and video, including streaming.

Question

How do you trim a video with AVFoundation?

Answer

Use AVAssetExportSession with a timeRange to export a portion of the source video.

Question

How do you record audio in iOS?

Answer

Use AVAudioRecorder with settings dictionary for format, sample rate, and channels.

Revision Notes

Key Takeaways

  • 1. Configure AVAudioSession before any audio playback
  • 2. AVAudioPlayer for local audio, AVPlayer for streaming
  • 3. AVPlayerViewController provides standard video UI
  • 4. AVAssetExportSession trims and converts media
  • 5. AVAudioRecorder captures microphone audio

Interview Tips

  • Explain the role of AVAudioSession in audio playback
  • Discuss when to use AVPlayer vs AVAudioPlayer
  • Describe how to trim a video using AVAssetExportSession

Cheat Sheet

AVFoundation Quick Reference

  • AVAudioSession - Configure audio behavior
  • AVAudioPlayer - Play local audio files
  • AVPlayer / AVPlayerItem - Play audio/video streams
  • VideoPlayer - SwiftUI video playback
  • AVPlayerViewController - Standard video player UI
  • AVAssetExportSession - Trim and convert media
  • AVAudioRecorder - Record audio
  • AVMutableComposition - Mix multiple tracks