Screen Share - Android
This feature enables hosts to start or stop sharing their screen with other hosts and audience members during the live stream. Only hosts (in SEND_AND_RECV mode) can broadcast their screen, while audience members (in RECV_ONLY mode) can view it in real time.
How Screen share works?
-
The following steps show the flow of the screen sharing in android using VideoSDK:
- Your app asks the user for permission to capture the screen.
- If the user allows it, your app passes the result to
enableScreenShare(). If not, nothing is shared. - The SDK starts a foreground service, shows its notification and starts sharing the screen.
- The screen share stream arrives on
onStreamEnabled(). Add it to aVideoViewto display it.
enableScreenShare()
-
By using
enableScreenShare()function ofRoomclass, the host can share their mobile screen to other hosts and audience members. -
enableScreenShare()is asuspendfunction. Call it from a coroutine, such aslifecycleScope.launch(fromandroidx.lifecycle:lifecycle-runtime-ktx). It returns once sharing has started, which can take a moment. -
It throws
VideoSDKExceptionwith3054(ERROR_ALREADY_IN_REQUESTED_STATE) when the screen is already being shared,3055(ERROR_OPERATION_IN_PROGRESS) while another screen share call is running, and3016(ERROR_GET_DISPLAY_MEDIA_PERMISSION_DENIED) when the permission result can't be used. -
Only
SEND_AND_RECVmode can publish a screen share. Called by an audience member (RECV_ONLYmode),enableScreenShare()anddisableScreenShare()throwVideoSDKExceptionwith3066(ERROR_ACTION_NOT_SUPPORTED_IN_MODE). -
Called before the live stream is joined, or while it is reconnecting,
enableScreenShare()anddisableScreenShare()do nothing and report3035(ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED) or3065(ERROR_ROOM_RECONNECTING) ononErrorinstead of throwing. -
To share the device's audio along with the screen, pass
enableAudio = true:enableScreenShare(data, enableAudio = true). It needs Android 10 (API level 29) or later and theRECORD_AUDIOpermission. The audio is mixed into the microphone track, so it is sent only while the mic is on, and muting the mic mutes it too. -
You can pass customised screenshare track in
enableScreenShare()by using Custom Screen Share Track. Create it withVideoSDK.createScreenShareVideoTrack(), and setwithAudio = truethere to share the device's audio. -
Screen Share stream of the participant can be accessed from the
onStreamEnabledevent ofParticipantEventListener.
Screenshare permission
-
A participant’s Screen share stream is provided via the
MediaProjectionAPI. -
Get an instance of the
MediaProjectionManagerand call thecreateScreenCaptureIntent()method in an activity. This initiates a prompt dialog for the user to confirm screen projection. -
The user sees a prompt dialog like this:

