Core features

View as Markdown

The Video SDK for Android lets users share content with others in a session. The SDK supports three kinds of share sources:

  • Screen share: mirror the device's screen using Android's MediaProjectionManager .
  • Camera share: broadcast a camera as a content stream alongside the user's normal video, useful for document cameras or secondary perspectives.
  • External source: feed in an arbitrary frame source through the SDK's preprocessing pipe.

Sharing the screen involves requesting permission, running a foreground service, and starting, stopping, and pausing a share. To broadcast a camera or external frame source instead, see Share a camera or external source.

To render an incoming share from another participant, see Receive a screen share. To draw on shared content, see Annotation.

Sharing the device's screen takes three steps:

  1. Request screen-capture permission from the user through Android's MediaProjectionManager.
  2. Start a foreground service with the mediaProjection foreground service type.
  3. Call startShareScreen on the ZoomVideoSDKShareHelper, passing the Intent returned by the permission flow.

Request screen-capture permission

Use ActivityResultLauncher (the modern replacement for startActivityForResult) to launch the system's screen-capture permission dialog.

private val screenCaptureLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == Activity.RESULT_OK && result.data != null) {
        startScreenShare(result.data!!)
    }
}

fun onShareScreenClicked() {
    val manager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
    screenCaptureLauncher.launch(manager.createScreenCaptureIntent())
}

Run a foreground service

Screen capture must run inside a foreground service. Implement a service that calls startForeground from its onCreate.

class ScreenShareService : Service() {
    companion object {
        private const val CHANNEL_ID = "screen_share_channel"
        private const val NOTIFICATION_ID = 1
    }

    override fun onCreate() {
        super.onCreate()
        val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        if (manager.getNotificationChannel(CHANNEL_ID) == null) {
            manager.createNotificationChannel(
                NotificationChannel(
                    CHANNEL_ID,
                    "Screen share",
                    NotificationManager.IMPORTANCE_LOW
                )
            )
        }

        val notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentText("Screen share")
            .setOngoing(true)
            .setAutoCancel(false)
            .build()

        startForeground(NOTIFICATION_ID, notification)
    }

    override fun onBind(intent: Intent?): IBinder? = null
}

Declare the service in AndroidManifest.xml with the mediaProjection type.

<service
    android:name=".ScreenShareService"
    android:foregroundServiceType="mediaProjection" />

Foreground permissions

Starting with Android 14, Google requires developers to specify appropriate foreground service types in their apps . The Video SDK uses these foreground service permissions.

PermissionDescription
FOREGROUND_SERVICE_MICROPHONEAllow the capability to receive audio when the app is put in the background.
FOREGROUND_SERVICE_MEDIA_PLAYBACKAllow the capability to share audio while screen sharing.
FOREGROUND_SERVICE_MEDIA_PROJECTIONAllow the capability to project the screen while screen sharing.
FOREGROUND_SERVICE_CONNECTED_DEVICEAllow the capability to use Bluetooth device as the audio source.
FOREGROUND_SERVICE_PHONE_CALLAllow the capability to use Bluetooth device for the meeting call.

The screen sharing feature in Video SDK requires foreground service. If the screen sharing feature is not included in your project, add the following code in Androidmanifest.xml to remove the service and permissions. Note that removing FOREGROUND_SERVICE_MICROPHONE permission might cause an audio issue when the application is in the background. Therefore, to ensure the audio works as expected, maintain FOREGROUND_SERVICE_MICROPHONE and FOREGROUND_SERVICE_CONNECTED_DEVICE permissions in the project and start the foreground service when joining a meeting.

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" tools:node="remove"/>

Start the share

After the foreground service is running, call startShareScreen on the ZoomVideoSDKShareHelper, passing the Intent returned from the permission flow.

private fun startScreenShare(data: Intent) {
    val serviceIntent = Intent(this, ScreenShareService::class.java)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(serviceIntent)
    } else {
        startService(serviceIntent)
    }
    ZoomVideoSDK.getInstance().shareHelper.startShareScreen(data)
}

startShareScreen returns an int. ZoomVideoSDKErrors.Errors_Success (value 0) means the share is starting; any other value is an error from ZoomVideoSDKErrors . Common reasons a call fails: another user is sharing while multi-share is disabled, the session host has locked sharing, or you're calling from outside an active session.

Asynchronous failures arrive on the ZoomVideoSDKDelegate through onFailedToStartShare. Surface the error to the user and stop the foreground service if you started one.

override fun onFailedToStartShare() {
    // The screen-capture session never began. Tear down the foreground service.
    stopService(Intent(this, ScreenShareService::class.java))
    showShareError()
}

Stop the share

To end a share programmatically, call stopShare. This works for screen, camera, and external-source shares.

ZoomVideoSDK.getInstance().shareHelper.stopShare()
stopService(Intent(this, ScreenShareService::class.java))

Inside the service, the recommended Android pattern for shutting down is stopForeground(STOP_FOREGROUND_REMOVE) followed by stopSelf().

override fun onDestroy() {
    stopForeground(STOP_FOREGROUND_REMOVE)
    super.onDestroy()
}

A share also stops when the user taps Stop sharing in the system Media Projection notification. The SDK reports both programmatic and system-initiated stops the same way: onUserShareStatusChanged fires with ZoomVideoSDKShareStatus_Stop. Tear down your foreground service from that callback so both paths converge on the same cleanup code. For the callback signature, see Receive a screen share.

Pause and resume

Pause an ongoing share without disconnecting from the screen-capture session. Viewers see a frozen frame until you resume.

val shareHelper = ZoomVideoSDK.getInstance().shareHelper
shareHelper.pauseShare()
// Later:
shareHelper.resumeShare()

Receivers detect pause and resume through the ZoomVideoSDKShareStatus_Pause and ZoomVideoSDKShareStatus_Resume values on onUserShareStatusChanged.

Share device audio

To send the device's audio alongside the screen capture (so viewers hear music, video sound, or app audio), enable share device audio before or during the share.

val shareHelper = ZoomVideoSDK.getInstance().shareHelper
shareHelper.enableShareDeviceAudio(true)

// Check whether device-audio capture is on.
val isOn = shareHelper.isShareDeviceAudioEnabled

Check the local share state

Use the share helper's state queries to drive your UI. For example, to disable a Share screen button while the local user is already sharing, or while another participant is.

val shareHelper = ZoomVideoSDK.getInstance().shareHelper

// The local user is currently sharing (any share type).
val sharing = shareHelper.isSharingOut

// The local user is specifically sharing the screen.
val sharingScreen = shareHelper.isScreenSharingOut

// Some other participant is sharing.
val otherSharing = shareHelper.isOtherSharing