Sesli not alan bir iOS uygulaması geliştirdim. AVFoundation’ın ses kaydı API’si doküman düzeyinde kolay görünüyor. Gerçek cihazda arka plan, interruption ve mix state yönetimi karışık. Çıkardığım 3 pitfall’u paylaşayım.
Pitfall 1: Background mode’u etkinleştirmek yetmez
Info.plist’e UIBackgroundModes içine audio eklemek ilk adım. Ama bu tek başına yeterli değil. Ses kaydı gerçekten arka planda devam etmesi için AVAudioSession‘u doğru konfigüre etmek şart.
let session = AVAudioSession.sharedInstance()
try session.setCategory(
.playAndRecord,
mode: .default,
options: [.defaultToSpeaker, .allowBluetoothA2DP]
)
try session.setActive(true)Category olarak .record yerine .playAndRecord tercih ediyorum; kullanıcı kayıt sırasında notification sesi için playback’e ihtiyaç duyabiliyor. Sadece .record kullanırsan Bluetooth kulaklık gibi mikser senaryolarda sorun çıkıyor.
Kritik nokta: bu konfigürasyonu kayıt başlarken değil, uygulama foreground’a geldiğinde yapıyorum. Background’dan dönerken setActive false -> true yapmak gerekiyor aksi halde audio route değişmiyor.
Pitfall 2: Interruption handling
Telefon geldiğinde veya başka uygulama ses çaldığında kayıt duruyor. Otomatik resume olmuyor. Interruption notification’unu dinlemen ve tepki vermen gerekiyor:
NotificationCenter.default.addObserver(
forName: AVAudioSession.interruptionNotification,
object: nil,
queue: .main
) { [weak self] note in
guard let info = note.userInfo,
let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue)
else { return }
switch type {
case .began:
self?.recorder?.pause()
case .ended:
guard let optionsValue = info[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
try? AVAudioSession.sharedInstance().setActive(true)
self?.recorder?.record()
}
@unknown default: break
}
}shouldResume bayrağı her durumda gelmiyor. Telefon görüşmesi bitince gelir, ama kullanıcı Siri tetiklediyse gelmez. Bizim uygulamada kullanıcıya “resume?” butonu gösterip manuel devam ettirmeyi tercih ettik; otomatik resume bekleyenler yarım kayıt elde etti.
Pitfall 3: Arkaplanda dosya yazma limitli
iOS background mode’u audio işlevsel ama sistemin I/O performansı arkaplanda değişiyor. AVAudioRecorder ile tek bir büyük dosyaya yazmak 40 dakikadan uzun kayıtlarda I/O latency yaşatıyor ve ara sıra frame drop oluyor.
Çözümüm: uzun kayıtları 5 dakikalık parçalara bölmek. Her 5 dakikada bir recorder’ı stop edip yeni dosya başlatıyorum. Background boyunca file system pressure düşük kalıyor. Dosyaları sonra concatenate ediyorum:
let composition = AVMutableComposition()
let track = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)!
var time = CMTime.zero
for url in chunkURLs {
let asset = AVURLAsset(url: url)
let assetTrack = try await asset.loadTracks(withMediaType: .audio).first!
let duration = try await asset.load(.duration)
try track.insertTimeRange(
CMTimeRange(start: .zero, duration: duration),
of: assetTrack,
at: time
)
time = CMTimeAdd(time, duration)
}Kullanıcı açısından tek bir kayıt dosyası görüyor; arkada ben 12 parçayı birleştiriyorum.
Power consumption
Arka planda kayıt batarya yakıcı. 1 saat arkaplan kayıt testte iPhone 14’te %11 batarya kullandı. Kullanıcıya kayıt sırasında bir banner göstermek şart (“arkada kayıt devam ediyor”) aksi halde “batarya neden bitti” şikayeti geliyor. Live Activity ile gösteriyorum; ayrıca deadline reminder’ı ile belirlenen süre sonunda otomatik durduruyorum.
Format seçimi: kalite ve dosya boyutu
Varsayılan LPCM formatı büyük dosya üretiyor. 1 saatlik ses 550 MB. AAC kullanınca 60 MB’a iniyor:
let settings: [String: Any] = [
AVFormatIDKey: kAudioFormatMPEG4AAC,
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 1,
AVEncoderBitRateKey: 96000
]
let recorder = try AVAudioRecorder(url: url, settings: settings)96 kbps mono insan sesi için yeterli kalite veriyor. Tek kanal tercihim bilinçli; stereo kayıt hem 2 kat dosya hem de mikser işlemleri için daha pahalı.
Test edemediğim şeyler
Simulator’de bu kodun çoğu doğru çalışmıyor. Özellikle interruption ve background mode’u gerçek cihazda test etmek şart. TestFlight’ta 15 farklı iPhone modelinde test ettim; en kritik bug’lar iPhone SE 2nd gen’de çıktı (kısıtlı RAM’de background recording agresif memory warning veriyor).
Son tavsiye
Ses kaydı özelliğini shipping’e çıkarmadan önce 2 hafta kendi kullanman şart. Edge case’lerin çoğunu ancak günlük kullanımda fark ediyorsun. Interruption + background + low power mode kombinasyonu production’da ilk 2 haftada 6 farklı bug raporu olarak geldi.