fix/ios camera memory - #284
Merged
Merged
Conversation
AndrewRoddy
commented
Sep 20, 2026
Collaborator
- Cut the segmentation memory peak so iOS stops killing the tab
- Say why the camera is unavailable, and how to get it back
Tapping an item on an iPhone reloaded the page. Nothing was caught and nothing was logged, because nothing threw: iOS gives a tab a few hundred megabytes and kills it outright when it goes over. The tap is where the encoder runs, so the tap is where the budget ran out. Four things were spending it before the model ever did any work: - The ORT bundle was ort.all, which carries WebGPU, WebGL, WebNN and the training runtime, and loads the 23 MB JSEP WebAssembly binary whether or not the device has a GPU. The plain WASM build is 12 MB. Pick the bundle from navigator.gpu, and skip the doomed WebGPU session attempt where the runtime was never loaded. - numThreads was set to min(4, cores) unconditionally. Threaded WASM runs on SharedArrayBuffer, which needs COOP/COEP headers this app does not send, so those threads could never exist. Ask for one. - Both models were loaded and instantiated in parallel, holding two ONNX buffers and the runtime's copy of each at once. Sequential, releasing each buffer before reaching for the next, halves that high water mark. The download is the slow part and it is cached after the first run. - Caching a downloaded model sliced it first, so a 40 MB encoder existed three times over: ours, the slice, and the Response body. Response copies what it is handed, so the slice bought nothing. The scratch canvas in prepareTensor is also given back explicitly now rather than waiting for a collection Safari is in no hurry to run.
Two failures looked identical from the viewfinder: a plain http:// origin, where Safari withholds navigator.mediaDevices entirely and there is no prompt to show, and a refusal, which Safari remembers per site and then repeats without ever prompting again. Both left the same inactive stage and a button that did nothing, and tapping it again could not help in either case. The browser is now asked what it supports before anything is offered, so an insecure origin says so instead of presenting a dead button. And openCamera reports its outcome rather than throwing it, because interop flattens a thrown error down to its message and the DOMException name is the part that separates a refusal the person can undo from a device that simply has no camera. A refusal now carries the steps back through Safari's own settings. Flipping the camera tears the old stream down before asking for the new one, so it reports the same way - a refusal there used to leave a blank stage with nothing said.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.