Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false

# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"react-native-screen": "^1.0.1",
"react-native-screens": "^3.20.0",
"react-native-svg": "^12.3.0",
"react-native-webrtc": "github:montanaeli/react-native-webrtc#2c7b6e3",
"react-native-webrtc": "github:aravind-raveendran/react-native-webrtc#045ef81",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"redux-persist": "^6.0.0"
Expand Down
1 change: 1 addition & 0 deletions src/components/BottomBar/BottomBar.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const styles = AppStyleSheet.create({
alignItems: 'stretch',
justifyContent: 'space-between',
paddingHorizontal: 20,
width: '100%',
},
});
export default styles;
11 changes: 10 additions & 1 deletion src/components/BottomBar/BottomBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { View, TouchableOpacity, Platform } from 'react-native';

import styles from './BottomBar.style';

export const BottomBar = ({ displayStatsInformation, focus }) => {
export const BottomBar = ({ displayStatsInformation, displaySimulcastSelection, focus }) => {
const iconSize = Platform.OS === 'android' && Platform.isTV ? 's' : 'm';
return (
<View style={styles.wrapper}>
Expand All @@ -17,6 +17,15 @@ export const BottomBar = ({ displayStatsInformation, focus }) => {
>
<Icon testID="infoIcon" name="info" size={iconSize} />
</TouchableOpacity>
<TouchableOpacity
testID="settingsIconButton"
hasTVPreferredFocus={focus}
onPress={() => {
displaySimulcastSelection();
}}
>
<Icon testID="settingsIcon" name="settings" size={iconSize} />
</TouchableOpacity>
</View>
);
};
48 changes: 48 additions & 0 deletions src/components/SimulcastView/SimulcastView.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { AppStyleSheet as StyleSheet } from '@dolbyio/uikit-react-native';
import { Platform } from 'react-native';

const styles = StyleSheet.create({
outerContainer: {
flex: 1,
backgroundColor: '#292930E5',
marginTop: 100,
borderTopLeftRadius: 14,
borderTopRightRadius: 14,
},
simulcastCell: {
width: '100%',
height: 50,
flexDirection: 'row',
backgroundColor: '#34343B',
marginVertical: 5,
justifyContent: 'center',
alignContent: 'center',
},
outerContainerTV: {
height: '50%',
width: '20%',
position: 'absolute',
backgroundColor: '#292930',
bottom: 20,
left: '80%',
borderRadius: 14,
},
innerContainer: {
marginTop: 10,
flexDirection: 'column',
alignItems: 'stretch',
justifyContent: 'space-between',
paddingHorizontal: 0,
},
simulcastOptionsContainer: {
marginTop: Platform.isTV ? 10 : 60,
marginHorizontal: 16,
},
closeIcon: {
flexDirection: 'row',
justifyContent: 'flex-end',
marginTop: 20,
paddingHorizontal: 20,
},
});
export default styles;
54 changes: 54 additions & 0 deletions src/components/SimulcastView/SimulcastView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { View, TouchableOpacity, FlatList, Platform } from 'react-native';

import Icon from '../../uikit/components/Icon/Icon';
import Text from '../text/Text';

import styles from './SimulcastView.style';

export const SimulcastView = ({ streamQualityList, selectedStreamQuality, onClose, onSelectStreamQuality }) => {
const isSelected = (streamQuality) => {
return selectedStreamQuality === streamQuality;
};
const renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => {
onSelectStreamQuality(item);
}}
>
<View style={styles.simulcastCell}>
{isSelected(item.streamQuality) && <Icon testID="checkmarkIcon" name="checkmark" size="xs" />}
<Text style={{ alignSelf: 'center', height: '100%' }} type="bodyDefault">
{item.streamQuality}
</Text>
</View>
</TouchableOpacity>
);

return (
<View style={Platform.isTV ? styles.outerContainerTV : styles.outerContainer}>
<View style={styles.closeIcon}>
<TouchableOpacity testID="closeIconButton" hasTVPreferredFocus onPress={onClose}>
<Icon testID="closeIcon" name="close" size="s" />
</TouchableOpacity>
</View>
<View style={styles.innerContainer}>
<Text
testID="simulcastTitle"
id="simulcastTitle"
type="h2"
align={Platform.isTV ? 'left' : 'center'}
style={{ paddingTop: 16, paddingLeft: 16 }}
/>
<View style={styles.simulcastOptionsContainer}>
<FlatList
testID="simulcastList"
data={streamQualityList}
keyExtractor={(item) => item.streamQuality}
renderItem={renderItem}
/>
</View>
</View>
</View>
);
};
3 changes: 3 additions & 0 deletions src/components/SimulcastView/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SimulcastView } from './SimulcastView';

