Server APIs v2
  • Server APIs overview
  • Accessing Server APIs
  • Room signaling
  • Stream mixing
  • Streaming moderation
  • Streaming control
  • CDN recording
  • Server callbacks
  • Return codes
  • API testing
  • FAQ
  • Documentation
  • Server APIs v2
  • Stream mixing
  • Start stream mixing

Start stream mixing

Last updated:2023-11-01 11:27

What is Stream-Mixing

Through the stream-mixing service, multiple published media streams can compose a single stream , which allows audiences to play just one stream to improve quality and reduce performance cost.

1 Description

Starts or updates a stream mixing task.

For more information about the stream mixing feature, see Stream mixing.

For callbacks related to stream mixing, see Callback on stream mixing started and Callback on stream mixing ended.

Before using this interface for the first time, you need to contact ZEGO technical support to activate it.

2 Prerequisites

Before you begin, make sure you complete the following:

  • Create a project in ZEGOCLOUD Admin Console and get the AppID and AppSign of your project.
  • Refer to the Quick Start doc to complete the SDK integration and basic function implementation.
  • Contact us to activate the Stream Mixing service.

3 Sample Code

ZEGOCLOUD provides example code in multiple programming languages. The following example code is for "mixing two audio and video streams (stream1, stream2) and outputting the mixed stream to a single stream (stream3)".

StartMix(Go)
package main

import (
    "bytes"
    "crypto/md5"
    "crypto/rand"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "strconv"
    "time"
)

const DOMAIN = "https://rtc-api.zego.im"

var (
    AppId uint32 = 
    Secret = 
)

type MixStartRequest struct {
    Appid     uint64       `json:"Appid"`
    UserId    string       `json:"UserId"`
    Sequence  int64        `json:"Sequence"`
    MixInput  []*MixInput  `json:"MixInput"`
    MixOutput []*MixOutput `json:"MixOutput"`
    MixTaskId string       `json:"TaskId"`
}

type RectInfo struct {
    Top    int32 `json:"Top"`
    Left   int32 `json:"Left"`
    Bottom int32 `json:"Bottom"`
    Right  int32 `json:"Right"`
}

type MixInput struct {
    StreamId  string    `json:"StreamId"`
    RectInfo  *RectInfo `json:"RectInfo"`
}

type MixOutput struct {
    StreamId     string `json:"StreamId"`
    VideoBitrate int32  `json:"VideoBitrate"`
    Fps          int32  `json:"Fps"`
    Height       int32  `json:"Height"`
    Width        int32  `json:"Width"`
}

func main() {
    nonce := make([]byte, 8)
    rand.Read(nonce)
    hexNonce := hex.EncodeToString(nonce)
    ts := time.Now()
    signature := GenerateSignature(AppId, hexNonce, Secret, ts.Unix())
    value := url.Values{}
    value.Add("AppId", strconv.FormatUint(AppId, 10))
    value.Add("SignatureNonce", hexNonce)
    value.Add("Timestamp", strconv.FormatInt(ts.Unix(), 10))
    value.Add("Signature", signature)
    value.Add("Action", "StartMix")
    value.Add("SignatureVersion", "2.0")
    urlData, err := url.Parse(DOMAIN)
    if err != nil {
        fmt.Println(err)
        return
    }
    urlData.RawQuery = value.Encode()
    dataJson, _ := json.Marshal(GenerateStartMixData())
    req, err := http.NewRequest("POST", urlData.String(), bytes.NewBuffer(dataJson))
    if err != nil {
        fmt.Println(err)
        return
    }
    req.Header.Set("Content-Type", "application/json")
    req.Close = true
    client := &http.Client{}
    r, err := client.Do(req)
    if err != nil {
        fmt.Println(err)
        return
    }
    if r.StatusCode != 200 {
        fmt.Printf("status code is:%v", r.StatusCode)
    }
    defer r.Body.Close()
    resp, err := ioutil.ReadAll(r.Body)
    if err != nil {
        return
    }
    fmt.Println(string(resp))
    return
}

