Розробка платформи для стрімінгу прямих трансляцій

Запуск власного стрімінгового сервісу часто стикається із затримками та нестабільністю трансляцій, особливо при зростанні аудиторії. Ми розробляємо платформи для прямих ефірів з нуля, підбираючи оптимальні протоколи та архітектуру під ваші завдання. Наша команда реалізує проєкт під ключ — від проєктування до впровадження та подальшої підтримки, забезпечуючи надійну роботу сервісу, який масштабується разом із вашим бізнесом.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Розробка платформи для стрімінгу прямих трансляцій
Складний
від 2 тижнів до 3 місяців
Часті запитання

Архітектура платформи для прямих трансляцій

Ми часто стикаємося із завданням: компанія хоче запустити свій стрімінг-сервіс, схожий на Twitch, але з власними правилами монетизації та контенту. Типова проблема — затримка зростає при піку до 10 секунд, якість падає, а інфраструктура не витримує навантаження. За 5+ років ми розробили понад 15 streaming-проєктів, від невеликих educational-платформ до великих media. Розберемо, як побудувати надійну live-систему з нуля з урахуванням вимог до затримки, сумісності з пристроями та масштабування до тисяч глядачів. В основі вибору протоколів лежать такі критерії, як затримка, підтримка CDN та сумісність із браузерами.

Схема доставки та протоколи

Стрімер → Ingest → Transcoding → CDN → Viewer

Вхідний потік від стрімера — зазвичай RTMP (OBS, StreamLabs, XSplit всі вміють RTMP із коробки). На виході до глядача — HLS або DASH для браузера, WebRTC для ultra-low-latency (< 1 сек).

RTMP забезпечує низьку затримку на етапі прийому, але не підходить для доставки через блокування фаєрволами. HLS — стандарт де-факто, працює через HTTP і легко кешується на CDN.

OBS/FFMPEG → RTMP → Nginx-RTMP/SRS/Wowza → FFmpeg transcoding ↓
HLS segments → S3/CDN
WebRTC → Selective Forwarding Unit

Чому SRS кращий за інші ingest-сервери?

SRS (Simple Realtime Server) — опенсорс, Go, чудово тримає навантаження до 10K+ підключень на одному сервері. У наших проєктах SRS показав продуктивність на 30% вищу, ніж Wowza, при ідентичній конфігурації. Налаштування через один конфіг:

# srs.conf
listen 1935;
max_connections 1000;
daemon off;
http_server {
    enabled on;
    listen 8080;
    dir ./objs/nginx/html;
}
vhost __defaultVhost__ {
    # Хук: повідомляємо backend про початок/кінець трансляції
    http_hooks {
        enabled on;
        on_publish http://api:8000/hooks/stream/start;
        on_unpublish http://api:8000/hooks/stream/stop;
        on_play http://api:8000/hooks/stream/view;
    }
    hls {
        enabled on;
        hls_path ./objs/nginx/html;
        hls_fragment 2; # 2 секунди — баланс затримки та стабільності
        hls_window 10; # 10 сегментів у вікні
    }
    transcode {
        enabled on;
        ffmpeg /usr/local/bin/ffmpeg;
        engine hd {
            enabled on;
            vcodec libx264;
            vbitrate 2000;
            vfps 30;
            vwidth 1280;
            vheight 720;
            acodec aac;
            abitrate 128;
            output rtmp://localhost:1935/[app]/[stream]_720p;
        }
        engine sd {
            enabled on;
            vcodec libx264;
            vbitrate 800;
            vfps 30;
            vwidth 854;
            vheight 480;
            acodec aac;
            abitrate 96;
            output rtmp://localhost:1935/[app]/[stream]_480p;
        }
    }
}

Аутентифікація стрімера

Стрімер публікує потік за stream key. Не можна приймати RTMP від невідомих джерел:

# FastAPI: хук для SRS on_publish
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

class PublishHook(BaseModel):
    action: str
    app: str
    stream: str  # stream key від стрімера
    param: str   # query string