export default SimulcastView;
1 change: 1 addition & 0 deletions src/components/StreamStats/StreamStats.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const styles = StyleSheet.create({
bottom: 20,
left: 20,
borderRadius: 14,
position: 'absolute',
},
innerContainer: {
marginTop: 10,
Expand Down
37 changes: 34 additions & 3 deletions src/screens/multiview/MultiView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
MediaTrackInfo,
ViewProjectSourceMapping,
MediaStreamSource,
MediaStreamLayers,
MediaLayer,
LayerInfo,
} from '@millicast/sdk';
import { useNetInfo } from '@react-native-community/netinfo';
import React, { useEffect, useRef, useState } from 'react';
Expand All @@ -25,7 +28,7 @@ import {
import { RTCView } from 'react-native-webrtc';
import { useSelector, useDispatch } from 'react-redux';

import { RemoteTrackSource } from '../../types/RemoteTrackSource.types';
import { RemoteTrackSource, SimulcastQuality } from '../../types/RemoteTrackSource.types';
import { Routes } from '../../types/routes.types';

window.Logger = MillicastLogger;
Expand All @@ -42,6 +45,7 @@ export const MultiView = ({ navigation }) => {
const playing = useSelector((state) => state.viewerReducer.playing);
const error = useSelector((state) => state.viewerReducer.error);
const audioRemoteTrackSource = useSelector((state) => state.viewerReducer.audioRemoteTrackSource);

const dispatch = useDispatch();
const { routes, index } = navigation.getState();
const currentRoute = routes[index].name;
Expand All @@ -51,6 +55,7 @@ export const MultiView = ({ navigation }) => {
const sourceIdsRef = useRef([]);
const netInfo = useNetInfo();
const audioRemoteTrackSourceRef = useRef(null);

const [isReconnectionScheduled, setIsReconnectionScheduled] = useState<boolean>(false);

remoteTrackSourcesRef.current = remoteTrackSources;
Expand Down Expand Up @@ -144,6 +149,25 @@ export const MultiView = ({ navigation }) => {
}
};

const buildQualityOptions = (active, layers) => {
const descendingLayers = active.sort((a, b) => b.height - a.height);

const qualityOptions: SimulcastQuality[] = descendingLayers.map((active) => ({
simulcastLayer: {
bitrate: active.bitrate,
encodingId: active.id,
simulcastIdx: active.simulcastIdx,
spatialLayerId: layers.find((layer) => layer.simulcastIdx === active.simulcastIdx)?.spatialLayerId,
temporalLayerId: layers.find((layer) => layer.simulcastIdx === active.simulcastIdx)?.temporalLayerId,
maxSpatialLayerId: layers.find((layer) => layer.simulcastIdx === active.simulcastIdx)?.maxSpatialLayerId,
maxTemporalLayerId: layers.find((layer) => layer.simulcastIdx === active.simulcastIdx)?.maxTemporalLayerId,
},
streamQuality: `${active.height}p`,
}));

return [{ streamQuality: 'Auto' } as SimulcastQuality, ...qualityOptions];
};

const subscribe = async () => {
if (millicastViewRef.current?.isActive()) {
return;
Expand Down Expand Up @@ -193,6 +217,7 @@ export const MultiView = ({ navigation }) => {
payload: newRemoteTrackSource,
});
}

await viewer.project(sourceId, mappingForProjection);
dispatch({
type: 'viewer/addRemoteTrackSource',
Expand Down Expand Up @@ -231,11 +256,17 @@ export const MultiView = ({ navigation }) => {
// A new source was multiplexed over the vad tracks
break;
case 'layers':
const { medias } = data;
const mediaId = Object.keys(medias)[0];
const { active, layers } = (data as MediaStreamLayers).medias[mediaId] ?? {};
const streamQualities = buildQualityOptions(active, layers);

console.log('---> data', data);

dispatch({
type: 'viewer/setActiveLayers',
payload: data.medias?.['0']?.active,
payload: { mediaId, streamQualities },
});
// Updated layer information for each simulcast/svc video track
break;
default:
console.log('Unknown event', name);
Expand Down
2 changes: 1 addition & 1 deletion src/screens/singleStreamView/SingleStreamView.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const styles = () =>
...StyleSheet.absoluteFill,
},
bottomMultimediaContainer: {
width,
width: '100%',
alignItems: 'stretch',
justifyContent: 'space-between',
paddingVertical: 15,
Expand Down
Loading