Anmelden
DE
games/webrtc-demo / src / Net / LocalBackend.php · commit 87ad512
<?phpnamespace App\Net;use JumPHP\WebRtc\Backend;/** * A stand-in for WebRTC where there is none (headless tests, a desktop without GStreamer): the peers of THIS process are paired with each * other through the same commands and events as the real backends (doc/sidecar.md of jumphp/webrtc), one frame of delay. It only joins * peers of the same game (the loopback screen, the bot): an online game needs real WebRTC. */final class LocalBackend implements Backend{    /** @var array<string, array{channels: list<string>, other: ?string, offerer: bool}> */    private array $peers = [];    /** @var list<callable> */    private array $listeners = [];    /** @var list<array<string, mixed>> */    private array $queue = [];    public function name(): string    {        return 'simulated';    }    public function isSupported(): bool    {        return true;    }    public function send(array $command): void    {        $id = (string)($command['id'] ?? '');        switch ($command['op'] ?? '') {            case 'peer':                $this->peers[$id] = ['channels' => [], 'other' => null, 'offerer' => false];                $this->queue[] = ['ev' => 'state', 'id' => $id, 'state' => 'new'];                break;            case 'channel':                if (isset($this->peers[$id])) {                    $this->peers[$id]['channels'][] = (string)$command['label'];                }                break;            case 'offer':                if (isset($this->peers[$id])) {                    $this->peers[$id]['offerer'] = true;                    $this->queue[] = ['ev' => 'state', 'id' => $id, 'state' => 'connecting'];                    $this->queue[] = ['ev' => 'offer', 'id' => $id, 'sdp' => 'sim:' . $id];                    $this->queue[] = ['ev' => 'ice', 'id' => $id, 'candidate' => 'candidate:1 1 UDP 1 127.0.0.1 9 typ host', 'mline' => 0];                }                break;            case 'remote':                $this->remote($id, (string)$command['type'], (string)$command['sdp']);                break;            case 'send':                $other = $this->peers[$id]['other'] ?? null;                if ($other !== null && isset($this->peers[$other])) {                    $event = ['ev' => 'message', 'id' => $other, 'label' => (string)$command['label']];                    $this->queue[] = $event + (isset($command['b64']) ? ['b64' => (string)$command['b64']] : ['text' => (string)($command['text'] ?? '')]);                }                break;            case 'close':                $other = $this->peers[$id]['other'] ?? null;                unset($this->peers[$id]);                if ($other !== null && isset($this->peers[$other])) {                    $this->peers[$other]['other'] = null;                    $this->queue[] = ['ev' => 'state', 'id' => $other, 'state' => 'disconnected'];                }                break;        }    }    public function listen(callable $listener): void    {        $this->listeners[] = $listener;    }    public function poll(): void    {        foreach (array_splice($this->queue, 0) as $event) {            foreach ($this->listeners as $fn) {                $fn($event);            }        }    }    private function remote(string $id, string $type, string $sdp): void    {        $other = substr($sdp, 0, 4) === 'sim:' ? substr($sdp, 4) : '';        if (!isset($this->peers[$id], $this->peers[$other])) {            $this->queue[] = ['ev' => 'error', 'id' => $id, 'message' => 'the simulated WebRTC only joins peers of this game'];            return;        }        $this->peers[$id]['other'] = $other;        if ($type === 'offer') {            $this->queue[] = ['ev' => 'state', 'id' => $id, 'state' => 'connecting'];            $this->queue[] = ['ev' => 'answer', 'id' => $id, 'sdp' => 'sim:' . $id];            return;        }        // the offerer got the answer: both sides are connected, the offerer's channels open on both        foreach ([$id, $other] as $p) {            $this->queue[] = ['ev' => 'state', 'id' => $p, 'state' => 'connected'];            foreach ($this->peers[$id]['channels'] as $label) {                $this->queue[] = ['ev' => 'open', 'id' => $p, 'label' => $label];            }        }    }}