Add candidates negotiation

This commit is contained in:
Tiago Jacobs
2022-03-29 14:57:03 -03:00
parent 184fb8a190
commit 7036a276ed
12 changed files with 130 additions and 8 deletions

View File

@@ -14,6 +14,7 @@ open class BBBSampleHandler : RPBroadcastSampleHandler {
private var appGroupName:String = "";
private var createOfferCallObserver:NSKeyValueObservation?;
private var setRemoteSDPCallObserver:NSKeyValueObservation?;
private var addScreenShareRemoteIceCandidateObserver:NSKeyValueObservation?;
private var screenBroadcaster:ScreenBroadcaster?;
open func setAppGroupName(appGroupName:String) {
@@ -57,7 +58,8 @@ 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)")
// self.logger.info("Observer detected a setScreenShareRemoteSDP request with payload \(payload)")
self.logger.info("Observer detected a setScreenShareRemoteSDP request")
let payloadData = payload.data(using: .utf8)!
let decodedPayload = (try? JSONDecoder().decode([String: String].self, from: payloadData))!
let sdp = decodedPayload["sdp"]
@@ -73,6 +75,29 @@ open class BBBSampleHandler : RPBroadcastSampleHandler {
}
}
}
logger.info("Configuring observer for addScreenShareRemoteIceCandidate")
self.addScreenShareRemoteIceCandidateObserver = userDefaults.observe(\.addScreenShareRemoteIceCandidate, options: [.new]) { (defaults, change) in
let payload:String = (change.newValue!);
// self.logger.info("Observer detected a addScreenShareRemoteIceCandidate request with payload \(payload)")
self.logger.info("Observer detected a addScreenShareRemoteIceCandidate request")
let payloadData = payload.data(using: .utf8)!
let decodedPayload = (try? JSONDecoder().decode([String: String].self, from: payloadData))!
let candidateAsString = decodedPayload["candidate"]!
let candidateAsData = candidateAsString.data(using: .utf8)!
let candidate = (try? JSONDecoder().decode(IceCandidate.self, from: candidateAsData))
Task.init {
let remoteCandidateAdded = await self.screenBroadcaster!.addRemoteCandidate(remoteCandidate: candidate!)
if(remoteCandidateAdded){
self.logger.info("Remote candidate added!")
BBBSharedData
.getUserDefaults(appGroupName: self.appGroupName)
.set(BBBSharedData.generatePayload(), forKey: BBBSharedData.SharedData.addScreenShareRemoteIceCandidateCompleted)
}
}
}
}
open override func broadcastPaused() {

View File

@@ -44,6 +44,17 @@ open class ScreenBroadcaster {
return false
}
}
public func addRemoteCandidate(remoteCandidate:IceCandidate) async -> Bool {
do {
try await self.webRTCClient.setRemoteCandidate(remoteIceCandidate: remoteCandidate)
return true
}
catch {
return false
}
}
}
extension ScreenBroadcaster: WebRTCClientDelegate {

View File

@@ -25,9 +25,13 @@ open class BBBSharedData {
public static let setScreenShareRemoteSDP = "setScreenShareRemoteSDP" // UI APP -> Broadcaster
public static let setScreenShareRemoteSDPCompleted = "setScreenShareRemoteSDPCompleted" // Broadcaster -> UI APP
public static let addScreenShareRemoteIceCandidate = "addScreenShareRemoteIceCandidate" // UI APP -> Broadcaster
public static let addScreenShareRemoteIceCandidateCompleted = "addScreenShareRemoteIceCandidateCompleted" // Broadcaster -> UI APP
public static let onScreenShareLocalIceCandidate = "onScreenShareLocalIceCandidate" // Broadcaster -> UI APP
public static let onScreenShareSignalingStateChange = "onScreenShareSignalingStateChange" // Broadcaster -> UI APP
}
// Get reference to userDefaults object (that's actually the object used to share information among UI APP and the BroadcastUploadExtension APP)

View File

@@ -45,6 +45,16 @@ extension UserDefaults {
return string(forKey: BBBSharedData.SharedData.setScreenShareRemoteSDPCompleted) ?? ""
}
// UI APP -> Broadcaster
@objc open dynamic var addScreenShareRemoteIceCandidate: String {
return string(forKey: BBBSharedData.SharedData.addScreenShareRemoteIceCandidate) ?? ""
}
// Broadcaster -> UI APP
@objc open dynamic var addScreenShareRemoteIceCandidateCompleted: String {
return string(forKey: BBBSharedData.SharedData.addScreenShareRemoteIceCandidateCompleted) ?? ""
}
// Broadcaster -> UI APP
@objc open dynamic var onScreenShareLocalIceCandidate: String {
return string(forKey: BBBSharedData.SharedData.onScreenShareLocalIceCandidate) ?? ""

View File

@@ -66,7 +66,7 @@ open class WebRTCClient: NSObject {
self.peerConnection = peerConnection
super.init()
// createMediaSenders()
createMediaSenders()
// configureAudioSession()
self.peerConnection.delegate = self
}
@@ -85,6 +85,10 @@ open class WebRTCClient: NSObject {
try await self.peerConnection.setRemoteDescription(rtcSessionDescription)
}
public func setRemoteCandidate(remoteIceCandidate: IceCandidate) async throws {
let rtcRemoteCandidate = RTCIceCandidate(sdp: remoteIceCandidate.candidate, sdpMLineIndex: remoteIceCandidate.sdpMLineIndex, sdpMid: remoteIceCandidate.sdpMid)
try await self.peerConnection.add(rtcRemoteCandidate)
}
func set(remoteCandidate: RTCIceCandidate, completion: @escaping (Error?) -> ()) {
self.peerConnection.add(remoteCandidate, completionHandler: completion)
@@ -109,18 +113,18 @@ open class WebRTCClient: NSObject {
self.rtcAudioSession.unlockForConfiguration()
}*/
/*private func createMediaSenders() {
private func createMediaSenders() {
let streamId = "stream"
// Audio
let audioTrack = self.createAudioTrack()
self.peerConnection.add(audioTrack, streamIds: [streamId])
// let audioTrack = self.createAudioTrack()
// self.peerConnection.add(audioTrack, streamIds: [streamId])
// Video
let videoTrack = self.createVideoTrack()
self.localVideoTrack = videoTrack
self.peerConnection.add(videoTrack, streamIds: [streamId])
}*/
}
/*private func createAudioTrack() -> RTCAudioTrack {
let audioConstrains = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil)
@@ -129,14 +133,14 @@ open class WebRTCClient: NSObject {
return audioTrack
}*/
/*private func createVideoTrack() -> RTCVideoTrack {
private func createVideoTrack() -> RTCVideoTrack {
videoSource = WebRTCClient.factory.videoSource(forScreenCast: true)
videoCapturer = RTCVideoCapturer(delegate: videoSource!)
videoSource!.adaptOutputFormat(toWidth: 600, height: 800, fps: 15)
let videoTrack = WebRTCClient.factory.videoTrack(with: videoSource!, trackId: "video0")
videoTrack.isEnabled = true
return videoTrack
}*/
}
}
// MARK: RTCPeerConnectionDelegate Methods

