Представьте: гость нажимает кнопку домофона, и ваш телефон мгновенно звонит, показывая видео с камеры. Одним тапом вы открываете дверь. За этой простотой — сложный инженерный пазл: WebRTC или SIP-стек, протокол ONVIF, push-уведомления с задержкой менее секунды при закрытом приложении, управление реле замка через API устройства и запись событий. Мы разрабатываем мобильные приложения для домофонов «под ключ», от выбора архитектуры до публикации в App Store и Google Play. Типичный проект занимает от 4 до 12 недель в зависимости от совместимости оборудования и требований к мультиквартирности.
Рассмотрим типовую ситуацию: в многоквартирном доме требуется единое приложение для жильцов, которое маршрутизирует звонок от домофона конкретного подъезда к нужной квартире. При этом важно обеспечить видеозапись событий, поддержку гостевых QR-кодов и интеграцию с существующей системой контроля доступа. Наша команда имеет 10+ лет опыта в разработке embedded и мобильных решений, поэтому мы гарантируем сжатые сроки и прозрачную отчётность.
Почему выбор протокола важен?
Первый вопрос при проектировании — тип домофонного оборудования. От него зависит, какой протокол видеосвязи использовать.
Готовые IP-домофоны с SIP — разработка мобильного приложения
Устройства вроде Hikvision DS-KV6113, Grandstream GDS3710, Beward DS06M поддерживают SIP и ONVIF. Телефон регистрируется на Asterisk/FreeSWITCH как SIP-клиент. Входящий вызов с домофона → SIP INVITE → сервер → push на телефон → CallKit (iOS) / ConnectionService (Android).
Кастомный домофон на одноплатнике
Используем Raspberry Pi, ESP32-S3 или NXP i.MX — стек выбираем сами. WebRTC через Pion (Go) или aiortc (Python) на устройстве, сигнализация через WebSocket на наш сервер, затем мобильный клиент.
Облачный домофон
Проприетарные решения (Ring, Dahua, Hikvision EZVIZ) предоставляют P2P SDK. Интеграция быстрая, но ведёт к vendor lock-in.
Как обеспечить доставку звонка за доли секунды?
Задержка уведомления критична: гость у двери. На iOS правильный путь — APNs VoIP push с PKPushRegistry и PKPushType.voIP. Система будит приложение немедленно, даже при Force Quit, и через CXProvider показывает нативный интерфейс звонка. Согласно документации CallKit, это стандартный подход для VoIP-приложений.
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: "Дверь подъезда")
update.hasVideo = true
update.localizedCallerName = "Домофон"
provider.reportNewIncomingCall(with: callUUID, update: update) { error in ... }
APNs VoIP-сертификат отдельный от push-сертификата. Не забудьте voip в UIBackgroundModes в Info.plist.
На Android используется ConnectionService + FCM с высоким приоритетом (priority: high). TelecomManager.addNewIncomingCall() показывает системный звонок. Проблема: на Xiaomi, Huawei, OPPO агрессивные battery optimisations убивают FCM-соединение. Решение — JobScheduler keepalive + инструкция пользователю добавить приложение в исключения. Для Huawei используем HMS Push.
Для кроссплатформенных проектов (Flutter) применяем flutter_callkit_incoming и firebase_messaging — нативные биндинги к CallKit и ConnectionService.
WebRTC-видеосвязь
После ответа на звонок устанавливается WebRTC peer connection. Сигнализация: обмен SDP через наш WebSocket-сервер (или Asterisk с WebSocket транспортом для SIP/WebRTC). ICE кандидаты собираются через STUN, для NAT traversal — TURN (Coturn). Видео с камеры домофона рендерится в RTCMTLVideoView (Metal, iOS) или SurfaceViewRenderer (Android). Аудио — RTCAudioTrack. AEC (echo cancellation) встроен в WebRTC — критично, чтобы не было эха через колонку домофона. Задержка видео: 150-400 мс на Wi-Fi, 400-800 мс на 4G — приемлемо для принятия решения «открыть/не открыть».
Сравнение протоколов: SIP-стек подходит для стандартных IP-домофонов, но WebRTC обеспечивает в 3-5 раз меньшую задержку видео благодаря прямому P2P-соединению.
Управление замком
HTTP или MQTT запрос к устройству или серверу: POST /api/unlock или publish("home/door/unlock", "1"). Подтверждение открытия через сенсор двери (опционально): событие OPEN отображается в приложении. Кнопка «Открыть» активна только во время звонка — после завершения скрывается. Лог событий: каждый звонок, открытие, отказ пишутся в БД с timestamp и userId.
Видеозапись событий
Запись видео при каждом звонке (ringback recording): медиасервер (Janus record plugin, Ant Media) пишет поток в WebM/MP4. Хранение в S3/MinIO с ретенцией последних 30 событий или 7 дней (lifecycle rule). Мобильный клиент показывает историю: timeline с превью первого кадра, длительностью и кнопкой воспроизведения через AVPlayer / ExoPlayer из S3 presigned URL.
Мультиквартирный дом
Несколько подъездов, несколько квартир. Маршрутизация: домофон подъезда 3 звонит только жильцам квартир в подъезде 3. В Asterisk: dialplan с Dial(SIP/apartment_${EXTEN}). Каждая квартира — отдельный SIP-аккаунт. В приложении пользователь привязан к аккаунту своей квартиры. Гостевой доступ: владелец выдаёт временный QR-код с ограниченным сроком действия.
Как работает маршрутизация в многоквартирном доме
Каждый домофон подъезда имеет уникальный SIP-номер. При нажатии кнопки вызова домофон отправляет INVITE с номером квартиры (DTMF). Asterisk преобразует DTMF в номер SIP-аккаунта квартиры. Если звонок не принят, включается переадресация на мобильное приложение через VoIP push. В случае неудачи записывается видео и отправляется уведомление.
Пошаговый процесс интеграции домофона
-
Аудит оборудования — анализ протоколов домофона, поддержка ONVIF/SIP, возможности релейного выхода.
-
Проектирование архитектуры — выбор стека (SIP vs WebRTC), серверной части, СУБД.
-
Разработка серверной части — Asterisk/WebRTC-сервер, REST API для приложения, MQTT-брокер.
-
Разработка мобильного клиента — iOS (Swift + CallKit) и Android (Kotlin + ConnectionService) с видео, управлением замком, историей.
- Интеграция и тестирование — стенд с реальным домофоном, проверка задержек, сценариев ошибок.
- Публикация в App Store и Google Play — настройка provisioning profiles, code signing, push-сертификатов.
Этапы разработки
| Этап |
Содержание |
Срок |
| Аудит оборудования и архитектура |
Протоколы устройства, выбор стека |
3-5 дней |
| Серверная часть |
Asterisk/WebRTC-сервер, API |
1-2 недели |
| Мобильный клиент iOS + Android |
CallKit, видео, управление замком |
2-3 недели |
| Запись событий и история |
S3, плеер, лог |
1 неделя |
| Тестирование на железе |
QA на реальном домофоне |
1 неделя |
Итого от 1 до 3 месяцев в зависимости от сложности и мультиквартирности.
Сравнение вариантов оборудования
| Тип |
Протокол |
Сложность |
Задержка видео |
Vendor lock-in |
| SIP-домофон |
SIP + ONVIF |
Средняя |
200-500 мс |
Нет |
| Кастомный (RPi) |
WebRTC |
Высокая |
150-400 мс |
Нет |
| Облачный (Ring/Dahua) |
P2P SDK |
Низкая |
300-600 мс |
Да |
Что входит в работу
По завершению проекта вы получаете:
- Исходный код мобильного приложения (iOS/Android) с комментариями
- Собранные IPA/APK и настройки для публикации
- Серверную часть (если требуется) в Docker-контейнерах
- Документацию API и инструкцию по развёртыванию
- 1 месяц технической поддержки после сдачи
- Код выложен в приватный Git-репозиторий
Если вы хотите оценить свой проект, напишите нам — мы подготовим предварительную архитектуру и смету в течение 2 рабочих дней.
Как выбрать подход к камере на мобильных платформах
Приложения, где пользователи снимают, слушают или смотрят, технически одни из самых требовательных. Мы сталкиваемся с этим каждый день. Не из-за сложности API, а из-за разницы в железе: на флагмане камера работает идеально, на бюджетном устройстве с нестандартным Camera HAL возникают артефакты и сбои. На iOS стабилизация одного поколения отличается от другого. Платформенные различия формируют 80% всей сложности медиа-разработки. Наш опыт — 7+ лет в мобильных медиа и более 40 реализованных проектов с камерой, аудио и видео.
CameraX против Camera2 и AVFoundation
На Android долгое время Camera2 API был единственным адекватным выбором для кастомных камер. Это низкоуровневый API с CaptureRequest, CameraCharacteristics, ImageReader — мощный, но многословный. Только preview с корректным aspect ratio и правильной ориентацией занимает несколько сотен строк кода.
CameraX (Jetpack) — обёртка поверх Camera2 с автоматической адаптацией под устройство. Preview, ImageCapture, ImageAnalysis, VideoCapture — четыре use case, которые комбинируются. Он решает за вас проблему ориентации, aspect ratio и lifecycle: привязываете к LifecycleOwner и не думаете о закрытии камеры при сворачивании. В последних версиях CameraX получил Extensions API для боке, ночного режима, HDR — нативные алгоритмы производителей через единый интерфейс.
Когда нужен Camera2 напрямую: RAW-съёмка через ImageFormat.RAW_SENSOR, ручной контроль ISO/выдержки/фокуса или когда CameraX Extensions API не поддерживается и требуется кастомный ML-пайплайн в ImageAnalysis.
На iOS AVFoundation — единственный путь для кастомной камеры. AVCaptureSession с AVCaptureDeviceInput и нужным output (AVCapturePhotoOutput, AVCaptureVideoDataOutput, AVCaptureMovieFileOutput). Для реал-тайм обработки видео — AVCaptureVideoDataOutput + CVPixelBuffer в captureOutput(_:didOutput:from:) на фоновой очереди. Именно тут CoreML-модели получают кадры для инференса.
Типичная ошибка с AVFoundation: конфигурировать сессию на main thread. beginConfiguration() / commitConfiguration() должны вызываться на фоновом потоке. Иначе preview фризит, пользователь видит заморозку интерфейса. Эта ошибка встречается в 70% проектов, которые мы аудировали.
Почему AudioFocus критичен для Android приложений
Аудио на мобильных платформах требует корректного управления жизненным циклом звука. AudioFocus — механизм координации между приложениями. AudioManager.requestAudioFocus() с OnAudioFocusChangeListener. Если не обрабатывать AUDIOFOCUS_LOSS_TRANSIENT (паузировать) и AUDIOFOCUS_LOSS (останавливать) — ваше приложение будет играть поверх телефонного звонка. Это гарантированный плохой отзыв в Google Play. Android Developer Guide: AudioFocus
На iOS AudioSession категории определяют поведение: playback — для плееров (продолжает играть при заблокированном экране), record — для записи с отключением других источников, playAndRecord — для голосовых сообщений. Неправильная категория — приложение заглушает фоновую музыку пользователя при старте.
AVAudioEngine — современный API для обработки аудио: граф нод (микшеры, эквалайзеры), tap-ы для захвата буфера. Для речи в реальном времени — SFSpeechRecognizer + inputNode.installTap.
На Android для записи с шумоподавлением — NoiseSuppressor.isAvailable() + create(audioRecord.audioSessionId). Работает не на всех устройствах, нужен fallback.
Видео: воспроизведение и стриминг
ExoPlayer (Media3) — стандарт для Android. Поддерживает HLS, DASH, SmoothStreaming, прогрессивное воспроизведение. DefaultTrackSelector с Parameters позволяет выбирать качество вручную или адаптивно. DRM через DefaultDrmSessionManager с Widevine L1/L3.
Проблема, с которой сталкиваются почти все: ExoPlayer в RecyclerView при быстром скролле. Нужен PlayerPool — пул переиспользуемых плееров. Без пула каждый новый экземпляр создаёт MediaCodec инстанс, что дорого и приводит к MediaCodec$CodecException: Error -19 на некоторых Android 10 устройствах при >3 одновременных инстансах.
AVPlayer / AVPlayerViewController на iOS — для воспроизведения. Для кастомного UI — AVPlayerLayer + собственные контролы. HLS работает нативно через AVPlayer(url:) с m3u8. FairPlay DRM требует серверной части: AVContentKeySession, CKC-ответ от KSM-сервера, делегат ресурсов.
Для Flutter — video_player как базовый слой, chewie для UI. Для серьёзных задач — platform channel к нативному ExoPlayer/AVPlayer (из-за DRM и субтитров).
| Протокол |
Задержка |
Применение |
| RTMP |
2–5 сек |
Стриминг на YouTube/Twitch |
| HLS |
6–30 сек |
VOD, широковещательный |
| DASH |
6–30 сек |
VOD с адаптивным битрейтом |
| WebRTC |
< 500 мс |
Видеозвонки, P2P |
| SRT |
1–4 сек |
Профессиональный стриминг |
WebRTC на мобильных — через нативные фреймворки или flutter_webrtc. Реальная сложность — не в самом протоколе, а в сигналинге и TURN-серверах. Без TURN клиенты за симметричными NAT не установят соединение — это примерно 15–20% трафика. Coturn — стандартный open-source сервер.
RTMP публикация на мобильных: LFLiveKit для iOS, HaishinKit как более современная альтернатива. На Android — rtmp-rtsp-stream-client-java или через FFmpeg с JNI. Последнее даёт максимальную гибкость, но бинарник растёт на 10–15 МБ.
Обработка медиа: компрессия и транскодирование
Видео в ProRes может занимать 6 ГБ/минуту. Перед загрузкой нужна компрессия. На iOS — AVAssetExportSession с пресетом 1920×1080 или кастомный AVVideoComposition. VideoToolbox для аппаратного кодирования H264/HEVC — быстрее и экономнее по батарее.
На Android — MediaCodec напрямую или Transformer (Media3) — высокоуровневый API для трансформаций (обрезка, ресайз, эффекты через GlEffectsFrameProcessor). Для изображений — BitmapFactory.Options.inSampleSize для даунсемплинга, Glide / Coil для кеширования. Coil на Coroutines хорошо вписывается в Compose. Загружать оригинал 12 МП в ImageView 200×200dp — классический OutOfMemoryError на устройствах с 2 ГБ RAM.
Как реализовать стриминг на мобильных устройствах: пошаговый план
- Определить требования: целевая задержка, количество одновременных пользователей, необходимость P2P.
- Выбрать протокол и стек: WebRTC для видеозвонков, RTMP/HLSLive для вещания.
- Настроить сигналинг (SIP, WebSocket, MQTT) и TURN-сервер.
- Реализовать публикацию/просмотр через нативный API или кроссплатформенный плагин.
- Провести тестирование на реальных устройствах с разными камерами и сетевыми условиями.
- Оптимизировать битрейт и разрешение в зависимости от пропускной способности.
Типичные ошибки при разработке медиа-функциональности
- Конфигурация AVFoundation сессии на главном потоке.
- Отсутствие обработки AudioFocus Loss на Android.
- Игнорирование
MediaCodec ограничений на дешёвых устройствах.
- Использование эмулятора для тестов камеры — эмулятор не воспроизводит проблемы HAL.
- Утечка памяти при пересоздании медиаплееров без пула.
Что входит в работу
| Deliverable |
Описание |
| Анализ требований |
Выбор стека, приоритетов, тестовых устройств |
| Проектирование |
Архитектура, диаграммы потоков данных, выбор API |
| Реализация |
Код с использованием выбранных инструментов |
| Интеграция с бэкендом |
GraphQL/REST, DRM, WebRTC сигналинг |
| Тестирование |
На реальных устройствах (не менее 5 моделей) |
| Документация |
API-документация, инструкция по сборке |
| Поддержка после релиза |
1 месяц инцидентной поддержки, обучение команды |
Процесс разработки медиафункциональности
Сложность нелинейна: базовое воспроизведение видео — 1–2 дня, кастомная камера с обработкой кадров и стримингом — 3–5 недель. Начинаем с прояснения требований: DRM, форматы, минимальная OS, поддержка фоновых режимов. Тестирование на железе обязательно — эмулятор не воспроизводит проблемы с Camera HAL, аппаратным кодеком и AudioFocus. Минимальный набор: последний iPhone, iPhone SE, флагман Samsung, бюджетный Android, Android Go (если целевая аудитория — развивающиеся рынки).
Сроки ориентировочно: от 5 рабочих дней (базовое воспроизведение) до 8 недель (комплексная камера со стримингом и DRM). Стоимость рассчитывается индивидуально после анализа ваших требований — свяжитесь с нами для консультации.
Фраза услуги: «Работа с медиа в мобильных приложениях» — это наш профиль. Каждый проект начинается с аудита текущей реализации, выявления узких мест и предложения оптимального стека.
Коммерческие сигналы: закажите аудит вашей медиа-функциональности, получите консультацию инженера без обязательств.