The renderer setting previously forced an app quit (exit(0)) because
switching backends between sessions crashed or leaked. Fix the
underlying lifecycle bugs and remove the restart requirement:
- FrameQueue: really release frames in clear(), clear on session
start/stop, and guard start/stop with an owner so a stale session's
async cleanup can't pause a new session's queue
- MetalView: weak delegate (breaks retain cycle leaking the whole Metal
stack), never start two render threads, bound the shutdown wait to
avoid deadlocking against the render thread's dispatch_sync to main
- MetalViewController: explicit idempotent shutdown called from stream
teardown (viewDidDisappear isn't guaranteed); snapshot the renderer
in render-thread callbacks to avoid use-after-free during shutdown
- MetalVideoRenderer: make the shared colorspace name thread-safe and
ARC-managed instead of a CFStringRef over-released in dealloc; guard
NULL format description extensions
- Connection: drop the static renderer reference in DrCleanup
- VideoDecoderRenderer: cache the application background state via
notifications instead of calling UIKit from the decode queue
(Main Thread Checker violation)
- Frame: don't CFRetain(NULL) when a format desc has no extensions
- StreamFrameViewController: fix _streamView cleanup ordering
- Settings: apply the backend change in place (with the Metal caveats
alert) and update localized tips; takes effect on next stream
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>