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.
Before you begin to use stream mixing in your project, make sure you complete the following steps:
)
With the manual stream mixing, you can customize the stream mixing tasks. which is often used for multiple users to co-host an interactive live streaming event and co-hosting across rooms.
To implement the stream mixing with SDK or ZEGO server API, refer to the Start stream mixing and Stop stream mixing.
The following describes how to implement the manual stream mixing in detail.
To set up a stream mixing task, create a ZegoMixStreamConfig object and set up the configuration parameters accordingly.
TaskID property of the ZegoMixStreamConfig object is a custom-defined ID of the stream mixing task, which must be unique.ZegoMixStreamInput[] inputStreamInfo = {streamInfoA, streamInfoB}.According to the actual business scenario, call the ZegoMixStreamConfig with the definition of inputList to input the list of video streams. The list contains objects of ZegoMixStreamInput, representing streams with "streamID". Build N ZegoMixStreamInput objects and put them into the input stream list.
ZegoMixStreamInput[] inputStreamInfo = {streamInfoA, streamInfoB}.Example of using ZegoMixStreamInput:
The layout of the input stream is based on the coordinate system with the upper-left corner of the output mixed stream as the origin. Set the layout of the input stream based on the reference origin, which is passed as the "layout" parameter. In addition, the layer order of the input stream is determined by its position in the input stream list. The later the position, the higher the layer order.
The explanation of the "layout" parameter is as follows:
| Parameter | Description |
|---|---|
left |
The x-coordinate of the upper-left corner of the input stream frame. |
top |
The y-coordinate of the upper-left corner of the input stream frame. |
right |
The x-coordinate of the lower-right corner of the input stream frame. |
bottom |
The y-coordinate of the lower-right corner of the input stream frame. |
Assuming that the upper-left corner of a certain stream is at coordinates (50, 300) and the lower-right corner is at coordinates (200, 450), the position of this stream in the final output mixed stream is shown in the following diagram:
)
/**
* The origin is at the upper left corner, top/bottom/left/right is defined as follows:
*
* (left, top)-----------------------
* | |
* | |
* | |
* | |
* -------------------(right, bottom)
*/
// inputList parameter settings
const inputList = [
// Screen A
{
streamID: "streamA",
layout: {
top: 0,
left: 0,
bottom: 375,
right: 667,
},
},
// Screen B
{
streamID: "streamB",
layout: {
top: 300,
left: 50,
bottom: 450,
right: 200,
},
},
];
Developers can refer to the following sample code to implement common mixing layouts: two screens tiled horizontally, four screens tiled horizontally and vertically, one large screen filling the layout, and two small screens floating.
The following layout examples are based on a resolution of 360×640.
)
// Set inputList
const inputList = [
{
streamID: "streamA", // Left stream
layout: {
top: 0,
left: 0,
bottom: 640,
right: 180,
},
},
{
streamID: "streamB", // Right stream
layout: {
top: 0,
left: 180,
bottom: 640,
right: 360,
},
}
]
// Start mixing
const result = await zg.startMixerTask({
taskID:'taskUUID',
inputList,
// Set mixing output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
)
// Set inputList
const inputList = [
{
streamID: "streamA", // Top-left stream
layout: {
top: 0,
left: 0,
bottom: 320,
right: 180,
},
},
{
streamID: "streamC", // Bottom-left stream
layout: {
top: 320,
left: 0,
bottom: 640,
right: 180,
},
},
{
streamID: "streamB", // Top-right stream
layout: {
top: 0,
left: 180,
bottom: 320,
right: 360,
},
},
{
streamID: "streamD", // Bottom-right stream
layout: {
top: 320,
left: 180,
bottom: 640,
right: 360,
},
}
]
// Start mixing
const result = await zg.startMixerTask({
taskID:'taskUUID',
inputList,
// Set mixing output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
)
The layer order of the input streams is determined by their position in the inputList. The higher the position in the list, the higher the layer order. In the example code below, the layer order of the second input stream and the third input stream is higher than the first input stream, so the second and third streams float above the first stream's screen.
// Set inputList
const inputList = [
{
streamID: "streamA", // First stream
layout: {
top: 0,
left: 0,
bottom: 640,
right: 320,
},
},
{
streamID: "streamB", // Second stream
layout: {
top:200,
left:230,
bottom:400,
right: 340,
},
},
{
streamID: "streamC", // Third stream
layout: {
top:420,
left:230,
bottom:620,
right: 340,
},
}
]
// Start mixing
const result = await zg.startMixerTask({
taskID:'taskUUID',
inputList,
// Set mixing output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
The target property of the outputList parameter can be a stream ID or a URL. If the mixed stream needs to be published to CDN, you must use a URL as the output target. Otherwise, it is up to you to use a URL or a stream ID.
The "outputConfig" parameter can be used to set the resolution, frame rate, bit rate, audio encoding, and other settings for the output stream.
const result = await zg.startMixerTask({
taskID:'taskUUID',
inputList,
// Set the mixed stream output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
If you need the URL of the watermark image, please contact ZEGOCLOUD technical support to obtain it.
The following code demonstrates setting a ZEGOCLOUD image watermark placed in the top left corner of the screen:
// Set the watermark image
const watermark = [
{
imageURL: "preset-id://zegowp.png",
layout: {
top: 0,
left: 0,
bottom: 100,
right: 200,
},
}
]
// Start mixing
const result = await zg.startMixerTask({
taskID:'taskUUID',
inputList,
watermark,
// Set the mixed stream output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
If you need the URL of the background image ZegoMixerImageInfo, please contact ZEGOCLOUD technical support to obtain it, or you can use a network image, but only HTTP protocol is supported.
// Set inputList
const inputList = [
{
streamID: "streamA", // Left stream
layout: {
top: 0,
left: 0,
bottom: 640,
right: 180,
},
// Set mixed stream background image
imageInfo: {
url: "preset-id://zegobg.png",
displayMode: 1, // Display the background image only when the camera is turned off. You can check the interface documentation for specific parameter values.
}
}
]
// Start mixing stream
const result = await zg.startMixerTask({
taskID:'taskUUID',
inputList,
// Set mixed stream output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
In video scenarios, it is not recommended to turn on the sound wave switch, otherwise the web pulling HLS protocol stream may have compatibility issues.
You can choose whether to enable the sound level callback of the mixed stream by setting the enableSoundLevel parameter. After enabling it (set to "True"), when the user pulls the mixed stream, they can receive the volume change (sound level) information of each individual stream through the mixerSoundLevelUpdate callback.
// Start mixing stream
const result = await zg.startMixerTask({
taskID:'taskUUID',
// Enable the sound level callback of the mixed stream. After enabling it, you can receive the sound level information of each individual stream through the [onMixerSoundLevelUpdate] callback when pulling the mixed stream.
enableSoundLevel: true,
inputList: {
streamID: "streamA", // Left stream
layout: {
top: 0,
left: 0,
bottom: 640,
right: 180,
},
soundLevelID: 1, // Mixed stream sound level ID, used to find the corresponding sound level value of the input stream in [mixerSoundLevelUpdate].
},
// Set mixed stream output
outputList:['mixStreamID'],
outputConfig: {
outputBitrate: 300,
outputFPS: 15,
outputWidth: 360,
outputHeight: 640,
}
})
After the stream publishing starts successfully, call startMixerTask to send the mixing configuration to the ZEGOCLOUD mixing server and trigger the mixing process.
const result = await zg.startMixerTask(config)
if(result.errorCode !== 0) {
// Mixing failed
console.error(result.extendedData)
}
If you want to mix pure audio data, some parameter configurations will have the following special handling:
When there are changes in the mixed stream information, such as adding or removing input stream lists for mixing, adjusting the output bitrate of the mixed video, you can modify the parameters of the mixer task object and then call startMixerTask again to update the mixing configuration on the ZEGOCLOUD mixing server.
When updating the configuration of a transcoding task, the "taskID" cannot be changed.
| Error code | Description |
|---|---|
| errorCode = 150 | Input stream does not exist. |
| errorCode = 151 | Stream mixing failed. |
| errorCode = 152 | Failed to stop stream mixing. |
| errorCode = 153 | Incorrect input parameters. |
| errorCode = 154 | Incorrect output parameters. |
| errorCode = 155 | Incorrect input resolution format. |
| errorCode = 156 | Incorrect output resolution format. |
| errorCode = 157 | Steam mixing not enabled. |
To stop a stream mixing task, call the stopMixerTask method.
try {
await zg.stopMixerTask(taskID);
alert('Stop mixing stream successfully...');
} catch (err) {
alert('Failed to stop mixing stream...');
console.log('stopMixStream err: ', err);
}
