---
id: ios-audio-video-avkit
title: iOS Audio/Video β AVFoundation / AVKit
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [ios, audio, video, vibe-coding]
tech_stack: { language: "Swift", applicable_to: ["iOS"] }
applied_in: []
aliases: [AVFoundation, AVPlayer, AVAudioEngine, AVKit, AirPlay, picture-in-picture]
---
# iOS Audio / Video
> AVFoundation = audio/video μ native. **AVPlayer (playback), AVAudioEngine (record/process), AVKit (UI)**. Background audio, AirPlay, PiP.
## π ν΅μ¬ κ°λ
- AVPlayer: video / audio μ¬μ.
- AVAudioEngine: μ λ° audio (record, mix).
- AVAudioSession: system κ³Ό νμ.
- HLS / MP4 / DASH μ§μ.
## π» μ½λ ν¨ν΄
### AVPlayer (κ°λ¨ video)
```swift
import AVKit
import SwiftUI
struct PlayerView: View {
let player = AVPlayer(url: URL(string: "https://...mp4")!)
var body: some View {
VideoPlayer(player: player)
.onAppear { player.play() }
.onDisappear { player.pause() }
}
}
```
### AVPlayerViewController (UIKit)
```swift
import AVKit
let player = AVPlayer(url: url)
let vc = AVPlayerViewController()
vc.player = player
present(vc, animated: true) { player.play() }
```
### Background audio
```swift
import AVFoundation
// AppDelegate / SwiftUI App
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
}
```
```xml
UIBackgroundModes
audio
```
β App backgrounded = audio κ³μ.
### Now Playing Info
```swift
import MediaPlayer
MPNowPlayingInfoCenter.default().nowPlayingInfo = [
MPMediaItemPropertyTitle: "Song Title",
MPMediaItemPropertyArtist: "Artist",
MPMediaItemPropertyArtwork: MPMediaItemArtwork(boundsSize: image.size) { _ in image },
MPMediaItemPropertyPlaybackDuration: duration,
MPNowPlayingInfoPropertyElapsedPlaybackTime: 0.0,
]
```
β Lock screen + Control Center + AirPods.
### Remote command (lock screen control)
```swift
let center = MPRemoteCommandCenter.shared()
center.playCommand.addTarget { _ in player.play(); return .success }
center.pauseCommand.addTarget { _ in player.pause(); return .success }
center.nextTrackCommand.addTarget { _ in nextTrack(); return .success }
```
### Picture-in-Picture
```swift
let pip = AVPictureInPictureController(playerLayer: playerLayer)
pip?.delegate = self
// μλ λλ manual
pip?.startPictureInPicture()
```
```xml
```
### AirPlay
```swift
let routePicker = AVRoutePickerView()
view.addSubview(routePicker)
```
β AirPlay μλ (Audio session κ° .playback).
### HLS streaming
```swift
let asset = AVURLAsset(url: URL(string: "https://.../master.m3u8")!)
let item = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: item)
```
β HLS κ° native. Adaptive bitrate.
### Download (offline)
```swift
import AVFoundation
let session = AVAssetDownloadURLSession(...)
let task = session.makeAssetDownloadTask(asset: asset, ...)
task.resume()
// Track progress
task.delegate = self
```
β HLS κ° offline κ°λ₯.
### AVAudioEngine (μ λ°)
```swift
let engine = AVAudioEngine()
let player = AVAudioPlayerNode()
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
let file = try AVAudioFile(forReading: url)
player.scheduleFile(file, at: nil)
try engine.start()
player.play()
```
β Effect, mixing, recording.
### Recording
```swift
let recorder = try AVAudioRecorder(url: url, settings: [
AVFormatIDKey: kAudioFormatMPEG4AAC,
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 1,
])
recorder.record()
// Stop
recorder.stop()
```
```swift
// Mic permission
AVAudioApplication.requestRecordPermission { granted in
if granted { ... }
}
```
```xml
NSMicrophoneUsageDescription
Record audio for ...
```
### AudioKit (high-level)
```swift
import AudioKit
let oscillator = Oscillator()
let mixer = Mixer(oscillator)
let engine = AudioEngine()
engine.output = mixer
try engine.start()
oscillator.start()
oscillator.frequency = 440
```
β AudioKit κ° AVAudioEngine μ wrapper.
### Effect chain
```swift
let player = AVAudioPlayerNode()
let reverb = AVAudioUnitReverb()
reverb.loadFactoryPreset(.cathedral)
reverb.wetDryMix = 50
engine.attach(reverb)
engine.connect(player, to: reverb, format: nil)
engine.connect(reverb, to: engine.mainMixerNode, format: nil)
```
β Multi-effect chain.
### Real-time (low latency)
```swift
session.setPreferredIOBufferDuration(0.005) // 5 ms
session.setPreferredSampleRate(48000)
```
β Latency β β battery / CPU β.
### AirPods ν΅ν©
```swift
// .playback κ° μλ AirPods.
// Spatial audio (iOS 14+):
session.setCategory(.playback, mode: .spokenAudio, options: [.allowBluetoothA2DP])
```
### Spatial audio (Dolby Atmos)
```swift
// AVPlayer κ° μλ.
// Track metadata κ° Dolby = automatic spatial.
```
### Video composition (edit)
```swift
let composition = AVMutableComposition()
let videoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)
try videoTrack?.insertTimeRange(
CMTimeRange(start: .zero, duration: asset.duration),
of: asset.tracks(withMediaType: .video).first!,
at: .zero
)
// Export
let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality)
exporter?.outputURL = outputUrl
exporter?.outputFileType = .mp4
exporter?.exportAsynchronously { ... }
```
β Trim / merge / overlay.
### Capture (camera + mic)
```swift
let session = AVCaptureSession()
session.sessionPreset = .high
if let device = AVCaptureDevice.default(for: .video),
let input = try? AVCaptureDeviceInput(device: device) {
session.addInput(input)
}
let output = AVCaptureMovieFileOutput()
session.addOutput(output)
session.startRunning()
// Record
output.startRecording(to: url, recordingDelegate: self)
```
### CMSampleBuffer (frame-by-frame)
```swift
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: queue)
session.addOutput(videoOutput)
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
// λ§€ frame μ²λ¦¬ (ML, filter, ...)
}
```
β Vision / Core ML pipeline.
### Now Playing β TimeControl
```swift
// Periodic time observer
let interval = CMTime(seconds: 1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { time in
let currentTime = time.seconds
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentTime
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
```
### Audio session interruption
```swift
NotificationCenter.default.addObserver(forName: AVAudioSession.interruptionNotification, object: nil, queue: .main) { note in
guard let info = note.userInfo,
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return }
if type == .began {
player.pause()
} else if type == .ended {
if let opts = info[AVAudioSessionInterruptionOptionKey] as? UInt,
AVAudioSession.InterruptionOptions(rawValue: opts).contains(.shouldResume) {
player.play()
}
}
}
```
β μ ν / Siri κ° interrupt.
### Route change (ν€λν° unplug)
```swift
NotificationCenter.default.addObserver(forName: AVAudioSession.routeChangeNotification, ...) { note in
// ν€λν° unplug = μλ pause (iOS κ°).
}
```
### Performance
```
- Background queue κ° audio processing.
- Main thread κ° UI λ§.
- Lazy load (ν° file).
- Cache HLS segment.
```
### SwiftUI VideoPlayer (κ°λ¨)
```swift
import AVKit
import SwiftUI
VideoPlayer(player: AVPlayer(url: url)) {
Text("Custom overlay")
}
```
β Built-in (iOS 14+).
### ν¨μ
```
- AVAudioSession μ setCategory: silent mode κ° audio mute.
- Background mode μ enable: app close μ audio λ©μΆ€.
- Now Playing μ update: lock screen κ° stale.
- Memory leak (player not released): file λ hold.
```
## π€ μμ¬κ²°μ κΈ°μ€
| μμ
| API |
|---|---|
| λ¨μ video | VideoPlayer |
| Custom UI | AVPlayer + AVPlayerLayer |
| Streaming | HLS + AVPlayer |
| Recording | AVAudioRecorder |
| Mix / effect | AVAudioEngine |
| μ λ° frame | CMSampleBuffer |
| Background music | .playback + Background Modes |
| AirPlay | .playback (μλ) |
## β μν°ν¨ν΄
- **AudioSession 무μ**: silent mode κΉ¨μ§.
- **Main thread audio process**: lag.
- **Background mode μ enable**: backgrounded λ©μΆ€.
- **Now Playing μ update**: lock screen μλͺ».
- **Interruption handle μ**: phone call ν μ¬μ X.
- **HLS μμ΄ mp4 streaming**: buffering μμ£Ό.
- **Memory leak**: file μ release.
## π€ LLM νμ© ννΈ
- AVPlayer / VideoPlayer κ° default.
- AVAudioEngine κ° μ λ°.
- Now Playing + Remote Command κ° lock screen.
- HLS κ° streaming νμ€.
## π κ΄λ ¨ λ¬Έμ
- [[Mobile_Spatial_Audio_Video]]
- [[iOS_Background_Tasks]]
- [[iOS_Push_Notifications]]