Screen Broadcasting с мобильного устройства: реализация и оптимизация

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Screen Broadcasting с мобильного устройства: реализация и оптимизация
Средний
~3-5 дней
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    744
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1161
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    563

Screen Broadcasting — трансляция экрана мобильного приложения — востребована в сценариях демонстрации, технической поддержки, стриминга и удалённого обучения. На iOS доступен только ReplayKit с жёстким лимитом памяти 50 МБ в Broadcast Extension, а на Android — MediaProjection с возможностью захвата в реальном времени. Неправильная реализация ведёт к потере кадров, перерасходу памяти и сбоям под нагрузкой. Мы решаем эти проблемы: оптимизируем downscale видео, внедряем heartbeat-мониторинг для контроля состояния трансляции и подбираем оптимальный протокол — RTMP, SRT или WebRTC. Наши инженеры имеют 7+ лет опыта в мобильной разработке, реализовали более 30 проектов со стримингом экрана и с 2018 года на рынке. Получите предварительную оценку вашего проекта — просто свяжитесь с нами.

Особенности Screen Broadcasting на iOS

Трансляция экрана на iOS работает только через ReplayKit. Попытки захватить UIScreen напрямую с помощью UIScreen.main.snapshot дают единичный снимок, а не видеопоток. Как указано в документации Apple, ReplayKit — единственный публичный API для захвата экрана ReplayKit. Однако он накладывает ограничения: задержка 2–5 секунд и лимит памяти 50 МБ для Broadcast Extension.

Два режима ReplayKit и когда что использовать

RPScreenRecorder (in-app recording). Захватывает только контент внутри приложения. Пользователь не видит системный picker. Подходит для записи геймплея, capture UI приложения. Недостаток — захват прекращается при сворачивании.

RPBroadcastSampleHandler (broadcast upload extension). Работает как системный Extension — процесс живёт отдельно от основного приложения. Захватывает весь экран устройства, включая другие приложения и уведомления. Пользователь запускает через Control Center или RPSystemBroadcastPickerView. Именно этот режим нужен для трансляции «всего экрана».

Архитектура Broadcast Extension:

 iOS System → RPBroadcastSampleHandler (Extension process)
                     ↓
          CMSampleBuffer (video + audio)
                     ↓
          App Group shared container (если нужна коммуникация с основным приложением)
                     ↓
          RTMP/SRT → сервер трансляции

Расширение не имеет UI и ограничено 50 МБ RAM. Это жёсткое ограничение: всё кодирование и отправка должны умещаться в этот бюджет.

RPBroadcastSampleHandler: реализация

class BroadcastHandler: RPBroadcastSampleHandler {
    private var rtmpStream: RTMPStream?

    override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
        // Инициализируем RTMP или SRT соединение
        // setupInfo — данные от основного приложения через Info.plist
    }

    override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer,
                                      with sampleBufferType: RPSampleBufferType) {
        switch sampleBufferType {
        case .video:
            rtmpStream?.append(sampleBuffer)
        case .audioApp:
            rtmpStream?.append(sampleBuffer) // аудио приложений
        case .audioMic:
            // аудио микрофона — отдельный поток, требует явного разрешения
            break
        }
    }

    override func broadcastFinished() {
        rtmpStream?.close()
    }
}

Передача параметров (stream key, endpoint) из основного приложения в Extension — через App Group UserDefaults:

let defaults = UserDefaults(suiteName: "group.com.yourapp.broadcast")
defaults?.set(streamKey, forKey: "streamKey")

Почему задержка на iOS неизбежна?

ReplayKit screen broadcast добавляет буферизацию ~2–5 секунд. Это не баг — Apple буферизирует для защиты конфиденциальности (показ системных диалогов с паролями). Снизить нельзя.

Разрешение зависит от модели устройства: современные топовые модели отдают 1668×2388 (native scale), что избыточно для стрима. В processSampleBuffer перед энкодированием нужно downscale через VTPixelTransferSession или CIContext:

// Масштабируем до 1280×720 перед отправкой в энкодер
let scaledBuffer = pixelTransferSession.scale(pixelBuffer, to: CGSize(width: 1280, height: 720))

Без downscale Extension превысит 50 МБ RAM на первом же I-frame в 4K.

Сравнение протоколов трансляции

Протокол Задержка Надёжность Сложность реализации
RTMP 2-5 с Средняя (требует ретрансляции) Низкая
SRT 0.5-2 с Высокая (FEC, автоматическое восстановление) Средняя
WebRTC <0.5 с Высокая (P2P, адаптивный битрейт) Высокая

