Skip to content

Commit 1b5a274

Browse files
committed
fix(frontend): ESLint fixes and cleanup
1 parent fec36f3 commit 1b5a274

File tree

3 files changed

+24
-28
lines changed

3 files changed

+24
-28
lines changed

streamlit_webrtc/frontend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"dev": "vite",
88
"build": "tsc -b && vite build",
99
"test": "vitest",
10-
"format": "run-p format:*",
11-
"format:eslint": "eslint --fix 'src/**/*.{ts,tsx}'",
10+
"format": "pnpm run format:prettier && pnpm run format:eslint",
11+
"format:eslint": "eslint --fix \"src/**/*.{ts,tsx}\"",
1212
"format:prettier": "prettier --write .",
1313
"lint": "run-p lint:*",
1414
"lint:eslint": "eslint .",

streamlit_webrtc/frontend/src/DeviceSelect/DeviceSelect.tsx

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ interface DeviceSelectionState {
4343
videoInputs: MediaDeviceInfo[];
4444
audioInputs: MediaDeviceInfo[];
4545
audioOutputs: MediaDeviceInfo[];
46-
// TODO: Add selectedAudioOutputDeviceId
4746
selectedVideoInputDeviceId: MediaDeviceInfo["deviceId"] | undefined;
4847
selectedAudioInputDeviceId: MediaDeviceInfo["deviceId"] | undefined;
4948
}
@@ -70,6 +69,7 @@ type DeviceSelectionAction =
7069
| DeviceSelectionSetUnavailableAction
7170
| DeviceSelectionUpdateDevicesAction
7271
| DeviceSelectionUpdateSelectedDeviceIdAction;
72+
7373
const deviceSelectionReducer: Reducer<
7474
DeviceSelectionState,
7575
DeviceSelectionAction
@@ -130,6 +130,7 @@ export interface DeviceSelectProps {
130130
audio: MediaDeviceInfo["deviceId"] | undefined;
131131
}) => void;
132132
}
133+
133134
function DeviceSelect(props: DeviceSelectProps) {
134135
const {
135136
video: useVideo,
@@ -139,6 +140,7 @@ function DeviceSelect(props: DeviceSelectProps) {
139140
onSelect,
140141
} = props;
141142

143+
// ✅ Initialize to "WAITING" directly, no need to set inside effect
142144
const [permissionState, setPermissionState] =
143145
useState<PermissionState>("WAITING");
144146

@@ -175,44 +177,36 @@ function DeviceSelect(props: DeviceSelectProps) {
175177
});
176178
}, []);
177179

178-
// These values are passed to inside the useEffect below via a ref
179-
// because they are used there only for UX improvement
180-
// and should not be added to the dependency list to avoid triggering re-execution.
181-
const defaultDeviceIdsRef = useRef({
182-
video: defaultVideoDeviceId,
183-
audio: defaultAudioDeviceId,
184-
});
185-
defaultDeviceIdsRef.current = {
186-
video: defaultVideoDeviceId,
187-
audio: defaultAudioDeviceId,
188-
};
189-
// Call `getUserMedia()` to ask the user for the permission.
180+
// Store default device IDs in a ref
181+
const defaultDeviceIdsRef = useRef<{ video?: string; audio?: string }>({});
182+
183+
useEffect(() => {
184+
defaultDeviceIdsRef.current = {
185+
video: defaultVideoDeviceId,
186+
audio: defaultAudioDeviceId,
187+
};
188+
}, [defaultVideoDeviceId, defaultAudioDeviceId]);
189+
190+
// Call `getUserMedia()` to ask the user for permission.
190191
useEffect(() => {
191192
if (typeof navigator?.mediaDevices?.getUserMedia !== "function") {
192193
deviceSelectionDispatch({ type: "SET_UNAVAILABLE" });
193194
return;
194195
}
195196

196-
setPermissionState("WAITING");
197-
198197
const { video: videoDeviceId, audio: audioDeviceId } =
199198
defaultDeviceIdsRef.current;
199+
200200
navigator.mediaDevices
201201
.getUserMedia({
202-
// Specify the target devices if the user already selected specific ones.
203-
// This is not mandatory but beneficial for better UX
204-
// as unused devices are not accessed so that their LED indicators
205-
// will not be unnecessarily turned on.
206202
video:
207203
useVideo && videoDeviceId ? { deviceId: videoDeviceId } : useVideo,
208204
audio:
209205
useAudio && audioDeviceId ? { deviceId: audioDeviceId } : useAudio,
210206
})
211207
.then(async (stream) => {
212208
stopAllTracks(stream);
213-
214209
await updateDeviceList();
215-
216210
setPermissionState("ALLOWED");
217211
})
218212
.catch((err) => {
@@ -254,7 +248,7 @@ function DeviceSelect(props: DeviceSelectProps) {
254248
});
255249
}, []);
256250

257-
// Call onSelect
251+
// Call onSelect whenever inputs change
258252
useEffect(() => {
259253
const videoInput = useVideo
260254
? videoInputs.find((d) => d.deviceId === selectedVideoInputDeviceId)

streamlit_webrtc/frontend/src/webrtc/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,12 @@ export const useWebRtc = (
9191
});
9292
}, [state.webRtcState]);
9393

94+
// ✅ keep stopRef but update inside useEffect
9495
const stopRef = useRef(stop);
95-
stopRef.current = stop;
96+
97+
useEffect(() => {
98+
stopRef.current = stop;
99+
}, [stop]);
96100

97101
const start = useCallback((): Promise<void> => {
98102
if (state.webRtcState !== "STOPPED") {
@@ -129,8 +133,6 @@ export const useWebRtc = (
129133

130134
if (constraints.audio || constraints.video) {
131135
if (navigator.mediaDevices == null) {
132-
// Ref: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#privacy_and_security
133-
// > A secure context is, in short, a page loaded using HTTPS or the file:/// URL scheme, or a page loaded from localhost.
134136
throw new Error(
135137
"navigator.mediaDevices is undefined. It seems the current document is not loaded securely.",
136138
);
@@ -192,7 +194,7 @@ export const useWebRtc = (
192194
pc.addEventListener("icecandidate", (evt) => {
193195
if (evt.candidate) {
194196
console.debug("icecandidate", evt.candidate);
195-
const id = uniqueIdGenerator.get(); // NOTE: Generate the ID here to ensure it is uniquely bound to the candidate. It can be violated if it's generated in the reducer.
197+
const id = uniqueIdGenerator.get();
196198
dispatch({ type: "ADD_ICE_CANDIDATE", id, candidate: evt.candidate });
197199
}
198200
});

0 commit comments

Comments
 (0)