- After permission is received from the user, you can call
enableScreenShare()method.
private fun enableScreenShare() {
val mediaProjectionManager = application.getSystemService(
MEDIA_PROJECTION_SERVICE
) as MediaProjectionManager
startActivityForResult(
mediaProjectionManager.createScreenCaptureIntent(), CAPTURE_PERMISSION_REQUEST_CODE
)
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode != CAPTURE_PERMISSION_REQUEST_CODE) return
if (resultCode == RESULT_OK && data != null) {
lifecycleScope.launch {
try {
// Enabling screen share
liveStream!!.enableScreenShare(data)
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Screen share failed: ${e.code} ${e.name}")
}
}
}
}
Screen share notification
-
While the screen is being shared, the SDK runs a foreground service and shows its notification: "VideoSDK is sharing your screen".
-
This notification can't be customised. The
notificationTitle,notificationContentandnotificationIconmeta-data entries inAndroidManifest.xmlhave no effect. -
On Android 13 (API level 33) and later, the notification shows in the notification drawer only if your app has the
POST_NOTIFICATIONSpermission. The screen share works either way. -
If the user swipes your app away from the recent apps screen, the screen share ends.
disableScreenShare()
-
By using
disableScreenShare()function ofRoomclass, the host can stop sharing their mobile screen to other hosts and audience members. -
disableScreenShare()is asuspendfunction. It throwsVideoSDKExceptionwith3054(ERROR_ALREADY_IN_REQUESTED_STATE) when nothing is being shared, and3055(ERROR_OPERATION_IN_PROGRESS) while another screen share call is running.
private fun disableScreenShare() {
lifecycleScope.launch {
try {
// Disabling screen share
liveStream!!.disableScreenShare()
} catch (e: VideoSDKException) {
Log.e("VideoSDK", "Stopping screen share failed: ${e.code} ${e.name}")
}
}
}
Events associated with enableScreenShare
-
Every participant receives
onStreamEnabled()on the sharingParticipant's listener, with anRTCStreamof kindMediaType.SHARE. -
Every Participant, including the one who shares, will receive
onPresenterChanged()callback of theRoomclass with the participantId aspresenterIdwho started the screen share.
Events associated with disableScreenShare
-
Every participant receives
onStreamDisabled()on the sharingParticipant's listener, with theRTCStreamthat stopped. -
Every Participant will receive
onPresenterChanged()callback of theRoomclass with thepresenterIdasnullindicating there is no presenter.
private fun setLocalListeners() {
liveStream!!.localParticipant.addEventListener(object : ParticipantEventListener() {
//Callback for when the participant starts a stream
override fun onStreamEnabled(stream: RTCStream) {
if (stream.kind == MediaType.SHARE) {
Log.d("VideoSDK","Share Stream On: onStreamEnabled $stream")
}
}
//Callback for when the participant stops a stream
override fun onStreamDisabled(stream: RTCStream) {
if (stream.kind == MediaType.SHARE) {
Log.d("VideoSDK","Share Stream Off: onStreamDisabled $stream")
}
}
})
}
private val roomEventListener: RoomEventListener = object : RoomEventListener() {
//Callback for when the presenter changes
override fun onPresenterChanged(presenterId: String?) {
if(!TextUtils.isEmpty(presenterId))
{
Log.d("VideoSDK","$presenterId started screen share")
}else{
Log.d("VideoSDK","some one stopped screen share")
}
}
}
Rendering Screen Share Stream
-
When a host participant shares their screen, the
onStreamEnabled()function of theParticipantEventListeneris triggered, allowing theRTCStreamto be added to aVideoView. -
VideoTrackcomes from thevideosdk.org.webrtcpackage.
import videosdk.org.webrtc.VideoTrack
private fun setLocalListeners() {
liveStream!!.localParticipant.addEventListener(object : ParticipantEventListener() {
override fun onStreamEnabled(stream: RTCStream) {
if (stream.kind == MediaType.SHARE) {
// display share video
val videoTrack = stream.track as? VideoTrack
shareView!!.addTrack(videoTrack)
}
}
override fun onStreamDisabled(stream: RTCStream) {
if (stream.kind == MediaType.SHARE) {
shareView!!.removeTrack()
}
}
})
}
- When another host shares their screen, every participant, the audience included, receives
onPresenterChanged()with thepresenterIdof that host. Use it to find the share stream and display it.
private val roomEventListener: RoomEventListener = object : RoomEventListener() {
override fun onPresenterChanged(presenterId: String?) {
updatePresenter(presenterId)
}
}
//Getting the stream from the participantId
private fun updatePresenter(participantId: String?) {
// find participant
val participant = liveStream!!.participants.get(participantId) ?: return
// find share stream in participant
var shareStream: RTCStream? = null
for (stream: RTCStream in participant.streams.values) {
if (stream.kind == MediaType.SHARE) {
shareStream = stream
break
}
}
if (shareStream == null) return
// display share video
val videoTrack = shareStream.track as? VideoTrack
shareView!!.addTrack(videoTrack)
// listen for share stop event
participant.addEventListener(object : ParticipantEventListener() {
override fun onStreamDisabled(stream: RTCStream) {
if (stream.kind == MediaType.SHARE) {
shareView!!.removeTrack()
}
}
})
}
API Reference
The API references for all the methods and events utilised in this guide are provided below.
Got a Question? Ask us on discord

