Quick Start
Introduction
ZEGO cloud communication products (real-time audio and video, real-time voice, etc.) provide multiple server-side API interfaces that support developers in sending requests to ZEGO servers to implement a series of backend services such as room signaling, media services, and audio/video stream mixing. Developers can call server-side APIs using GET or POST methods by initiating HTTPS network requests to interact with ZEGO servers.
This article uses "How to call a server-side API interface" as an example to help developers quickly understand the usage of various server-side API interfaces.
Prerequisites
Before calling server-side API interfaces, make sure that:
- You have created a project in the ZEGOCLOUD Console and applied for a valid AppId and ServerSecret. For details, please refer to "Project Information" in Console - Project Management.
- You have prepared a development environment for debugging server-side API interfaces
- You have prepared your own client and set up relevant business scenarios. For example, before calling the server-side API interface Start Mix, developers need to initiate audio/video publishing and playing in the Room through their own client.
GET Request Example Code
ZEGO provides sample code in multiple programming languages for developers to reference. Taking the Describe User Number interface as an example to send a GET request to the ZEGO server:
package main
import (
"crypto/md5"
"crypto/rand"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
)
//Please modify AppId to your AppId, AppId is uint32
//Example: 1234567890
var appId uint32 = 1234567890
//Please modify serverSecret to your serverSecret, serverSecret is string
//Example: "abcde1234aaaaaaaabbbbbbb"
var serverSecret =
func main() {
queryParams := url.Values{}
roomId := "room1"
queryParams.Add("RoomId[]", roomId)
timestamp := time.Now().Unix()
// Generate 16-digit hexadecimal random string (16 bits)
nonce := make([]byte, 8)
rand.Read(nonce)
hexNonce := hex.EncodeToString(nonce)
// Generate signature
signature := generateSignature(appId, serverSecret, hexNonce, timestamp)
authParams := url.Values{}
authParams.Set("AppId", fmt.Sprintf("%d", appId))
// The random number in public parameters must be consistent with the random number used to generate the signature
authParams.Set("SignatureNonce", hexNonce)
authParams.Set("SignatureVersion", "2.0")
// The timestamp in public parameters must be consistent with the timestamp used to generate the signature
authParams.Set("Timestamp", fmt.Sprintf("%d", timestamp))
authParams.Set("Signature", signature)
// rtc-api.zego.im indicates that the product used is the cloud communication product, including real-time audio and video (Express Video), real-time audio (Express Audio), and low-latency live (L3)
// The following example calls the "DescribeUserNum" API to get the number of users in the Room with RoomId room1
addr := fmt.Sprintf("https://rtc-api.zego.im?Action=DescribeUserNum&%s&%s", authParams.Encode(), queryParams.Encode())
rsp, err := http.Get(addr)
if err != nil {
fmt.Printf("http.Get err:%+v", err)
return
}
defer rsp.Body.Close()
body, err := ioutil.ReadAll(rsp.Body)
if err != nil {
fmt.Printf("ioutil.ReadAll err:%+v", err)
return
}
fmt.Printf("body:%+v", string(body))
}
// Generate signature
// Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
func generateSignature(appId uint32, serverSecret, signatureNonce string, timeStamp int64) string {
data := fmt.Sprintf("%d%s%s%d", appId, signatureNonce, serverSecret, timeStamp)
h := md5.New()
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}# -*- coding: UTF-8 -*-
import hashlib
import secrets
import time
from urllib.parse import urlencode
import requests
# Generate signature
# Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
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__':
# Please modify appId to your AppId, AppId is a number
# Example: 1234567890
appId = 1234567890
# Please modify serverSecret to your serverSecret, serverSecret is string
# Example: "abcde1234aaaaaaaabbbbbbb"
serverSecret =
# Generate random number
signatureNonce = secrets.token_hex(8)
timestamp = int(time.time())
# Generate signature
sig = GenerateSignature(appId, signatureNonce, serverSecret, timestamp)
# The following example calls the "DescribeUserNum" API to get the number of users in the Room with RoomId room1
par = {
"Action": "DescribeUserNum",
"AppId": appId,
"Signature": sig,
"SignatureNonce": signatureNonce, # The timestamp in public parameters must be consistent with the timestamp used to generate the signature
"SignatureVersion": "2.0",
"Timestamp": timestamp, # The timestamp in public parameters must be consistent with the timestamp used to generate the signature
"RoomId[]": "room1"
}
url = 'https://rtc-api.zego.im/'
req = requests.get(url, params=par)
print("Url: ", req.url)
print("StatusCode: ", req.status_code)
print("Respone: ", req.text)package org.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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;
public class DescribeUserNum {
public static void main(String[] args) {
// Get the number of users in the Room
describeUserNum();
}
/**
* Test getting the number of users in the Room
*/
public static void describeUserNum() {
// Please fill in the Room ID you want to count
String roomId = "room1";
// Please fill in the APP ID you obtained from the console,
// Example: 1234567890L, APP_ID is of Long type
Long APP_ID = 1234567890L;
// Please fill in the SERVER SECRET you obtained from the console,
// Example: "abcde1234aaaaaaaabbbbbbb"
String SERVER_SECRET = ;
// Generate 16-digit hexadecimal random string (16 bits)
byte[] bytes = new byte[8];
SecureRandom sr = new SecureRandom();
sr.nextBytes(bytes);
String signatureNonce = bytesToHex(bytes);
// Set timestamp
long timestamp = System.currentTimeMillis() / 1000L;
// Generate signature Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
String signatue = generateSignature(APP_ID, signatureNonce, SERVER_SECRET, timestamp);
// Assemble request URL
Map<String, Object> params = new HashMap<String, Object>();
params.put("Action", "DescribeUserNum");
params.put("RoomId[]", roomId);
params.put("AppId", APP_ID);
// The random number in public parameters must be consistent with the random number used to generate the signature
params.put("SignatureNonce", signatureNonce);
// The timestamp in public parameters must be consistent with the timestamp used to generate the signature
params.put("Timestamp", timestamp);
params.put("Signature", signatue);
params.put("SignatureVersion", "2.0");
String url = buildAPIUrl("https://rtc-api.zego.im/", params);
String result = sendGet(url);
System.out.println(result);
}
/**
* Generate signature
* @param appId Application AppId
* @param signatureNonce Signature random code
* @param serverSecret Server-side API key
* @param timestamp Signature timestamp
* @return Generated signature string
*/
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{
//Create an object that provides the message digest algorithm, initialized as an md5 algorithm object
MessageDigest md = MessageDigest.getInstance("MD5");
//Calculate to get byte array
byte[] bytes = md.digest(str.getBytes("utf-8"));
//Convert each byte of the array to hexadecimal and concatenate into md5 string
signature = bytesToHex(bytes);
}catch (Exception e) {
e.printStackTrace();
}
return signature;
}
/**
* Convert byte array to hexadecimal
* @param bytes The byte array to be converted
* @return Converted Hex string
*/
public static String bytesToHex(byte[] bytes) {
StringBuffer md5str = new StringBuffer();
//Convert each byte of the array to hexadecimal and concatenate into md5 string
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();
}
/**
* Send HTTP-GET request
* @param httpurl Request path
* @return Response content
*/
public static String sendGet(String httpurl) {
HttpURLConnection connection = null;
InputStream is = null;
BufferedReader br = null;
String result = null;// Return result string
try {
// Create remote URL connection object
URL url = new URL(httpurl);
// Open a connection through the remote URL connection object and cast it to HttpURLConnection class
connection = (HttpURLConnection) url.openConnection();
// Set connection method: get
connection.setRequestMethod("GET");
// Set connection timeout to host server: 15000 milliseconds
connection.setConnectTimeout(15000);
// Set timeout for reading remote return data: 60000 milliseconds
connection.setReadTimeout(60000);
// Send request
connection.connect();
// Get input stream through connection connection
if (connection.getResponseCode() == 200) {
is = connection.getInputStream();
// Encapsulate input stream is and specify character set
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
// Store data
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 {
// Close resources
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
connection.disconnect();// Close remote connection
}
return result;
}
/**
* Assemble API address string
* @param url API address
* @param params Request parameters
* @return Assembled API address string
*/
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;
}
}
}<?php
/**
* Simplest example code to get the number of users in room room1
*/
//Please modify appId to your AppId
//Example: 1234567890
$appId = 1234567890;
//Please modify serverSecret to your serverSecret, serverSecret is a string
//Example: "1234567890bbc111111da999ef05f0ee"
$serverSecret = ;
//Generate signature
//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
function GenerateSignature($appId, $signatureNonce, $serverSecret, $timeStamp){
$str = $appId . $signatureNonce . $serverSecret . $timeStamp;
//Use the standard MD5 algorithm in PHP, which returns a 32-character hexadecimal number by default
return md5($str);
}
//Get random string and convert to hexadecimal value
$signatureNonce = bin2hex(random_bytes(8));
//Get millisecond-level timestamp
list($msec, $sec) = explode(' ', microtime());
$msecTime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
//Round $msecTime to get the second-level timestamp
$timeStamp = round($msecTime/1000);
// Generate signature
// The Timestamp used when generating the signature must be consistent with the Timestamp in the url parameter, and the SignatureNonce used when generating the signature must also be consistent with the SignatureNonce in the url parameter
$sig = GenerateSignature($appId, $signatureNonce, $serverSecret, $timeStamp);
//The following example calls the "DescribeUserNum" API to get the number of users in the Room with RoomID room1
$url = "https://rtc-api.zego.im/?Action=DescribeUserNum&RoomId[]=room1&AppId=$appId&SignatureNonce=$signatureNonce&Timestamp=$timeStamp&Signature=$sig&SignatureVersion=2.0&IsTest=false";
//Use curl library
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//Set request connection timeout, unit: seconds
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
$response = curl_exec($ch);
curl_close($ch);
//Requested url
echo "Url: " . $url ."\r\n";
//Returned result
echo "response:" . $response;const crypto = require('crypto');
const request = require('request');
//Please modify appId to your AppId, AppId is number
var appId = 1234567890;
//Please modify serverSecret to your serverSecret, serverSecret is string
//Example: "1234567890bbc111111da999ef05f0ee"
var serverSecret = ;
//Generate signature
//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
function GenerateUASignature(appId, signatureNonce, serverSecret, timeStamp){
const hash = crypto.createHash('md5'); //Specify using MD5 algorithm in hash algorithm
var str = appId + signatureNonce + serverSecret + timeStamp;
hash.update(str);
//hash.digest('hex') indicates the output format is hexadecimal
return hash.digest('hex');
}
var signatureNonce = crypto.randomBytes(8).toString('hex');
var timeStamp = Math.round(Date.now()/1000);
// Generate signature
// The Timestamp used when generating the signature must be consistent with the Timestamp in the url parameter, and the SignatureNonce used when generating the signature must also be consistent with the SignatureNonce in the url parameter
var sig = GenerateUASignature(appId, signatureNonce, serverSecret, timeStamp)
// rtc-api.zego.im indicates that the product used is the cloud communication product, including real-time audio and video (Express Video), real-time audio (Express Audio), and low-latency live (L3)
//The following example can get the number of users in the Room with RoomID room1
var url = `https://rtc-api.zego.im/?Action=DescribeUserNum&RoomId[]=room1&AppId=${appId}&SignatureNonce=${signatureNonce}&Timestamp=${timeStamp}&Signature=${sig}&SignatureVersion=2.0&IsTest=false`;
request(url, function(error, response, body){
console.log('Url: ',url)
console.log('StatusCode: ',response.statusCode)
console.log('Error: ', error)
if(!error && response.statusCode){
console.log(body)
}
})POST Request Example Code
ZEGO provides sample code in multiple programming languages for developers to reference. We take Start Mix as an example to send a POST request to the ZEGO server.
package main
import (
"bytes"
"crypto/md5"
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"time"
)
// rtc-api.zego.im indicates that the product used is the cloud communication product, including real-time audio and video (Express Video), real-time audio (Express Audio), and low-latency live (L3)
const DOMAIN = "https://rtc-api.zego.im"
var (
//Please modify AppId to your AppId, AppId is uint32
//Example: 1234567890
AppId uint32 = 1234567890
//Please modify serverSecret to your serverSecret, serverSecret is string
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
}
//The following example mixes the audio and video stream with streamId "stream1" with the audio and video stream with streamId "stream2" to output the audio and video stream with streamId "stream3"
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
}
//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
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() //Specify using MD5 algorithm in hash algorithm
h.Write([]byte(data))
//hex.EncodeToString(h.Sum(nil)) outputs hexadecimal string
return hex.EncodeToString(h.Sum(nil))
}# -*- coding: UTF-8 -*-
import hashlib
import secrets
import time
# Generate signature
# 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__':
# Please modify appId to your AppId, AppId is a number
# Example: 1234567890
appId = 1234567890
# Please modify serverSecret to your serverSecret, serverSecret is string
serverSecret = ""
signatureNonce = secrets.token_hex(8)
timestamp = int(time.time())
sig = GenerateSignature(appId, signatureNonce, serverSecret, timestamp)
# The following example mixes the audio and video stream with streamId "stream1" with the audio and video stream with streamId "stream2" to output the audio and video stream with streamId "stream3"
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)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;
/**
* Please first import com.alibaba.fastjson to facilitate building request body parameters
*/
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
public class StartMix {
//
public static void main(String[] args) {
// Start stream mixing
startMixStream();
}
/**
* Start stream mixing
*/
public static void startMixStream() {
// Please fill in the APP ID you obtained from the console,
// Example: 1234567890L
Long APP_ID = 1234567890L;
// Please fill in the SERVER SECRET you obtained from the console,
// Example: "abcde1234aaaaaaaabbbbbbb"
String SERVER_SECRET = ;
// Generate 16-digit hexadecimal random string (16 bits)
byte[] bytes = new byte[8];
SecureRandom sr = new SecureRandom();
sr.nextBytes(bytes);
String signatureNonce = bytesToHex(bytes);
// Set timestamp
long timestamp = System.currentTimeMillis() / 1000L;
// Generate signature Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
String signatue = generateSignature(APP_ID, signatureNonce, SERVER_SECRET, timestamp);
// Assemble request URL
//The following example mixes the audio and video stream with streamId "stream1" with the audio and video stream with streamId "stream2" to output the audio and video stream with streamId "stream3"
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");
// rtc-api.zego.im 表示使用的产品是云通讯产品,包括了实时音视频(Express Video)、实时音频(Express Audio)、低延迟直播(L3)
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);
}
/**
* Generate signature
* @param appId Application AppId
* @param signatureNonce Signature random code
* @param serverSecret Server-side API key
* @param timestamp Signature timestamp
* @return Generated signature string
*/
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{
//Create an object that provides the message digest algorithm, initialized as an md5 algorithm object
MessageDigest md = MessageDigest.getInstance("MD5");
//Calculate to get byte array
byte[] bytes = md.digest(str.getBytes("utf-8"));
//Convert each byte of the array to hexadecimal and concatenate into md5 string
signature = bytesToHex(bytes);
}catch (Exception e) {
e.printStackTrace();
}
return signature;
}
/**
* Convert byte array to hexadecimal
* @param bytes The byte array to be converted
* @return Converted Hex string
*/
public static String bytesToHex(byte[] bytes) {
StringBuffer md5str = new StringBuffer();
//Convert each byte of the array to hexadecimal and concatenate into md5 string
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();
}
/**
* Send HTTP-GET request
* @param httpurl Request path
* @return Response content
*/
public static String sendGet(String httpurl) {
HttpURLConnection connection = null;
InputStream is = null;
BufferedReader br = null;
String result = null;// Return result string
try {
// Create remote URL connection object
URL url = new URL(httpurl);
// Open a connection through the remote URL connection object and cast it to HttpURLConnection class
connection = (HttpURLConnection) url.openConnection();
// Set connection method: get
connection.setRequestMethod("GET");
// Set connection timeout to host server: 15000 milliseconds
connection.setConnectTimeout(15000);
// Set timeout for reading remote return data: 60000 milliseconds
connection.setReadTimeout(60000);
// Send request
connection.connect();
// Get input stream through connection connection
if (connection.getResponseCode() == 200) {
is = connection.getInputStream();
// Encapsulate input stream is and specify character set
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
// Store data
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 {
// Close resources
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
connection.disconnect();// Close remote connection
}
return result;
}
/**
* Send HTTP-POST request
* @param param Message body parameter
* @return Response content
*/
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);
// Open connection through remote URL connection object
connection = (HttpURLConnection) url.openConnection();
// Set connection request method
connection.setRequestMethod("POST");
// Set connection timeout to host server: 15000 milliseconds
connection.setConnectTimeout(15000);
// Set timeout for reading host server return data: 60000 milliseconds
connection.setReadTimeout(60000);
// Default value: false, must be set to true when transmitting/writing data to remote server
connection.setDoOutput(true);
// Default value: true, set to true when reading data from remote service, this parameter is optional
connection.setDoInput(true);
// Set the format of incoming parameters: request parameters should be in the form of name1=value1&name2=value2
connection.setRequestProperty("Content-Type", "application/json");
// Establish connection
connection.connect();
// Get an output stream object through the connection object
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(),"UTF-8");
writer.write(param);
writer.flush();
// Get an input stream through the connection object to read remotely
if (connection.getResponseCode() == 200) {
is = connection.getInputStream();
// Wrap the input stream object: charset is set according to the requirements of the project team
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuffer sbf = new StringBuffer();
String temp = null;
// Loop to read data line by line
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 {
// Close resources
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();
}
}
// Disconnect from remote URL
connection.disconnect();
}
return result;
}
/**
* Assemble API address string
* @param url API address
* @param params Request parameters
* @return Assembled API address string
*/
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;
}
}
}<?php
/**
* Simplest example code to initiate stream mixing
*/
//Please modify appId to your AppId
//Example: 1234567890
$appId = 1234567890;
//Please modify serverSecret to your serverSecret, serverSecret is string
$serverSecret = "";
//Generate signature
//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
function GenerateSignature($appId, $signatureNonce, $serverSecret, $timeStamp){
$str = $appId . $signatureNonce . $serverSecret . $timeStamp;
//Use the standard MD5 algorithm in PHP, which returns a 32-character hexadecimal number by default
return md5($str);
}
//Get random string and convert to hexadecimal value
$signatureNonce = bin2hex(random_bytes(8));
//Get millisecond-level timestamp
list($msec, $sec) = explode(' ', microtime());
$msecTime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
//Round $msecTime to get the second-level timestamp
$timeStamp = round($msecTime/1000);
$sig = GenerateSignature($appId, $signatureNonce, $serverSecret, $timeStamp);
//The following example mixes the audio and video stream with streamId "stream1" with the audio and video stream with streamId "stream2" to output the audio and video stream with streamId "stream3"
$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);
//Set request connection timeout, unit: seconds
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;const crypto = require('crypto');
const request = require('request');
//Please modify appId to your AppId, AppId is number
var appId = ;
//Please modify serverSecret to your serverSecret, serverSecret is string
var serverSecret = "";
//Signature=md5(AppId + SignatureNonce + ServerSecret + Timestamp)
function GenerateSignature(appId, signatureNonce, serverSecret, timeStamp) {
const hash = crypto.createHash('md5'); //Specify using MD5 algorithm in hash algorithm
var str = appId + signatureNonce + serverSecret + timeStamp;
hash.update(str);
//hash.digest('hex') indicates the output format is hexadecimal
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)
//The following example mixes the audio and video stream with streamID "stream1" with the audio and video stream with streamID "stream2" to output the audio and video stream with streamID "stream3"
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)
}
})Usage Flow
Developers can quickly initiate requests to ZEGO servers through the following process:
- The developer's server first confirms the URL address of the request;
- Obtain signature information according to the signature generation rules;
- The developer's server configures common request parameters;
- Configure API-related business parameters;
- The developer's server accesses the ZEGO server through the URL address, carrying request information (including business parameters, signature information, etc.);
- ZEGO server returns response information.
We take the API interface Describe User List as an example to send a GET request to the ZEGO server and introduce the usage flow in detail.
Confirm URL Address
ZEGO server distinguishes different requests based on different URL addresses (for specific formats, please refer to "Request Method Overview" in Calling Method). Therefore, when the developer's server accesses the ZEGO server, please first obtain the request URL address from the corresponding interface documentation.
The following is the URL address for Describe User List:
https://rtc-api.zego.im/?Action=DescribeUserListWhere:
- https: Specifies the request communication protocol.
- rtc-api.zego.im: Specifies the access address of the ZEGO server, where
rtcrepresents that the product used is the cloud communication product (including real-time audio and video, real-time voice, etc.), see Calling Method - Request Structure - Access Address for details. - Action=DescribeUserList: Specifies that the API interface to be called is
DescribeUserList.
Generate Signature Information
To ensure the secure calling of APIs, ZEGO server will authenticate each API access request. When calling APIs, developers need to include signature Signature information in the request.
Developers can refer to the sample code in various languages in Calling Method - Signature Mechanism, use the AppId and ServerSecret obtained in Prerequisites of this article to generate their own signature information.
Configure Common Request Parameters
Before calling each ZEGO server-side API, developers need to configure the common request parameters of the API first.
Common request parameters refer to the request parameters that need to be used by each interface, including AppId, Signature (referring to the 2 generated signature information), SignatureNonce (random string), Timestamp (timestamp), etc. Please modify according to the actual situation. For the specific introduction of common parameters, please refer to Calling Method - Common Parameters.
https://rtc-api.zego.im/?Action=DescribeUserList&AppId=1234567890&SignatureNonce=15215528852396&Timestamp=1234567890&Signature=Pc5WB8gokVn0xfeu%2FZV%2BiNM1dgI%3D&SignatureVersion=2.0&IsTest=falseDevelopers can enter the URL address on the Server API Verification page to verify whether the signature information, common parameters, and URL format are legal.
Configure API-Related Business Parameters
After configuring the common parameters, configure the business parameters related to the API to set the required target operation.
For the specific introduction of business parameters, please refer to Request Parameters.
Developer's Server Initiates Request
After the above configuration is completed, the developer's server can send a request to the ZEGO server through the URL address.
The request example is as follows:
//This request is to get the list of users in the Room with RoomId `room_demo`
https://rtc-api.zego.im/?Action=DescribeUserList
&RoomId=room_demo
&Mode=0
&Limit=2
&Marker=1635940599950-user2
&<Common Request Parameters>ZEGO Server Responds to Request
After receiving the developer's request information, ZEGO server returns the response information.
{
"Code": 0,
"Message": "success",
"RequestId": "TestRequestId1635940600561291000",
"Data": {
"Marker": "1635940599950-user2",
"UserList": [
{
"UserId": "user1",
"UserName": "user1"
},
{
"UserId": "user2",
"UserName": "user2"
}
]
}
}In the returned information field, if Code is "0", it means the access is successful and you can view the member list in the Room; if it is not "0", please refer to Global Return Codes for handling.
At this point, the developer's server and ZEGO server have completed an information interaction.
