У відеодзвінках на мобільних платформах головні проблеми — lifecycle та управління токенами. Без правильного налаштування отримуєте витік ресурсів, обриви сесій та перевитрату ліцензій. Наш досвід більше 30 проектів з Agora SDK дозволив сформулювати робочий підхід. Ми гарантуємо якість інтеграції завдяки 10-річному досвіду та сертифікованим фахівцям.
Чому Agora SDK — найкращий вибір для відеодзвінків?
Agora SDK — WebRTC managed service, який бере на себе WebRTC під капотом, власну транспортну мережу SD-RTN, адаптивний бітрейт та кодеки. Порівняно з raw WebRTC, Agora SDK краще в 12 разів за швидкістю розробки (з 3 місяців до 1 тижня) та у 3 рази за обсягом коду. Правильна інтеграція Agora SDK дає скорочення витрат на інфраструктуру до 40% порівняно з іншими рішеннями.
Як правильно налаштувати токени та уникнути помилок?
Agora працює за моделлю App ID + Token. App ID — публічний ідентифікатор з консолі. Token — короткоживучий JWT, який ваш бекенд генерує через Agora Token Builder і передає клієнту при вході в канал. Для правильної інтеграції Agora SDK важливе налаштування токенів. Найчастіші помилки в продакшені: tokenExpired (109) і invalidToken (110). Token має обмежений TTL (від 24 годин до 1 години). Реалізуємо обробку через tokenPrivilegeWillExpire делегатний метод — отримуємо новий токен з бекенду та викликаємо renewToken() без розриву з'єднання.
Таблиця рекомендованих TTL токенів
| Сценарій |
TTL |
Рекомендація |
| Стандартний |
24 години |
Баланс безпеки та частоти оновлень |
| Високе навантаження |
1 година |
Знижує ризик компрометації токена |
Типова помилка: токен генерується з UID 0 на бекенді, але клієнт після joinChannel отримує конкретний UID від Agora — і при наступному renewToken передає токен під неправильний UID. Рішення: зберігаємо UID з didJoinChannel і використовуємо його при запиті нового токена.
Ініціалізація двигуна (Agora engine)
Покрокова інструкція:
- Ініціалізуйте двигун один раз при старті додатку.
- Налаштуйте токени.
- Підключіться до каналу.
- Обробіть відео.
Ініціалізація движка:
let config = AgoraRtcEngineConfig()
config.appId = "YOUR_APP_ID"
agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
val config = RtcEngineConfig()
config.mContext = context
config.mAppId = "YOUR_APP_ID"
config.mEventHandler = handler
rtcEngine = RtcEngine.create(config)
Не створюйте движок заново під кожен дзвінок. sharedEngine — синглтон, повторний виклик з тим же App ID повертає існуючий екземпляр. На Android RtcEngine.create() кожного разу створює новий екземпляр; попередній потрібно знищити через RtcEngine.destroy(). Інакше витік нативних ресурсів проявляється через 3–5 дзвінків. Використовуйте LifecycleObserver для автоматичного знищення движка при завершенні активності.
Підключення до каналу та обробка відео
let option = AgoraRtcChannelMediaOptions()
option.clientRoleType = .broadcaster
option.channelProfile = .communication
agoraKit.joinChannel(
byToken: token,
channelId: channelName,
uid: 0,
mediaOptions: option
)
uid: 0 — Agora призначає UID самостійно. Якщо потрібна прив'язка до користувача — передавайте детермінований числовий ID (UInt32).
Локальне відео виводимо через AgoraRtcVideoCanvas з setupLocalVideo(). Віддалене — через setupRemoteVideo() в делегатному методі didJoinedOfUid. Важливо: setupRemoteVideo() викликайте на main thread, інакше EXC_BAD_ACCESS при швидкому підключенні/відключенні учасників.
func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
DispatchQueue.main.async {
let canvas = AgoraRtcVideoCanvas()
canvas.uid = uid
canvas.renderMode = .hidden
canvas.view = self.remoteVideoView
self.agoraKit.setupRemoteVideo(canvas)
}
}
Налаштування якості відео
Agora надає передустановки AgoraVideoEncoderConfiguration та кастомні параметри:
let config = AgoraVideoEncoderConfiguration(
size: CGSize(width: 640, height: 360),
frameRate: .fps15,
bitrate: AgoraVideoBitrateStandard,
orientationMode: .adaptative,
mirrorMode: .auto
)
agoraKit.setVideoEncoderConfiguration(config)
Для мобільного додатку 360p/15fps — розумний баланс якості та батарейного навантаження. 720p/30fps — для планшетів або коли якість критична. 1080p не підходить для мобільних: споживає багато енергії та ресурсів, а різниця у сприйнятті між 720p та 1080p незначна.
Порівняльна таблиця налаштувань відео
| Роздільна здатність |
fps |
Бітрейт |
Навантаження на батарею |
| 360p |
15 |
Standard |
Низьке |
| 720p |
30 |
Standard |
Середнє |
| 1080p |
30 |
High |
Високе |
Як обробити переривання та lifecycle?
На iOS AVAudioSession.routeChangeNotification та AVAudioSession.interruptionNotification — Agora SDK обробляє їх автоматично при коректному налаштуванні AgoraAudioScenario. Сценарій .meeting — оптимальний для відеодзвінків: включає AEC, ANS, AGC.
При вхідному системному дзвінку Agora не паузиться автоматично. Реалізуємо через CXCallObserver: при CXCall.hasConnected == true — muteLocalAudioStream(true), при завершенні — розмьютуємо. Для вхідних дзвінків також налаштовуємо push notifications, щоб миттєво сповіщати користувача.
На Android без ForegroundService Android 8+ уб'є процес через 5–10 хвилин. Запускаємо ForegroundService при початку дзвінка з повідомленням. android:foregroundServiceType="camera|microphone" в маніфесті обов'язковий з Android 14.
Що входить в інтеграцію
- Аналіз вимог: кількість учасників, якість, бекенд-інтеграція, бюджет.
- Налаштування токенів: генерація, кешування, обробка протухань.
- Реалізація UI: відеоканваси, органи управління, віртуальний фон Agora.
- Lifecycle: ForegroundService на Android, CXCallObserver на iOS.
- Тестування: 10+ сценаріїв (обрив мережі, вхідний дзвінок, швидка перекомутація).
- Документація: README, коментарі коду, схема токенів.
- Підтримка: 2 тижні після релізу, фіксація багів.
- Запис дзвінків Agora: за потреби налаштовуємо recording.
Терміни та вартість
Пропонуємо інтеграцію Agora SDK під ключ від $2000. Базова інтеграція (1-на-1 відеодзвінок з управлінням камерою, mute, flip) — 3–5 днів, вартість від $2000. З підтримкою групи до 8 учасників, токен-менеджментом та фоновим режимом — 1–2 тижні, вартість до $5000. Економія на ліцензіях Agora може сягати $1000 на місяць при середньому навантаженні. Вартість точного рішення розраховується після аналізу вимог. Напишіть нам для консультації — ми безкоштовно оцінимо ваш проект та підготуємо кошторис і roadmap.
Як вибрати підхід до камери в застосунках?
Застосунки, де користувачі знімають, слухають або дивляться, технічно одні з найвимогливіших. Ми стикаємося з цим щодня. Не через складність API, а через різницю в залізі: на флагмані камера працює ідеально, на бюджетному пристрої з нестандартним Camera HAL виникають артефакти та збої. На iOS стабілізація одного покоління відрізняється від іншого. Платформенні відмінності формують 80% всієї складності медіа-розробки. Наш досвід — 10+ років у мобільних медіа та понад 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 — нативні алгоритми виробників через єдиний інтерфейс. CameraX дозволяє скоротити час розробки вдвічі порівняно з Camera2.
Коли потрібен 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 та AudioSession на iOS?
Аудіо на мобільних платформах вимагає коректного управління життєвим циклом звуку. AudioFocus — механізм координації між застосунками. AudioManager.requestAudioFocus() з OnAudioFocusChangeListener. Якщо не обробляти AUDIOFOCUS_LOSS_TRANSIENT (паузувати) та AUDIOFOCUS_LOSS (зупиняти) — ваш застосунок гратиме поверх телефонного дзвінка. Це гарантований поганий відгук у Google Play (Wikipedia: 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 одночасних інстансах. Використання пулу зменшує споживання пам'яті до 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 МБ перед відправкою.
Як реалізувати стрімінг на мобільних пристроях: покроковий план?
- Визначити вимоги: цільова затримка (наприклад, <100 мс), кількість одночасних користувачів (до 1000), необхідність P2P.
- Обрати протокол та стек: WebRTC для відеодзвінків, RTMP/HLSLive для мовлення.
- Налаштувати сигналінг (SIP, WebSocket, MQTT) та TURN-сервер.
- Реалізувати публікацію/перегляд через нативний API або кроссплатформенний плагін.
- Провести тестування на реальних пристроях з різними камерами та мережевими умовами.
- Оптимізувати бітрейт (до 2 Мбіт/с для HD) та роздільну здатність залежно від пропускної здатності.
Типові помилки при розробці медіа-функціональності: конфігурація AVFoundation сесії на головному потоці, відсутність обробки AudioFocus Loss на Android, ігнорування обмежень MediaCodec на дешевих пристроях, використання емулятора для тестів камери (емулятор не відтворює проблеми HAL), витік пам'яті при перестворенні медіаплеєрів без пулу.
Що входить в роботу?
| Deliverable |
Опис |
| Аналіз вимог |
Вибір стеку, пріоритетів, тестових пристроїв (мінімум 5 моделей) |
| Проектування |
Архітектура, діаграми потоків даних, вибір 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). Вартість розраховується індивідуально після аналізу ваших вимог — зв'яжіться з нами для консультації. Типовий бюджет таких проєктів: від $2,000 до $15,000.
Фраза послуги: «Робота з медіа в мобільних застосунках» — це наш профіль. Кожен проєкт починається з аудиту поточної реалізації, виявлення вузьких місць та пропозиції оптимального стеку. Замовте аудит вашої медіа-функціональності, отримайте консультацію інженера без зобов'язань.