func GenerateStartMixData() *MixStartRequest {
    inputs := make([]*MixInput, 0)
    input1 := MixInput{
        StreamId: "stream1",
        RectInfo: &RectInfo{
            Top:    70,
            Left:   100,
            Bottom: 160,
            Right:  260,
        },
    }
    inputs = append(inputs, &input1)
    input2 := MixInput{
        StreamId: "stream2",
        RectInfo: &RectInfo{
            Top:    200,
            Left:   100,
            Bottom: 290,
            Right:  260,
        },
    }
    inputs = append(inputs, &input2)
    output := MixOutput{
        StreamId:     "stream3",
        VideoBitrate: 12000,
        Fps:          15,
        Height:       360,
        Width:        360,
    }
    outputs := append([]*MixOutput{}, &output)
    req := &MixStartRequest{
        Appid:     AppId,
        UserId:    "123",
        Sequence:  123,
        MixInput:  inputs,
        MixOutput: outputs,
        MixTaskId: "123",
    }
    return req
}

func GenerateSignature(appid uint64, nonce string, appSecret string, timestamp int64) (signature string) {
    data := fmt.Sprintf("%d%s%s%d", appid, nonce, appSecret, timestamp)
    h := md5.New() 
    h.Write([]byte(data))
    return hex.EncodeToString(h.Sum(nil))
}
StartMix(Python)
# -*- coding: UTF-8 -*-
import hashlib
import secrets
import time

# Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
from urllib.parse import urlencode

import requests


def GenerateSignature(appId, signatureNonce, serverSecret, timestamp):
    str1 = str(appId) + signatureNonce + serverSecret + str(timestamp)
    hash = hashlib.md5()
    hash.update(str1.encode("utf8"))
    signature = hash.hexdigest()
    return signature


if __name__ == '__main__':
    appId = 
    serverSecret = ""

    signatureNonce = secrets.token_hex(8)
    timestamp = int(time.time())
    sig = GenerateSignature(appId, signatureNonce, serverSecret, timestamp)

    par = {
        "Action": "StartMix",
        "AppId": appId,
        "Signature": sig,
        "SignatureNonce": signatureNonce,
        "SignatureVersion": "2.0",
        "Timestamp": timestamp,
        "IsTest": "False"
    }
    body = {
        'TaskId': '123',
        'Sequence': 123,
        'UserId': '123',
        'MixInput': [
            {
                'StreamId': 'stream1',
                'RectInfo': {
                    "Top": 70,
                    "Bottom": 160,
                    "Left": 100,
                    "Right": 260,
                },

            },
            {
                'StreamId': 'stream2',
                'RectInfo': {
                    "Top": 200,
                    "Bottom": 290,
                    "Left": 100,
                    "Right": 260,
                },
            }
        ],
        'MixOutput': [{
            'StreamId': 'stream3',
            'Width': 360,
            'Height': 360,
            'VideoBitrate': 12000,
            'Fps': 15
        }]
    }
    url = 'https://rtc-api.zego.im/'
    req = requests.post(url, params=par, json=body)
    print("Url: ", req.url)
    print("StatusCode", req.status_code)
    print("Respone:", req.text)
