A USB3 3D camera that runs for a minute and then drags the whole Linux desktop down is rarely a driver bug. The log tells the real story: streams enumerate, the first frames arrive, and then control-transfer warnings repeat until they end with 'Resource temporarily unavailable', number 11. That is EAGAIN, and it means the host controller is out of budget — the streams you switched on, plus the host-side filters processing them, have filled the link and the queues behind it.
This page gives you the arithmetic to size that load before you stream, the four causes ranked by how often each is the culprit, a test for every cause, and the fixes that keep a depth camera alive on a bench PC or a laptop.
What the freeze looks like
The sequence is consistent enough to diagnose from the log alone. Enumeration completes, the driver prints every stream with its resolution, rate and format, and the node comes up. Seconds or minutes later the warnings begin. Start-up warnings where the error field reads 'Success' and the number 0 are descriptor retries; ignore them. The fatal signature is the same warning recurring mid-stream with 'Resource temporarily unavailable', number 11 — a control transfer that could not be serviced — followed by random freezes of the whole session.
Two more log lines are worth reading. A device USB type of 3.2 confirms the link negotiated SuperSpeed. A physical ID such as 2-4-3 means bus 2 and two hub levels below it: your camera sits behind at least one hub before you plug in anything of your own. Both facts decide causes 2 and 3.
The arithmetic: what each stream costs
Size the load before you configure anything. Every image stream costs width × height × bytes per pixel × fps bytes per second:
MB/s here means one million bytes per second. For the configuration that keeps freezing:
| Stream | Format | Bytes per pixel | Rate at 30 fps |
|---|---|---|---|
| Depth, 640x480 | Z16 | 2 | 18.4 MB/s |
| Color, 1280x720 | RGB8 | 3 | 82.9 MB/s |
| Aligned depth to color | host-side re-projection | — | 0 on the wire |
| Gyro and accel, 200 Hz each | motion samples | — | a few kB/s, 400 interrupts/s |
| Total wire load | 101.4 MB/s |
The aligned-depth stream costs nothing on the cable: the host computes it from depth and color frames you have already paid for. A useful rule of thumb falls out of the formula: one megapixel at 2 bytes per pixel and 30 fps is about 60 MB/s.
The budget side is fixed by the link. A SuperSpeed host controller sizes isochronous video to about 393 MB/s per controller (1024 bytes × 16 packets × 3 per 125 µs service interval = 393.2 MB/s), the arithmetic hub vendors publish for USB 3.x video. If the link falls back to High-Speed, the cable carries 480 Mbit/s — 60 MB/s of signaling — and a single isochronous endpoint tops out at 1024 × 3 × 8,000 = 24.6 MB/s.
Cause 1, most likely: host-side filters starve the queues
Pointcloud generation and depth alignment are host work, not camera work. At 30 fps the CPU re-projects a full depth frame into the color frame every 33.3 ms, builds a cloud from depth plus texture, and services 400 IMU interrupts per second, while the driver runs its work in a large worker-thread pool and a desktop competes for the same cores. When the filters fall behind, their queues back up, the USB host controller misses deadlines, and control transfers start returning EAGAIN.
Test: watch top or htop while the camera streams. Cores pinned at or near 100% while frames still flow is your answer.
Fix: cut host load before touching code. Set the pointcloud flag (enable_pointcloud) and the depth-alignment flag (align_depth) to false, and take the gyro and accel streams (enable_gyro, enable_accel) out unless you actually fuse them. If you need the cloud, compute it downstream from the depth frames at a reduced rate. The CPU this frees usually ends the EAGAIN storm on its own. The processing-side failure is covered in Pointcloud filter slows depth camera FPS: fix the CPU load, and the combined USB3 and CPU budget for small boards in 3D depth camera on an ARM SBC: USB3 bandwidth and CPU budget.
Cause 2: the link fell back to High-Speed
A worn cable, a USB 2-era hub, or a front-panel port wired through a 480 Mbit/s path drops the link to about a tenth of its rate. On such a fallback the color stream alone, 82.9 MB/s, exceeds the 24.6 MB/s per-endpoint cap, so the camera stutters, drops frames or refuses to stream at all, and control transfers starve while the host retries.
Test: print the USB tree with speeds (lsusb -t) and read the camera's own branch. 5000M means SuperSpeed; 480M means fallback. The same output shows the topology you need for cause 3.
Fix: a short, USB 3-rated cable — passive runs past about 2 m are a common fallback source — straight into a native motherboard port, with no hub in between. If you are forced onto a fallback link, the arithmetic still gives you a plan: depth-only at 30 fps is 18.4 MB/s and fits under the 24.6 MB/s cap, so drop color and keep depth. Virtual machines are their own trap, because passed-through devices lose isochronous guarantees; run the camera natively. The refusal patterns are covered in Depth camera fails on a USB hub: why raw streams refuse to start and USB3 Vision transfer errors: diagnose bandwidth and buffers, and the VM case in Depth camera color stream timeout in a VM: fix the USB link.
Cause 3: a hub or a shared controller splits the budget
About 393 MB/s is the budget of one host controller, not of one port. Laptops wire several external ports, the internal webcam, Bluetooth and the card reader through one or two controllers behind internal hubs, and a desktop front panel is a hub in a box. A second high-rate device on the same branch doubles your load: two cameras at 101.4 MB/s each draw 202.8 MB/s, roughly 52% of one controller's budget — acceptable on a dedicated controller, risky when a webcam and card reader share it.
Test: in the USB tree, note every device that shares a branch or a bus number with the camera. Each one is competition for the same 393 MB/s.
Fix: give each high-rate camera its own root port on its own controller, and leave that controller otherwise empty. If your driver exposes a port-id setting (usb_port_id in the usual parameter tree), pin each camera to a physical port so replug order cannot shuffle them. The splitting method is the same one applied to hubs in USB3 hub bandwidth for multiple machine vision cameras and to whole hosts in Multiple USB cameras on one host: bandwidth and power budget.
Cause 4: autosuspend and power
Linux runtime power management suspends a USB device it believes is idle. A depth camera between frame bursts can look idle, the kernel suspends it, and the next control transfer wakes nothing: EAGAIN again, at random intervals. The signature is worst on pipelines whose consumers pause while streams stay open.
Test: follow the kernel log while streaming (dmesg -w, or journalctl -kf) and watch for the camera disconnecting and returning with a new device number. Then read its power/control attribute — for a device on bus 2, port 4 that is /sys/bus/usb/devices/2-4/power/control. A camera that must never sleep should read on, not auto.
Fix: set that attribute to on through a udev rule so it survives replugs, or disable autosuspend bench-wide with usbcore.autosuspend=-1. Power brownouts produce the same reconnect loop: a bus-powered camera on a long cable dips under load, and the log shows it vanishing and returning. Feed it a port that delivers full power and retest. If the IMU stream is the first to die, the isolation order is in Camera IMU stream freezes: isolate USB and pipeline faults.
Worked example: before and after
Fix the failing configuration with numbers, not hunches.
Before: depth at 640 × 480 × 2 × 30 = 18,432,000 B/s and color at 1280 × 720 × 3 × 30 = 82,944,000 B/s, so 18,432,000 + 82,944,000 = 101,376,000 B/s ≈ 101.4 MB/s on the wire — 26% of one controller's 393.2 MB/s. The wire had room. The host, though, ran 30 alignment passes and 30 pointcloud builds per second over frames of 307,200 and 921,600 pixels, plus 400 IMU interrupts, on a machine also driving a desktop. The EAGAIN at that point is a CPU budget failure, not a link failure.
After: pointcloud off, alignment off, IMU off, color reduced to 15 fps. Color becomes 1280 × 720 × 3 × 15 = 41,472,000 B/s ≈ 41.5 MB/s, so the new total is 18.4 + 41.5 = 59.9 MB/s, about 15% of the budget — and the CPU drops two full-frame passes per frame interval plus all 400 interrupts.
The decision ladder that follows:
- One trimmed camera at 59.9 MB/s: any native SuperSpeed port carries it indefinitely.
- Two cameras at the full 101.4 MB/s each: 202.8 MB/s, 52% — one dedicated controller per camera, both verified at 5000M.
- Three trimmed cameras: 179.7 MB/s, 46% — one strong controller can hold all three.
- Three cameras at full rate: 304.1 MB/s, 77% — legal but without margin, so trim rates before adding a fourth.
- Keep every controller under about 315 MB/s, 80% of budget, so control transfers and retries always have room.
When it is not bandwidth
Three signatures point away from bandwidth. Start-up retries whose error field reads 'Success' stop once streams run; they are descriptor reads, not faults. An instant disconnect that returns with a new device number on every plug is a cable or power fault — swap the cable before anything else. And a freeze with a clean USB log, no EAGAIN and no disconnects, usually belongs to the graphics stack on a laptop: test by streaming headless on the bench before blaming the camera.
If control transfers stall while frames keep flowing, the recovery pattern — serialise control access and recover the device without re-enumerating — is in Multi-camera USB control transfer freezes: serialise and recover.
Fix checklist
Run this list in order on any USB3 depth camera that freezes:
- Compute the wire total first — width × height × bytes per pixel × fps for every stream, then summed. It decides everything after it.
- Read the USB tree and confirm the camera's branch shows 5000M. A 480M line invalidates every later test.
- Trim the launch file: pointcloud and depth alignment off unless consumed, gyro and accel off unless fused, color at the lowest fps your algorithm accepts.
- Give each high-rate camera its own root port on its own controller, and nothing else shares that controller.
- Pin power management: the camera's power/control reads on, or autosuspend is off bench-wide.
- Log the kernel during the first hour of soak testing. A reconnect with a new device number is cable or power, not software.
- Before ordering hardware, re-run the ladder with your own resolutions and rates — it is two multiplications per stream. The sibling pages under 3D vision cover the GigE and ARM variants.
Bench hardware that keeps the links separate
On a bench that must run for shifts, the cleanest fix is a fanless vision controller with several USB 3 ports beside its own LAN ports, so no internal hub shares your camera's link. The vision controllers category exists for exactly this problem, and the same arithmetic carries over to 3D sensors on GigE, as Two GigE cameras on one host: NIC ports and bandwidth budget shows for the wired case.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 8 built-in channels
For a multi-camera bench, the MV-VC5525-256G70-NN pairs 3-4 USB 3 ports with 5+ LAN ports and PoE camera ports, so a USB3 depth camera and GigE profilers each get their own ports, with a 12th-I5 CPU and 32 GB of memory behind them.
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 6 built-in channels
When the pointcloud stays on at full rate, the MV-VC4712-256G10-2TH brings an Ultra 7 255H CPU, 2 USB 3 ports and PoE camera ports — the headroom case from the ladder above.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
For a single trimmed camera, the MV-VC3301H-128G66 provides 3-4 USB 3 ports and 5+ LAN ports on the entry end and includes the VM6200Pro license.
Size your camera list with the ladder, then run it through the configurator below, or ask us — in-stock items ship within one business day.
The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.
Questions
How much USB3 bandwidth does a 640x480 depth stream need at 30 fps?
Z16 depth carries 2 bytes per pixel, so one frame is 640 × 480 × 2 = 614,400 bytes and 30 fps moves 18.4 MB/s. Add a 1280x720 RGB8 color stream at the same rate and the pair draws 82.9 + 18.4 ≈ 101.4 MB/s. That is about 26% of the roughly 393 MB/s one SuperSpeed host controller budgets for isochronous video, so it fits a clean dedicated link with room to spare.
What does 'Resource temporarily unavailable' on a control transfer mean?
That string is errno 11, EAGAIN: the request could not be serviced right now. Mid-stream it almost always means the host controller is saturated — image streams plus host-side filters have filled the queues, so parameter and frame requests time out. It is a contention symptom rather than a broken driver, so treat recurring EAGAIN as a bandwidth and CPU budget alarm and cut load before you touch code.
Can one USB3 controller carry two depth cameras?
Yes, if the arithmetic fits. One SuperSpeed controller budgets about 393 MB/s for isochronous video; two cameras drawing 101.4 MB/s each total 202.8 MB/s, roughly 52%. That is workable on a dedicated controller and risky through a hub or a controller that also carries a webcam and card reader. For three cameras, trim each stream's rate first — three trimmed cameras at 59.9 MB/s each sit near 46% and run comfortably.
Does the pointcloud filter consume USB bandwidth?
No. The cloud is computed on the host from depth and color frames the camera already sent, so its cost is CPU and memory, not wire. The indirect effect is real: when the filter falls behind, its queues back up and the USB host controller misses deadlines, which is when control transfers start failing with EAGAIN. Compute the cloud downstream from the depth frames, or at a reduced rate, instead of abandoning the stream.
What should the camera's branch show in the USB tree?
5000M, which means SuperSpeed. If it reads 480M the link has fallen back to High-Speed, where the cable carries 60 MB/s of signaling and one isochronous endpoint tops out at 24.6 MB/s. An 82.9 MB/s color stream cannot run on that link at any frame rate you would accept, while depth-only at 18.4 MB/s fits, so a fallback link means: new cable, native port, depth-only as the stopgap.


