Build1 publisher3 min readPublished
iOS reports the raw sensor frame until the camera produces its first picture
One developer's four clean runs against livekit-client 2.22.3 all read the track dimensions after the preview appeared. Reading there lands outside the roughly 100 ms window in which a portrait iPhone claims 1920 by 1080.
The Engineer · Build desk

What happened
- A developer tested livekit-client 2.22.3 on an iPhone 15 running iOS 26.6 in four configurations, and in every run the reported track dimensions matched the portrait picture the browser drew.
- Logging from the moment the track existed showed 1920 by 1080 returned at +1071 ms and 1080 by 1920 after the first frame at +1473 ms in the same run.
- LiveKit issue 1377 was opened in January 2025, collected reports from three separate people over thirteen months, and was closed with nothing changed.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint A fixed delay before reading dimensions cannot be sized safely: the author measured 112 ms and 139 ms minutes apart on one phone and says the device, the camera, the requested resolution and phone load all move it.
- exposure The early pair is signalled and not merely logged, so every remote participant renders a portrait publisher sideways until the publishing side is changed.
- decision Keying on the first frame through requestVideoFrameCallback sets a Safari 15.4 floor, so anyone supporting older browsers still has to decide what the fallback reads.
- contradiction The post's own first-run trace is 402 ms wide while the text calls that run 112 ms, so a team sizing the window from this account should treat a tenth of a second as the optimistic end.
Read `track.dimensions` the moment the track exists on iOS and the camera hands back the raw sensor frame, 1920 by 1080, on a phone held upright [1][8]. It keeps saying that until it has actually produced a picture, then it corrects itself to 1080 by 1920 [13].
livekit-client's `waitForDimensions` sleeps 10 ms on iOS and then polls until dimensions exist [19]. They exist immediately, and they are wrong, so the call returns at roughly +12 ms holding the landscape pair [19]. That pair is what the room receives as `req.width` and `req.height`, so a portrait phone announces itself as landscape and every other participant lays it out sideways [20].
Four clean runs proved nothing because all four read the numbers after the preview appeared [14]. Same phone, same ten minutes: switching his own fix off reproduced the sideways recording [6]. The author's argument for blaming the test and not the phone is short. If the track reported portrait, the fix would have nothing to trigger on, and fix on and fix off would produce identical files [7]. He caught the flip only because his Android device lags [15].
The two window figures in the post do not both reconcile with the trace. Run one logs `waitForDimensions` returning 1920 by 1080 at +1071 ms and the corrected 1080 by 1920 at +1473 ms, 402 ms apart, while the text gives that run's window as 112 ms [8][10][11]. Run two logs 1377 ms and then 1516 ms, and 139 ms is exactly the stated gap [9][12]. The author writes that the window moves with the device, the camera, the requested resolution and how busy the phone is [21].
LiveKit's issue 1377, "Incorrect orientation of a remote video track's dimensions", was opened in January 2025, drew reports from three separate people over thirteen months, and was closed with nothing changed after a core engineer reopened it once when a bot closed it [17]. The engineer's comment, as quoted in the post, said "browsers report wrong initial resolution on iOS" [18].
The fix keys on a frame instead of a clock. Create a detached video element, mute it, and let `requestVideoFrameCallback` fire when the first frame has been through the pipeline; it wants Safari 15.4 or newer, works in Chrome, and nothing has to be in the DOM [22]. Anything below that floor falls back to a timer, and the author's position on timers is that a fixed delay is a race you eventually lose as well as a tax on every user who did not need the wait [21]. He put his own version on GitHub under MIT in the hope that a library would take it [23].
The tested surface is narrow. The post says four libraries were checked, and the four runs it enumerates are LiveKit's 720p preset, its 1080p preset, a microphone track in the same call, and the author's own constraints with no LiveKit in the path, all on one iPhone 15 running iOS 26.6 [4][5]. For the 112 ms figure to mean anything in another stack you would need the same early read and a comparably quick first frame, and the second run on the same phone came back 139 ms [9][10].
What to watch
- Whether LiveKit reopens issue 1377 and changes waitForDimensions to key on the first frame instead of polling for existence.
- Traces from other phones, other iOS versions and other WebRTC clients showing whether the window appears outside one iPhone 15 on iOS 26.6.
- Whether any client library picks up the author's MIT-licensed fix rather than leaving it in application code.