Skip to content

Commit

Permalink
feat: use the shared sfu call object in react native (#60)
Browse files Browse the repository at this point in the history
* feat: make sfu call object to accept rn webrtc

* patch rtcrtpsender and rtcrtpreceiver and add polyfill for uuid

* chore: fix issues after merge with main

* fix: remove numeric symbols as its not compatible with metro for react-native

ref: facebook/metro#645

* feat: add healper to get username fragment in rn webrtc

* feat: add callID randomiser to RN

* feat: add callID randomiser to RN

* fix: typing issues with stream video client

* chore(react-native): remove unused modules

* fix: remove numeric symbols as its not compatible with metro for react-native

ref: facebook/metro#645

* chore(react-native): remove unused modules

* fix: remove numeric symbols as its not compatible with metro for react-native

ref: facebook/metro#645

* chore: remove usage of webrtc/types

* chore: remove the previously made generics for connection config and use global polyfilling

* feat: add polyfill of rn-webrtc

* feat: wip use participant videos from the shared state store

* feat: add timeout in measureResourceLoadLatencyTo

* chore: remove the temporary method that was used by react native

* chore: remove unnecessary console log

* fix: floating point numbers are not allowed in update subscriptions

* chore: remove unnecessary console log

* feat: filter out current user participant

* fix:  remove linking event listener

* chore: remove unused imports

* fix: patch crash in rn webrtc for undefined method on track

* chore: revert to using the staging urls by default

* chore: update yarn lock for webrtc patch

* chore: update the rn webrtc patch

* chore: remove the generics implementation in react-sdk

* chore: remove the generics implementation in react dogfood

* fix: latency call must get the blob of response

* chore: revert the changes done to sfu call object

* feat: patch ice candidate getter for react-native

* fix: if only local participant is present then show it as full view

* chore: align coordinator ws url

* chore: use same length to get random call id as react dogfood app

* fix: adding angular-sdk dir to metro.config blockList

Co-authored-by: vanGalilea <galiliziv@gmail.com>
  • Loading branch information
santhoshvai and vanGalilea authored Nov 11, 2022
1 parent 7d6c4a8 commit 1693d63
Show file tree
Hide file tree
Showing 33 changed files with 271 additions and 1,197 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/src/RTCPeerConnection.ts b/src/RTCPeerConnection.ts
index 20de0069ce6137c1a10f65c2164084cf124c7ffe..46d89f399f65af135789b23ecd51258ce9df94f7 100644
--- a/src/RTCPeerConnection.ts
+++ b/src/RTCPeerConnection.ts
@@ -497,6 +497,7 @@ export default class RTCPeerConnection extends defineCustomEventTarget(...PEER_C

if (oldTransceiver) {
transceiver = oldTransceiver;
+ transceiver._receiver._track = new MediaStreamTrack(transceiver._receiver._track);
track = transceiver._receiver._track;
transceiver._mid = ev.transceiver.mid;
transceiver._currentDirection = ev.transceiver.currentDirection;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
},
"resolutions": {
"react-native-pure-jwt@^3.0.1": "patch:react-native-pure-jwt@npm%3A3.0.1#./.yarn/patches/react-native-pure-jwt-npm-3.0.1-3e5e2c9059.patch",
"react-native-callkeep@^4.3.3": "patch:react-native-callkeep@npm%3A4.3.3#./.yarn/patches/react-native-callkeep-npm-4.3.3-71db80f4ef.patch"
"react-native-callkeep@^4.3.3": "patch:react-native-callkeep@npm%3A4.3.3#./.yarn/patches/react-native-callkeep-npm-4.3.3-71db80f4ef.patch",
"react-native-webrtc@106.0.0-beta.6": "patch:react-native-webrtc@npm%3A106.0.0-beta.6#./.yarn/patches/react-native-webrtc-npm-106.0.0-beta.6-795b82ce91.patch"
}
}
4 changes: 3 additions & 1 deletion packages/client/src/StreamVideoClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ describe('StreamVideoClient', () => {
createSocketConnection: vi.fn(),
};
});
client = new StreamVideoClient('123', { token: 'abc' });
client = new StreamVideoClient('123', {
token: 'abc',
});
});

