diff --git a/example/ios/BigbluebuttonMobileSdkExample/Info.plist b/example/ios/BigbluebuttonMobileSdkExample/Info.plist
index abe2966..bba9d48 100644
--- a/example/ios/BigbluebuttonMobileSdkExample/Info.plist
+++ b/example/ios/BigbluebuttonMobileSdkExample/Info.plist
@@ -24,6 +24,10 @@
1
LSRequiresIPhoneOS
+ NSMicrophoneUsageDescription
+ Needs microphone access for streaming your voice when you're joined in full audio mode
+ NSCameraUsageDescription
+ Needs camera access for streaming your camera when you're sharing it
NSAppTransportSecurity
NSAllowsArbitraryLoads
diff --git a/ios-broadcast-upload-extension/Classes/BBBSampleHandler.swift b/ios-broadcast-upload-extension/Classes/BBBSampleHandler.swift
index ea351fe..33706ef 100644
--- a/ios-broadcast-upload-extension/Classes/BBBSampleHandler.swift
+++ b/ios-broadcast-upload-extension/Classes/BBBSampleHandler.swift
@@ -12,7 +12,8 @@ open class BBBSampleHandler : RPBroadcastSampleHandler {
// Logger (these messages are displayed in the console application)
private var logger = os.Logger(subsystem: "BigBlueButtonMobileSDK", category: "BBBSampleHandler")
private var appGroupName:String = "";
- private var observer:NSKeyValueObservation?;
+ private var createOfferCallObserver:NSKeyValueObservation?;
+ private var setRemoteSDPCallObserver:NSKeyValueObservation?;
private var screenBroadcaster:ScreenBroadcaster?;
open func setAppGroupName(appGroupName:String) {
@@ -35,8 +36,8 @@ open class BBBSampleHandler : RPBroadcastSampleHandler {
self.screenBroadcaster = ScreenBroadcaster()
// Listen for createOffer requests from the UI APP
- logger.info("Configuring observer")
- self.observer = userDefaults.observe(\.createScreenShareOffer, options: [.new]) { (defaults, change) in
+ logger.info("Configuring observer for createOffer")
+ self.createOfferCallObserver = userDefaults.observe(\.createScreenShareOffer, options: [.new]) { (defaults, change) in
self.logger.info("Observer detected a createScreenShareOffer request!")
Task.init {
@@ -52,6 +53,26 @@ open class BBBSampleHandler : RPBroadcastSampleHandler {
}
}
}
+
+ logger.info("Configuring observer for setRemoteSDP")
+ self.setRemoteSDPCallObserver = userDefaults.observe(\.setScreenShareRemoteSDP, options: [.new]) { (defaults, change) in
+ let payload:String = (change.newValue!);
+ self.logger.info("Observer detected a setScreenShareRemoteSDP request with payload \(payload)")
+ let payloadData = payload.data(using: .utf8)!
+ let decodedPayload = (try? JSONDecoder().decode([String: String].self, from: payloadData))!
+ let sdp = decodedPayload["sdp"]
+
+ Task.init {
+ let remoteSDPDefined = await self.screenBroadcaster!.setRemoteSDP(remoteSDP: sdp!)
+
+ if(remoteSDPDefined){
+ self.logger.info("Remote SDP defined!")
+ BBBSharedData
+ .getUserDefaults(appGroupName: self.appGroupName)
+ .set(BBBSharedData.generatePayload(), forKey: BBBSharedData.SharedData.setScreenShareRemoteSDPCompleted)
+ }
+ }
+ }
}
open override func broadcastPaused() {
diff --git a/ios-broadcast-upload-extension/Classes/ScreenBroadcaster.swift b/ios-broadcast-upload-extension/Classes/ScreenBroadcaster.swift
index 689a391..09be567 100644
--- a/ios-broadcast-upload-extension/Classes/ScreenBroadcaster.swift
+++ b/ios-broadcast-upload-extension/Classes/ScreenBroadcaster.swift
@@ -29,4 +29,15 @@ open class ScreenBroadcaster {
}
}
+ public func setRemoteSDP(remoteSDP:String) async -> Bool {
+ do {
+ try await self.webRTCClient.setRemoteSDP(remoteSDP: remoteSDP)
+ return true
+ }
+ catch {
+ return false
+ }
+ }
+
+
}
diff --git a/ios-common/Classes/BBBSharedData.swift b/ios-common/Classes/BBBSharedData.swift
index eb95d4a..251968d 100644
--- a/ios-common/Classes/BBBSharedData.swift
+++ b/ios-common/Classes/BBBSharedData.swift
@@ -20,6 +20,8 @@ open class BBBSharedData {
public static let broadcastFinished = "broadcastFinished" // Broadcaster -> UI APP
public static let createScreenShareOffer = "createScreenShareOffer" // UI APP -> Broadcaster
public static let screenShareOfferCreated = "screenShareOfferCreated" // Broadcaster -> UI APP
+ public static let setScreenShareRemoteSDP = "setScreenShareRemoteSDP" // UI APP -> Broadcaster
+ public static let setScreenShareRemoteSDPCompleted = "setScreenShareRemoteSDPCompleted" // Broadcaster -> UI APP
}
// Get reference to userDefaults object (that's actually the object used to share information among UI APP and the BroadcastUploadExtension APP)
diff --git a/ios-common/Classes/UserDefaults.swift b/ios-common/Classes/UserDefaults.swift
index f89dd5f..d9464d6 100644
--- a/ios-common/Classes/UserDefaults.swift
+++ b/ios-common/Classes/UserDefaults.swift
@@ -34,5 +34,15 @@ extension UserDefaults {
@objc open dynamic var screenShareOfferCreated: String {
return string(forKey: BBBSharedData.SharedData.createScreenShareOffer) ?? ""
}
+
+ // UI APP -> Broadcaster
+ @objc open dynamic var setScreenShareRemoteSDP: String {
+ return string(forKey: BBBSharedData.SharedData.setScreenShareRemoteSDP) ?? ""
+ }
+
+ // Broadcaster -> UI APP
+ @objc open dynamic var setScreenShareRemoteSDPCompleted: String {
+ return string(forKey: BBBSharedData.SharedData.setScreenShareRemoteSDPCompleted) ?? ""
+ }
}
diff --git a/ios-common/Classes/WebRTCClient.swift b/ios-common/Classes/WebRTCClient.swift
index ec199cf..b31b6ed 100644
--- a/ios-common/Classes/WebRTCClient.swift
+++ b/ios-common/Classes/WebRTCClient.swift
@@ -7,6 +7,7 @@
import Foundation
import WebRTC
+import os
protocol WebRTCClientDelegate: AnyObject {
func webRTCClient(_ client: WebRTCClient, didDiscoverLocalCandidate candidate: RTCIceCandidate)
@@ -14,6 +15,7 @@ protocol WebRTCClientDelegate: AnyObject {
}
open class WebRTCClient: NSObject {
+ private var logger = os.Logger(subsystem: "BigBlueButtonMobileSDK", category: "WebRTCClient")
// The `RTCPeerConnectionFactory` is in charge of creating new RTCPeerConnection instances.
// A new RTCPeerConnection should be created every new call, but the factory is shared.
@@ -76,10 +78,16 @@ open class WebRTCClient: NSObject {
return sdp
}
- func set(remoteSdp: RTCSessionDescription, completion: @escaping (Error?) -> ()) {
- self.peerConnection.setRemoteDescription(remoteSdp, completionHandler: completion)
+ public func setRemoteSDP(remoteSDP: String) async {
+ do {
+ let rtcSessionDescription = RTCSessionDescription(type: RTCSdpType.answer, sdp: remoteSDP)
+ try await self.peerConnection.setRemoteDescription(rtcSessionDescription)
+ } catch {
+ self.logger.error("Error setting remote SDP")
+ }
}
+
func set(remoteCandidate: RTCIceCandidate, completion: @escaping (Error?) -> ()) {
self.peerConnection.add(remoteCandidate, completionHandler: completion)
}
@@ -138,41 +146,41 @@ open class WebRTCClient: NSObject {
extension WebRTCClient: RTCPeerConnectionDelegate {
public func peerConnection(_ peerConnection: RTCPeerConnection, didChange stateChanged: RTCSignalingState) {
- debugPrint("peerConnection new signaling state: \(stateChanged)")
+ self.logger.info("peerConnection new signaling state: \(stateChanged.rawValue)")
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didAdd stream: RTCMediaStream) {
- debugPrint("peerConnection did add stream \(stream)")
+ self.logger.info("peerConnection did add stream \(stream.streamId)")
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove stream: RTCMediaStream) {
- debugPrint("peerConnection did remove stream \(stream)")
+ self.logger.info("peerConnection did remove stream \(stream.streamId)")
}
public func peerConnectionShouldNegotiate(_ peerConnection: RTCPeerConnection) {
- debugPrint("peerConnection should negotiate")
+ self.logger.info("peerConnection should negotiate")
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCIceConnectionState) {
- debugPrint("peerConnection new connection state: \(newState)")
+ self.logger.info("peerConnection new connection state: \(newState.rawValue)")
self.delegate?.webRTCClient(self, didChangeConnectionState: newState)
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCIceGatheringState) {
- debugPrint("peerConnection new gathering state: \(newState)")
+ self.logger.info("peerConnection new gathering state: \(newState.rawValue)")
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didGenerate candidate: RTCIceCandidate) {
- debugPrint("peerConnection discovered new candidate")
+ self.logger.info("peerConnection discovered new candidate")
self.delegate?.webRTCClient(self, didDiscoverLocalCandidate: candidate)
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]) {
- debugPrint("peerConnection did remove candidate(s)")
+ self.logger.info("peerConnection did remove candidate(s)")
}
public func peerConnection(_ peerConnection: RTCPeerConnection, didOpen dataChannel: RTCDataChannel) {
- debugPrint("peerConnection did open data channel")
+ self.logger.info("peerConnection did open data channel")
}
}
diff --git a/ios/NativeOnly/BigBlueButtonSDK.swift b/ios/NativeOnly/BigBlueButtonSDK.swift
index c8c8c33..bbd9d71 100644
--- a/ios/NativeOnly/BigBlueButtonSDK.swift
+++ b/ios/NativeOnly/BigBlueButtonSDK.swift
@@ -17,6 +17,7 @@ open class BigBlueButtonSDK: NSObject {
private static var userDefaults:UserDefaults?
private static var observer1: NSKeyValueObservation?
private static var observer2: NSKeyValueObservation?
+ private static var observer3: NSKeyValueObservation?
public static func initialize(broadcastExtensionBundleId:String, appGroupName:String) {
self.broadcastExtensionBundleId = broadcastExtensionBundleId
@@ -44,6 +45,11 @@ open class BigBlueButtonSDK: NSObject {
ReactNativeEventEmitter.emitter.sendEvent(withName: ReactNativeEventEmitter.EVENT.onScreenShareOfferCreated.rawValue, body: sdp)
}
+ //setScreenShareRemoteSDPCompleted
+ observer3 = userDefaults?.observe(\.setScreenShareRemoteSDPCompleted, options: [.new]) { (defaults, change) in
+ logger.info("Detected a change in userDefaults for key setScreenShareRemoteSDPCompleted")
+ ReactNativeEventEmitter.emitter.sendEvent(withName: ReactNativeEventEmitter.EVENT.onSetScreenShareRemoteSDPCompleted.rawValue, body: nil)
+ }
}
public static func getBroadcastExtensionBundleId() -> String {
diff --git a/ios/ReactExported/ReactNativeEventEmitter.swift b/ios/ReactExported/ReactNativeEventEmitter.swift
index 7084e34..faff596 100644
--- a/ios/ReactExported/ReactNativeEventEmitter.swift
+++ b/ios/ReactExported/ReactNativeEventEmitter.swift
@@ -19,6 +19,7 @@ open class ReactNativeEventEmitter: RCTEventEmitter {
case onBroadcastResumed = "onBroadcastResumed"
case onBroadcastFinished = "onBroadcastFinished"
case onScreenShareOfferCreated = "onScreenShareOfferCreated"
+ case onSetScreenShareRemoteSDPCompleted = "onSetScreenShareRemoteSDPCompleted"
}
override init() {
diff --git a/ios/ReactExported/ScreenShareServiceManager.m b/ios/ReactExported/ScreenShareServiceManager.m
index d005e89..b98c1b8 100644
--- a/ios/ReactExported/ScreenShareServiceManager.m
+++ b/ios/ReactExported/ScreenShareServiceManager.m
@@ -11,4 +11,5 @@
RCT_EXTERN_METHOD(initializeScreenShare)
RCT_EXTERN_METHOD(createScreenShareOffer)
+RCT_EXTERN_METHOD(setScreenShareRemoteSDP: (NSString *)remoteSDP)
@end
diff --git a/ios/ReactExported/ScreenShareServiceManager.swift b/ios/ReactExported/ScreenShareServiceManager.swift
index 1075112..5406527 100644
--- a/ios/ReactExported/ScreenShareServiceManager.swift
+++ b/ios/ReactExported/ScreenShareServiceManager.swift
@@ -39,4 +39,17 @@ class ScreenShareServiceManager: NSObject {
}
+
+ @objc func setScreenShareRemoteSDP(_ remoteSDP:String) -> Void {
+ logger.info("setScreenShareRemoteSDP call arrived on swift: \(remoteSDP)")
+ // Send request of "set remote SDP" to broadcast upload extension
+ // TIP - the handling of this method response is done in observer3 of BigBlueButtonSDK class
+ logger.info("setScreenShareRemoteSDP - persisting information on UserDefaults")
+ BBBSharedData
+ .getUserDefaults(appGroupName: BigBlueButtonSDK.getAppGroupName())
+ .set(BBBSharedData.generatePayload(properties: [
+ "sdp": remoteSDP
+ ]), forKey: BBBSharedData.SharedData.setScreenShareRemoteSDP)
+
+ }
}
diff --git a/src/methods/setScreenShareRemoteSDP.tsx b/src/methods/setScreenShareRemoteSDP.tsx
new file mode 100644
index 0000000..706fc13
--- /dev/null
+++ b/src/methods/setScreenShareRemoteSDP.tsx
@@ -0,0 +1,32 @@
+import { setScreenShareRemoteSDP as nativeSetScreenShareRemoteSDP } from '../native-components/BBBN_ScreenShareService';
+import nativeEmitter from '../native-messaging/emitter';
+
+// Reference to the resolver of last call
+let resolve = (value: unknown) => {
+ console.log(
+ `default resolve function called, this should never happen: ${value}`
+ );
+};
+
+// Resolve promise when SDP offer is available
+nativeEmitter.addListener('onSetScreenShareRemoteSDPCompleted', () => {
+ resolve(undefined);
+});
+
+// Entry point of this method
+function setScreenShareRemoteSDP(remoteSdp: string) {
+ return new Promise((res, rej) => {
+ // store the resolver for later call (when event is received)
+ resolve = res;
+
+ try {
+ console.log(`>nativeSetScreenShareRemoteSDP ${remoteSdp}`);
+ // call native swift method that triggers the broadcast popup
+ nativeSetScreenShareRemoteSDP(remoteSdp);
+ } catch (e) {
+ rej(`Call to nativeSetScreenShareRemoteSDP failed`);
+ }
+ });
+}
+
+export default setScreenShareRemoteSDP;
diff --git a/src/native-components/BBBN_ScreenShareService.tsx b/src/native-components/BBBN_ScreenShareService.tsx
index 571690f..62fd8fd 100644
--- a/src/native-components/BBBN_ScreenShareService.tsx
+++ b/src/native-components/BBBN_ScreenShareService.tsx
@@ -9,3 +9,7 @@ export function initializeScreenShare() {
export function createScreenShareOffer() {
ScreenShareService.createScreenShareOffer();
}
+
+export function setScreenShareRemoteSDP(remoteSDP: string) {
+ ScreenShareService.setScreenShareRemoteSDP(remoteSDP);
+}
diff --git a/src/webview/message-handler.tsx b/src/webview/message-handler.tsx
index 4225e04..63de7d0 100644
--- a/src/webview/message-handler.tsx
+++ b/src/webview/message-handler.tsx
@@ -2,6 +2,7 @@ import type { MutableRefObject } from 'react';
import type { WebView, WebViewMessageEvent } from 'react-native-webview';
import initializeScreenShare from '../methods/initializeScreenShare';
import createScreenShareOffer from '../methods/createScreenShareOffer';
+import setScreenShareRemoteSDP from '../methods/setScreenShareRemoteSDP';
function observePromiseResult(
webViewRef: MutableRefObject,
@@ -43,6 +44,9 @@ export function handleWebviewMessage(
case 'createOffer':
promise = createScreenShareOffer();
break;
+ case 'setRemoteDescription':
+ promise = setScreenShareRemoteSDP(data?.arguments[0].sdp);
+ break;
default:
throw `Unknown method ${data?.method}`;
}