During the live streaming, the host can share his screen content with the viewers in the form of a video to enhance interaction and improve the live streaming experience.
This doc will introduce how to implement the screen sharing feature in the live streaming scenario.
Before you begin, make sure you complete the following:
You can achieve the following effect with the demo provided in this doc:
Screen sharing not enabled | Host is sharing the screen | What viewers see when host switches apps |
---|---|---|
![]() |
![]() |
![]() |
1. You should already have some knowledge of streams when following the integration instructions in **Quick Start doc.**
2. What is a screen-sharing stream?
In the Express SDK, screen sharing is abstracted as a stream, just like the stream for the camera and microphone. This stream transmits the visual data of the shared screen.
3. How to publish multiple streams?
In the SDK's stream publishing interface startPublishingStream, there is an additional parameter ZegoPublishChannel, which defaults to ZegoPublishChannel.MAIN
. This channel uses the device's camera and microphone as the audio and video source.
If you need to publish multiple streams, specify a ZegoPublishChannel
when calling this interface and configure the audio and video source for that channel.
Upcoming chapters will cover how to create a screen sharing source and configure it to a channel.
We recommend managing ZegoPublishChannel
as follows:
ZegoPublishChannel.MAIN
to share the host's camera and microphone (SDK configures the Main channel's audio and video sources to use the camera and microphone by default).ZegoPublishChannel.AUX
for screen sharing and manually configure its audio and video sources.ZegoPublishChannel.THIRD
and ZegoPublishChannel.FOURTH
for other audio and video sources.Regarding whether to publish multiple streams simultaneously:
The following example shows how to implement screen sharing while publishing both screen-sharing and audio/video streams simultaneously.
PublishChannel
as SCREEN_CAPTURE
.For example, to use ZegoPublishChannel.AUX
:
ZegoExpressEngine.getEngine().setVideoSource(ZegoVideoSourceType.SCREEN_CAPTURE, ZegoPublishChannel.AUX);
ZegoVideoConfig videoConfig = new ZegoVideoConfig(ZegoVideoConfigPreset.PRESET_720P);
ZegoExpressEngine.getEngine().setVideoConfig(videoConfig, ZegoPublishChannel.AUX);
After calling startCapture
on the Android platform, a system pop-up will automatically prompt to allow the app to record the screen. You need to actively grant the permission.
If you refuse to grant permission, screen sharing will fail. In this case, you need to handle it correspondingly in onApiCalledResult, for example, stop screen sharing when startScreenCapture method throws an error:
ZegoExpressEngine.setApiCalledCallback(new IZegoApiCalledEventHandler() {
@Override
public void onApiCalledResult(int errorCode, String funcName, String info) {
super.onApiCalledResult(errorCode, funcName, info);
if ("startScreenCapture".equals(funcName)) {
stopScreenSharing();
}
}
});
Start screen sharing using the startScreenCapture method, and when calling startPublishingStream, specify ZegoPublishChannel.AUX
as the ZegoPublishChannel
used for screen sharing:
ZegoExpressEngine.getEngine().startScreenCapture();
String streamID = roomID + "_" + userID + "_share";
ZegoExpressEngine.getEngine().startPublishingStream(streamID, ZegoPublishChannel.AUX);
ZegoCanvas previewCanvas = new ZegoCanvas(binding.videoView);
ZegoExpressEngine.getEngine().startPreview(previewCanvas,ZegoPublishChannel.AUX);
Stop screen sharing using the stopScreenCapture method, and when calling stopPublishingStream, specify ZegoPublishChannel.AUX
as the ZegoPublishChannel
used for screen sharing:
ZegoExpressEngine.getEngine().setVideoSource(ZegoVideoSourceType.ZEGO_VIDEO_SOURCE_DEFAULT, ZegoPublishChannel.AUX);
ZegoExpressEngine.getEngine().stopPreview(ZegoPublishChannel.AUX);
ZegoExpressEngine.getEngine().stopPublishingStream(ZegoPublishChannel.AUX);
ZegoExpressEngine.getEngine().stopScreenCapture();
For viewers, the rendering method for screen-sharing streams is the same as that for normal camera streams.
In the demo, stream types are distinguished by stream name (see the FAQs at the end of the document). Therefore, you can determine the stream type in this way when playing streams and rendering different streams to different positions on the screen.
void startPlayStream(String streamID) {
// Start to play streams. Set the view for rendering the remote streams.
if(streamID.endsWith("share")){
showSmallVideoView();
ZegoCanvas playCanvas = new ZegoCanvas(binding.screenShareView);
playCanvas.viewMode = ZegoViewMode.ASPECT_FIT;
ZegoExpressEngine.getEngine().startPlayingStream(streamID, playCanvas);
binding.screenShareView.setVisibility(View.VISIBLE);
}
}
In general, the type of stream can be agreed upon through the construction rules of stream ID, which is suitable for most scenarios:
You can configure the stream ID of the camera and microphone on ZegoPublishChannel.MAIN
as ${roomID}_${localUserID}_main
, and configure the stream ID of screen sharing on ZegoPublishChannel.AUX
as ${roomID}_${localUserID}_share
.
When the callback on the stream added is received by the stream players, the stream type can be judged according to the stream ID rule.
The server callback can also judge the stream type according to the same rule.
If using stream ID to identify stream type is not suitable, you can use stream attachment information to mark stream type. See setStreamExtraInfo method for details.
In this case, publishing multiple streams is not required. You just need to replace the video source of the main channel with the screen sharing source:
ZegoPublishChannel.MAIN
, like this:ZegoExpressEngine.getEngine().setVideoSource(ZegoVideoSourceType.SCREEN_CAPTURE, ZegoPublishChannel.MAIN);
ZegoVideoConfig videoConfig = new ZegoVideoConfig(ZegoVideoConfigPreset.PRESET_720P);
ZegoExpressEngine.getEngine().setVideoConfig(videoConfig, ZegoPublishChannel.MAIN);
This way, the ZegoPublishChannel.MAIN
channel will use screen sharing as the video source and use the microphone as the audio source.
ZegoPublishChannel.MAIN
as the channel parameter in the following steps. Like this:ZegoExpressEngine.getEngine().startPublishingStream(streamID, ZegoPublishChannel.MAIN);
ZegoExpressEngine.getEngine().stopPublishingStream(ZegoPublishChannel.MAIN);
Therefore, your app's host side does not need to do any additional processing.
If the viewer needs to identify the screen orientation based on the resolution of the received video stream and adjust the UI accordingly, you can achieve this by listening to the onPlayerVideoSizeChanged event callback.
ZegoExpressEngine.getEngine().setEventHandler(new IZegoEventHandler() {
@Override
public void onPlayerVideoSizeChanged(String streamID, int width, int height) {
super.onPlayerVideoSizeChanged(streamID, width, height);
if (width < height) {
}else{
}
}
}
The SDK captures the camera feed based on the portrait resolution by default, regardless of whether the host's phone is in landscape or portrait mode. In a game live streaming scenario, you may need to adjust the camera feed to landscape resolution when the host's phone is in landscape mode.
Step 1. config your Activity configuration in AndroidManifest.xml
as follows:
<activity
android:name=".LiveActivity"
// add this line
android:configChanges="locale|keyboardHidden|fontScale|orientation|screenSize|screenLayout|layoutDirection|density|uiMode"
android:exported="false" />
Step 2. add a BroadcastReceiver for configuration change,and register after join room:
IntentFilter configurationChangeFilter = new IntentFilter();
configurationChangeFilter.addAction("android.intent.action.CONFIGURATION_CHANGED");
BroadcastReceiver configurationChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ZegoOrientation orientation = ZegoOrientation.ORIENTATION_0;
ZegoVideoConfig videoConfig = new ZegoVideoConfig(videoConfigPreset);
ZegoVideoConfig preset540 = new ZegoVideoConfig(ZegoVideoConfigPreset.PRESET_540P);
if (Surface.ROTATION_0 == getWindowManager().getDefaultDisplay().getRotation()) {
orientation = ZegoOrientation.ORIENTATION_0;
videoConfig.setEncodeResolution(preset540.encodeWidth, preset540.encodeHeight);
} else if (Surface.ROTATION_180 == getWindowManager().getDefaultDisplay().getRotation()) {
orientation = ZegoOrientation.ORIENTATION_180;
videoConfig.setEncodeResolution(preset540.encodeWidth, preset540.encodeHeight);
} else if (Surface.ROTATION_270 == getWindowManager().getDefaultDisplay().getRotation()) {
orientation = ZegoOrientation.ORIENTATION_270;
videoConfig.setEncodeResolution(preset540.encodeHeight, preset540.encodeWidth);
} else if (Surface.ROTATION_90 == getWindowManager().getDefaultDisplay().getRotation()) {
orientation = ZegoOrientation.ORIENTATION_90;
videoConfig.setEncodeResolution(preset540.encodeHeight, preset540.encodeWidth);
}
ZegoExpressEngine.getEngine().setAppOrientation(orientation);
ZegoExpressEngine.getEngine().setVideoConfig(videoConfig);
}
};
registerReceiver(configurationChangeReceiver, configurationChangeFilter);
Congratulations! Hereby you have completed the development of the screen sharing feature.
If you have any suggestions or comments, feel free to share them with us via Discord. We value your feedback.