StartMix(Java)
package org.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class StartMix {

    //
    public static void main(String[] args) {
        startMixStream();
    }

    public static void startMixStream() {
        Long APP_ID = 
        String SERVER_SECRET = ;
        byte[] bytes = new byte[8];
        SecureRandom sr = new SecureRandom();
        sr.nextBytes(bytes);
        String signatureNonce = bytesToHex(bytes);
        long timestamp = System.currentTimeMillis() / 1000L;

        String signatue = generateSignature(APP_ID, signatureNonce, SERVER_SECRET, timestamp);

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("Action", "StartMix");
        params.put("AppId", APP_ID);
        params.put("SignatureNonce", signatureNonce);
        params.put("Timestamp", timestamp);
        params.put("Signature", signatue);
        params.put("SignatureVersion", "2.0");
        String url = buildAPIUrl("https://rtc-api.zego.im/", params);

        JSONObject body = new JSONObject()
                .fluentPut("TaskId", "123")
                .fluentPut("Sequence", 123)
                .fluentPut("UserId", "123");

        JSONArray mixInputList = new JSONArray();
        mixInputList.add(new JSONObject()
                .fluentPut("StreamId", "stream1")
                .fluentPut("RectInfo", new JSONObject()
                        .fluentPut("Top", 70)
                        .fluentPut("Bottom", 160)
                        .fluentPut("Left", 100)
                        .fluentPut("Right", 260)));
        mixInputList.add(new JSONObject()
                .fluentPut("StreamId", "stream2")
                .fluentPut("RectInfo", new JSONObject()
                        .fluentPut("Top", 200)
                        .fluentPut("Bottom", 290)
                        .fluentPut("Left", 100)
                        .fluentPut("Right", 260)));
        body.put("MixInput", mixInputList);

        JSONArray mixOutputList = new JSONArray();
        mixOutputList.add(new JSONObject()
                .fluentPut("StreamId", "stream3")
                .fluentPut("Width", 360)
                .fluentPut("Height", 360)
                .fluentPut("VideoBitrate", 12000)
                .fluentPut("Fps", 15));
        body.put("MixOutput", mixOutputList);

        String result = sendPost(url, body.toString());
        System.out.println(result);
    }


    public static String generateSignature(long appId, String signatureNonce, String serverSecret, long timestamp){
        String str = String.valueOf(appId) + signatureNonce + serverSecret + String.valueOf(timestamp);
        String signature = "";
        try{
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(str.getBytes("utf-8"));
            signature = bytesToHex(bytes);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return signature;
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuffer md5str = new StringBuffer();
        int digital;
        for (int i = 0; i < bytes.length; i++) {
            digital = bytes[i];
            if (digital < 0) {
                digital += 256;
            }
            if (digital < 16) {
                md5str.append("0");
            }
            md5str.append(Integer.toHexString(digital));
        }
        return md5str.toString();
    }

    public static String sendGet(String httpurl) {
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpurl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(60000);
            connection.connect();
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                StringBuffer sbf = new StringBuffer();
                String temp = null;
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            connection.disconnect();
        }
        return result;
    }

    public static String sendPost(String httpUrl, String param) {
        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(60000);
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestProperty("Content-Type", "application/json");
            connection.connect();
            OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(),"UTF-8");
            writer.write(param);
            writer.flush();
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                StringBuffer sbf = new StringBuffer();
                String temp = null;
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            connection.disconnect();
        }
        return result;
    }

    public static String buildAPIUrl(String url, Map<String, Object> params) {
        if(params.isEmpty()) {
            return url;
        }
        StringBuffer buffer = new StringBuffer(url).append("?");
        for(String key : params.keySet()) {
            buffer.append(key).append("=").append(params.get(key)).append("&");
        }
        String apiurl = buffer.toString();
        if(apiurl.endsWith("&")) {
            return apiurl.substring(0, apiurl.length()-1);
        } else {
            return apiurl;
        }
    }

}
StartMix(PHP)
<?php

$appId = 
$serverSecret = 

//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
function GenerateSignature($appId, $signatureNonce, $serverSecret, $timeStamp){
    $str = $appId . $signatureNonce . $serverSecret . $timeStamp;
    return md5($str);
}

$signatureNonce = bin2hex(random_bytes(8));

list($msec, $sec) = explode(' ', microtime());
$msecTime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
$timeStamp = round($msecTime/1000);
$sig = GenerateSignature($appId, $signatureNonce, $serverSecret, $timeStamp);

$url = "https://rtc-api.zego.im/?Action=StartMix&AppId=$appId&SignatureNonce=$signatureNonce&Timestamp=$timeStamp&Signature=$sig&SignatureVersion=2.0&IsTest=false";

$body = [
    "TaskId"   => "123",
    "Sequence" => 123,
    "UserId"   => "123",
    "MixInput" => [
        [
            "StreamId" => "stream1",
            "RectInfo" => [
            "Top"    => 70,
                "Bottom" => 160,
                "Left"   => 100,
                "Right"  => 260,
            ],
        ],
        [
            "StreamId" => "stream2",
            "RectInfo" => [
            "Top"    => 200,
                "Bottom" => 290,
                "Left"   => 100,
                "Right"  => 260,
            ],
        ]
    ],
    "MixOutput" => [
        [
            "StreamId" => "stream3",
            "Width"    => 360,
            "Height"   => 360,
            "VideoBitrate" => 12000,
            "Fps"      => 15
        ]
    ]
];

$post_string = json_encode($body);

$ch = curl_init();

curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json; charset=utf-8',
    )
);
$response = curl_exec($ch);
curl_close($ch);

echo "Url:" . $url;
echo "\r\n";
echo "request body:" . $post_string;
echo "\r\n";
echo "response:" . $response;
StartMix(Node.js)
const crypto = require('crypto');
const request = require('request');

var appId = ;
var serverSecret = ;