Выбор протокола зависит от сценария: RTMP — для массовых стримов, SRT — для стабильности, WebRTC — для минимальной задержки. Мы помогаем подобрать оптимальный вариант под ваш проект.

Реализация трансляции экрана на Android

На Android аналог — MediaProjection. Пользователь подтверждает разрешение через системный диалог (startActivityForResult с MediaProjectionManager.createScreenCaptureIntent()). После получения MediaProjection создаём VirtualDisplay и направляем его в MediaCodec через Surface:

val virtualDisplay = mediaProjection.createVirtualDisplay(
    "ScreenCapture",
    width, height, dpi,
    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
    mediaCodec.createInputSurface(), null, null
)

В отличие от iOS, задержки ReplayKit нет — захват идёт почти в реальном времени. Но на более новых версиях Android появилось требование: если MediaProjection-сессия используется в ForegroundService, нужен тип FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION. Документация MediaProjection API описывает все нюансы.

Параметр iOS (ReplayKit) Android (MediaProjection)
Задержка 2–5 секунд (встроенная) Минимальная (реальное время)
Ограничение памяти 50 МБ RAM на Extension Нет жёсткого лимита, но рекомендуется управление
Захват других приложений Да (Broadcast Extension) Да (с разрешения)
Версии iOS 10+ Android 5+ (API 21)
Параметры запуска Через Control Center Через системный диалог

Android MediaProjection обеспечивает задержку менее 100 мс, что в 20–50 раз меньше задержки ReplayKit на iOS.

Как избежать падения Broadcast Extension?

На iOS Extension может работать бесконечно, но если процесс превышает 50 МБ — система его убивает без предупреждения. Для мониторинга из основного приложения — heartbeat через App Group: Extension пишет timestamp каждые 5 секунд, приложение проверяет. Если timestamp не обновлялся 15 секунд — считаем Extension упавшим и показываем предупреждение.

Мы внедряем heartbeat-механизм: Extension каждые 5 секунд сохраняет текущее время в UserDefaults через App Group. Основное приложение проверяет это значение каждые 15 секунд. Если с момента последнего обновления прошло больше 15 секунд — значит Extension упал. Пользователь получает уведомление и может перезапустить трансляцию.

Что входит в работу

  • Проектирование архитектуры с выбором протокола (RTMP, SRT, WebRTC) и сервера.
  • Разработка Broadcast Extension для iOS или сервиса захвата для Android.
  • Настройка App Group и коммуникации между процессами.
  • Оптимизация downscale видео и настройка битрейта.
  • Внедрение heartbeat-мониторинга и обработки ошибок.
  • Интеграция с сервером и тестирование на реальных устройствах.
  • Документация по интеграции и обучение команды.
  • Поддержка при релизе в App Store и Google Play.

Сроки ориентировочно

iOS Broadcast Extension с RTMP/SRT, downscaling, App Group коммуникацией: 2–3 недели. Android MediaProjection: 1.5–2 недели. Кросс-платформа с общим управляющим кодом: 4–5 недель. Стоимость рассчитывается индивидуально. Закажите предварительную оценку — свяжитесь с нами.

Важно соблюдать App Store Review Guidelines Section 4.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.

Как реализовать стриминг на мобильных устройствах: пошаговый план

  1. Определить требования: целевая задержка, количество одновременных пользователей, необходимость P2P.
  2. Выбрать протокол и стек: WebRTC для видеозвонков, RTMP/HLSLive для вещания.
  3. Настроить сигналинг (SIP, WebSocket, MQTT) и TURN-сервер.
  4. Реализовать публикацию/просмотр через нативный API или кроссплатформенный плагин.
  5. Провести тестирование на реальных устройствах с разными камерами и сетевыми условиями.
  6. Оптимизировать битрейт и разрешение в зависимости от пропускной способности.
Типичные ошибки при разработке медиа-функциональности
  • Конфигурация 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). Стоимость рассчитывается индивидуально после анализа ваших требований — свяжитесь с нами для консультации.

Фраза услуги: «Работа с медиа в мобильных приложениях» — это наш профиль. Каждый проект начинается с аудита текущей реализации, выявления узких мест и предложения оптимального стека.

Коммерческие сигналы: закажите аудит вашей медиа-функциональности, получите консультацию инженера без обязательств.