@app.post("/hooks/stream/start")
async def on_stream_start(hook: PublishHook):
    # Валідуємо stream key
    streamer = await db.fetchrow(
        "SELECT id, user_id, is_active FROM stream_keys WHERE key = $1",
        hook.stream
    )
    if not streamer or not streamer['is_active']:
        raise HTTPException(status_code=403, detail="Invalid stream key")

    # Запускаємо трансляцію в БД
    await db.execute("""
        INSERT INTO live_streams (user_id, stream_key_id, started_at, status)
        VALUES ($1, $2, NOW(), 'live')
        ON CONFLICT (stream_key_id) DO UPDATE SET started_at = NOW(), status = 'live'
    """, streamer['user_id'], streamer['id'])

    # Повідомляємо підписників через WebSocket
    await notify_followers(streamer['user_id'], 'stream_started')

    return {"code": 0}  # SRS очікує code=0 для дозволу
Як оптимізувати завантаження HLS-сегментів у S3?

Моніторимо директорію із сегментами через cron або системний таймер. Для .m3u8 файлів встановлюємо Cache-Control: max-age=2, для .ts — max-age=86400, immutable. Використовуємо aws s3 cp з правильними заголовками.

Як працює чат у реальному часі?

Чат трансляції — обов'язковий елемент. WebSocket через Redis Pub/Sub з rate limiting та зберіганням ковзного вікна повідомлень:

// Node.js: WebSocket-сервер для чату
import { WebSocketServer } from 'ws';
import { createClient } from 'redis';

const wss = new WebSocketServer({ port: 3001 });
const redis = createClient({ url: process.env.REDIS_URL });
const redisSub = redis.duplicate();

await redis.connect();
await redisSub.connect();

interface ChatMessage {
  type: 'message' | 'emote' | 'sub' | 'ban';
  streamId: string;
  userId: string;
  username: string;
  text: string;
  badges: string[];
  timestamp: number;
}

// Підписуємося на канал трансляції
wss.on('connection', (ws, req) => {
  const streamId = new URL(req.url!, 'ws://x').searchParams.get('stream');
  if (!streamId) return ws.close();

  const channel = `chat:${streamId}`;

  // Слухаємо Redis Pub/Sub для цього стріму
  redisSub.subscribe(channel, (message) => {
    if (ws.readyState === ws.OPEN) {
      ws.send(message);
    }
  });

  ws.on('message', async (data) => {
    const msg: ChatMessage = JSON.parse(data.toString());

    // Антиспам: rate limit на користувача
    const key = `chat_limit:${msg.userId}:${streamId}`;
    const count = await redis.incr(key);
    if (count === 1) await redis.expire(key, 5);
    if (count > 20) {
      // 20 повідомлень за 5 секунд — забагато
      ws.send(JSON.stringify({ type: 'slowmode', waitMs: 5000 }));
      return;
    }

    // Зберігаємо в Redis Stream (ковзне вікно 1000 повідомлень)
    await redis.xAdd(`stream_chat:${streamId}`, '*', msg as any, {
      TRIM: { strategy: 'MAXLEN', threshold: 1000 }
    });

    // Публікуємо всім підключеним
    await redis.publish(channel, JSON.stringify(msg));
  });

  ws.on('close', () => {
    redisSub.unsubscribe(channel);
  });
});

Запис трансляцій у VOD

Після закінчення стріму склеюємо TS-сегменти та перекодовуємо з faststart для псевдострімінгу. Офіційна документація FFmpeg рекомендує використовувати прапорець -movflags +faststart для переміщення атома moov на початок файлу, що прискорює початок відтворення.