//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
function GenerateSignature(appId, signatureNonce, serverSecret, timeStamp) {
    const hash = crypto.createHash('md5'); 
    var str = appId + signatureNonce + serverSecret + timeStamp;
    hash.update(str);
    return hash.digest('hex');
}

var signatureNonce = crypto.randomBytes(8).toString('hex');
var timeStamp = Math.round(Date.now() / 1000);
var sig = GenerateSignature(appId, signatureNonce, serverSecret, timeStamp)

var url = `https://rtc-api.zego.im/?Action=StartMix&AppId=${appId}&SignatureNonce=${signatureNonce}&Timestamp=${timeStamp}&Signature=${sig}&SignatureVersion=2.0&IsTest=false`
var body = {
    'TaskId': '123',
    'Sequence': 123,
    'UserId': '123',
    'MixInput': [
    {    
        'StreamId': 'stream1',
        'RectInfo': {
            "Top": 70,
            "Bottom": 160,
            "Left": 100,
            "Right": 260,
        },
    }, 
    {
        'StreamId': 'stream2',
        'RectInfo': {
            "Top": 200,
            "Bottom": 290,
            "Left": 100,
            "Right": 260,
        },
    }
    ],
    'MixOutput': [{
        'StreamId': 'stream3',
        'Width': 360,
        'Height': 360,
        'VideoBitrate': 12000,
        'Fps': 15
    }]
}

request({
    url: url,
    method: 'POST',
    json: true,
    headers: {
        'content-type': 'application/json'
    },
    body: body
}, function (error, response, body) {
    console.log(error)
    console.log(response.statusCode)
    if (!error && response.statusCode === 200) {
        console.log(body.Data)
    }
})

4 Request method and endpoint

  • Request method: POST/JSON
  • Request endpoint: https://rtc-api.zego.im/?Action=StartMix
  • Protocol: HTTPS
  • Rate limit: 100 requests/second

5 Request parameters

Listed below are the parameters specific to this request and part of the public request parameters. For the complete list of public request parameters, see Server APIs public request parameters.

Only some parameters in this API support dynamic updates after the stream mixing starts. For details, refer to the description in the following table.

For all the request parameters below, parameters with the type "String" only support numbers, English characters, and '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', ''。

Name Type Required Description
TaskId
String
Yes
Task ID, the unique identifier of a stream mixing task, which can be used to update a stream mixing task or determine whether a stream mixing task is newly added.
UserId
String
Yes
User ID. The user ID of the operations on the same stream mixing task must be consistent. The user ID can be used as an identifier of the task owner, which means only the user with this user ID can update or stop the task. To use this feature, contact ZEGO technical support to enable it first.
MixInput
Array of Object
Yes
Input streams. By default, a stream mixing task can have up to 9 input streams. If you need to have more input streams, contact ZEGO Technical Support for assistance.
└ StreamId
String
Yes
Stream ID of the input stream. If an input stream has a stream ID, it comes from the ZEGO RTC service.
└ StreamUrl
String
Yes
URL of the input stream, which must be an RTMP or HTTP-FLV URL. You can use either StreamID or StreamUrl to specify an input stream. If StreamUrl is specified, StreamId doesn't take effect.
└ RectInfo
Object
Yes
Position information of the input stream.
  └ Layer
Int
No
Picture layer level. 0 represents the lowest level. The higher the value, the higher the level.

This parameter supports dynamic updates after the stream mixing starts.

  └ Top
Int
No
Position of this input stream's top border. Pixel distance from the top border of the output stream's canvas.

This parameter supports dynamic updates after the stream mixing starts.

  └ Left
Int
No
Position of this input stream's left border. Pixel distance from the left border of the output stream's canvas.

This parameter supports dynamic updates after the stream mixing starts.

  └ Bottom
Int
No
Position of this input stream's bottom border. Pixel distance from the bottom border of the output stream's canvas.

This parameter supports dynamic updates after the stream mixing starts.

  └ Right
Int
No
Position of this input stream's right border. Pixel distance from the right border of the output stream's canvas.

This parameter supports dynamic updates after the stream mixing starts.

  └ CornerRadius
Int
No
Video corner radius. This parameter supports dynamic updates after the stream mixing starts.The effect is shown below:
└ Image
Object
No
Set an image for this input stream to overlay the video content; when using an image, the video content will not be displayed.

