[RN] Promised-base RTCPeerConnection API

Recent changes in lib-jitsi-meet probably led to (1) our
RTCPeerConnection customizations on react-native not being used which is
a problem because we need them for at least NAT64 on iOS in order to
pass the review in Apple's App Store and (2) unexpected exceptions
inside react-native-webrtc.

The Promise-based WebRTC API should be merged from react-native-webrtc's
upstream but I don't want to do it right now because last time we got
multiple bugs in addition.
This commit is contained in:
Lyubo Marinov 2018-02-28 13:55:11 -06:00
parent 037e7f59b0
commit e622829c1c
2 changed files with 66 additions and 4 deletions

View File

@ -1,3 +1,5 @@
// @flow
import { NativeModules } from 'react-native';
import { RTCPeerConnection, RTCSessionDescription } from 'react-native-webrtc';
@ -33,7 +35,7 @@ const SOCK_STREAM = 1; /* stream socket */
*
* @class
*/
export default function _RTCPeerConnection(...args) {
export default function _RTCPeerConnection(...args: any[]) {
/* eslint-disable indent, no-invalid-this */
@ -50,6 +52,8 @@ export default function _RTCPeerConnection(...args) {
// _RTCPeerConnection's prototype may (or may not, I don't know) work but I
// don't want to try because the following approach appears to work and I
// understand it.
// $FlowFixMe
Object.defineProperty(this, 'onaddstream', {
configurable: true,
enumerable: true,
@ -67,6 +71,14 @@ export default function _RTCPeerConnection(...args) {
_RTCPeerConnection.prototype = Object.create(RTCPeerConnection.prototype);
_RTCPeerConnection.prototype.constructor = _RTCPeerConnection;
_RTCPeerConnection.prototype.addIceCandidate
= _makePromiseAware(RTCPeerConnection.prototype.addIceCandidate, 1, 0);
_RTCPeerConnection.prototype.createAnswer
= _makePromiseAware(RTCPeerConnection.prototype.createAnswer, 0, 1);
_RTCPeerConnection.prototype.createOffer
= _makePromiseAware(RTCPeerConnection.prototype.createOffer, 0, 1);
_RTCPeerConnection.prototype._invokeOnaddstream = function(...args) {
const onaddstream = this._onaddstream;
@ -90,6 +102,9 @@ _RTCPeerConnection.prototype._queueOnaddstream = function(...args) {
this._onaddstreamQueue.push(Array.from(args));
};
_RTCPeerConnection.prototype.setLocalDescription
= _makePromiseAware(RTCPeerConnection.prototype.setLocalDescription, 1, 0);
_RTCPeerConnection.prototype.setRemoteDescription = function(
sessionDescription,
successCallback,
@ -128,6 +143,50 @@ function _LOGE(...args) {
console && console.error && console.error(...args);
}
/**
* Makes a {@code Promise}-returning function out of a specific void function
* with {@code successCallback} and {@code failureCallback}.
*
* @param {Function} f - The (void) function with {@code successCallback} and
* {@code failureCallback}.
* @param {number} beforeCallbacks - The number of arguments before
* {@code successCallback} and {@code failureCallback}.
* @param {number} afterCallbacks - The number of arguments after
* {@code successCallback} and {@code failureCallback}.
* @returns {Promise}
*/
function _makePromiseAware(
f: Function,
beforeCallbacks: number,
afterCallbacks: number) {
return function(...args) {
return new Promise((resolve, reject) => {
if (args.length <= beforeCallbacks + afterCallbacks) {
args.splice(beforeCallbacks, 0, resolve, reject);
}
let fPromise;
try {
// eslint-disable-next-line no-invalid-this
fPromise = f.apply(this, args);
} catch (e) {
reject(e);
}
// If the super implementation returns a Promise from the deprecated
// invocation by any chance, try to make sense of it.
if (fPromise) {
const { then } = fPromise;
typeof then === 'function'
&& then.call(fPromise, resolve, reject);
}
});
};
}
/**
* Adapts react-native-webrtc's {@link RTCPeerConnection#setRemoteDescription}
* implementation which uses the deprecated, callback-based version to the

View File

@ -15,15 +15,18 @@ import RTCPeerConnection from './RTCPeerConnection';
if (typeof global.MediaStreamTrack === 'undefined') {
global.MediaStreamTrack = MediaStreamTrack;
}
if (typeof global.RTCIceCandidate === 'undefined') {
global.RTCIceCandidate = RTCIceCandidate;
}
if (typeof global.RTCPeerConnection === 'undefined') {
global.RTCPeerConnection = RTCPeerConnection;
}
if (typeof global.webkitRTCPeerConnection === 'undefined') {
global.webkitRTCPeerConnection = RTCPeerConnection;
}
if (typeof global.RTCSessionDescription === 'undefined') {
global.RTCSessionDescription = RTCSessionDescription;
}
if (typeof global.RTCIceCandidate === 'undefined') {
global.RTCIceCandidate = RTCIceCandidate;
}
const navigator = global.navigator;