Skip to content

Commit

Permalink
[FCE-402] Simplify start camera api (#81)
Browse files Browse the repository at this point in the history
## Description

Remove possibility to set Track Metadata when enabling camera
Simplify simulcast configuration (as SDK will now only enable/disable
this config - and values will be set automatically)

## Motivation and Context

Make our API simpler

## How has this been tested?

It was tested on example app

## Types of changes

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to
      not work as expected)

## Checklist:

- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.

## Screenshots (if appropriate)
  • Loading branch information
mironiasty authored Aug 26, 2024
1 parent 5fde67b commit 7afa7f9
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 109 deletions.
26 changes: 0 additions & 26 deletions examples/video-chat/hooks/useToggleCamera.ts

This file was deleted.

14 changes: 2 additions & 12 deletions examples/video-chat/screens/PreviewScreen/PreviewScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import {
displayIosSimulatorCameraAlert,
isIosSimulator,
} from '../../utils/deviceUtils';
import { useToggleCamera } from '../../hooks/useToggleCamera';

type Props = NativeStackScreenProps<AppRootStackParamList, 'Preview'>;
type BottomSheetRef = Props & {
Expand All @@ -60,6 +59,7 @@ function PreviewScreen({
simulcastConfig,
toggleVideoTrackEncoding,
switchCamera,
toggleCamera,
} = useCamera();
const { isMicrophoneOn, toggleMicrophone } = useMicrophone();

Expand Down Expand Up @@ -87,17 +87,9 @@ function PreviewScreen({
const captureDevice = devices.find((device) => device.isFrontFacing);

startCamera({
simulcastConfig: {
enabled: true,
activeEncodings:
// iOS has a limit of 3 hardware encoders
// 3 simulcast layers + 1 screencast layer = 4, which is too much
// so we limit simulcast layers to 2
Platform.OS === 'android' ? ['l', 'm', 'h'] : ['l', 'h'],
},
simulcastEnabled: true,
quality: 'HD169',
maxBandwidth: { l: 150, m: 500, h: 1500 },
videoTrackMetadata: { active: true, type: 'camera' },
captureDeviceId: captureDevice?.id,
cameraEnabled: true,
});
Expand All @@ -124,8 +116,6 @@ function PreviewScreen({
}
}, []);

const { toggleCamera } = useToggleCamera();

return (
<SafeAreaView style={styles.container}>
<View style={styles.cameraPreview}>
Expand Down
4 changes: 1 addition & 3 deletions examples/video-chat/screens/RoomScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
useForegroundService,
} from '../hooks/useForegroundService';
import { usePreventBackButton } from '../hooks/usePreventBackButton';
import { useToggleCamera } from '../hooks/useToggleCamera';
import type { AppRootStackParamList } from '../navigators/AppNavigator';
import { roomScreenLabels } from '../types/ComponentLabels';
import { parsePeersToTracks } from '../components/VideosGrid';
Expand All @@ -42,8 +41,7 @@ const RoomScreen = ({ navigation, route }: Props) => {
usePreventBackButton();
const audioSettings = useAudioSettings();

const { isCameraOn, flipCamera } = useCamera();
const { toggleCamera } = useToggleCamera();
const { isCameraOn, flipCamera, toggleCamera } = useCamera();
const { isMicrophoneOn, toggleMicrophone } = useMicrophone();

useForegroundService();
Expand Down
21 changes: 3 additions & 18 deletions packages/react-native-client/src/RNFishjamClientModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,12 @@ import { requireNativeModule } from 'expo-modules-core';
import { NativeModule } from 'react-native';

import type { RTCStats } from './stats/types';
import type {
BandwidthLimit,
Metadata,
SimulcastBandwidthLimit,
SimulcastConfig,
} from './types';
import type { CameraConfig, CaptureDevice } from './hooks/useCamera';
import type { Metadata, SimulcastConfig } from './types';
import type { CameraConfigInternal, CaptureDevice } from './hooks/useCamera';
import type { Peer } from './hooks/usePeers';
import type { ScreencastOptions } from './hooks/useScreencast';
import type { ConnectionConfig } from './common/client';

type InternalCameraConfig<MetadataType extends Metadata> = Partial<
CameraConfig<MetadataType> &
(
| { maxBandwidthInt: BandwidthLimit }
| { maxBandwidthMap: SimulcastBandwidthLimit }
)
>;

type RNFishjamClient = {
connect: (
url: string,
Expand All @@ -29,9 +16,7 @@ type RNFishjamClient = {
config: ConnectionConfig,
) => Promise<void>;
leaveRoom: () => Promise<void>;
startCamera: <MetadataType extends Metadata>(
config: InternalCameraConfig<MetadataType>,
) => Promise<void>;
startCamera: (config: CameraConfigInternal) => Promise<void>;
isMicrophoneOn: boolean;
toggleMicrophone: () => Promise<boolean>;
isCameraOn: boolean;
Expand Down
10 changes: 0 additions & 10 deletions packages/react-native-client/src/common/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,3 @@ export async function updatePeerMetadata<PeerMetadataType extends Metadata>(
) {
await RNFishjamClientModule.updatePeerMetadata(metadata);
}

/**
* a function that updates video metadata on the server.
* @param metadata a map string -> any containing video track metadata to be sent to the server
*/
export async function updateVideoTrackMetadata<
VideoTrackMetadataType extends Metadata,
>(metadata: VideoTrackMetadataType) {
await RNFishjamClientModule.updateVideoTrackMetadata(metadata);
}
120 changes: 84 additions & 36 deletions packages/react-native-client/src/hooks/useCamera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BandwidthLimit,
Brand,
Metadata,
SimulcastBandwidthLimit,
SimulcastConfig,
TrackBandwidthLimit,
TrackEncoding,
Expand Down Expand Up @@ -35,7 +36,7 @@ export type VideoQuality =
| 'HD43'
| 'FHD43';

export type CameraConfig<MetadataType extends Metadata> = {
type CameraConfigBase = {
/**
* resolution + aspect ratio of local video track, one of: `QVGA_169`, `VGA_169`, `QHD_169`, `HD_169`,
* `FHD_169`, `QVGA_43`, `VGA_43`, `QHD_43`, `HD_43`, `FHD_43`. Note that quality might be worse than
Expand All @@ -48,18 +49,6 @@ export type CameraConfig<MetadataType extends Metadata> = {
* @default `true`
*/
flipVideo?: boolean;
/**
* a map `string -> any` containing video track metadata to be sent to the server.
*/
videoTrackMetadata?: MetadataType;
/**
* SimulcastConfig of a video track. By default simulcast is disabled.
*/
simulcastConfig?: SimulcastConfig;
/**
* bandwidth limit of a video track. By default there is no bandwidth limit.
*/
maxBandwidth?: TrackBandwidthLimit;
/**
* whether the camera track is initially enabled, you can toggle it on/off later with toggleCamera method
* @default `true`
Expand All @@ -73,15 +62,83 @@ export type CameraConfig<MetadataType extends Metadata> = {
captureDeviceId?: CaptureDeviceId;
};

type StartCameraConfig = <CameraConfigMetadataType extends Metadata>(
config?: Readonly<CameraConfig<CameraConfigMetadataType>>,
) => Promise<void>;
export type CameraConfig = CameraConfigBase & {
/**
* whether video track uses simulcast. By default simulcast is disabled.
*/
simulcastEnabled?: boolean;
/**
* bandwidth limit of a video track. By default there is no bandwidth limit.
*/
maxBandwidth?: TrackBandwidthLimit;
};

export type CameraConfigInternal = CameraConfigBase & {
/**
* a map `string -> any` containing video track metadata to be sent to the server.
*/
videoTrackMetadata?: Metadata;
/**
* SimulcastConfig of a video track. By default simulcast is disabled.
*/
simulcastConfig?: SimulcastConfig;
/**
* bandwidth limit of a video track. By default there is no bandwidth limit.
*/
maxBandwidth?: TrackBandwidthLimit;
} & (
| { maxBandwidthInt?: BandwidthLimit }
| { maxBandwidthMap?: SimulcastBandwidthLimit }
);

const defaultSimulcastConfig = () => ({
enabled: false,
activeEncodings: [],
});

function maxBandwidthConfig(maxBandwidth: TrackBandwidthLimit | undefined) {
if (Platform.OS === 'android') {
if (typeof maxBandwidth === 'object') {
return {
maxBandwidth: undefined,
maxBandwidthMap: maxBandwidth,
};
} else {
return {
maxBandwidth: undefined,
maxBandwidthInt: maxBandwidth,
};
}
}
return { maxBandwidth };
}

function simulcastConfig(
simulcastEnabled: boolean | undefined,
): SimulcastConfig | undefined {
// iOS has a limit of 3 hardware encoders
// 3 simulcast layers + 1 screencast layer = 4, which is too much
// so we limit simulcast layers to 2
if (simulcastEnabled) {
return Platform.select<SimulcastConfig>({
ios: { enabled: true, activeEncodings: ['l', 'h'] },
android: { enabled: true, activeEncodings: ['l', 'm', 'h'] },
});
}
return undefined;
}

export function updateCameraConfig(
config: Readonly<CameraConfig>,
): CameraConfigInternal {
return {
...config,
...maxBandwidthConfig(config.maxBandwidth),
videoTrackMetadata: { active: true, type: 'camera' },
simulcastConfig: simulcastConfig(config.simulcastEnabled),
};
}

/**
* This hook can toggle camera on/off and provides current camera state.
*/
Expand Down Expand Up @@ -144,6 +201,10 @@ export function useCamera() {
*/
const toggleCamera = useCallback(async () => {
const state = await RNFishjamClientModule.toggleCamera();
await RNFishjamClientModule.updateVideoTrackMetadata({
active: state,
type: 'camera',
});
setIsCameraOn(state);
}, []);

Expand All @@ -153,26 +214,13 @@ export function useCamera() {
* @returns A promise that resolves when camera is started.
*/

const startCamera = useCallback<StartCameraConfig>(async (config = {}) => {
// expo-modules on Android don't support Either type, so we workaround it
if (Platform.OS === 'android') {
if (typeof config.maxBandwidth === 'object') {
await RNFishjamClientModule.startCamera({
...config,
maxBandwidth: undefined,
maxBandwidthMap: config.maxBandwidth,
});
} else {
await RNFishjamClientModule.startCamera({
...config,
maxBandwidth: undefined,
maxBandwidthInt: config.maxBandwidth,
});
}
} else {
await RNFishjamClientModule.startCamera(config);
}
}, []);
const startCamera = useCallback(
async (config: Readonly<CameraConfig> = {}) => {
const updatedConfig = updateCameraConfig(config);
await RNFishjamClientModule.startCamera(updatedConfig);
},
[],
);

/**
* Function that toggles between front and back camera. By default the front camera is used.
Expand Down
5 changes: 1 addition & 4 deletions packages/react-native-client/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ export { useScreencast } from './hooks/useScreencast';
export type { ReconnectionStatus } from './hooks/useReconnection';
export { useReconnection } from './hooks/useReconnection';

export {
updatePeerMetadata,
updateVideoTrackMetadata,
} from './common/metadata';
export { updatePeerMetadata } from './common/metadata';

export type { LoggingSeverity } from './common/webRTC';
export {
Expand Down

0 comments on commit 7afa7f9

Please sign in to comment.