View File

@@ -20,6 +20,7 @@ open class BigBlueButtonSDK: NSObject {
private static var observer3: NSKeyValueObservation?
private static var observer4: NSKeyValueObservation?
private static var observer5: NSKeyValueObservation?
private static var observer6: NSKeyValueObservation?
public static func initialize(broadcastExtensionBundleId:String, appGroupName:String) {
self.broadcastExtensionBundleId = broadcastExtensionBundleId
@@ -77,6 +78,12 @@ open class BigBlueButtonSDK: NSObject {
ReactNativeEventEmitter.emitter.sendEvent(withName: ReactNativeEventEmitter.EVENT.onScreenShareSignalingStateChange.rawValue, body: newState)
}
//addScreenShareRemoteIceCandidateCompleted
observer6 = userDefaults?.observe(\.addScreenShareRemoteIceCandidateCompleted, options: [.new]) { (defaults, change) in
logger.info("Detected a change in userDefaults for key addScreenShareRemoteIceCandidateCompleted")
ReactNativeEventEmitter.emitter.sendEvent(withName: ReactNativeEventEmitter.EVENT.onAddScreenShareRemoteIceCandidateCompleted.rawValue, body: nil)
}
}
public static func getBroadcastExtensionBundleId() -> String {

View File

@@ -22,6 +22,7 @@ open class ReactNativeEventEmitter: RCTEventEmitter {
case onSetScreenShareRemoteSDPCompleted = "onSetScreenShareRemoteSDPCompleted"
case onScreenShareLocalIceCandidate = "onScreenShareLocalIceCandidate"
case onScreenShareSignalingStateChange = "onScreenShareSignalingStateChange"
case onAddScreenShareRemoteIceCandidateCompleted = "onAddScreenShareRemoteIceCandidateCompleted"
}
override init() {

View File

@@ -12,4 +12,5 @@
RCT_EXTERN_METHOD(initializeScreenShare)
RCT_EXTERN_METHOD(createScreenShareOffer)
RCT_EXTERN_METHOD(setScreenShareRemoteSDP: (NSString *)remoteSDP)
RCT_EXTERN_METHOD(addScreenShareRemoteIceCandidate: (NSString *)remoteCandidate)
@end

View File

@@ -52,4 +52,19 @@ class ScreenShareServiceManager: NSObject {
]), forKey: BBBSharedData.SharedData.setScreenShareRemoteSDP)
}
@objc func addScreenShareRemoteIceCandidate(_ remoteCandidate:String) -> Void {
logger.info("addScreenShareRemoteIceCandidate call arrived on swift: \(remoteCandidate)")
// Send request of "add remote ICE candidate" to broadcast upload extension
// TIP - the handling of this method response is done in observer6 of BigBlueButtonSDK class
logger.info("addScreenShareRemoteIceCandidate - persisting information on UserDefaults")
BBBSharedData
.getUserDefaults(appGroupName: BigBlueButtonSDK.getAppGroupName())
.set(BBBSharedData.generatePayload(properties: [
"candidate": remoteCandidate
]), forKey: BBBSharedData.SharedData.addScreenShareRemoteIceCandidate)
}
}

