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?
2. Which class is best for playing local audio files?
3. What does AVAssetExportSession do?
4. How do you play video in SwiftUI?
Flashcards
Question
What is AVAudioSession used for?
Click to reveal answer
Answer
It configures how your app interacts with other audio sources and handles audio interruptions.
Question
What is the difference between AVAudioPlayer and AVPlayer?
Click to reveal answer
Answer
AVAudioPlayer plays local audio files. AVPlayer handles both audio and video, including streaming.
Question
How do you trim a video with AVFoundation?
Click to reveal answer
Answer
Use AVAssetExportSession with a timeRange to export a portion of the source video.
Question
How do you record audio in iOS?
Click to reveal answer
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