Skip to main content
Version: 4.x.x

Screen Share - iOS

Follow the below listed steps to add the screensharing capability in your iOS App.

Create Broadcast Upload Extension in iOS​

Step 1 : Open Target​

Open your project in Xcode, then select File > New > Target in the menu bar.

IOS Screen Share

Step 2 : Select Target​

Select Broadcast Upload Extension and click next.

IOS Screen Share

Step 3 : Configure Broadcast Upload Extension​

Enter the extension's name in the Product Name field, choose the team from the dropdown, uncheck the "Include UI extension" field, and click "Finish."

IOS Screen Share

Step 4 : Activate Extension scheme​

You will be prompted with a popup : Activate "Your-Extension-name" scheme?, click on activate.

IOS Screen Share

Now, the "Broadcast" folder will appear in the Xcode left side bar.

IOS Screen Share

Step 5 : Add External file in Created Extension​

Open the videosdk-rtc-ios-sdk-example repository, and copy the following files: SampleUploader.swift, SocketConnection.swift, DarwinNotification.swift, and Atomic.swift to your extension's folder. Ensure that these files are added to the target.

Step 6 : Update SampleHandler.swift file​

Open SampleHandler.swift, and copy the content of the file. Paste this content into your extension's SampleHandler.swift file.

Step 7 : Add Capability in App​

In Xcode, navigate to YourappName > Signing & Capabilities, and click on +Capability to configure the app group.

IOS Screen Share

Choose App Groups from the list.

IOS Screen Share

After that, select or add the generated App Group ID that you have created before.

IOS Screen Share

Step 8 : Add Capability in Extension​

Go to Your-Extension-Name > Signing & Capabilities and configure App Group functionality as you did in the previous step. (Group id should be same for both targets).

IOS Screen Share

Step 9 : Add App Group Id in Extension File​

Go to the extension's SampleHandler.swift file and paste your group ID in the appGroupIdentifier constant.

IOS Screen Share

Step 10 : Update App level info.plist file​

  1. Add a new key RTCScreenSharingExtension in Info.plist with the extension's Bundle Identifier as the value.
  2. Add a new key RTCAppGroupIdentifier in Info.plist with the extension's App groups Id as the value.

Note : For the extension's Bundle Identifier, go to TARGETS > Your-Extension-Name > Signing & Capabilities .

IOS Screen Share

note

You can also check out the extension's example code on GitHub.

Integrate ScreenShare in your App​

After successfully creating Broadcast Upload Extension using the above listed steps, we can start using the enableScreenShare and disableScreenShare functions of the Room class.

How to use the ScreenShare functions​

@IBAction func ScreenShareButtonTapped(_ sender: Any) {
Task {
do {
try await self.room?.enableScreenShare()
} catch {
print("Could not start screen share: \(error)")
}
}
}

@IBAction func StopScreenShareButtonTapped(_ sender: Any) {
Task {
do {
try await self.room?.disableScreenShare()
} catch {
print("Could not stop screen share: \(error)")
}
}
}
caution

The functions enableScreenShare and disableScreenShare are async throws functions; therefore call them with try await inside a Task, as shown above. If the app is not set up for screen sharing, enableScreenShare throws ERROR_GET_DISPLAY_MEDIA. See Errors below.

Calling enableScreenShare() shows an RPSystemBroadcastPickerView with the extension that was created using the above steps.

IOS Screen Share

After clicking the Start Broadcast button, you will be able to get the screen share stream in the session.

  • If the user closes the picker without starting the broadcast, call enableScreenShare() again to show the picker again. If no broadcast starts within about 30 seconds of the picker appearing, the SDK cancels the screen share.

  • The user can also stop the broadcast from Control Center. The SDK then ends the screen share for you, so you do not need to call disableScreenShare().

  • When the broadcast is started, it creates a Stream that has RTCStream.kind == .share. Using the stream kind, you can prompt a ScreenShare view for remote peer when ScreenShare is started by the local peer.

  • Similarly, you can use the same kind to dismiss the screenshare view on the remote peer when the screenshare was stopped.

Example​

