Skip to content
This repository was archived by the owner on Jun 28, 2024. It is now read-only.

Commit 2d616b9

Browse files
authored
Add simulcast to tracks
* add simulcast to local tracks * add simulcast to remote tracks * allow user to change local tracks encoding * allow user to change remote track encoding
1 parent 913f274 commit 2d616b9

File tree

20 files changed

+25198
-970
lines changed

20 files changed

+25198
-970
lines changed

example/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ yarn-error.log
6666
# Env
6767
.env.development
6868
/ios/JellyfishExample.xcworkspace/contents.xcworkspacedata
69-
/ios/jellyfish_ipa/
69+
/ios/jf/

example/android/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
distributionBase=GRADLE_USER_HOME
23
distributionPath=wrapper/dists
34
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip

example/components/InCallButton.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {MaterialCommunityIcons} from '@expo/vector-icons';
33
import React from 'react';
44
import {
55
type GestureResponderEvent,
6-
Pressable,
76
StyleSheet,
7+
TouchableHighlight,
88
View,
99
} from 'react-native';
1010
import type AccessibilityLabel from '../types/AccessibilityLabel';
@@ -63,15 +63,18 @@ const InCallButton = ({
6363
};
6464

6565
return (
66-
<Pressable onPress={onPress} accessibilityLabel={accessibilityLabel}>
66+
<TouchableHighlight
67+
onPress={onPress}
68+
style={InCallButtonStyles.common}
69+
accessibilityLabel={accessibilityLabel}>
6770
<View style={GetStylesForButtonType(type)}>
6871
<MaterialCommunityIcons
6972
name={iconName}
7073
size={IconSize}
7174
color={GetIconColorForButtonType(type)}
7275
/>
7376
</View>
74-
</Pressable>
77+
</TouchableHighlight>
7578
);
7679
};
7780

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {BrandColors} from '../utils/Colors';
2+
import React from 'react';
3+
import {
4+
type GestureResponderEvent,
5+
StyleSheet,
6+
Text,
7+
TouchableHighlight,
8+
View,
9+
} from 'react-native';
10+
import AccessibilityLabel from '../types/AccessibilityLabel';
11+
import {TrackEncoding} from '@jellyfish-dev/react-native-client-sdk';
12+
13+
const LetterButtonStyles = StyleSheet.create({
14+
common: {
15+
width: 44,
16+
height: 44,
17+
borderRadius: 22,
18+
justifyContent: 'center',
19+
alignItems: 'center',
20+
},
21+
button: {
22+
borderWidth: 1,
23+
borderStyle: 'solid',
24+
borderColor: BrandColors.darkBlue100,
25+
},
26+
buttonSelected: {
27+
backgroundColor: BrandColors.darkBlue100,
28+
},
29+
buttonUnSelected: {
30+
backgroundColor: BrandColors.darkBlue20,
31+
},
32+
text: {
33+
fontSize: 18,
34+
},
35+
textSelected: {
36+
color: BrandColors.darkBlue20,
37+
},
38+
textUnselected: {
39+
color: BrandColors.darkBlue100,
40+
},
41+
});
42+
43+
type LetterButtonProps = {
44+
onPress: (event: GestureResponderEvent) => void;
45+
trackEncoding: TrackEncoding;
46+
selected: boolean;
47+
} & AccessibilityLabel;
48+
49+
const LetterButton = ({
50+
onPress,
51+
trackEncoding,
52+
selected,
53+
}: LetterButtonProps) => {
54+
const stylesForText = () => {
55+
return selected
56+
? LetterButtonStyles.textSelected
57+
: LetterButtonStyles.textUnselected;
58+
};
59+
60+
const stylesForButton = () => {
61+
return selected
62+
? LetterButtonStyles.buttonSelected
63+
: LetterButtonStyles.buttonUnSelected;
64+
};
65+
return (
66+
<TouchableHighlight
67+
onPress={onPress}
68+
style={[LetterButtonStyles.common, stylesForButton()]}
69+
key={trackEncoding}>
70+
<View
71+
style={[
72+
LetterButtonStyles.common,
73+
LetterButtonStyles.button,
74+
stylesForButton(),
75+
]}>
76+
<Text style={[LetterButtonStyles.text, stylesForText()]}>
77+
{trackEncoding.toUpperCase()}
78+
</Text>
79+
</View>
80+
</TouchableHighlight>
81+
);
82+
};
83+
84+
export default LetterButton;

