Android WebRtc多会话场景下VideoCapturerThread崩溃问题求助
Hey there, let's tackle this tricky intermittent crash you're seeing with WebRTC video calls on Android. The error Not on camera thread is a classic sign that camera-related operations are being executed on the wrong thread—especially problematic when dealing with multiple user sessions, since camera resources and their associated threads can get tangled up.
Why This Happens
WebRTC's CameraCapturer enforces that all camera lifecycle operations (like configuring the capture session) run on its internal dedicated camera thread. When you have multiple active sessions, if you're creating new VideoCapturer instances without properly cleaning up old ones, or if callbacks from the camera framework get routed to a thread that's no longer associated with the active capturer, you'll hit this crash. The stack trace points to Camera2Session$CaptureSessionCallback.onConfigured firing on a thread that isn't the capturer's designated camera thread.
Step-by-Step Fixes
1. Reuse a Single VideoCapturer Instance (or Strictly Manage Lifecycles)
Instead of creating a new VideoCapturer for every session, maintain a global singleton instance. This avoids thread conflicts from multiple capturers competing for camera resources. If you need separate capturers for different sessions (unlikely for most use cases), make sure to fully stop and release the old capturer before creating a new one.
Here's how to adjust your createCameraCapturer method to use a singleton:
// Declare a global static variable to hold the capturer private static VideoCapturer sCameraCapturer; private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { // Return existing capturer if it's already initialized if (sCameraCapturer != null) { return sCameraCapturer; } final String[] deviceNames = enumerator.getDeviceNames(); Logging.d(TAG, "Looking for front facing cameras."); for (String deviceName : deviceNames) { if (enumerator.isFrontFacing(deviceName)) { Logging.d(TAG, "Creating front facing camera capturer."); sCameraCapturer = enumerator.createCapturer(deviceName, null); if (sCameraCapturer != null) { return sCameraCapturer; } } } // Fallback to back camera if front isn't found Logging.d(TAG, "Looking for back facing cameras."); for (String deviceName : deviceNames) { if (!enumerator.isFrontFacing(deviceName)) { Logging.d(TAG, "Creating back facing camera capturer."); sCameraCapturer = enumerator.createCapturer(deviceName, null); if (sCameraCapturer != null) { return sCameraCapturer; } } } return null; }
2. Properly Release Camera Resources When Sessions End
When a user session finishes, you must stop the capture and release the capturer (if you're not reusing it). This ensures the old camera thread is cleaned up, preventing stray callbacks from triggering the crash:
private void cleanupCameraCapturer() { if (sCameraCapturer != null) { try { sCameraCapturer.stopCapture(); // For CameraCapturer implementations, cast to the specific type if needed to release if (sCameraCapturer instanceof Camera2Capturer) { ((Camera2Capturer) sCameraCapturer).dispose(); } sCameraCapturer = null; } catch (InterruptedException e) { Logging.e(TAG, "Failed to stop camera capture", e); } } }
Call this method before starting a new session or when the app moves to the background.
3. Force Callbacks to Run on the Camera Thread
If you must use multiple capturers, ensure all camera framework callbacks are posted to the capturer's dedicated thread. You can get the capturer's handler via reflection (since it's a protected member):
// After creating the capturer, get its camera thread handler Handler cameraThreadHandler = null; if (sCameraCapturer instanceof CameraCapturer) { try { Field handlerField = CameraCapturer.class.getDeclaredField("handler"); handlerField.setAccessible(true); cameraThreadHandler = (Handler) handlerField.get(sCameraCapturer); } catch (NoSuchFieldException | IllegalAccessException e) { Logging.e(TAG, "Failed to get camera thread handler", e); } } // If you have custom camera callbacks, post them to this handler if (cameraThreadHandler != null) { cameraThreadHandler.post(() -> { // Execute camera-related operations here }); }
Verify the Fix
Test your app with multiple consecutive sessions, making sure to properly clean up resources between each one. This should eliminate the intermittent "Not on camera thread" crash by ensuring all camera operations run on the correct thread and resources are properly managed.
内容的提问来源于stack exchange,提问作者Jhon