The configured image will reuse the position information set by RectInfo.

  └ Url
String
No
Image path, supports JPG and PNG formats. Supports the following 2 usage modes:

  • URI: Provide the image to ZEGO technical support for configuration. After configuration, an image URI will be provided, for example: preset-id://xxx.jpg.
  • URL: Supports HTTP/HTTPS protocols, the image size should be limited to within 1MB.

If this parameter is empty, video content will be displayed.This parameter supports dynamic updates after the stream mixing starts.

  └ DisplayMode
Int
No
Image display mode.

  • 0: Default value. When the URL is not empty, the image will overlay the video content and be displayed.
  • 1: Determine whether to display the image based on the camera status:

    • Camera is turned off, display the image.
    • Camera is turned on, display the video content (no need to manually clear the URL parameter).
└ ContentControl
Int
No
Content control.
  • 0: Use both audio and video (by default)
  • 2: Use video only.

    This parameter supports dynamic updates after the stream mixing starts.

└ SoundLevelId
Int
Yes
ID of the input stream's sound level data.
MixOutput
Array of Object
Yes
Output streams. A stream mixing task can have up to 3 mixing outputs.
└ StreamId
String
Yes
Stream ID of the output stream. By default, the mixed streams are sent to ZEGO's RTC servers or ZEGO's low-latency live streaming servers. You can also contact ZEGO Technical Support to configure the system to send the outputs to the CDNs supported by ZEGO, which will be applied to all mixing outputs in the entire scope of your AppID. If you want to specify the CDN destination for individual output streams, you must specify the streamURL accordingly instead.
└ StreamUrl
String
Yes
The destination URL of the output stream, which must be an RTMP URL. Users can receive and play the mixed stream directly from this URL. You can use either StreamId or StreamUrl to specify an output stream. If StreamUrl is specified, StreamId doesn't take effect.
└ VideoBitrate
Int
Yes
Video bitrate (bps) of the output stream. When mixing audio-only streams, set this value to 1. You can update this value in real time while the stream mixing task is running.

This parameter supports dynamic updates after the stream mixing starts.

└ VideoEncId
Int
No
Output video encoding.

  • 0: H264, default value
  • 2:VP8
  • 3:H265

This parameter does not support dynamic updates after the stream mixing starts.

Supports different output streams to use different video encoding formats, with a maximum limit of two. When using multiple video encoding formats, please contact ZEGO technical support to enable the "mutil_encode" backend parameter first.

└ Fps
Int
Yes
Video frame rate.
└ Width
Int
Yes
Video frame Width of the output stream. This value must be in the range [0, 3000] and must be a multiple of 2. When mixing audio-only streams, set this value to 1. You can update this value in real time while the stream mixing task is running.

This parameter supports dynamic updates after the stream mixing starts.

└ Height
Int
Yes
Video frame height of the output stream. This value must be in the range [0, 3000] and must be a multiple of 2. When mixing audio-only streams, set this value to 1. You can update this value in real time while the stream mixing task is running.

This parameter supports dynamic updates after the stream mixing starts.

└ AudioCodec
Int
No
Audio coding format and sampling rate of the output stream. To modify the sampling rate, please contact ZEGO Technical Support.
  • 0: HE-AAC, sampling rate: 44100 KHz (the default value).
  • 1: AAC-LC, sampling rate: 44100 KHz.
  • 2: MP3, sampling rate: 44100 KHz.
  • 3: OPUS, sampling rate: 48000 KHz.
└ AudioBitrate
Int
NO
Audio bitrate of the output stream. The default value is 48000 bps.
└ SoundChannel
Int
No
The number of audio channels of the output stream, which takes precedence over the global parameter.
  • 1: Mono (the default value)
  • 2: Stereo
Sequence
Int
Yes
The sequence number of the stream mixing request, which is used to ensure the sequence of task operations. Requests must be sent with ascending sequence numbers.
RoomId
String
No
Room ID.
UserData
String
No
User data. On the client side, this custom-defined data is received through the callback onPlayerRecvSEI. The data length must be in the range of [1, 1000] bytes, and the recommended length is 850 bytes or less. You can update the user data in real time while the stream mixing task is running.

This parameter supports dynamic updates after the stream mixing starts.

SoundLevel
Int
No
The sound level of the mixed stream. You can update this sound level value in real time while the stream mixing task is running.
  • 1: Enabled
  • 0: Disabled (by default)

    This parameter supports dynamic updates after the stream mixing starts.

