Реализация записи аудио в мобильном приложении
Диктофон, войс-сообщения, запись интервью в журналистском приложении — задача одна, требования разные. Войс-сообщение нужно в AAC/M4A, 32 кбит/с, маленький файл. Диктофон для подкастов — WAV или FLAC, 44100 Гц, без потерь. Начинаем с аудиосессии, иначе потом не разберёмся с конфликтами.
Аудиосессия и категории
iOS. AVAudioSession — центральный объект управления. Для записи:
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playAndRecord,
mode: .default,
options: [.defaultToSpeaker, .allowBluetooth])
try session.setActive(true)
.playAndRecord позволяет одновременно воспроизводить и писать. .allowBluetooth включает запись с AirPods. Без .defaultToSpeaker — звук при воспроизведении идёт в ухо, не в динамик.
Проблема, которая встречается в продакшене: другое приложение (навигатор, музыкальный плеер) перехватывает сессию. Подписываемся на AVAudioSession.interruptionNotification, при .began паузируем запись, при .ended с .shouldResume — возобновляем.
Android. AudioRecord для прямого доступа к PCM-данным. MediaRecorder — проще, но меньше контроля над форматом. Для большинства задач MediaRecorder достаточен:
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder.setAudioSamplingRate(44100)
mediaRecorder.setAudioEncodingBitRate(128000)
VOICE_COMMUNICATION вместо MIC включает эхоподавление и шумоподавление на уровне системы — полезно для войс-сообщений.
Визуализация уровня звука
Амплитудный волновой индикатор — пользователь видит, что запись идёт. На iOS: AVAudioRecorder.averagePower(forChannel: 0) возвращает дБ (от -160 до 0). Нормализуем в 0..1:
let power = recorder.averagePower(forChannel: 0)
let level = pow(10, power / 20) // dBFS → linear
Опрашиваем через Timer.scheduledTimer(withTimeInterval: 0.05) — 20 fps для плавной анимации.
На Android: MediaRecorder.getMaxAmplitude() — максимальная амплитуда с последнего вызова (0–32767). Делаем Handler.postDelayed каждые 50 мс.
Для Flutter: record (pub.dev) предоставляет onAmplitudeChanged stream.
Waveform при воспроизведении
Записанный файл анализируем офлайн: читаем PCM-сэмплы, разбиваем на чанки по N сэмплов, берём RMS каждого чанка. Получаем массив float-значений — рисуем через Canvas или Path. На iOS нужен AVAssetReader + AVAssetReaderTrackOutput с kAudioFormatLinearPCM.
Форматы и совместимость
| Формат | Размер 1 мин | Совместимость | Применение |
|---|---|---|---|
| AAC (M4A) | ~480 КБ | iOS, Android, Web | войс-сообщения |
| MP3 | ~960 КБ | везде | общий случай |
| WAV (PCM) | ~10 МБ | везде | без потерь, диктофон |
| FLAC | ~3–5 МБ | Android native, iOS 11+ | без потерь, компактнее WAV |
| OGG/Opus | ~300 КБ | Android, Web | оптимальный для VoIP |
Фоновая запись
Если пользователь сворачивает приложение — запись должна продолжаться. iOS: UIBackgroundModes: audio в Info.plist, AVAudioSession остаётся активной. Android: ForegroundService с типом microphone (android:foregroundServiceType="microphone" в манифесте, обязательно с Android 10). Уведомление с кнопкой «Остановить» — стандарт.
Без ForegroundService на Android 9+ система убьёт процесс через несколько минут в фоне. На iOS без UIBackgroundModes запись остановится через 3 секунды после сворачивания.
Сроки
Запись с визуализацией уровня и сохранением файла — 1–2 дня. Полноценный диктофон с waveform, паузой, переименованием и фоновой записью — 3–4 дня.







