Top of pageSkip to main content

Broadcast the device screen

This tutorial demonstrates the steps required to enable and start broadcasting a user's screen in a session using ReplayKit and the Video SDK.

Prerequisites

1. Create a new target

Use the Broadcast Upload Extension template to create a new target in your app. Click File->New->Target, select Broadcast Upload Extension in the iOS tab, and click Next. Set the target name as ScreenShare, select your desired language, and click Finish. If you are prompted to activate a scheme, click Activate.

After the target creation, Replaykit framework will be added automatically under Frameworks and Libraries option of the ScreenShare target. Ensure that the Do not Embed option is applied to this framework.

2. Configure target settings

The Video SDK does not support Bitcode. Therefore, you must disable bitcode for your targets.

Under Targets, navigate to ScreenShare -> Build Settings -> Build Options -> Setting and set the value of Enable Bitcode setting to No. Repeat this step for your main target if you haven't already done so.

Note: Ensure that the deployment target version is lower than or equal to your device's OS version, for both the main target and the ScreenShare target.

The ZoomVideoSDKScreenShare framework utilizes C++ libraries. To make your project compatible with these libraries, make the following changes within your ScreenShare target:

  • If you are using Objective-C, navigate to ScreenShare> SampleHandler.m and rename it to SampleHandler.mm.

  • If you are using Swift, navigate to the ScreenShare target -> Build Settings -> Other Linker Flags, and add the value “-lc++”.

3. Import frameworks

Import the ZoomVideoSDKScreenShare framework into the ScreenShare app extension target. You can do so by either dragging the framework into Xcode or by navigating to the Frameworks section of the ScreenShare target. If you are asked to specify the target, select the ScreenShare target(not the main target).

The ZoomVideoSDKScreenShare framework utilizes the following Apple video frameworks to improve the screen sharing experience.

  • CoreGraphics.framework
  • CoreVideo.framework
  • CoreMedia.framework
  • VideoToolbox.framework

Navigate to the Frameworks and Libraries option in the General tab of the ScreenShare target and click the “+” icon to search and include these frameworks.

Note: In certain versions of Xcode, you may have to navigate to Build Phases -> Link Binary with Libraries to import these frameworks.

4. Implement a bridging header

The ZoomVideoSDKScreenShare framework works by utilizing the callbacks within the SampleHandler. If you are using Swift in your project , you must implement a bridging header to expose the ZoomVideoSDKScreenShare framework to SampleHandler.swift.

If you are using Objective-C instead of Swift in your project, skip this step and move to the Set up SampleHandler section.

Create a temporary Objective-C file within your target by navigating to SampleHandler.swift in the project explorer, and clicking File -> New File -> Objective-C File. Give this file a name and click Next. Add this file to the ScreenShare target only and click Create.

Once Xcode prompts you to create an Objective-C bridging header, click Create Bridging Header. If you didn't see a prompt, you must create the bridging header manually within the ScreenShare target.

After completing these steps, in the ScreenShare target, you should see the bridging header file. The file name contains the product module name followed by “-Bridging-Header.h”.

Import the ZoomVideoSDKScreenShareService framework by adding the following line of code in the bridging header file:

ScreenShare-Bridging-Header.h
#import <ZoomVideoSDKScreenShare/ZoomVideoSDKScreenShareService.h>

This framework will now be exposed to all the Swift files in your ScreenShare target. Thus, you do not need to include import statements for this framework in your Swift files.

You may now delete the temporary Objective-C file(not the bridging header file) that you created earlier.

5. Set up SampleHandler

The SampleHandler class is where the code to handle different broadcasting events resides. To handle the events, you must:

  1. Conform SampleHandler to ZoomVideoSDKScreenShareServiceDelegate to establish communication between ReplayKit and the Video SDK.

  2. Pass the SampleHandler callbacks into the VideoSDK. To do this, create a ZoomVideoSDKScreenShare property, assign the SampleHandler as its delegate, and call the delegate functions from the relative SampleHandler callbacks.

SampleHandler.m