ByPass
Int
No
Switch of the single-stream passthrough feature. This switch controls whether to recode the stream according to the output settings when there is only one input stream. To use this feature, contact ZEGO technical support to enable it first.
  • 1: Enabled
  • 0: Disabled (by default)
SoundChannel
String
No
Output audio channel count, this configuration will take effect when the channel count is not specified for the output stream.

  • 1: Mono (the default value)
  • 2: Stereo
BackgroundImage
String
No
Background image of the mixed stream. You can use images in JPG and PNG formats as the background images and set up the background image using either one of these methods:
  • Using URI: Provide the image to ZEGO Technical Support for configuration. Once the configuration is done, ZEGO Technical Support will provide you with the image URI, for example: "preset-id://xxx.jpg".
  • Using URLs: with this method, only HTTP protocol is supported. By default, the number of URLs allowed is 20. If you need to change the background image, we recommend you update the image file while keeping the file name (the same URL).

    This parameter supports dynamic updates after the stream mixing starts.

BackGroundColorHex
String
No
The background color of the mix stream corresponds to the RGBA color value of 0xRRGGBBAA. Currently, setting the transparency of the background color is not supported. You can set AA in 0xRRGGBBAA to 00. For example, for the RGB color #87CEFA, the corresponding parameter value would be 0x87CEFA00.

This parameter supports dynamic updates after the stream mixing starts.

WaterMark
Object
No
Watermark configuration.
└ Image
String
No
Watermark image. You can use images in JPG and PNG formats as watermark images and set up the watermark image the same way as you do for BackgroundImage.

This parameter supports dynamic updates after the stream mixing starts.

└ RectInfo
Object
No
Position information of the watermark.

This parameter supports dynamic updates after the stream mixing starts.

  └ Top
Int
No
Position of the watermark's top border. Pixel distance from the top border of the output stream's canvas.
  └ Left
Int
No
Position of the watermark's left border. Pixel distance from the left border of the output stream's canvas.
  └ Bottom
Int
No
Position of the watermark's bottom border. Pixel distance from the bottom border of the output stream's canvas.
  └ Right
Int
No
Position of the watermark's right border. Pixel distance from the right border of the output stream's canvas.
ExPara
Array of Object
No
Extension parameters, which can be specified according to the actual situation. For regular mixing tasks, you can skip this parameter.
└ Key
String
No
The Key of the parameter (key-value pair).
└ Value
String
No
The Key of the parameter (key-value pair).
AlignmentType
Int
No
Control whether the real-time audio and video streams need to be mixed after precise alignment according to NTP (Network Time Protocol).This parameter is mainly used in KTV scenarios and will introduce a certain mixing delay. It is not recommended to set this parameter for non-KTV or similar scenarios.

  • 0:Not aligned, default value.
  • 1:Specify stream alignment.
  • 2:Force alignment for all streams.
RecvBufferLevel
Int
No
Used to control the minimum buffering time for pulling streams (unit: milliseconds), with a value range of [0, 4000]. The default minimum buffering time is 0.

6 Sample request

6.1 A sample URL request

https://rtc-api.zego.im/?Action=StartMix
&AppId=1234567890
&SignatureNonce=15215528852396
&Timestamp=1234567890
&Signature=7a2c0f11145fb760d607a07b54825013
&SignatureVersion=2.0
&IsTest=false

6.2 A sample request with all of the business parameters

