Add message flow for createScreenShareOffer

This commit is contained in:
Tiago Jacobs
2022-03-18 16:39:14 -03:00
parent 9c4d341d42
commit 56b3b5f747
11 changed files with 138 additions and 18 deletions

View File

@@ -11,18 +11,35 @@ 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?;
open func setAppGroupName(appGroupName:String) {
self.appGroupName = appGroupName;
logger.info("Received appGroupName: \(appGroupName)")
self.appGroupName = appGroupName
}
// Called by IOS when the user authorized to start the broadcast
open override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
logger.info("ReplayKit2 event - broadcastStarted")
logger.info("ReplayKit2 event - broadcastStarted - persisting information on UserDefaults")
BBBSharedData
// Object used to share data
let userDefaults = BBBSharedData
.getUserDefaults(appGroupName: self.appGroupName)
.set(BBBSharedData.generatePayload(), forKey: BBBSharedData.SharedData.broadcastStarted)
// Notify the UI app that the broadcast has been started
logger.info("ReplayKit2 event - broadcastStarted - persisting information on UserDefaults")
userDefaults.set(BBBSharedData.generatePayload(), forKey: BBBSharedData.SharedData.broadcastStarted)
// Listen for createOffer requests from the UI APP
logger.info("Configuring observer")
self.observer = userDefaults.observe(\.createScreenShareOffer, options: [.new]) { (defaults, change) in
self.logger.info("Observer detected a createScreenShareOffer request!")
BBBSharedData
.getUserDefaults(appGroupName: self.appGroupName)
.set(BBBSharedData.generatePayload(properties: [
"sdp": "this is SDP from extension"
]), forKey: BBBSharedData.SharedData.screenShareOfferCreated)
}
}
open override func broadcastPaused() {

View File

@@ -14,12 +14,15 @@ open class BBBSharedData {
private static var userDefaultsGroup:String?
public enum SharedData {
public static let broadcastStarted = "broadcastStarted"
public static let broadcastPaused = "broadcastPaused"
public static let broadcastResumed = "broadcastResumed"
public static let broadcastFinished = "broadcastFinished"
public static let broadcastStarted = "broadcastStarted" // Broadcaster -> UI APP
public static let broadcastPaused = "broadcastPaused" // Broadcaster -> UI APP
public static let broadcastResumed = "broadcastResumed" // Broadcaster -> UI APP
public static let broadcastFinished = "broadcastFinished" // Broadcaster -> UI APP
public static let createScreenShareOffer = "createScreenShareOffer" // UI APP -> Broadcaster
public static let screenShareOfferCreated = "screenShareOfferCreated" // Broadcaster -> UI APP
}
// Get reference to userDefaults object (that's actually the object used to share information among UI APP and the BroadcastUploadExtension APP)
public static func getUserDefaults(appGroupName:String) -> UserDefaults {
if(userDefaults == nil || userDefaultsGroup == nil || userDefaultsGroup != appGroupName) {
logger.info("getUserDefaults \(appGroupName) -> Created")
@@ -33,10 +36,22 @@ open class BBBSharedData {
}
// Generates a unique payload
public static func generatePayload() -> String {
// TODO - replace by UUID
public static func generatePayload(properties:Dictionary<String,String> = [:]) -> String {
let now=String(DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .short));
return "{\"timestamp\": \(now)}";
var payload = properties;
payload["uuid"] = UUID().uuidString;
payload["timestamp"] = now;
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(payload) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
print("JSON = \(jsonString)")
return jsonString
}
}
logger.error("JSON encoder error, returning empty object")
return "{}";
}
}

View File

@@ -5,21 +5,34 @@
//
extension UserDefaults {
// Broadcaster -> UI APP
@objc open dynamic var broadcastStarted: String {
return string(forKey: BBBSharedData.SharedData.broadcastStarted) ?? ""
}
// Broadcaster -> UI APP
@objc open dynamic var broadcastPaused: String {
return string(forKey: BBBSharedData.SharedData.broadcastPaused) ?? ""
}
// Broadcaster -> UI APP
@objc open dynamic var broadcastResumed: String {
return string(forKey: BBBSharedData.SharedData.broadcastResumed) ?? ""
}
// Broadcaster -> UI APP
@objc open dynamic var broadcastFinished: String {
return string(forKey: BBBSharedData.SharedData.broadcastFinished) ?? ""
}
// UI APP -> Broadcaster
@objc open dynamic var createScreenShareOffer: String {
return string(forKey: BBBSharedData.SharedData.createScreenShareOffer) ?? ""
}
// Broadcaster -> UI APP
@objc open dynamic var screenShareOfferCreated: String {
return string(forKey: BBBSharedData.SharedData.createScreenShareOffer) ?? ""
}
}

View File

@@ -15,7 +15,8 @@ open class BigBlueButtonSDK: NSObject {
private static var broadcastExtensionBundleId = ""
private static var appGroupName = ""
private static var userDefaults:UserDefaults?
private static var observer: NSKeyValueObservation?
private static var observer1: NSKeyValueObservation?
private static var observer2: NSKeyValueObservation?
public static func initialize(broadcastExtensionBundleId:String, appGroupName:String) {
self.broadcastExtensionBundleId = broadcastExtensionBundleId
@@ -26,10 +27,22 @@ open class BigBlueButtonSDK: NSObject {
// Observe keys modified by BroadcastUploadExtension and emit this event to react native
//broadcastStarted
observer = userDefaults?.observe(\.broadcastStarted, options: [.new]) { (defaults, change) in
observer1 = userDefaults?.observe(\.broadcastStarted, options: [.new]) { (defaults, change) in
logger.info("Detected a change in userDefaults for key broadcastStarted")
ReactNativeEventEmitter.emitter.sendEvent(withName: ReactNativeEventEmitter.EVENT.onBroadcastStarted.rawValue, body: nil)
}
//screenShareOfferCreated
observer2 = userDefaults?.observe(\.screenShareOfferCreated, options: [.new]) { (defaults, change) in
let payload:String = (change.newValue!);
logger.info("Detected a change in userDefaults for key screenShareOfferCreated \(payload)")
let payloadData = payload.data(using: .utf8)!
let decodedPayload = (try? JSONDecoder().decode([String: String].self, from: payloadData))!
let sdp = decodedPayload["sdp"]
ReactNativeEventEmitter.emitter.sendEvent(withName: ReactNativeEventEmitter.EVENT.onScreenShareOfferCreated.rawValue, body: sdp)
}
}
@@ -37,8 +50,13 @@ open class BigBlueButtonSDK: NSObject {
return self.broadcastExtensionBundleId;
}
public static func getAppGroupName() -> String {
return self.appGroupName;
}
public static func deinitialize () {
observer?.invalidate()
observer1?.invalidate()
observer2?.invalidate()
}
}

View File

@@ -18,6 +18,7 @@ open class ReactNativeEventEmitter: RCTEventEmitter {
case onBroadcastPaused = "onBroadcastPaused"
case onBroadcastResumed = "onBroadcastResumed"
case onBroadcastFinished = "onBroadcastFinished"
case onScreenShareOfferCreated = "onScreenShareOfferCreated"
}
override init() {

View File

@@ -10,4 +10,5 @@
@interface RCT_EXTERN_REMAP_MODULE(BBBN_ScreenShareService, ScreenShareServiceManager, NSObject)
RCT_EXTERN_METHOD(initializeScreenShare)
RCT_EXTERN_METHOD(createScreenShareOffer)
@end

View File

@@ -6,6 +6,7 @@
import Foundation
import os
import bigbluebutton_mobile_sdk_common
@objc(ScreenShareServiceManager)
class ScreenShareServiceManager: NSObject {
@@ -25,4 +26,17 @@ class ScreenShareServiceManager: NSObject {
ReactNativeEventEmitter.emitter.sendEvent(withName: eventName, body: nil);
}
// React native exposed method (called when user click the button to share screen)
@objc func createScreenShareOffer() -> Void {
logger.info("createScreenShareOffer")
// Send request of SDP to the broadcast upload extension
// TIP - the handling of SDP response is done in observer2 of BigBlueButtonSDK class
logger.info("createScreenShareOffer - persisting information on UserDefaults")
BBBSharedData
.getUserDefaults(appGroupName: BigBlueButtonSDK.getAppGroupName())
.set(BBBSharedData.generatePayload(), forKey: BBBSharedData.SharedData.createScreenShareOffer)
}
}

View File

@@ -0,0 +1,32 @@
import { createScreenShareOffer as nativeCreateScreenShareOffer } from '../native-components/BBBN_ScreenShareService';
import nativeEmitter from '../native-messaging/emitter';
// Reference to the resolver of last call
let resolve = (a: String) => {
console.log(
`default resolve function called, this should never happen: ${a}`
);
};
// Resolve promise when SDP offer is available
nativeEmitter.addListener('onScreenShareOfferCreated', (sdp) => {
resolve(sdp);
});
// Entry point of this method
function createScreenShareOffer() {
return new Promise((res, rej) => {
// store the resolver for later call (when event is received)
resolve = res;
try {
console.log(`>nativeCreateScreenShareOffer`);
// call native swift method that triggers the broadcast popup
nativeCreateScreenShareOffer();
} catch (e) {
rej(`Call to nativeCreateScreenShareOffer failed`);
}
});
}
export default createScreenShareOffer;

View File

@@ -2,7 +2,7 @@ import { initializeScreenShare as nativeInitializeScreenShare } from '../native-
import nativeEmitter from '../native-messaging/emitter';
// Reference to the resolver of last call
let resolve = (a: String) => {
let resolve = (a: String | null) => {
console.log(
`default resolve function called, this should never happen: ${a}`
);
@@ -15,7 +15,7 @@ nativeEmitter.addListener('onBroadcastRequested', () => {
// Resolve promise when broadcast is started (this event means that user confirmed the screenshare)
nativeEmitter.addListener('onBroadcastStarted', () => {
resolve('null');
resolve(null);
});
// Entry point of this method
@@ -26,9 +26,10 @@ function initializeScreenShare() {
try {
// call native swift method that triggers the broadcast popup
console.log(`>nativeInitializeScreenShare`);
nativeInitializeScreenShare();
} catch (e) {
rej(`Call to nativeInitializeScreenShare failed`);
rej(`Call to nativeInitializeScreenShare failed zzy`);
}
});
}

View File

@@ -5,3 +5,7 @@ const ScreenShareService = NativeModules.BBBN_ScreenShareService;
export function initializeScreenShare() {
ScreenShareService.initializeScreenShare();
}
export function createScreenShareOffer() {
ScreenShareService.createScreenShareOffer();
}

View File

@@ -1,6 +1,7 @@
import type { MutableRefObject } from 'react';
import type { WebView, WebViewMessageEvent } from 'react-native-webview';
import initializeScreenShare from '../methods/initializeScreenShare';
import createScreenShareOffer from '../methods/createScreenShareOffer';
function observePromiseResult(
webViewRef: MutableRefObject<WebView>,
@@ -39,6 +40,9 @@ export function handleWebviewMessage(
case 'initializeScreenShare':
promise = initializeScreenShare();
break;
case 'createOffer':
promise = createScreenShareOffer();
break;
default:
throw `Unknown method ${data?.method}`;
}