nimeet Docs
中文

Media Push (Push to CDN)

rtmp-converters lifecycle, output addresses, legacy entry_points migration and callbacks.

Version v1.1.0 · Updated 2026-10-26 · revision 1

Media Push pushes the audio and video of a channel to an RTMP address (a CDN, a live-streaming platform, or your own transcoder). This page describes the current implementation (rtmp-converters), its lifecycle and state semantics, and how Agora's legacy entry_points (FLS) model relates to it and migrates onto it.

Concepts

ConceptMeaning
converterA push task: it pushes the mixed stream of one channel to one rtmpUrl. It has an id, a state, and creation/update timestamps
regionA region prefix (such as cn-shanghai), placed at the very front of the path
idleTimeoutSeconds after which the task is reclaimed automatically when there are no viewers or no publishers
transcodeOptions / rawOptionsTranscoding parameters; when omitted, the original parameters are passed through untouched

The mapping between a converter and our internal Egress task is 1:1: every converter owns one real room_composite egress task.

Creating a converter

bash
curl -s -X POST "$NIMEET_API_BASE/cn-shanghai/v1/projects/$APP_ID/rtmp-converters?regionHintIp=$REGION_HINT_IP" \
  -H "Authorization: Basic $NIMEET_CUSTOMER_BASIC" \
  -H 'Content-Type: application/json' \
  -d '{
    "converter": {
      "name": "weekly-live",
      "rtmpUrl": "rtmp://live.example.com/live/weekly",
      "idleTimeout": 300,
      "jitterBufferSizeMs": 500
    }
  }'

The request body has exactly one field, converter (required), which contains:

FieldTypeDescription
namestring \nullBusiness name, makes queries easier
rtmpUrlstringPush address; when it carries an authentication string it is used as-is and redacted in logs
idleTimeoutintegerIdle reclamation seconds
jitterBufferSizeMsintegerJitter buffer; lower it when chasing low latency for live
transcodeOptionsobjectTranscoding parameters (resolution / bitrate / frame rate)
rawOptionsobjectRaw parameters (used when not transcoding)

converter.id / state / createTs in the response are what later operations rely on.

Lifecycle

text
create convert(POST)  → state: connecting → running → (stop / idle reclamation) stopped
                         │
                         └─ failure → failed (the error is in the error field of the keepalive query)
OperationEndpointDescription
CreatePOST /{region}/v1/projects/{appId}/rtmp-convertersStarts pushing immediately
Query stateGET /{region}/v1/projects/{appId}/rtmp-converters/{converterId}Returns state, rtmpUrl, idleTimeout…
UpdatePATCH /{region}/v1/projects/{appId}/rtmp-converters/{converterId}Can change rtmpUrl / transcoding parameters; pass sequence for optimistic concurrency
ListGET /v1/projects/{appId}/rtmp-convertersSupports cursor and channel filters
DestroyDELETE /{region}/v1/projects/{appId}/rtmp-converters/{converterId}Stops the push and releases the egress task

Signaling and keepalive

  • There is no heartbeat API: a converter keeps pushing while the channel has participants; if nobody is present for idleTimeout, it is reclaimed automatically;
  • Both reclamation and failure emit a callback with event code 202 (streaming_state_changed), see Callback event reference;
  • When a PATCH carrying sequence targets an id that has been updated concurrently, it returns 409; GET again and then retry.

Relationship with the legacy entry_points (FLS) model

Dimensionentry_points (legacy)rtmp-converters (current)
Resource modelCreate an entry point first, then attach "push this stream name" beneath itOne converter = one push target
Path/v1/projects/{appid}/fls/*/{region}/v1/projects/{appId}/rtmp-converters*
Multiple targetsMultiple streams under one entry pointMultiple converters
Agora statusAPI sunsetCurrent documentation
Our stanceCompatibility implementation, not recommendedRecommended

Migration mapping: "one entry point + multiple stream names" corresponds to "multiple converters". The hls switch of the legacy API is handled by the output side (the CDN) in Media Push — we no longer generate an HLS manifest. If you need HLS, use bypass streaming (Legacy).

Playback address

After a successful push, viewers play the HLS/FLV address that corresponds to rtmpUrl through the CDN — that address is decided by your CDN, not generated by us. Our responsibility ends at "pushing the stream to rtmpUrl".

Quotas and errors

ScenarioResponse
Service not enabled403 service_not_enabled
Concurrent converters exceeded429 streaming_quota_exceeded (see Usage and quotas)
Duplicate converter name in the same project409 streaming_invalid_state, and details.existingConverterId points at the existing task (names are unique; duplicates are not allowed)
Missing transcodeOptions.rtcChannel (or rawOptions)400 invalid_parameter: you must say which channel to pull the stream from
Unreachable RTMP addressCreation succeeds and state reflects the failure reason in the keepalive query; the create call does not block waiting for the push handshake

End-to-end example

bash
node run-all.mjs --only=18

18-media-push-lifecycle.mjs walks through "create → query state → update → destroy" and asserts the envelope and the state at every step (it performs writes, so it needs --all or NIMEET_EXAMPLES_MUTATING=1).

Generated by the documentation build pipeline · 2026-10-31 01:24:02 UTC · Documentation center v1.1.0.

Content follows the public API definitions.

ni-meet is a self-hosted RTC PaaS with a LiveKit-based media plane (Apache-2.0) and an Agora-compatible API.