it('should connect', async () => {
Expand Down
16 changes: 0 additions & 16 deletions packages/client/src/StreamVideoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,22 +128,6 @@ export class StreamVideoClient {
return callEnvelope;
};

// TODO: remove this method (it's only used in react-native for now until the sfu-Call object is merged)
joinCallRaw = async (data: JoinCallRequest, sessionId?: string) => {
const { response } = await this.client.joinCall({
...data,
// FIXME: OL this needs to come from somewhere
datacenterId: 'amsterdam',
});
if (response.call && response.call.call && response.edges) {
const edge = await this.getCallEdgeServer(
response.call.call,
response.edges,
);
return { response, edge };
}
};

joinCall = async (data: JoinCallRequest, sessionId?: string) => {
const { response } = await this.client.joinCall(data);
if (response.call && response.call.call && response.edges) {
Expand Down
7 changes: 6 additions & 1 deletion packages/client/src/rpc/latency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ export const measureResourceLoadLatencyTo = async (
.fill(undefined)
.map(async () => {
const start = Date.now();
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000); // 3 second timeout:
try {
const src = new URL(endpoint);
src.searchParams.set('rand', `react_${Math.random() * 10000000}`);
await fetch(src.toString()).then((response) => response.blob());
await fetch(src.toString(), {
signal: controller.signal,
}).then((response) => response.blob());
} catch (e) {
console.warn(`failed to measure latency to ${endpoint}`, e);
}
clearTimeout(timeoutId); // clear timeout incase fetch completes before timeout
const latency = Date.now() - start;
measurements.push(toSeconds(latency));
}),
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/rtc/codecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ export const defaultVideoPublishEncodings: RTCRtpEncodingParameters[] = [
{
rid: 'f',
active: true,
maxBitrate: 1_280_000,
maxBitrate: 1280000,
},
{
rid: 'h',
active: true,
scaleResolutionDownBy: 2.0,
maxBitrate: 768_000,
maxBitrate: 768000,
},
{
rid: 'q',
active: true,
scaleResolutionDownBy: 4.0,
maxBitrate: 384_000,
maxBitrate: 384000,
},
];

Expand Down
16 changes: 16 additions & 0 deletions packages/client/src/rtc/helpers/iceCandidate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ICETrickle } from '../../gen/video/sfu/models/models';

export function getIceCandidate(
candidate: RTCIceCandidate,
): ICETrickle['iceCandidate'] {
if (!candidate.usernameFragment) {
// react-native-webrtc doesn't include usernameFragment in the candidate
const splittedCandidate = candidate.candidate.split(' ');
const ufragIndex =
splittedCandidate.findIndex((s: string) => s === 'ufrag') + 1;
const usernameFragment = splittedCandidate[ufragIndex];
return JSON.stringify({ ...candidate, usernameFragment });
} else {
return JSON.stringify(candidate.toJSON());
}
}
3 changes: 2 additions & 1 deletion packages/client/src/rtc/publisher.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { StreamSfuClient } from '../StreamSfuClient';
import { ICETrickle, PeerType } from '../gen/video/sfu/models/models';
import { ReplaySubject } from 'rxjs';
import { getIceCandidate } from './helpers/iceCandidate';

export type PublisherOpts = {
rpcClient: StreamSfuClient;
Expand All @@ -22,7 +23,7 @@ export const createPublisher = ({
}
await rpcClient.rpc.iceTrickle({
sessionId: rpcClient.sessionId,
iceCandidate: JSON.stringify(candidate.toJSON()),
iceCandidate: getIceCandidate(candidate),
peerType: PeerType.PUBLISHER_UNSPECIFIED,
});
});
Expand Down
3 changes: 2 additions & 1 deletion packages/client/src/rtc/subscriber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { StreamSfuClient } from '../StreamSfuClient';
import { Dispatcher } from './Dispatcher';
import { ICETrickle, PeerType } from '../gen/video/sfu/models/models';
import { ReplaySubject } from 'rxjs';
import { getIceCandidate } from './helpers/iceCandidate';

export type SubscriberOpts = {
rpcClient: StreamSfuClient;
Expand All @@ -28,7 +29,7 @@ export const createSubscriber = ({

await rpcClient.rpc.iceTrickle({
sessionId: rpcClient.sessionId,
iceCandidate: JSON.stringify(candidate.toJSON()),
iceCandidate: getIceCandidate(candidate),
peerType: PeerType.SUBSCRIBER,
});
});
Expand Down
14 changes: 7 additions & 7 deletions packages/client/src/rtc/videoLayers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ export const findOptimalVideoLayers = async (mediaStream: MediaStream) => {
const steps: [number, number, number][] = [
// [4096, 2160], // 4K
// [1920, 1080, 3_072_000], // Full-HD
[1280, 720, 1_280_000], // HD
[640, 480, 768_000], // VGA
[320, 240, 384_000], // QVGA
[160, 120, 128_000],
[1280, 720, 1280000], // HD
[640, 480, 768000], // VGA
[320, 240, 384000], // QVGA
[160, 120, 128000],
];

const optimalVideoLayers: OptimalVideoLayer[] = [];
Expand Down Expand Up @@ -43,20 +43,20 @@ export const findOptimalVideoLayers = async (mediaStream: MediaStream) => {
export const defaultVideoLayers: OptimalVideoLayer[] = [
{
rid: 'f',
maxBitrate: 1_280_000,
maxBitrate: 1280000,
width: 1280,
height: 720,
},
{
rid: 'h',
maxBitrate: 768_000,
maxBitrate: 768000,
width: 640,
height: 480,
scaleResolutionDownBy: 2.0,
},
{
rid: 'q',
maxBitrate: 384_000,
maxBitrate: 384000,
width: 480,
height: 360,
scaleResolutionDownBy: 4.0,
Expand Down
12 changes: 9 additions & 3 deletions packages/react-native-dogfood/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
/**
* @format
*/
/** URL polyfill */
import 'text-encoding-polyfill';
/** Text decoder polyfill */
import 'react-native-url-polyfill/auto';
/** crypto.getRandomValues polyfill for uuid */
import 'react-native-get-random-values';

import { registerGlobals } from 'react-native-webrtc';

if (Platform.OS !== 'web') {
registerGlobals();
}

import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-dogfood/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const getConfig = async () => {
resolveRequest: MetroSymlinksResolver(),
// add any custom asset options here (if any).. example "bin"
assetExts: [...defaultConfig.resolver.assetExts],
blockList: [/angular-sdk/],
},
});
return config;
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-dogfood/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@stardazed/streams-polyfill": "^2.4.0",
"@stream-io/video-client": "workspace:^",
"js-base64": "^3.7.2",
"nanoid": "^4.0.0",
"react": "18.1.0",
"react-native": "0.70.4",
"react-native-callkeep": "^4.3.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ const PhoneButton = () => {
primaryVideoTrack._switchCamera();
newState.cameraBackFacingMode = !cameraBackFacingMode;
}
newState.callState = undefined;
newState.isAudioMuted = false;
newState.isVideoMuted = false;
newState.participants = [];
return newState;
});
}).current;
Expand All @@ -36,10 +34,10 @@ const PhoneButton = () => {
return;
}
try {
await call.leave();
resetCallState();
call.leave();
InCallManager.stop();
navigation.navigate('HomeScreen');
resetCallState();
} catch (err) {
console.warn('failed to leave call', err);
}
Expand Down
Loading

0 comments on commit 1693d63

Please sign in to comment.