Skip to content

Commit 813014f

Browse files
FCE-2645: Investigate iOS error when leaving screen with screen sharing (#542)
## Description - Add `presentBroadcastPicker()` to `useScreenShare()` (mobile-client) and the underlying SDK - Bump `packages/react-native-webrtc` to FCE-2645 (adds the native helper + `presentBroadcastPicker` RCT method) - FishjamChat: on iOS, route disconnect / toggle-off through the system Stop Broadcast sheet; user taps Leave again after stopping ## Motivation and Context Leaving the call with screen sharing active on iOS triggered a system "Screen sharing stopped" error dialog because `stopStreaming()` force-closes the host socket and the extension can only terminate via `finishBroadcastWithError(_:)`. Presenting the system Stop sheet routes termination through `broadcastFinished()` instead, which is dialog-free. ## 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 2d124d8 commit 813014f

4 files changed

Lines changed: 35 additions & 5 deletions

File tree

examples/mobile-client/fishjam-chat/app/room/[roomName].tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from '@fishjam-cloud/react-native-client';
1010
import { router, useLocalSearchParams } from 'expo-router';
1111
import React, { useCallback, useEffect } from 'react';
12-
import { StyleSheet, View } from 'react-native';
12+
import { Platform, StyleSheet, View } from 'react-native';
1313
import { SafeAreaView } from 'react-native-safe-area-context';
1414

1515
import { InCallButton, VideosGrid } from '../../components';
@@ -28,9 +28,20 @@ export default function RoomScreen() {
2828
startStreaming,
2929
stopStreaming,
3030
stream: screenShareStream,
31+
presentBroadcastPicker,
3132
} = useScreenShare();
3233

3334
const handleDisconnect = useCallback(async () => {
35+
if (screenShareStream && Platform.OS === 'ios') {
36+
// iOS: must end the broadcast via the system sheet first to avoid
37+
// the "Screen sharing stopped" error dialog. Tap leave again after.
38+
try {
39+
await presentBroadcastPicker();
40+
return;
41+
} catch (e) {
42+
console.error('Error presenting broadcast picker:', e);
43+
}
44+
}
3445
try {
3546
if (screenShareStream) {
3647
await stopStreaming();
@@ -40,19 +51,28 @@ export default function RoomScreen() {
4051
console.error('Error leaving room:', e);
4152
}
4253
router.replace('/(tabs)/room');
43-
}, [leaveRoom, screenShareStream, stopStreaming]);
54+
}, [leaveRoom, presentBroadcastPicker, screenShareStream, stopStreaming]);
4455

4556
const handleToggleScreenShare = useCallback(async () => {
4657
try {
4758
if (screenShareStream) {
48-
await stopStreaming();
59+
if (Platform.OS === 'ios') {
60+
await presentBroadcastPicker();
61+
} else {
62+
await stopStreaming();
63+
}
4964
} else {
5065
await startStreaming();
5166
}
5267
} catch (e) {
5368
console.error('Error toggling screen share:', e);
5469
}
55-
}, [screenShareStream, startStreaming, stopStreaming]);
70+
}, [
71+
presentBroadcastPicker,
72+
screenShareStream,
73+
startStreaming,
74+
stopStreaming,
75+
]);
5676

5777
useForegroundService({
5878
channelName: 'Fishjam Chat Notifications',

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '@fishjam-cloud/react-client';
1313
import type { CallKitAction, CallKitConfig, MediaStream as RNMediaStream } from '@fishjam-cloud/react-native-webrtc';
1414
import {
15+
presentBroadcastPicker,
1516
useCallKit as useCallKitRNWebRTC,
1617
useCallKitEvent as useCallKitEventRNWebRTC,
1718
useCallKitService as useCallKitServiceRNWebRTC,
@@ -78,6 +79,7 @@ export function useScreenShare(): UseScreenShareResult {
7879
audioTrack: result.audioTrack as UseScreenShareResult['audioTrack'],
7980
currentTracksMiddleware: result.currentTracksMiddleware as TracksMiddleware | null,
8081
setTracksMiddleware,
82+
presentBroadcastPicker,
8183
};
8284
}
8385

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ export type UseScreenShareResult = Omit<
8787
audioTrack: RNMediaStreamTrack | null;
8888
currentTracksMiddleware: TracksMiddleware | null;
8989
setTracksMiddleware: (middleware: TracksMiddleware | null) => Promise<void>;
90+
/**
91+
* iOS only. Presents the system `RPSystemBroadcastPickerView`. When a
92+
* broadcast is active, this opens the system "Stop Broadcast" sheet so
93+
* the user can end it cleanly (via `broadcastFinished()`) and avoid the
94+
* "Screen sharing stopped" error dialog that `stopStreaming` triggers
95+
* by force-closing the host-side socket. No-op on non-iOS.
96+
*/
97+
presentBroadcastPicker: () => Promise<void>;
9098
};
9199

92100
export type UseCustomSourceResult = Omit<ReturnType<typeof useCustomSourceReactClient>, 'stream' | 'setStream'> & {

0 commit comments

Comments
 (0)