From 6fce1d61f308ba024be4e01b575be4b2333fb06f Mon Sep 17 00:00:00 2001 From: Tiago Jacobs Date: Sun, 27 Mar 2022 15:05:47 -0300 Subject: [PATCH] Add setRemoteSDP method --- .../BigbluebuttonMobileSdkExample/Info.plist | 4 +++ .../Classes/BBBSampleHandler.swift | 27 ++++++++++++++-- .../Classes/ScreenBroadcaster.swift | 11 +++++++ ios-common/Classes/BBBSharedData.swift | 2 ++ ios-common/Classes/UserDefaults.swift | 10 ++++++ ios-common/Classes/WebRTCClient.swift | 30 ++++++++++------- ios/NativeOnly/BigBlueButtonSDK.swift | 6 ++++ .../ReactNativeEventEmitter.swift | 1 + ios/ReactExported/ScreenShareServiceManager.m | 1 + .../ScreenShareServiceManager.swift | 13 ++++++++ src/methods/setScreenShareRemoteSDP.tsx | 32 +++++++++++++++++++ .../BBBN_ScreenShareService.tsx | 4 +++ src/webview/message-handler.tsx | 4 +++ 13 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 src/methods/setScreenShareRemoteSDP.tsx 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}`; }