# Celery task: конвертація в VOD
@app.task
def process_vod(stream_id: int):
    stream = LiveStream.objects.get(id=stream_id)
    segments = sorted(
        glob(f"/var/srs/hls/{stream.stream_key}/*.ts"),
        key=lambda f: int(Path(f).stem.split('_')[-1])
    )
    concat_list = "/tmp/vod_concat.txt"
    with open(concat_list, 'w') as f:
        for s in segments:
            f.write(f"file '{s}'\n")
    raw_mp4 = f"/tmp/vod_{stream_id}_raw.mp4"
    subprocess.run([
        'ffmpeg',
        '-f', 'concat',
        '-safe', '0',
        '-i', concat_list,
        '-c', 'copy',
        raw_mp4
    ], check=True)
    vod_mp4 = f"/var/vod/{stream_id}.mp4"
    subprocess.run([
        'ffmpeg',
        '-i', raw_mp4,
        '-c:v', 'libx264',
        '-preset', 'fast',
        '-crf', '23',
        '-c:a', 'aac',
        '-b:a', '128k',
        '-movflags', '+faststart',
        vod_mp4
    ], check=True)
    stream.vod_path = vod_mp4
    stream.status = 'ended'
    stream.save()

Як налаштувати транскодинг у кілька якостей: покрокова інструкція

  1. Встановіть SRS та FFmpeg на сервер.
  2. У конфігу SRS увімкніть секцію transcode та вкажіть шляхи до FFmpeg.
  3. Визначте профілі транскодингу (наприклад, HD: 720p, 30fps, 2 Mbps; SD: 480p, 30fps, 800 Kbps).
  4. Вкажіть у вихідних URL [stream]_720p та [stream]_480p, щоб SRS автоматично додавав суфікс.
  5. Перевірте, що HLS-сегменти створюються для кожного профілю в окремих піддиректоріях.
  6. Протестуйте з OBS, надсилаючи потік на RTMP ingest. Переконайтеся, що плеєр може перемикатися між quality levels.

Порівняння протоколів доставки

Протокол Затримка Сумісність Кешування CDN Використання
RTMP < 1 сек Flash/старі плеєри Ні Ingest
HLS 2-30 сек HTML5, iOS, Android Так Доставка
DASH 2-10 сек HTML5, SmartTV Так Доставка
WebRTC < 500 мс Браузери, P2P Ні Інтерактив

Порівняння популярних CDN для HLS-доставки

CDN Кешування HLS Origin Shield GeoDNS Ціна за TB (орієнтовно)
Cloudflare Так Так Так $0.036
AWS CloudFront Так Так Так $0.085
Fastly Так Так Так $0.10
Akamai Так Так Так >$0.15

Що входить у розробку платформи під ключ

  • Архітектурне проектування: вибір протоколів, CDN, capacity planning.
  • Ingest-сервер: налаштування SRS/Nginx-RTMP, транскодинг у кілька якостей.
  • Бекенд: API для керування стрімами, аутентифікація, монетизація.
  • Фронтенд: кастомізований плеєр, дашборд стрімера, чат.
  • Інфраструктура: Docker-контейнеризація, автоскейлінг, моніторинг.
  • Документація: повна технічна документація, інструкції для адміністраторів.
  • Навчання: сесія для команди, підтримка 2 тижні після запуску.
  • Гарантія: виправляємо баги протягом місяця безкоштовно.

Масштабування: багатосерверний ingest

Один ingest-сервер — SPOF. Для продакшну потрібен кластер з балансуванням:

DNS → Load Balancer (GeoDNS) → Ingest cluster ↓ Transcoding workers (GPU) ↓ HLS → S3 → CDN 

Стрімери направляються на найближчий ingest за GeoDNS. Кожен ingest пише в загальне об'єктне сховище або реплікує сегменти синхронно. Зв'яжіться з нами для обговорення архітектури вашого проєкту — ми підберемо оптимальну конфігурацію.

Строки

MVP із RTMP-прийомом, HLS-доставкою, WebSocket-чатом та записом у VOD — 10–12 тижнів. Додавання транскодингу кількох якостей, gift-subscriptions, модерації чату, мобільного плеєра — ще 8–10 тижнів. Масштабування до 10k+ concurrent viewers, балансування ingest, CDN з origin shield — окремий етап.

Хочете запустити свій стрімінг-сервіс? Отримайте консультацію — оцінимо ваш проєкт за 2 дні. Пишіть.

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

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1141
  • Розробка веб-сайту для компанії ФІКСПЕР
    Розробка веб-сайту для компанії ФІКСПЕР
    1060