#import "SampleHandler.h"
#import <ZoomVideoSDKScreenShare/ZoomVideoSDKScreenShareService.h>
@interface SampleHandler () <ZoomVideoSDKScreenShareServiceDelegate>
@property (strong, nonatomic) ZoomVideoSDKScreenShareService * screenShareService;
@end
@implementation SampleHandler
- (instancetype)init
{
    self = [super init];
    if (self) {
        // Create an instance of ZoomVideoSDKScreenShareService to handle broadcast actions.
        ZoomVideoSDKScreenShareServiceInitParams *params = [[ZoomVideoSDKScreenShareServiceInitParams alloc] init];
        // Provide your app group id from your Apple Developer account.
        params.appGroupId = @"your app group ID here";
        // Set this to true to enable sharing device audio during screenshare
        params.isWithDeviceAudio = YES;
        ZoomVideoSDKScreenShareService * service = [[ZoomVideoSDKScreenShareService alloc]initWithParams:params];
        self.screenShareService = service;
    }
    return self;
}
- (void)dealloc
{
    self.screenShareService = nil;
}
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
    // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
    [self.screenShareService broadcastStartedWithSetupInfo:setupInfo];
}
- (void)broadcastPaused {
    [self.screenShareService broadcastPaused];
    // User has requested to pause the broadcast. Samples will stop being delivered.
}
- (void)broadcastResumed {
    [self.screenShareService broadcastResumed];
    // User has requested to resume the broadcast. Samples delivery will resume.
}
- (void)broadcastFinished {
    // User has requested to finish the broadcast.
    [self.screenShareService broadcastFinished];
}
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    [self.screenShareService processSampleBuffer:sampleBuffer withType:sampleBufferType];
}
- (void)ZoomVideoSDKScreenShareServiceFinishBroadcastWithError:(NSError *)error
{
    [self finishBroadcastWithError:error];
}
@end
SampleHandler.swift

import Foundation
import ReplayKit
class SampleHandler: RPBroadcastSampleHandler, ZoomVideoSDKScreenShareServiceDelegate {
    var screenShareService: ZoomVideoSDKScreenShareService?
    override init() {
        super.init()
        // Create an instance of ZoomVideoSDKScreenShareService to handle broadcast actions.
        let params = ZoomVideoSDKScreenShareServiceInitParams()
        // Provide your app group id from your Apple Developer account.
        params.appGroupId = "your app group ID here"
        // Set this to true to enable sharing device audio during screenshare
        params.isWithDeviceAudio = true
        let service = ZoomVideoSDKScreenShareService(params: params)
        self.screenShareService = service
    }
    override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
        guard let setupInfo = setupInfo else { return }
        // Pass setup info to SDK.
        screenShareService?.broadcastStarted(withSetupInfo: setupInfo)
    }
    override func broadcastPaused() {
        // Notify SDK the broadcast was paused.
        screenShareService?.broadcastPaused()
    }
    override func broadcastResumed() {
        // Notify SDK the broadcast was resumed.
        screenShareService?.broadcastResumed()
    }
    override func broadcastFinished() {
        // Notify SDK the broadcast has finished.
        screenShareService?.broadcastFinished()
    }
    override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
        // Pass sample bugger into SDK.
        screenShareService?.processSampleBuffer(sampleBuffer, with: sampleBufferType)
    }
    func zoomVideoSDKScreenShareServiceFinishBroadcastWithError(_ error: Error?) {
        guard let error = error else { return }
        // Terminate broadcast when notified of error from SDK.
        finishBroadcastWithError(error)
    }
}

Note: If using the virtual speaker, screen share will only share video data and will not share the audio data.

6. Set up App Groups

Utilize App Groups to establish communication between your ScreenShare target, and your application's main target.

Enable App Groups by navigating to your application's main target -> Signing and Capabilities -> + Capability and selecting App Groups.

Click the “+” icon at the bottom of the App Groups section to create a new App Group in your main target and set its name. This name will serve as the App Group ID. Similar to Bundle IDs, these are in reverse domain order starting with “group.”.

We recommend appending your Bundle ID to “group.” to form the App Group ID as it is easy to keep track of. The following image shows an example of what an App Group ID could look like. You must create your own unique App Group ID.

Next, enable this App Group by selecting the checkbox next to the App Group ID.