{
    "TaskId": "2213699902971205739",  // N, string, Task ID, needs to be consistent for the same task
    "Sequence": 1,  // Y, int, Sequence number of the mix stream request, ensure increasing when modifying mix stream parameters
    "UserId": "123",  // Y, string, User ID
    "RoomId": "321",  // N, string, Room ID
    "UserData": "DoraTest",  // N, string, Custom user data, needs to be base64 encoded, length limit is 4000 bytes, recommended not to exceed 850 bytes; The custom user data will be transmitted as SEI information to the player, and the player can obtain this data through the onPlayerSyncRecvSEI callback; Supports real-time update during mix stream process
    "SoundLevel": 1,  // N, int, Sound level of the mix stream, 1: enabled, 0: disabled; Default value is 0; Supports real-time update during mix stream process
    "BackgroundImage": "http://47.101.46.7:8090/no_camera_icon.png",  // N, string, Background image, supports online URL
    "BackGroundColorHex": "0x87CEFA00",  // N, string, Background color
    "ByPass": 1,  // N, single stream bypass switch, whether to mix when there is only one input stream (default is not enabled), 1: enabled, 0: disabled
    "AlignmentType": 0, // Alignment type: 0 - Not aligned (default), 1 - Specify stream alignment, 2 - Force alignment for all streams
    "MixInput": [
        {
            "RectInfo": {
                "Bottom": 640,
                "Layer": 1,  // N, int, Layer level
                "Left": 0,
                "Right": 180,
                "Top": 0,
                "CornerRadius": 10  // N, int, Corner radius
                // The origin is at the top-left corner, top/bottom/left/right are defined as follows:
                //
                //   (left, top)-----------------------
                //   |                                |
                //   |                                |
                //   |                                |
                //   |                                |
                //   -------------------(right, bottom)
            },
            "SoundLevelId": 1,
            "StreamId": "stream1",
            "Image": {
                "Url": "http://47.101.46.7:8090/no_camera_icon.png",
                "DisplayMode": 0
            },
            "ContentControl": 2,  // N, int, Content control. 0: audio and video, 2: video only
            "RenderMode": 0,  // N, int, Mix input fill mode. 0: cropping mode (default), 1: stretching mode
            "Volume": 100,
            "Label": {
                "Text": "Hello",
                "Left": 10,
                "Top": 10,
                "Font": {
                    "FontType": 1,
                    "FontSize": 26,
                    "FontColor": 256,
                    "Transparency": 50
                }
            }
        },
        {
            "RectInfo": {
                "Bottom": 640,
                "Layer": 2,
                "Left": 180,
                "Right": 360,
                "Top": 0
            },
            "SoundLevelId": 2,
            "StreamId": "stream2",
            "ContentControl": 2,
            "RenderMode": 0
        }
    ],
    "WaterMark": {
        "Image": "http://47.101.46.7:8090/no_camera_icon.png",  // Y, string, Watermark image
        "RectInfo": {  // Watermark position information; Required
            "Top": 0,  // Required
            "Left": 0,  // Required
            "Bottom": 200,  // Required
            "Right": 150  // Required
        }
    },
    "MixOutput": [  // Output stream list; Required
        {
            "StreamId": "stream3",  // Y, input stream address, either StreamId or StreamUrl is required. If both StreamId and StreamUrl are provided, StreamUrl takes effect.
            //"StreamUrl": "rtmp://ip/appname/streamid", either StreamId or StreamUrl is required. If both StreamId and StreamUrl are provided, StreamUrl takes effect.
            "VideoBitrate": 1200000,  // Y, int, video bitrate (unit: bps). Recommended to fill in 0 for pure audio mix stream; Supports real-time update during mix stream process
            "Fps": 15,  // Y, int, video frame rate
            "Width": 360,  // Y, int, width, range [0-3000]. The value must be a multiple of 2. Recommended to fill in 0 for pure audio mix stream.
            "Height": 640,  // Y, int, height, range [0-3000]. The value must be a multiple of 2. Recommended to fill in 0 for pure audio mix stream.
            "AudioCodec": 0,  // N, int, audio codec. 0: HE-AAC, 1: AAC-LC, 2: MP3; Default is 0.
            "AudioBitrate": 48000,  // N, int, mixed output audio bitrate. Default is 48000, in bps.
            "SoundChannel": 2,  // N, int, number of sound channels. 1: mono, 2: stereo.
            "VideoEncId": 0  // N, int, video encoding. 0: H264, 2: VP8, 3: H265
        }
    ],
    //"ExPara",  // N, extended parameters (in json struct format). Please contact technical support for details, such as video_encode/sei_mode. See data example for reference.
    "ExPara": [
        {
            "Key": "video_encode",
            "Value": "h264"
        },
        {
            "Key": "sei_mode",
            "Value": "1"
        },
        {
            "Key": "mixowner_userid",
            "Value": "[\"456\"]"
        }
    ],
    "RecvBufferLevel": 0  // N, int, minimum buffering time for pulling streams (unit: milliseconds). Default is 0.
}

7 Response parameters

Parameter Type Description
Code
Number
Return code.
Message
String
Description of the request execution result.
RequestId
String
Request ID.
Data
Array of Object
Returned data.
└ UserId
String
User ID.
└ Sequence
Int
Serial number.
└ RoomId
String
Room ID.
└ PlayInfo
Array of Object
Playback information of the mixed stream.
  └ StreamId
