Play cameras through the relay instead of straight at the gateway
The player posted its SDP offer to the gateway's go2rtc directly, which cannot work from a browser on another origin: no CORS headers on any go2rtc response, a preflight required because application/sdp is not CORS-safelisted, and the password checked before CORS so that preflight gets a 401. It now hands the offer to a `signal` function the app supplies, which relays it through the backend. Pinned to iceTransportPolicy "relay" whenever ICE servers are present, so media always goes through the TURN relay and never peer-to-peer. A hosted console cannot rely on reaching a customer's gateway directly, and a camera that works from the workshop but not from home is worse than one that behaves the same everywhere. With no TURN configured it falls back to "all", which still works for a viewer on the gateway's own network. Relay-only with no relay would gather no candidates and fail every time, so the fallback is what makes an unconfigured deployment degrade rather than break - and a failed connection in that state now says so, since the browser reports nothing but "failed" and the fix is a deployment setting. It also waits for ICE gathering before signalling rather than trickling: the answer comes back through a single request/response relay hop, so there is no channel to trickle over afterwards and the offer has to carry its candidates. Bounded at 3s, because gathering can hang on a candidate that never resolves and signalling with what we have beats waiting forever. `signal` is a prop rather than a fetch in the component, like `stream` already was: @continuum/ui stays plain Vue that knows nothing of the API, which is what lets it render from a test or the desktop shell.
This commit is contained in:
@@ -17,8 +17,9 @@ import WebRTCStreamView from "./WebRTCStreamView.vue";
|
||||
* `usePrinterStream`. The player is simply not rendered.
|
||||
*/
|
||||
interface PrinterStream {
|
||||
streamUrl: string;
|
||||
cameraId: string;
|
||||
iceServers: RTCIceServer[];
|
||||
turnConfigured: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -33,6 +34,15 @@ const props = defineProps<{
|
||||
*/
|
||||
printer: AppPrinterState;
|
||||
stream?: PrinterStream | null;
|
||||
/**
|
||||
* Exchanges an offer SDP for an answer SDP, via the backend's relay.
|
||||
*
|
||||
* Passed in rather than called here, like `stream` itself: this package is
|
||||
* plain Vue with no knowledge of the API or of Nuxt, which is what lets
|
||||
* these components render from a test or the desktop shell with no server.
|
||||
* No function means no player, rather than a player that cannot signal.
|
||||
*/
|
||||
signal?: (offerSdp: string) => Promise<string>;
|
||||
}>();
|
||||
|
||||
// `status` is open-ended and null for a printer that has never reported.
|
||||
@@ -73,9 +83,11 @@ const lastSeen = computed(() => {
|
||||
</p>
|
||||
|
||||
<WebRTCStreamView
|
||||
v-if="stream"
|
||||
:stream-base-url="stream.streamUrl"
|
||||
v-if="stream && signal"
|
||||
:camera-id="stream.cameraId"
|
||||
:ice-servers="stream.iceServers"
|
||||
:turn-configured="stream.turnConfigured"
|
||||
:signal="signal"
|
||||
/>
|
||||
|
||||
<TemperatureGraph
|
||||
|
||||
Reference in New Issue
Block a user