Repeat the above steps to enable the same App Group in your Screenshare extension target. Note that the same App Group ID must be used in both targets.

After completing these steps, navigate to the code where you have initialized the Video SDK in your application and pass the App Group ID to your SDKInitContext object.


initParams.appGroupId = @"Your AppGroupId.";

initParams.appGroupId = "Your AppGroupId."

Next, pass the App Group ID into the ZoomVideoSDKScreenShare within your SampleHandler. Add the following code inside the init method where the other screenShareService properties are set.

SampleHandler.m

//Pass your App Group ID to the SDK.
self.screenShareService.appGroup = @"Your AppGroupId.";
SampleHandler.swift

//Pass your App Group ID to the SDK.
screenShareService?.appGroup = "Your AppGroupId."

7. Run the App

Run your app extension to start broadcasting. To do this, first, select the ScreenShare scheme at the top left corner of Xcode and click Run.

If you're prompted to choose an app to run, select your main target application and click Run.

Note: To avoid this prompt and allow Xcode to select your application for you, click your ScreenShare scheme -> Edit Scheme and select your application under “Executable”. By default, you can either debug your ScreenShare extension or your main application. If you would like to debug both, select “Debug executable”.

While your application is running, navigate to the Control Center of your iOS device, tap the Screen Record button, choose the ScreenShare application extension and tap the Start Broadcast option to start broadcasting your screen.

8. Manage the display of the shared content

Once a user starts broadcasting during a session, you must utilize the onUserShareStatusChanged callback function of the ZoomVideoSDKDelegate to monitor screen share events. ZoomVideoSDKDelegate is located within ZoomVideoSDK.xcframework, so this delegate should be implemented within your main target.

The onUserShareStatusChanged function is called when a user starts or stops the broadcast in a session.

Once the user starts sharing the screen, call the subscribeWithView method to start rendering the shared screen in the session. To stop sharing the screen, call the unSubscribeWithView method.


- (void)onUserShareStatusChanged:(ZoomVideoSDKShareHelper *)helper user:(ZoomVideoSDKUser *)user status:(ZoomVideoSDKReceiveSharingStatus)status {
    // Use helper to perform sharing actions.
    // The value of status is the new share status of the user.
    switch (status) {
        // User has begun sharing.
        case ZoomVideoSDKReceiveSharingStatus_Start: {
            // To render the share stream, you must update the relevant share canvas.
            // Obtain the share canvas for a user using getShareCanvas.
            ZoomVideoSDKVideoCanvas *usersShareCanvas = [user getShareCanvas];
            // Render the share video on the UIView.
            [usersShareCanvas subscribeWithView:self.view andAspectMode:ZoomVideoSDKVideoAspect_PanAndScan];
            break;
        }
          // User has stopped sharing.
        case ZoomVideoSDKReceiveSharingStatus_Stop: {
            // Obtain the share canvas for a user using getShareCanvas.
            ZoomVideoSDKVideoCanvas *usersShareCanvas = [user getShareCanvas];
            // To stop rendering the share stream of that user, call unSubscribe.
            [usersShareCanvas unSubscribeWithView:self.view];
        }
        default:
            break;
    }
}

func onUserShareStatusChanged(_ helper: ZoomVideoSDKShareHelper!, user: ZoomVideoSDKUser!, status: ZoomVideoSDKReceiveSharingStatus) {
    // Use helper to perform sharing actions.
    // The value of status is the new share status of the user.
    switch status {
       // User has begun sharing.
        case .start:   
            // To render the share stream, you must update the relevant share canvas.
            // Obtain the share canvas for a user using getShareCanvas.
            let usersShareCanvas = user.getShareCanvas()
            // Render the share video on the UIView.
            usersShareCanvas?.subscribe(with: self.view, andAspectMode: .panAndScan)
        // User has stopped sharing.
        case .stop:
            // Obtain the share canvas for a user using getShareCanvas.
            let userShareCanvas = user.getShareCanvas()
            // To stop rendering the share stream of that user, call unSubscribe.
            userShareCanvas?.unSubscribe(with: self.view)
        default:
            break
    }
}

Need help?

If you're looking for help, try Developer Support or our Developer Forum. Priority support is also available with Premier Developer Support plans.