Merge branch 'main' into finish_broadcast_when_quit_application

This commit is contained in:
Tiago Jacobs 2022-05-16 19:21:50 -03:00 committed by GitHub
commit 4f3aff1296
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 670 additions and 328 deletions

1
.gitignore vendored
View File

@ -95,3 +95,4 @@ Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
/package-lock.json

View File

@ -1,12 +1,12 @@
PODS: PODS:
- bigbluebutton-mobile-sdk (0.1.16): - bigbluebutton-mobile-sdk (0.1.18):
- bigbluebutton-mobile-sdk-common - bigbluebutton-mobile-sdk-common
- React-Core - React-Core
- WebRTC-lib - WebRTC-lib
- bigbluebutton-mobile-sdk-broadcast-upload-extension (0.1.16): - bigbluebutton-mobile-sdk-broadcast-upload-extension (0.1.18):
- bigbluebutton-mobile-sdk-common - bigbluebutton-mobile-sdk-common
- WebRTC-lib - WebRTC-lib
- bigbluebutton-mobile-sdk-common (0.1.16): - bigbluebutton-mobile-sdk-common (0.1.18):
- WebRTC-lib - WebRTC-lib
- boost-for-react-native (1.63.0) - boost-for-react-native (1.63.0)
- DoubleConversion (1.1.6) - DoubleConversion (1.1.6)
@ -361,9 +361,9 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga" :path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS: SPEC CHECKSUMS:
bigbluebutton-mobile-sdk: c22205a921c38e43d5c5ec2c8f47d890db5e189e bigbluebutton-mobile-sdk: 9bf75ac3644dba36c7f696218a08d132bb10d847
bigbluebutton-mobile-sdk-broadcast-upload-extension: 755c8bb697a1a45855ad44b6b0ad95a62cc978d7 bigbluebutton-mobile-sdk-broadcast-upload-extension: 36b8ba6058fab3e37b1f002c285a501647dd2c64
bigbluebutton-mobile-sdk-common: 287c9acc965d00e72d71a0d2b020fa8e483e7a11 bigbluebutton-mobile-sdk-common: ff6095f82f81817271f7dede86b5d5356b6311e8
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
DoubleConversion: cde416483dac037923206447da6e1454df403714 DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
@ -396,4 +396,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 1cef60f4fb4cef93dc6de3cb3b53463e5f48a9bc PODFILE CHECKSUM: 1cef60f4fb4cef93dc6de3cb3b53463e5f48a9bc
COCOAPODS: 1.11.3 COCOAPODS: 1.11.2

View File

