Skip to content

Commit e066486

Browse files
FCE-3322: Fix react native MediaStreamTrack (#539)
## Description - Re-export `MediaStreamTrack` from `@fishjam-cloud/react-native-webrtc` so mobile consumers get the RN-native track type. - Override `Track` and `RemoteTrack` so their `track` field is typed as `RNMediaStreamTrack` instead of the web type. - Override `useCamera`, `useMicrophone`, `useScreenShare` results (and middleware types) to use RN media types for `startCamera`/`startMicrophone` returns, `videoTrack`/`audioTrack`, and `*Middleware` setters. - Move `MiddlewareResult`, `TrackMiddleware`, `TracksMiddleware`, `TracksMiddlewareResult` exports to the mobile overrides. ## Motivation and Context The mobile client was leaking the web `MediaStreamTrack` type through hooks and track objects, causing type mismatches for RN consumers. This aligns all media track types with `react-native-webrtc`. ## Documentation impact - [ ] Documentation update required - [ ] Documentation updated [in another PR](_) - [x] No documentation update required ## Types of changes - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
1 parent 173f98e commit e066486

3 files changed

Lines changed: 95 additions & 13 deletions

File tree

packages/mobile-client/src/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export type {
2929
CallKitAction,
3030
CallKitConfig,
3131
MediaStream,
32+
MediaStreamTrack,
3233
AudioDevice,
3334
AudioOutputChangedInfo,
3435
UseAudioOutputResult,
@@ -77,6 +78,10 @@ export type {
7778
InitializeDevicesResult,
7879
PeerWithTracks,
7980
TrackFields,
81+
MiddlewareResult,
82+
TrackMiddleware,
83+
TracksMiddleware,
84+
TracksMiddlewareResult,
8085
} from './overrides/types';
8186

8287
export type {
@@ -90,16 +95,12 @@ export type {
9095
DeviceError,
9196
DeviceItem,
9297
InitializeDevicesStatus,
93-
MiddlewareResult,
9498
PeerId,
9599
PeerStatus,
96100
PersistLastDeviceHandlers,
97101
SimulcastBandwidthLimits,
98102
StreamConfig,
99103
TrackId,
100-
TrackMiddleware,
101-
TracksMiddleware,
102-
TracksMiddlewareResult,
103104
AuthErrorReason,
104105
JoinErrorReason,
105106
UseDataChannelResult,

packages/mobile-client/src/overrides/hooks.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import {
2+
type TrackMiddleware as ReactTrackMiddleware,
3+
type TracksMiddleware as ReactTracksMiddleware,
24
useCamera as useCameraReactClient,
35
useCustomSource as useCustomSourceReactClient,
46
useInitializeDevices as useInitializeDevicesReactClient,
@@ -21,31 +23,61 @@ import type {
2123
InitializeDevicesResult,
2224
PeerWithTracks,
2325
RemoteTrack,
26+
TrackMiddleware,
27+
TracksMiddleware,
28+
UseCameraResult,
2429
UseLivestreamStreamerResult,
2530
UseLivestreamViewerResult,
31+
UseMicrophoneResult,
32+
UseScreenShareResult,
2633
} from './types';
2734

28-
export function useCamera() {
35+
export function useCamera(): UseCameraResult {
2936
const result = useCameraReactClient();
37+
const { setCameraTrackMiddleware: setCameraTrackMiddlewareReact } = result;
38+
const setCameraTrackMiddleware = useCallback(
39+
(middleware: TrackMiddleware) => setCameraTrackMiddlewareReact(middleware as ReactTrackMiddleware),
40+
[setCameraTrackMiddlewareReact],
41+
);
3042
return {
3143
...result,
3244
cameraStream: result.cameraStream as RNMediaStream | null,
45+
startCamera: result.startCamera as UseCameraResult['startCamera'],
46+
currentCameraMiddleware: result.currentCameraMiddleware as TrackMiddleware,
47+
setCameraTrackMiddleware,
3348
};
3449
}
3550

36-
export function useMicrophone() {
51+
export function useMicrophone(): UseMicrophoneResult {
3752
const { toggleMicrophoneMute: _, ...rest } = useMicrophoneReactClient();
53+
const { setMicrophoneTrackMiddleware: setMicrophoneTrackMiddlewareReact } = rest;
54+
const setMicrophoneTrackMiddleware = useCallback(
55+
(middleware: TrackMiddleware) => setMicrophoneTrackMiddlewareReact(middleware as ReactTrackMiddleware),
56+
[setMicrophoneTrackMiddlewareReact],
57+
);
3858
return {
3959
...rest,
4060
microphoneStream: rest.microphoneStream as RNMediaStream | null,
61+
startMicrophone: rest.startMicrophone as UseMicrophoneResult['startMicrophone'],
62+
currentMicrophoneMiddleware: rest.currentMicrophoneMiddleware as TrackMiddleware,
63+
setMicrophoneTrackMiddleware,
4164
};
4265
}
4366

44-
export function useScreenShare() {
67+
export function useScreenShare(): UseScreenShareResult {
4568
const result = useScreenShareReactClient();
69+
const { setTracksMiddleware: setTracksMiddlewareReact } = result;
70+
const setTracksMiddleware = useCallback(
71+
(middleware: TracksMiddleware | null) => setTracksMiddlewareReact(middleware as ReactTracksMiddleware | null),
72+
[setTracksMiddlewareReact],
73+
);
4674
return {
4775
...result,
4876
stream: result.stream as RNMediaStream | null,
77+
videoTrack: result.videoTrack as UseScreenShareResult['videoTrack'],
78+
audioTrack: result.audioTrack as UseScreenShareResult['audioTrack'],
79+
currentTracksMiddleware: result.currentTracksMiddleware as TracksMiddleware | null,
80+
setTracksMiddleware,
4981
};
5082
}
5183

packages/mobile-client/src/overrides/types.ts

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {
22
CustomSource as ReactClientCustomSource,
3+
DeviceError,
34
InitializeDevicesResult as ReactClientInitializeDevicesResult,
45
PeerWithTracks as ReactClientPeerWithTracks,
56
RemoteTrack as ReactClientRemoteTrack,
@@ -12,7 +13,10 @@ import type {
1213
useMicrophone as useMicrophoneReactClient,
1314
useScreenShare as useScreenShareReactClient,
1415
} from '@fishjam-cloud/react-client';
15-
import type { MediaStream as RNMediaStream } from '@fishjam-cloud/react-native-webrtc';
16+
import type {
17+
MediaStream as RNMediaStream,
18+
MediaStreamTrack as RNMediaStreamTrack,
19+
} from '@fishjam-cloud/react-native-webrtc';
1620

1721
export type StreamerInputs =
1822
| { video: RNMediaStream; audio?: RNMediaStream | null }
@@ -31,19 +35,58 @@ export type UseLivestreamViewerResult = Omit<ReactClientUseLivestreamViewerResul
3135
stream: RNMediaStream | null;
3236
};
3337

34-
export type UseCameraResult = Omit<ReturnType<typeof useCameraReactClient>, 'cameraStream'> & {
38+
export type MiddlewareResult = { track: RNMediaStreamTrack; onClear?: () => void };
39+
40+
export type TrackMiddleware = ((track: RNMediaStreamTrack) => MiddlewareResult | Promise<MiddlewareResult>) | null;
41+
42+
export type TracksMiddlewareResult = {
43+
videoTrack: RNMediaStreamTrack;
44+
audioTrack: RNMediaStreamTrack | null;
45+
onClear: () => void;
46+
};
47+
48+
export type TracksMiddleware = (
49+
videoTrack: RNMediaStreamTrack,
50+
audioTrack: RNMediaStreamTrack | null,
51+
) => TracksMiddlewareResult | Promise<TracksMiddlewareResult>;
52+
53+
export type UseCameraResult = Omit<
54+
ReturnType<typeof useCameraReactClient>,
55+
'cameraStream' | 'startCamera' | 'currentCameraMiddleware' | 'setCameraTrackMiddleware'
56+
> & {
3557
cameraStream: RNMediaStream | null;
58+
startCamera: (
59+
...args: Parameters<ReturnType<typeof useCameraReactClient>['startCamera']>
60+
) => Promise<[RNMediaStreamTrack, null] | [null, DeviceError]>;
61+
currentCameraMiddleware: TrackMiddleware;
62+
setCameraTrackMiddleware: (middleware: TrackMiddleware) => Promise<void>;
3663
};
3764

3865
export type UseMicrophoneResult = Omit<
3966
ReturnType<typeof useMicrophoneReactClient>,
40-
'toggleMicrophoneMute' | 'microphoneStream'
67+
| 'toggleMicrophoneMute'
68+
| 'microphoneStream'
69+
| 'startMicrophone'
70+
| 'currentMicrophoneMiddleware'
71+
| 'setMicrophoneTrackMiddleware'
4172
> & {
4273
microphoneStream: RNMediaStream | null;
74+
startMicrophone: (
75+
...args: Parameters<ReturnType<typeof useMicrophoneReactClient>['startMicrophone']>
76+
) => Promise<[RNMediaStreamTrack, null] | [null, DeviceError]>;
77+
currentMicrophoneMiddleware: TrackMiddleware;
78+
setMicrophoneTrackMiddleware: (middleware: TrackMiddleware) => Promise<void>;
4379
};
4480

45-
export type UseScreenShareResult = Omit<ReturnType<typeof useScreenShareReactClient>, 'stream'> & {
81+
export type UseScreenShareResult = Omit<
82+
ReturnType<typeof useScreenShareReactClient>,
83+
'stream' | 'videoTrack' | 'audioTrack' | 'currentTracksMiddleware' | 'setTracksMiddleware'
84+
> & {
4685
stream: RNMediaStream | null;
86+
videoTrack: RNMediaStreamTrack | null;
87+
audioTrack: RNMediaStreamTrack | null;
88+
currentTracksMiddleware: TracksMiddleware | null;
89+
setTracksMiddleware: (middleware: TracksMiddleware | null) => Promise<void>;
4790
};
4891

4992
export type UseCustomSourceResult = Omit<ReturnType<typeof useCustomSourceReactClient>, 'stream' | 'setStream'> & {
@@ -57,9 +100,15 @@ export type UseInitializeDevicesReturn = {
57100
) => Promise<InitializeDevicesResult>;
58101
};
59102

60-
export type Track = Omit<ReactClientTrack, 'stream'> & { stream: RNMediaStream | null };
103+
export type Track = Omit<ReactClientTrack, 'stream' | 'track'> & {
104+
stream: RNMediaStream | null;
105+
track: RNMediaStreamTrack | null;
106+
};
61107

62-
export type RemoteTrack = Omit<ReactClientRemoteTrack, 'stream'> & { stream: RNMediaStream | null };
108+
export type RemoteTrack = Omit<ReactClientRemoteTrack, 'stream' | 'track'> & {
109+
stream: RNMediaStream | null;
110+
track: RNMediaStreamTrack | null;
111+
};
63112

64113
export type CustomSource<T extends string> = Omit<ReactClientCustomSource<T>, 'stream'> & { stream?: RNMediaStream };
65114

0 commit comments

Comments
 (0)