View File

@@ -0,0 +1,34 @@
import { addScreenShareRemoteIceCandidate as nativeAddScreenShareRemoteIceCandidate } 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('onAddScreenShareRemoteIceCandidateCompleted', () => {
resolve(undefined);
});
// Entry point of this method
function addScreenShareRemoteIceCandidate(remoteCandidateJson: string) {
return new Promise((res, rej) => {
// store the resolver for later call (when event is received)
resolve = res;
try {
console.log(
`>nativeAddScreenShareRemoteIceCandidate ${remoteCandidateJson}`
);
// call native swift method that triggers the broadcast popup
nativeAddScreenShareRemoteIceCandidate(remoteCandidateJson);
} catch (e) {
rej(`Call to nativeAddScreenShareRemoteIceCandidate failed`);
}
});
}
export default addScreenShareRemoteIceCandidate;

View File

@@ -13,3 +13,7 @@ export function createScreenShareOffer() {
export function setScreenShareRemoteSDP(remoteSDP: string) {
ScreenShareService.setScreenShareRemoteSDP(remoteSDP);
}
export function addScreenShareRemoteIceCandidate(remoteCandidateJson: string) {
ScreenShareService.addScreenShareRemoteIceCandidate(remoteCandidateJson);
}

View File

@@ -3,6 +3,7 @@ import type { WebView, WebViewMessageEvent } from 'react-native-webview';
import initializeScreenShare from '../methods/initializeScreenShare';
import createScreenShareOffer from '../methods/createScreenShareOffer';
import setScreenShareRemoteSDP from '../methods/setScreenShareRemoteSDP';
import addScreenShareRemoteIceCandidate from '../methods/addScreenShareRemoteIceCandidate';
function observePromiseResult(
webViewRef: MutableRefObject<WebView>,
@@ -47,6 +48,11 @@ export function handleWebviewMessage(
case 'setRemoteDescription':
promise = setScreenShareRemoteSDP(data?.arguments[0].sdp);
break;
case 'addRemoteIceCandidate':
promise = addScreenShareRemoteIceCandidate(
JSON.stringify(data?.arguments[0])
);
break;
default:
throw `Unknown method ${data?.method}`;
}