Add candidates negotiation
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) ?? ""
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -22,6 +22,7 @@ open class ReactNativeEventEmitter: RCTEventEmitter {
|
||||
case onSetScreenShareRemoteSDPCompleted = "onSetScreenShareRemoteSDPCompleted"
|
||||
case onScreenShareLocalIceCandidate = "onScreenShareLocalIceCandidate"
|
||||
case onScreenShareSignalingStateChange = "onScreenShareSignalingStateChange"
|
||||
case onAddScreenShareRemoteIceCandidateCompleted = "onAddScreenShareRemoteIceCandidateCompleted"
|
||||
}
|
||||
|
||||
override init() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
34
src/methods/addScreenShareRemoteIceCandidate.tsx
Normal file
34
src/methods/addScreenShareRemoteIceCandidate.tsx
Normal 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;
|
||||
@@ -13,3 +13,7 @@ export function createScreenShareOffer() {
|
||||
export function setScreenShareRemoteSDP(remoteSDP: string) {
|
||||
ScreenShareService.setScreenShareRemoteSDP(remoteSDP);
|
||||
}
|
||||
|
||||
export function addScreenShareRemoteIceCandidate(remoteCandidateJson: string) {
|
||||
ScreenShareService.addScreenShareRemoteIceCandidate(remoteCandidateJson);
|
||||
}
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user