# Listen for video events The Video SDK for Android fires several video-related callbacks through `ZoomVideoSDKDelegate`. Implement the delegate and override the callbacks below to react to video state changes in your session. If you haven't already set up a delegate, see [Integrate](/docs/video-sdk/android/integrate/) for details. ## User video status `onUserVideoStatusChanged` fires when any user starts or stops their video. Use this callback to update your UI. For example, swap a "video off" placeholder for the rendered video, or vice versa. ```kotlin override fun onUserVideoStatusChanged(videoHelper: ZoomVideoSDKVideoHelper?, userList: MutableList) { userList.forEach { user -> val isOn = user.videoStatus.isOn // update the rendered tile or placeholder for this user } } ``` ```java @Override public void onUserVideoStatusChanged(ZoomVideoSDKVideoHelper videoHelper, List userList) { for (ZoomVideoSDKUser user : userList) { boolean isOn = user.getVideoStatus().isOn(); // update the rendered tile or placeholder for this user } } ``` ## Spotlight list changes `onSpotlightVideoChanged` fires whenever the spotlighted user list changes, either because a user was added to or removed from the spotlight. Use this to re-render your gallery layout (for example, to enlarge the spotlighted user's tile). ```kotlin override fun onSpotlightVideoChanged(videoHelper: ZoomVideoSDKVideoHelper?, userList: MutableList) { // userList contains the current spotlighted users // re-render your gallery to reflect the new spotlight state } ``` ```java @Override public void onSpotlightVideoChanged(ZoomVideoSDKVideoHelper videoHelper, List userList) { // userList contains the current spotlighted users // re-render your gallery to reflect the new spotlight state } ``` For more information on how to add and remove users from the spotlight, see [Spotlight a user](/docs/video-sdk/android/video/spotlight/). ## Multi-camera stream status `onMultiCameraStreamStatusChanged` fires when a user enables, disables, mutes, or unmutes a multi-camera stream. The delegate exposes two overloads, one for the raw-data-pipe approach and one for the canvas approach. ```kotlin override fun onMultiCameraStreamStatusChanged( status: ZoomVideoSDKMultiCameraStreamStatus?, user: ZoomVideoSDKUser?, videoPipe: ZoomVideoSDKRawDataPipe? ) { // Raw data pipe variant — see the multi-camera and raw-data docs } override fun onMultiCameraStreamStatusChanged( status: ZoomVideoSDKMultiCameraStreamStatus?, user: ZoomVideoSDKUser?, canvas: ZoomVideoSDKVideoCanvas? ) { // Canvas variant — subscribe a ZoomVideoSDKVideoView to the canvas to render } ``` ```java @Override public void onMultiCameraStreamStatusChanged(ZoomVideoSDKMultiCameraStreamStatus status, ZoomVideoSDKUser user, ZoomVideoSDKRawDataPipe videoPipe) { // Raw data pipe variant — see the multi-camera and raw-data docs } @Override public void onMultiCameraStreamStatusChanged(ZoomVideoSDKMultiCameraStreamStatus status, ZoomVideoSDKUser user, ZoomVideoSDKVideoCanvas canvas) { // Canvas variant — subscribe a ZoomVideoSDKVideoView to the canvas to render } ``` For more on how to enable, disable, mute, and unmute multi-camera streams, see [Multiple camera support](/docs/video-sdk/android/video/multiple-cameras/). ## External USB camera connected or disconnected `onUVCCameraStatusChange` fires when an external USB Video Class (UVC) camera is plugged into or removed from the device. This is useful on tablets that support USB cameras. Surface a "new camera available" UI when a camera is connected, and refresh your camera list when one is removed. ```kotlin override fun onUVCCameraStatusChange(cameraId: String?, status: UVCCameraStatus?) { // Refresh your camera list and update any settings UI } ``` ```java @Override public void onUVCCameraStatusChange(String cameraId, UVCCameraStatus status) { // Refresh your camera list and update any settings UI } ``` ## Alpha channel mode `onVideoAlphaChannelStatusChanged` fires when alpha channel mode (transparent-background video) is toggled on or off. ```kotlin override fun onVideoAlphaChannelStatusChanged(isAlphaModeOn: Boolean) { // Adjust rendering to handle transparency } ``` ```java @Override public void onVideoAlphaChannelStatusChanged(boolean isAlphaModeOn) { // Adjust rendering to handle transparency } ``` ## Video canvas subscription failure `onVideoCanvasSubscribeFail` fires when a call to subscribe a `ZoomVideoSDKVideoView` to a user's video canvas fails. The reason is returned as a `ZoomVideoSDKVideoSubscribeFailReason`. Common failure cases include exceeding the device's render limit or attempting to subscribe before the SDK has finished initializing. ```kotlin override fun onVideoCanvasSubscribeFail( failReason: ZoomVideoSDKVideoSubscribeFailReason?, user: ZoomVideoSDKUser?, view: ZoomVideoSDKVideoView? ) { // Surface an error in your UI, or retry after the underlying issue is resolved } ``` ```java @Override public void onVideoCanvasSubscribeFail(ZoomVideoSDKVideoSubscribeFailReason failReason, ZoomVideoSDKUser user, ZoomVideoSDKVideoView view) { // Surface an error in your UI, or retry after the underlying issue is resolved } ``` ## Camera control requests A remote user can request control of the current user's camera. Two callbacks cover the request/response cycle. `onCameraControlRequestReceived` fires when another user requests control. Use the `requestHandler` parameter to approve or decline. ```kotlin override fun onCameraControlRequestReceived( user: ZoomVideoSDKUser?, requestType: ZoomVideoSDKCameraControlRequestType?, requestHandler: ZoomVideoSDKCameraControlRequestHandler? ) { // Show a confirmation dialog, then call requestHandler.approve() or .decline() } ``` ```java @Override public void onCameraControlRequestReceived(ZoomVideoSDKUser user, ZoomVideoSDKCameraControlRequestType requestType, ZoomVideoSDKCameraControlRequestHandler requestHandler) { // Show a confirmation dialog, then call requestHandler.approve() or .decline() } ``` `onCameraControlRequestResult` fires on the requesting user's side, with the approval result. ```kotlin override fun onCameraControlRequestResult(user: ZoomVideoSDKUser?, isApproved: Boolean) { // Update the UI based on whether the request was approved } ``` ```java @Override public void onCameraControlRequestResult(ZoomVideoSDKUser user, boolean isApproved) { // Update the UI based on whether the request was approved } ``` ## Canvas snapshots `onCanvasSnapshotTaken` fires when a snapshot of a video canvas is successfully captured. `onCanvasSnapshotIncompatible` fires when a snapshot fails because the target user's stream is not compatible with snapshots. ```kotlin override fun onCanvasSnapshotTaken(user: ZoomVideoSDKUser?, isShare: Boolean) { // The snapshot is ready — handle it in your UI } override fun onCanvasSnapshotIncompatible(user: ZoomVideoSDKUser?) { // Snapshot was not possible — fall back gracefully } ``` ```java @Override public void onCanvasSnapshotTaken(ZoomVideoSDKUser user, boolean isShare) { // The snapshot is ready — handle it in your UI } @Override public void onCanvasSnapshotIncompatible(ZoomVideoSDKUser user) { // Snapshot was not possible — fall back gracefully } ``` ## Network status For per-user video network quality changes, listen to `onUserNetworkStatusChanged` and check for the video-specific data type, or use `onUserOverallNetworkStatusChanged` for the user's overall quality across all data types. > **Note** > > The dedicated `onUserVideoNetworkStatusChanged` callback is deprecated in favor of the more general `onUserNetworkStatusChanged` and `onUserOverallNetworkStatusChanged` callbacks.