@ -39,6 +39,8 @@ open class AudioWebRTCClient: NSObject {
private var localVideoTrack: RTCVideoTrack? private var localVideoTrack: RTCVideoTrack?
private var isRatioDefined:Bool=false private var isRatioDefined:Bool=false
private var isActiveObserver1:NSKeyValueObservation?
@available(*, unavailable) @available(*, unavailable)
override init() { override init() {
fatalError("WebRTCClient:init is unavailable") fatalError("WebRTCClient:init is unavailable")
@ -105,6 +107,7 @@ open class AudioWebRTCClient: NSObject {
private func configureAudioSession() { private func configureAudioSession() {
self.rtcAudioSession.lockForConfiguration() self.rtcAudioSession.lockForConfiguration()
do { do {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue) try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue)
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue) try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
@ -112,6 +115,13 @@ open class AudioWebRTCClient: NSObject {
debugPrint("Error changing AVAudioSession category: \(error)") debugPrint("Error changing AVAudioSession category: \(error)")
} }
self.rtcAudioSession.unlockForConfiguration() self.rtcAudioSession.unlockForConfiguration()
self.isActiveObserver1 = self.rtcAudioSession.observe(\.isActive, options: [.new]) { (defaults, change) in
if(!self.rtcAudioSession.isActive) {
self.logger.info("isActive changed to false, restoring it");
self.restoreAudioSession()
}
}
} }
private func createMediaSenders() { private func createMediaSenders() {
@ -232,6 +242,7 @@ extension AudioWebRTCClient {
self.rtcAudioSession.lockForConfiguration() self.rtcAudioSession.lockForConfiguration()
do { do {
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue) try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue)
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
try self.rtcAudioSession.overrideOutputAudioPort(.none) try self.rtcAudioSession.overrideOutputAudioPort(.none)
} catch let error { } catch let error {
debugPrint("Error setting AVAudioSession category: \(error)") debugPrint("Error setting AVAudioSession category: \(error)")
@ -259,6 +270,22 @@ extension AudioWebRTCClient {
} }
} }
public func restoreAudioSession() {
self.audioQueue.async { [weak self] in
guard let self = self else {
return
}
do {
self.rtcAudioSession.lockForConfiguration()
try RTCAudioSession.sharedInstance().setActive(true)
self.rtcAudioSession.unlockForConfiguration()
} catch let error {
debugPrint("Couldn't restore isActive: \(error)")
}
}
}
private func setAudioEnabled(_ isEnabled: Bool) { private func setAudioEnabled(_ isEnabled: Bool) {
setTrackEnabled(RTCAudioTrack.self, isEnabled: isEnabled) setTrackEnabled(RTCAudioTrack.self, isEnabled: isEnabled)
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "bigbluebutton-mobile-sdk", "name": "bigbluebutton-mobile-sdk",
"version": "0.1.16", "version": "0.1.18",
"description": "This repository contains BigBlueButton react-native component, that's used in our [sample implementation](https://github.com/bigbluebutton/bigbluebutton-mobile).", "description": "This repository contains BigBlueButton react-native component, that's used in our [sample implementation](https://github.com/bigbluebutton/bigbluebutton-mobile).",
"main": "lib/commonjs/index", "main": "lib/commonjs/index",
"module": "lib/module/index", "module": "lib/module/index",
@ -63,8 +63,8 @@
"jest": "^26.0.1", "jest": "^26.0.1",
"pod-install": "^0.1.0", "pod-install": "^0.1.0",
"prettier": "^2.0.5", "prettier": "^2.0.5",
"react": "16.13.1", "react": "17.0.2",
"react-native": "^0.67.2", "react-native": "0.68.1",
"react-native-builder-bob": "^0.18.0", "react-native-builder-bob": "^0.18.0",
"release-it": "^14.2.2", "release-it": "^14.2.2",
"typescript": "^4.1.3" "typescript": "^4.1.3"

View File

@ -1,9 +1,10 @@
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import type { EmitterSubscription } from 'react-native';
import nativeEmitter from '../native-messaging/emitter'; import nativeEmitter from '../native-messaging/emitter';
export function setupListener(_webViewRef: MutableRefObject<any>) { export function setupListener(_webViewRef: MutableRefObject<any>):EmitterSubscription {
// Resolve promise when SDP offer is available // Resolve promise when SDP offer is available
nativeEmitter.addListener('onBroadcastFinished', () => { return nativeEmitter.addListener('onBroadcastFinished', () => {
console.log(`Broadcast finished`); console.log(`Broadcast finished`);
_webViewRef.current.injectJavaScript( _webViewRef.current.injectJavaScript(
`window.bbbMobileScreenShareBroadcastFinishedCallback && window.bbbMobileScreenShareBroadcastFinishedCallback();` `window.bbbMobileScreenShareBroadcastFinishedCallback && window.bbbMobileScreenShareBroadcastFinishedCallback();`

View File

@ -1,9 +1,10 @@
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import type { EmitterSubscription } from 'react-native';
import nativeEmitter from '../native-messaging/emitter'; import nativeEmitter from '../native-messaging/emitter';
export function setupListener(_webViewRef: MutableRefObject<any>) { export function setupListener(_webViewRef: MutableRefObject<any>):EmitterSubscription {
// Resolve promise when SDP offer is available // Resolve promise when SDP offer is available
nativeEmitter.addListener( return nativeEmitter.addListener(
'onScreenShareLocalIceCandidate', 'onScreenShareLocalIceCandidate',
(jsonEncodedIceCandidate) => { (jsonEncodedIceCandidate) => {
let iceCandidate = JSON.parse(jsonEncodedIceCandidate); let iceCandidate = JSON.parse(jsonEncodedIceCandidate);

View File

@ -1,9 +1,10 @@
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import type { EmitterSubscription } from 'react-native';
import nativeEmitter from '../native-messaging/emitter'; import nativeEmitter from '../native-messaging/emitter';
export function setupListener(_webViewRef: MutableRefObject<any>) { export function setupListener(_webViewRef: MutableRefObject<any>):EmitterSubscription {
// Resolve promise when SDP offer is available // Resolve promise when SDP offer is available
nativeEmitter.addListener('onScreenShareSignalingStateChange', (newState) => { return nativeEmitter.addListener('onScreenShareSignalingStateChange', (newState) => {
console.log(`Temos um novo state: ${newState}`); console.log(`Temos um novo state: ${newState}`);
_webViewRef.current.injectJavaScript( _webViewRef.current.injectJavaScript(
`window.bbbMobileScreenShareSignalingStateChangeCallback && window.bbbMobileScreenShareSignalingStateChangeCallback(${JSON.stringify( `window.bbbMobileScreenShareSignalingStateChangeCallback && window.bbbMobileScreenShareSignalingStateChangeCallback(${JSON.stringify(

View File

@ -1,4 +1,4 @@
import { Platform, ViewStyle } from 'react-native'; import { EmitterSubscription, Platform, ViewStyle } from 'react-native';
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import BBBN_SystemBroadcastPicker from './native-components/BBBN_SystemBroadcastPicker'; import BBBN_SystemBroadcastPicker from './native-components/BBBN_SystemBroadcastPicker';
import { WebView } from 'react-native-webview'; import { WebView } from 'react-native-webview';
@ -14,6 +14,10 @@ type BigbluebuttonMobileSdkProps = {
onSuccess?: any; onSuccess?: any;
}; };
const data = {
instances: 0
}
const renderPlatformSpecificComponents = () => const renderPlatformSpecificComponents = () =>
Platform.select({ Platform.select({
ios: <BBBN_SystemBroadcastPicker />, ios: <BBBN_SystemBroadcastPicker />,
@ -27,11 +31,27 @@ export const BigBlueButtonMobile = ({
onSuccess, onSuccess,
}: BigbluebuttonMobileSdkProps) => { }: BigbluebuttonMobileSdkProps) => {
const webViewRef = useRef(null); const webViewRef = useRef(null);
const thisInstanceId = ++data.instances;
// console.log("XXX - ", thisInstanceId);
useEffect(() => { useEffect(() => {
onScreenShareLocalIceCandidate.setupListener(webViewRef); const logPrefix = `[${thisInstanceId}] - ${url.substring(8, 16)}`;
onScreenShareSignalingStateChange.setupListener(webViewRef);
onBroadcastFinished.setupListener(webViewRef); console.log(`${logPrefix} - addingListeners`);
const listeners:EmitterSubscription[] = [];
listeners.push(onScreenShareLocalIceCandidate.setupListener(webViewRef));
listeners.push(onScreenShareSignalingStateChange.setupListener(webViewRef));
listeners.push(onBroadcastFinished.setupListener(webViewRef));
return () => {
console.log(`${logPrefix} - Removing listeners`);
listeners.forEach( (listener, index) => {
console.log(`${logPrefix} - Removing listener ${index}`);
listener.remove();
} );
}
}, [webViewRef]); }, [webViewRef]);
return ( return (
@ -43,7 +63,7 @@ export const BigBlueButtonMobile = ({
source={{ uri: url }} source={{ uri: url }}
style={{ ...style }} style={{ ...style }}
contentMode={'mobile'} contentMode={'mobile'}
onMessage={(msg) => handleWebviewMessage(webViewRef, msg)} onMessage={(msg) => handleWebviewMessage(thisInstanceId, webViewRef, msg)}
applicationNameForUserAgent="BBBMobile" applicationNameForUserAgent="BBBMobile"
allowsInlineMediaPlayback={true} allowsInlineMediaPlayback={true}
onLoadEnd={(content: any) => { onLoadEnd={(content: any) => {

View File

@ -14,14 +14,14 @@ nativeEmitter.addListener('onAddScreenShareRemoteIceCandidateCompleted', () => {
}); });
// Entry point of this method // Entry point of this method
function addScreenShareRemoteIceCandidate(remoteCandidateJson: string) { function addScreenShareRemoteIceCandidate(instanceId: Number, remoteCandidateJson: string) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
// store the resolver for later call (when event is received) // store the resolver for later call (when event is received)
resolve = res; resolve = res;
try { try {
console.log( console.log(
`>nativeAddScreenShareRemoteIceCandidate ${remoteCandidateJson}` `[${instanceId}] - >nativeAddScreenShareRemoteIceCandidate ${remoteCandidateJson}`
); );
// call native swift method that triggers the broadcast popup // call native swift method that triggers the broadcast popup
nativeAddScreenShareRemoteIceCandidate(remoteCandidateJson); nativeAddScreenShareRemoteIceCandidate(remoteCandidateJson);

View File

@ -14,13 +14,13 @@ nativeEmitter.addListener('onFullAudioOfferCreated', (sdp) => {
}); });
// Entry point of this method // Entry point of this method
function createFullAudioOffer() { function createFullAudioOffer(instanceId: Number) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
// store the resolver for later call (when event is received) // store the resolver for later call (when event is received)
resolve = res; resolve = res;
try { try {
console.log(`>nativeCreateFullAudioOffer`); console.log(`[${instanceId}] - >nativeCreateFullAudioOffer`);
// call native swift method that triggers the broadcast popup // call native swift method that triggers the broadcast popup
nativeCreateFullAudioOffer(); nativeCreateFullAudioOffer();
} catch (e) { } catch (e) {

View File

@ -14,13 +14,13 @@ nativeEmitter.addListener('onScreenShareOfferCreated', (sdp) => {
}); });
// Entry point of this method // Entry point of this method
function createScreenShareOffer() { function createScreenShareOffer(instanceId: Number) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
// store the resolver for later call (when event is received) // store the resolver for later call (when event is received)
resolve = res; resolve = res;
try { try {
console.log(`>nativeCreateScreenShareOffer`); console.log(`[${instanceId}] - >nativeCreateScreenShareOffer`);
// call native swift method that triggers the broadcast popup // call native swift method that triggers the broadcast popup
nativeCreateScreenShareOffer(); nativeCreateScreenShareOffer();
} catch (e) { } catch (e) {

View File

@ -19,14 +19,14 @@ nativeEmitter.addListener('onBroadcastStarted', () => {
}); });
// Entry point of this method // Entry point of this method
function initializeScreenShare() { function initializeScreenShare(instanceId: Number) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
// store the resolver for later call (when event is received) // store the resolver for later call (when event is received)
resolve = res; resolve = res;
try { try {
// call native swift method that triggers the broadcast popup // call native swift method that triggers the broadcast popup
console.log(`>nativeInitializeScreenShare`); console.log(`[${instanceId}] - >nativeInitializeScreenShare`);
nativeInitializeScreenShare(); nativeInitializeScreenShare();
} catch (e) { } catch (e) {
rej(`Call to nativeInitializeScreenShare failed zzy`); rej(`Call to nativeInitializeScreenShare failed zzy`);

View File

@ -14,13 +14,13 @@ nativeEmitter.addListener('onSetFullAudioRemoteSDPCompleted', () => {
}); });
// Entry point of this method // Entry point of this method
function setFullAudioRemoteSDP(remoteSdp: string) { function setFullAudioRemoteSDP(instanceId: Number, remoteSdp: string) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
// store the resolver for later call (when event is received) // store the resolver for later call (when event is received)
resolve = res; resolve = res;
try { try {
console.log(`>nativeSetFullAudioRemoteSDP ${remoteSdp}`); console.log(`[${instanceId}] - >nativeSetFullAudioRemoteSDP ${remoteSdp}`);
// call native swift method that triggers the broadcast popup // call native swift method that triggers the broadcast popup
nativeSetFullAudioRemoteSDP(remoteSdp); nativeSetFullAudioRemoteSDP(remoteSdp);
} catch (e) { } catch (e) {

View File

@ -14,13 +14,13 @@ nativeEmitter.addListener('onSetScreenShareRemoteSDPCompleted', () => {
}); });
// Entry point of this method // Entry point of this method
function setScreenShareRemoteSDP(remoteSdp: string) { function setScreenShareRemoteSDP(instanceId: Number, remoteSdp: string) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
// store the resolver for later call (when event is received) // store the resolver for later call (when event is received)
resolve = res; resolve = res;
try { try {
console.log(`>nativeSetScreenShareRemoteSDP ${remoteSdp}`); console.log(`[${instanceId}] - >nativeSetScreenShareRemoteSDP ${remoteSdp}`);
// call native swift method that triggers the broadcast popup // call native swift method that triggers the broadcast popup
nativeSetScreenShareRemoteSDP(remoteSdp); nativeSetScreenShareRemoteSDP(remoteSdp);
} catch (e) { } catch (e) {

View File

@ -8,13 +8,14 @@ import addScreenShareRemoteIceCandidate from '../methods/addScreenShareRemoteIce
import createFullAudioOffer from '../methods/createFullAudioOffer'; import createFullAudioOffer from '../methods/createFullAudioOffer';
function observePromiseResult( function observePromiseResult(
instanceId: Number,
webViewRef: MutableRefObject<WebView>, webViewRef: MutableRefObject<WebView>,
sequence: number, sequence: number,
prom: Promise<any> prom: Promise<any>
) { ) {
prom prom
.then((result: any) => { .then((result: any) => {
console.log(`Promise ${sequence} resolved!`, result); console.log(`[${instanceId}] - Promise ${sequence} resolved!`, result);
webViewRef.current.injectJavaScript( webViewRef.current.injectJavaScript(
`window.nativeMethodCallResult(${sequence}, true ${ `window.nativeMethodCallResult(${sequence}, true ${
result ? ',' + JSON.stringify(result) : '' result ? ',' + JSON.stringify(result) : ''
@ -22,7 +23,7 @@ function observePromiseResult(
); );
}) })
.catch((exception: any) => { .catch((exception: any) => {
console.error(`Promise ${sequence} failed!`, exception); console.error(`[${instanceId}] - Promise ${sequence} failed!`, exception);
webViewRef.current.injectJavaScript( webViewRef.current.injectJavaScript(
`window.nativeMethodCallResult(${sequence}, false ${ `window.nativeMethodCallResult(${sequence}, false ${
exception ? ',' + JSON.stringify(exception) : '' exception ? ',' + JSON.stringify(exception) : ''
@ -32,41 +33,45 @@ function observePromiseResult(
} }
export function handleWebviewMessage( export function handleWebviewMessage(
instanceId: Number,
webViewRef: MutableRefObject<any>, webViewRef: MutableRefObject<any>,
event: WebViewMessageEvent event: WebViewMessageEvent
) { ) {
const stringData = event?.nativeEvent?.data; const stringData = event?.nativeEvent?.data;
console.log("handleWebviewMessage - ", instanceId);
const data = JSON.parse(stringData); const data = JSON.parse(stringData);
if (data?.method && data?.sequence) { if (data?.method && data?.sequence) {
let promise; let promise;
switch (data?.method) { switch (data?.method) {
case 'initializeScreenShare': case 'initializeScreenShare':
promise = initializeScreenShare(); promise = initializeScreenShare(instanceId);
break; break;
case 'createFullAudioOffer': case 'createFullAudioOffer':
promise = createFullAudioOffer(); promise = createFullAudioOffer(instanceId);
break; break;
case 'createScreenShareOffer': case 'createScreenShareOffer':
promise = createScreenShareOffer(); promise = createScreenShareOffer(instanceId);
break; break;
case 'setScreenShareRemoteSDP': case 'setScreenShareRemoteSDP':
promise = setScreenShareRemoteSDP(data?.arguments[0].sdp); promise = setScreenShareRemoteSDP(instanceId, data?.arguments[0].sdp);
break; break;
case 'setFullAudioRemoteSDP': case 'setFullAudioRemoteSDP':
promise = setFullAudioRemoteSDP(data?.arguments[0].sdp); promise = setFullAudioRemoteSDP(instanceId, data?.arguments[0].sdp);
break; break;
case 'addRemoteIceCandidate': case 'addRemoteIceCandidate':
promise = addScreenShareRemoteIceCandidate( promise = addScreenShareRemoteIceCandidate(
instanceId,
JSON.stringify(data?.arguments[0]) JSON.stringify(data?.arguments[0])
); );
break; break;
default: default:
throw `Unknown method ${data?.method}`; throw `[${instanceId}] - Unknown method ${data?.method}`;
} }
observePromiseResult(webViewRef, data.sequence, promise); observePromiseResult(instanceId, webViewRef, data.sequence, promise);
} else { } else {
console.log(`Ignoring unknown message: $stringData`); console.log(`[${instanceId}] - Ignoring unknown message: $stringData`);
} }
} }

856
yarn.lock

File diff suppressed because it is too large Load Diff