String
Stream ID.
  └ RTMP
String
The CDN URL for playback using the RTMP protocol (if the output destination is configured as a CDN URL for RTMP streaming).
  └ HLS
String
The CDN URL for playback using the HLS protocol (if the output destination is configured as a CDN URL for HLS streaming).
  └ FLV
String
The CDN URL for playback using the HTTP-FLV protocol (if the output destination is configured as a CDN URL for HTTP-FLV streaming).

8 Sample response

{
    "Code": 0, 
    "Data": {
        "PlayInfo": [
            {
                "FLV": "http://domain/appname/test.flv", 
                "HLS": "http://domain/appname/test/playlist.m3u8", 
                "RTMP": "rtmp://domain/appname/test", 
                "Status": 0, 
                "StreamId": "test", 
                "UserName": ""
            }
        ], 
        "RoomId": "321", 
        "Sequence": 1, 
        "UserId": "123"
    }, 
    "Message": "success", 
    "RequestId": "8472822294336370476"
}

9 Return codes

Listed below are the return codes related to this API. For the complete list of return codes, see Return codes.

Return code Description
110200001 Failed.
110200002 Input error.
110200003 Authentication failed.
110200004 Failed to parse the input parameter.
110200005 Failed to obtain distributed locks when starting the stream mixing.
110200006 Failed to obtain distributed locks when stoping the stream mixing.
110200007 Failed to update the stream mixing request.
110200008 Failed to transfer protocol when stream mixing started.
110200009 Failed to forward the request to start stream mixing.
110200010 Callback on stream mixing started failed.
110200011 Failed to bypass data when starting stream mixing.
110200012 Failed to close the other stream mixing tasks of the task owner.
110200013 Failed to bind the ownership between the user and the stream mixing task.
110200014 Failed to transfer protocol when stream mixing ended.
110200015 Failed to forward the request to stop stream mixing.
110200016 Callback on stream mixing ended failed.
110200017 Failed to clean the stream mixing status info.
110200103 SEQ error.
110200150 Input stream of the stream mixing task does not exist.
110200151 Stream mixing failed.
110200152 Failed to stop stream mixing.
110200153 Input stream error.
110200154 Output stream error.
110200155 Input stream format error.
110200156 Output stream format error.
110200157 Permission of stream mixing is not enabled.
110200158 The number of input streams has exceeded the limit.
110200159 Failed to dispatch stream mixing.
110200160 The stream mixing is stopped by a non-owner user of the stream mixing task.
110200170 Watermark parameter error.
110200171 Watermark parameter is empty.
110200172 Extended parameter error.
110200173 The number of background images has exceeded the limit.
110200174 The number of watermarks has exceeded the limit.
110200175 Input stream repeated.
110200176 Output stream repeated.
110200177 The number of focused audio streams has exceeded the limit.
110200178 The number of output streams has exceeded the limit.
110200180 The token for starting stream mixing is empty.
110200181 The token for starting stream mixing is invalid.
110200182 The token for stoping stream mixing is empty.
110200183 The token for stoping stream mixing is invalid.
110200184 Failed to parse parameters when starting stream mixing.
110200185 Failed to parse parameters when stoping stream mixing.
110200190 Request to start stream mixing overload.
110200191 Request to stop stream mixing overload.
110200192 Request to search stream mixing tasks overload.
110200193 Request to search stream mixing task overload.
110200194 Stream mixing request overload.
110240002 Token is invalid.
110240003 AppId is empty.
110240004 AppId is incorrect.
110200901 The parameter of the LiveRoom stream mixing command is empty.
110200902 The parameter of the LiveRoom stream mixing command does not exist.
110208000 Error occurred while forwarding the mixed stream.
110208001 Decoding error occurred while forwarding the mixed stream.
110208002 The address for forwarding the mixed stream is not configured.
110208003 Request to forward the mixed stream overload.
110208004 Error occurred while forwarding mixed stream.

10 FAQ

  1. When pushing pure audio mix stream and setting a background image, if the background image cannot be displayed correctly, how to handle it?

    In this case, the customer needs to correctly set the width and height of the output layout according to their business needs, and contact ZEGO technical support to configure and enable black frame filling.

Page Directory