example/components/VideosGrid.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import {VideoRendererView} from '@jellyfish-dev/react-native-client-sdk';
1+
import {
2+
Track,
3+
VideoRendererView,
4+
setTargetTrackEncoding,
5+
Metadata,
6+
} from '@jellyfish-dev/react-native-client-sdk';
27
import React from 'react';
38
import {Dimensions, StyleSheet, View} from 'react-native';
49
import Animated, {FadeInDown, Layout} from 'react-native-reanimated';
510
import {roomScreenLabels} from '../types/ComponentLabels';
11+
import LetterButton from './LetterButton';
612

713
type Props = {
8-
tracks: string[];
14+
tracks: Track<Metadata>[];
915
};
1016

1117
const {width} = Dimensions.get('window');
@@ -32,13 +38,24 @@ export function VideosGrid({tracks}: Props) {
3238
? [styles.video2, {width: videoWidth, height: videoWidth}]
3339
: [styles.video1, {maxWidth: width - 20}]
3440
}
35-
key={v}>
41+
key={v.id}>
3642
<AnimatedVideoRenderer
37-
trackId={v}
43+
trackId={v.id}
3844
entering={FadeInDown.duration(200)}
3945
layout={Layout.duration(150)}
4046
style={styles.animatedView}
4147
/>
48+
{(v.simulcastConfig?.enabled ?? false) && (
49+
<View style={styles.buttons}>
50+
{v.simulcastConfig?.activeEncodings.map(e => (
51+
<LetterButton
52+
trackEncoding={e}
53+
selected={v.encoding === e}
54+
onPress={() => setTargetTrackEncoding(v.id, e)}
55+
/>
56+
))}
57+
</View>
58+
)}
4259
</Animated.View>
4360
))}
4461
</View>
@@ -85,6 +102,16 @@ const styles = StyleSheet.create({
85102
video: {
86103
flex: 1,
87104
},
105+
buttons: {
106+
flexDirection: 'row',
107+
gap: 8,
108+
padding: 4,
109+
borderRadius: 8,
110+
position: 'absolute',
111+
opacity: 0.5,
112+
backgroundColor: 'white',
113+
right: 0,
114+
},
88115
});
89116

90117
export default VideosGrid;

example/contexts/JellyfishExampleContext.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import {
99
updateAudioTrackMetadata,
1010
CaptureDevice,
1111
VideoQuality,
12+
SimulcastConfig,
13+
TrackEncoding,
14+
CameraConfig,
15+
Metadata,
1216
} from '@jellyfish-dev/react-native-client-sdk';
1317

1418
import {Platform} from 'expo-modules-core';
@@ -22,12 +26,19 @@ const JellyfishExampleContext = React.createContext<
2226
isMicrophoneOn: boolean;
2327
toggleMicrophone: () => void;
2428
joinRoom: () => Promise<void>;
29+
startCamera: <CameraConfigMetadataType extends Metadata>(
30+
config?: Partial<CameraConfig<CameraConfigMetadataType>>,
31+
) => Promise<void>;
2532
flipCamera: () => void;
2633
getCaptureDevices: () => Promise<CaptureDevice[]>;
2734
setCurrentCamera: React.Dispatch<
2835
React.SetStateAction<CaptureDevice | null>
2936
>;
3037
currentCamera: CaptureDevice | null;
38+
localCameraSimulcastConfig: SimulcastConfig;
39+
toggleLocalCameraTrackEncoding: (
40+
encoding: TrackEncoding,
41+
) => Promise<void>;
3142
}
3243
| undefined
3344
>(undefined);
@@ -44,6 +55,8 @@ const JellyfishExampleContextProvider = (props: any) => {
4455
startCamera,
4556
flipCamera,
4657
getCaptureDevices,
58+
simulcastConfig: localCameraSimulcastConfig,
59+
toggleVideoTrackEncoding: toggleLocalCameraTrackEncoding,
4760
} = useCamera();
4861
const {toggleMicrophone: membraneToggleMicrophone, startMicrophone} =
4962
useMicrophone();
@@ -113,11 +126,14 @@ const JellyfishExampleContextProvider = (props: any) => {
113126
flipCamera,
114127
toggleCamera,
115128
toggleMicrophone,
129+
startCamera,
116130
isCameraOn,
117131
isMicrophoneOn,
118132
currentCamera,
119133
setCurrentCamera,
120134
getCaptureDevices,
135+
localCameraSimulcastConfig,
136+
toggleLocalCameraTrackEncoding,
121137
};
122138

123139
return (

0 commit comments

Comments
 (0)