extension RoomViewController: ParticipantEventListener {
/// Participant has enabled mic, video or screenshare
/// - Parameters:
/// - stream: enabled stream object
/// - participant: participant object
func onStreamEnabled(_ stream: RTCStream, forParticipant participant: Participant) {

if stream.kind == .share {
// show screen share
showScreenSharingView(true)
screenSharingView.showMediastream(stream)
return
}

// show stream in cell
if let cell = self.cellForParticipant(participant) {
cell.updateView(forStream: stream, enabled: true)
}

if participant.isLocal {
// turn on controls for local participant
self.buttonControlsView.updateButtons(forStream: stream, enabled: true)
}
}

/// Participant has disabled mic, video or screenshare
/// - Parameters:
/// - stream: disabled stream object
/// - participant: participant object
func onStreamDisabled(_ stream: RTCStream, forParticipant participant: Participant) {

if stream.kind == .share {
// remove screen share
showScreenSharingView(false)
screenSharingView.hideMediastream(stream)
return
}

// hide stream in cell
if let cell = self.cellForParticipant(participant) {
cell.updateView(forStream: stream, enabled: false)
}

if participant.isLocal {
// turn off controls for local participant
self.buttonControlsView.updateButtons(forStream: stream, enabled: false)
}
}
}

Check whether you are sharing​

  • isScreenSharing of the Room class is true from the moment enableScreenShare() shows the picker until the screen share ends, whether you end it, the user stops it from Control Center, iOS ends the broadcast, or the SDK cancels it because no broadcast started.

  • Use it to drive a single share button, instead of a flag of your own.

  • If the user closes the picker without starting the broadcast, isScreenSharing stays true until the SDK cancels the share, about 30 seconds after the picker appeared. With the button below, a tap in that time calls disableScreenShare(), and the next tap shows the picker again.

@IBAction func screenShareButtonTapped(_ sender: Any) {
Task {
do {
if self.room?.isScreenSharing == true {
try await self.room?.disableScreenShare()
} else {
try await self.room?.enableScreenShare()
}
} catch {
print("Screen share failed: \(error)")
}
}
}

Screen share quality​

  • By default, the screen is shared at 720p and 15 frames per second (.h720p_15fps). To choose another quality, pass a CustomScreenShareTrackConfig value to enableScreenShare(_:). It does not change the quality of the camera video.

  • The available values are .h360p_30fps, .h480p_15fps, .h480p_30fps, .h720p_5fps, .h720p_15fps, .h720p_30fps, .h1080p_15fps and .h1080p_30fps.

Task {
do {
// share the screen at 1080p and 15 frames per second
try await self.room?.enableScreenShare(.h1080p_15fps)
} catch {
print("Could not start screen share: \(error)")
}
}
  • To create the settings once and use them for every screen share, create a track with VideoSDK.createScreenShareVideoTrack(encoderConfig:multiStream:withAudio:) and pass it to enableScreenShare(_:). With multiStream: true, the screen share is sent in three quality layers. The default, false, sends one layer. withAudio is accepted and ignored: iOS shares no audio.
let screenShareTrack = VideoSDK.createScreenShareVideoTrack(encoderConfig: .h720p_30fps, multiStream: true)

Task {
do {
try await self.room?.enableScreenShare(screenShareTrack)
} catch {
print("Could not start screen share: \(error)")
}
}

Errors​

enableScreenShare() and disableScreenShare() throw a VideoSDKError when the call is refused:

  • ERROR_GET_DISPLAY_MEDIA (3013) when the app is not set up for screen sharing: Info.plist has no RTCScreenSharingExtension or RTCAppGroupIdentifier key, the app is not in that App Group, or there is no window to show the picker in. Check Steps 7 to 10 above.

  • ERROR_ALREADY_IN_REQUESTED_STATE (3054) when the screen share is already on (enableScreenShare()) or already off (disableScreenShare()).

  • ERROR_OPERATION_IN_PROGRESS (3055) when the previous broadcast is still stopping. Try again in a moment.

  • ERROR_ACTION_PERFORMED_BEFORE_ROOM_JOINED (3035) before you join the room, and ERROR_ROOM_RECONNECTING (3065) while the room is reconnecting.

  • ERROR_ACTION_NOT_SUPPORTED_IN_MODE (3066) from enableScreenShare() when the room is in RECV_ONLY or SIGNALLING_ONLY mode.

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