ApsaraVideo Live supports co-streaming on the Web. A viewer can become a co-streamer to interact with the streamer on web pages, which eliminates the need to install additional applications. This topic describes how to implement co-streaming on the web and provides relevant sample code.
Overview of how to implement co-streaming
Push SDK implements co-streaming based on ApsaraVideo Real-time Communication (ARTC). This can help users start interactive streaming that engages more people at an ultra-low latency.
Before co-streaming: The streamer uses an ingest URL for ARTC-based co-streaming to ingest a stream, and the viewer pulls the stream from CDN.
During co-streaming: The viewer becomes a co-streamer. The co-streamer uses an ingest URL for ARTC-based co-streaming to ingest a stream and uses a streaming URL for ARTC-based co-streaming to pull the stream of the streamer at an ultra-low latency. The streamer uses a streaming URL for ARTC-based co-streaming to pull the stream of the co-streamer at an ultra-low latency.
After co-streaming: The co-streamer becomes an ordinary viewer. ARTC-based stream ingest and stream pulling by the viewer are stopped. The viewer pulls the stream from CDN again.
Usage notes
In co-streaming mode, the streamer and co-streamer can use only the AlivcLivePlayer object to play the stream of each other. The AlivcLivePlayer object supports only streams whose URL starts with
artc://live.aliyun.com/play/
.The following section describes how to use the co-streaming feature on the web. For more information about how to integrate the co-streaming SDK for Web, see Integrate the co-streaming SDK for Web.
ImportantAn upgrade for the co-streaming SDK for Web was launched on March 15, 2024, which allows the SDK to be compatible with the new version of Google Chrome. Users who are using the old SDK need to upgrade the SDK as soon as possible to avoid availability issues. For more information about how to integrate the latest version of the SDK, see Integrate the co-streaming SDK for Web.
Step 1: Enable the co-streaming feature
To use the co-streaming feature, you must create a co-streaming application and configure the streaming domain of viewers. For more information, see Get started with co-streaming.
Step 2: Generate ingest and streaming URLs for co-streaming
You can generate ingest and streaming URLs of the streamer and co-streamer and the CDN streaming URL of viewers by using the ApsaraVideo Live console, or construct these URLs by using the concatenation rules.
Method 1: Generate the URLs by using the console
You can use the URL generator in the ApsaraVideo Live console to generate the ingest and streaming URLs of the streamer and co-streamer and the CDN streaming URL of viewers. For more information, see Co-streaming URL generator.
Method 2: Construct the URLs
Tokens in ingest and streaming URLs of the streamer and co-streamer that are generated by using the console are temporary, and are usually used for testing. If you need ingest and streaming URLs that are used for business purposes, construct the URLs by using the concatenation rules for security reasons. Tokens in URLs that you construct by using the concatenation rules are calculated based on the SdkAppID, AppKey, room ID, UserID, and timestamp by using the SHA-256 encryption algorithm. These tokens provide higher security. For more information, see Ingest and streaming URLs of streamers and co-streamers in co-streaming scenarios and CDN streaming URLs of viewers.
Step 3: Create objects related to stream ingest
This step is required on both the streamer side and the co-streamer side.
Create an AlivcLivePusher object
Create an AlivcLivePusher object as the stream ingest instance and configure relevant callbacks.
const pusher = new window.AlivcLivePush.AlivcLivePusher();
await pusher.init({
resolution: window.AlivcLivePush.AlivcResolutionEnum.RESOLUTION_540P,
fps: window.AlivcLivePush.AlivcFpsEnum.FPS_30,
// audioOnly: true, Only for scenarios in which audio-only streams are ingested.
});
pusher.info.on('pushstatistics', _stat => {
// TODO... Process stream ingest statistics data.
// console.log(_stat);
});
pusher.error.on('system', error => {
console.log(error);
});
pusher.network.on('connectionlost', () => {
console.log('connectionlost');
});
Start stream ingest in co-streaming mode
Use an ingest URL for co-streaming to ingest a stream.
await pusher.startPreview(videoElement);
await pusher.startPush("artc://live.aliyun.com/push/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX"); // The ingest URL of the streamer or co-streamer.
Both startPreview and startPush are asynchronous methods. To ensure the order of calls, you must use the await keyword or a Promise object.
If you want to implement co-streaming between a native client on Android or iOS and the web, the HTML5 compatibility mode must be enabled on the native client. Otherwise, users on the web are seeing a black screen sent from users on the native client. To enable the HTML5 compatibility mode, call AlivcLivePushConfig#setH5CompatibleMode on the Native client. For more information, see the API reference of the native SDK.
Step 4: Create an AliPlayer object for CDN playback
This step is required on the viewer side.
To use an AliPlayer object for CDN playback, obtain the CDN streaming URL of viewers first. For more information, see Step 2: Generate ingest and streaming URLs for co-streaming.
We recommend that you use a streaming URL in the HTTP-FLV format instead of a streaming URL in the Real-Time Messaging Protocol (RTMP) format. When you use the ApsaraVideo Live console to generate URLs, URLs in the RTMP and HTTP-FLV formats are generated. A URL in the RTMP format and a URL in the HTTP-FLV format contain the same data content, but use different protocols. HTTP is the primary protocol for transmission of information across the Internet. Connections over the HTTP protocol, such as connections among Alibaba Cloud CDN, Internet service providers (ISPs), and intermediary devices, are highly optimized. The default port for the HTTP protocol is 80 and the default port for the HTTPS protocol is 443. In most cases, the ports are added to the whitelist and cannot be disabled. RTMP is an outdated protocol and uses 1935 as the default port. Port 1935 may be disabled by the firewall. This may cause errors. Compared with RTMP, HTTP-FLV is more stable and provides better performance. For example, video playback over HTTP-FLV has a lower stuttering rate and lower latency than RTMP.
const player = new window.Aliplayer(
{
id: videoId, // video element ID
source: url, // The streaming URL, which can be a third-party streaming URL or a streaming URL from ApsaraVideo Live.
isLive: true, // Specify whether the content that you want to play is a live stream.
},
function (player: any) {
console.log('The player is created.', player);
}
);
Step 5: Start co-streaming
Streamer A ingests a stream based on ARTC
Streamer A uses the AlivcLivePusher object to start stream ingest. Sample code:
await pusher.startPreview(videoElement); // You can use methods of the Document interface (such as getElementById) to obtain the videoElement object.
await pusher.startPush("artc://live.aliyun.com/push/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX"); // The ingest URL of the streamer or co-streamer.
Viewers use a CDN streaming URL to play the stream of Streamer A
All viewers use the AliPlayer object to play the stream of Streamer A. Sample code:
const player = new window.Aliplayer(
{
id: videoId, // video element ID
source: 'rtmp://test.alivecdn.com/live/streamId?auth_key=XXX', // The streaming URL, which can be a third-party streaming URL or a streaming URL from ApsaraVideo Live.
isLive: true, // Specify whether the content that you want to play is a live stream.
},
function (player: any) {
console.log('The player is created.', player);
}
);
Viewer D initiates co-streaming
Viewer D creates an AlivcLivePusher object and use an ingest URL for co-streaming to ingest a stream. In this case, Viewer D becomes a co-streamer. Sample code:
const pusher = new window.AlivcLivePush.AlivcLivePusher(); pusher.init({ resolution: window.AlivcLivePush.AlivcResolutionEnum.RESOLUTION_540P, fps: window.AlivcLivePush.AlivcFpsEnum.FPS_30, // audioOnly: true, Only for scenarios in which audio-only streams are ingested. }); pusher.info.on('pushstatistics', _stat => { // TODO... Process stream ingest statistics data. // console.log(_stat); }); pusher.error.on('system', error => { console.log(error); }); pusher.network.on('connectionlost', () => { console.log('connectionlost'); }); await pusher.startPreview(videoElement); // You can use methods of the Document interface (such as getElementById) to obtain the videoElement object. await pusher.startPush("artc://live.aliyun.com/push/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX"); // The ingest URL of the streamer or co-streamer.
Streamer A obtains the streaming URL for co-streaming of Co-streamer D, and creates an AlivcLivePlayer object to pull the stream of Co-streamer D in real time. Sample code:
const player = new window.AlivcLivePush.AlivcLivePlayer(); // Specify the streaming URL of Co-streamer D, which starts with artc://. const playInfo = await player.startPlay("artc://live.aliyun.com/play/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX", videoElement); playInfo.on('userleft', () => { // Handle the event that is triggered when Co-streamer D leaves the room. }); playInfo.on('canplay', () => { // Handle the event that is triggered when the video is available for playback. }
At the same time, Co-streamer D obtains the streaming URL for co-streaming of Streamer A, and creates an AlivcLivePlayer object to pull the stream of Streamer A in real time. Sample code:
const player = new window.AlivcLivePush.AlivcLivePlayer(); // Specify the streaming URL of Streamer A, which starts with artc://. const playInfo = await player.startPlay("artc://live.aliyun.com/play/6375?timestamp=1661596947&token=XXX&userId=7135&sdkAppId=XXX", videoElement); playInfo.on('userleft', () => { // Handle the event that is triggered when Streamer A leaves the room. }); playInfo.on('canplay', () => { // Handle the event that is triggered when the video is available for playback. }
Streamer A updates the mixed stream after co-streaming succeeds
In order to ensure that Viewer B and Viewer C (who are not co-streamers) can watch the stream of Co-streamer D, Streamer A must perform the stream mixing operation. This way, the streams of Streamer A and Co-streamer D can be mixed into a single stream, which the viewers can pull from CDN for playback.
Specifically, Streamer A calls the setLiveMixTranscodingConfig method to start a mixed-stream transcoding task and specify the streams to be mixed. Parameters such as the resolution and frame rate of the mixed stream are those that Streamer A configured in AlivcLivePushConfig when creating the AlivcLivePusher object. For example, if Streamer A set the resolution to 720p in AlivcLivePushConfig when creating the AlivcLivePusher object, the resolution of the mixed stream is 720p.
const resolution = pusher.getResolution();
const width = window.AlivcLivePush.AlivcResolution.GetResolutionWidth(resolution);
const height = window.AlivcLivePush.AlivcResolution.GetResolutionHeight(resolution);
const mixStreams = [];
const transcodingConfig = new window.AlivcLivePush.AlivcLiveTranscodingConfig();
const anchorMixStream = new window.AlivcLivePush.AlivcLiveMixStream(
userA, // Specify the user ID of Streamer A.
0,
0,
width,
height,
1
);
// Add the stream of Streamer A for mixing.
mixStreams.push(anchorMixStream);
const audienceMixStream = new window.AlivcLivePush.AlivcLiveMixStream(
userD, // Specify the user ID of Co-streamer D.
100,
200,
200,
300,
2
);
// Add the stream of Co-streamer D for mixing.
mixStreams.push(audienceMixStream);
transcodingConfig.mixStreams = mixStreams;
await pusher.setLiveMixTranscodingConfig(transcodingConfig);
Viewers can watch the mixed stream of Streamer A and Co-streamer D.
Co-streamer D ends co-streaming
To stop co-streaming, Co-streamer D must call the method used to stop stream ingest in AlivcLivePusher and then destroy AlivcLivePusher. Sample code:
await pusher.destroy(); pusher = null;
At the same time, Co-streamer D must also call the method used to stop playback in AlivcLivePlayer and then destroy AlivcLivePlayer. Sample code:
await player.destroy(); player = null;
Co-streamer D becomes an ordinary viewer, and can pull the stream from CDN. For more information, see Step 4: Create an AliPlayer object for CDN playback.
Streamer A needs to call the method used to stop playback in AlivcLivePlayer and then destroy AlivcLivePlayer. Sample code:
await player.destroy(); player = null;
At the same time, Streamer A needs to call the setLiveMixTranscodingConfig method and pass in an empty value. This way, stream mixing is stopped. Take note that whenever viewers only want to watch the stream of Streamer A, Streamer A can perform the preceding operations to stop stream mixing.
WarningIf the streamer is still in the room but does not require stream mixing, make sure that stream mixing is stopped. If stream mixing is not stopped, the stream mixing module that continues to run will incur unnecessary fees.
pusher.setLiveMixTranscodingConfig();