nandi/frqpublic Fork 0
ddbf5e1
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Run without a media plane

`libjoltmoq` is not on the phone — nobody has cross-built the media plane for
Android — and `-main` called into it before the window was up, so the whole
client died at startup with "no entry for joltmoq_init_logging" and took the
event loop with it.

A client that cannot make calls is still a client. Whether the library is
there at all is asked once, by calling the smallest thing in it, and that
answer gates the call surface: no pump, no Call button, and no dial from an
incoming call. Everything else — the channels, the pictures, the sign-in —
does not care.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-08-30T18:31:21-07:00 Browse files
ddbf5e1 parent: 556ab58
modified src/frq/app.jolt +1 -0
@@ -718,6 +718,7 @@
718718 [:vbox {:key :call}
719719 (when (and name
720720 (str/starts-with? name "#")
721+ (av/available?)
721722 (not (av/call-in name))
722723 (not (av/in-call?)))
723724 [:button {:label "Call" :on-click #(s/start-call! name)}])]]
@@ -718,6 +718,7 @@
718 [:vbox {:key :call}718 [:vbox {:key :call}
719 (when (and name719 (when (and name
720 (str/starts-with? name "#")720 (str/starts-with? name "#")
721+ (av/available?)
721 (not (av/call-in name))722 (not (av/call-in name))
722 (not (av/in-call?)))723 (not (av/in-call?)))
723 [:button {:label "Call" :on-click #(s/start-call! name)}])]]724 [:button {:label "Call" :on-click #(s/start-call! name)}])]]
modified src/frq/av.jolt +25 -5
@@ -73,6 +73,21 @@
7373 (def ^:private status-ended 2)
7474 (def ^:private status-failed 3)
7575
76+(defonce ^:private media-plane
77+ ;; Whether `libjoltmoq` is here at all, asked once by calling the smallest
78+ ;; thing in it. It is not on the phone nobody has cross-built the media
79+ ;; plane for Android and a client that cannot make calls is still a client,
80+ ;; so the answer gates the call surface rather than ending the run. Every
81+ ;; other binding in this namespace is reached only from behind it.
82+ (delay
83+ (try (raw-init-logging) true
84+ (catch Exception _ false))))
85+
86+(defn available?
87+ "Whether calls can happen here at all."
88+ []
89+ @media-plane)
90+
7691 (defn- flag [b] (if b 1 0))
7792 (defn- pref [s] (or s ""))
7893
@@ -335,7 +350,8 @@
335350 alone rather than re-dialled."
336351 [server]
337352 (when-let [{:keys [session-id token media]} @local-call]
338- (when (and (seq session-id)
353+ (when (and (available?)
354+ (seq session-id)
339355 (not (contains? #{:dialling :live} media))
340356 (can-dial? server token))
341357 (start-media! server))))
@@ -541,17 +557,21 @@
541557 Worth doing unconditionally: it says nothing at all without a `RUST_LOG`,
542558 and when a call misbehaves it is the only thing that knows why — MoQ
543559 subscription, codec negotiation and device open all happen on the far side of
544- the boundary, where no jolt-level trace can see them."
560+ the boundary, where no jolt-level trace can see them.
561+
562+ Asking whether the media plane is there is the same call, so this is it."
545563 []
546- (raw-init-logging))
564+ (available?))
547565
548566 (defn install-pump!
549- "Start pumping the media plane every frame. Returns a timer id.
567+ "Start pumping the media plane every frame. Returns a timer id, or nil where
568+ there is no media plane to pump.
550569
551570 Sixteen milliseconds rather than a longer gap because this is where video
552571 arrives: polling slower than the window paints would show every other frame."
553572 []
554- (vidya/every! 16 pump!))
573+ (when (available?)
574+ (vidya/every! 16 pump!)))
555575
556576 (defn tiles
557577 "Everyone with a picture in the current call, the self-view last.
@@ -73,6 +73,21 @@
73 (def ^:private status-ended 2)73 (def ^:private status-ended 2)
74 (def ^:private status-failed 3)74 (def ^:private status-failed 3)
75 75
76+(defonce ^:private media-plane
77+ ;; Whether `libjoltmoq` is here at all, asked once by calling the smallest
78+ ;; thing in it. It is not on the phone nobody has cross-built the media
79+ ;; plane for Android and a client that cannot make calls is still a client,
80+ ;; so the answer gates the call surface rather than ending the run. Every
81+ ;; other binding in this namespace is reached only from behind it.
82+ (delay
83+ (try (raw-init-logging) true
84+ (catch Exception _ false))))
85+
86+(defn available?
87+ "Whether calls can happen here at all."
88+ []
89+ @media-plane)
90+
76 (defn- flag [b] (if b 1 0))91 (defn- flag [b] (if b 1 0))
77 (defn- pref [s] (or s ""))92 (defn- pref [s] (or s ""))
78 93
@@ -335,7 +350,8 @@
335 alone rather than re-dialled."350 alone rather than re-dialled."
336 [server]351 [server]
337 (when-let [{:keys [session-id token media]} @local-call]352 (when-let [{:keys [session-id token media]} @local-call]
338- (when (and (seq session-id)353+ (when (and (available?)
354+ (seq session-id)
339 (not (contains? #{:dialling :live} media))355 (not (contains? #{:dialling :live} media))
340 (can-dial? server token))356 (can-dial? server token))
341 (start-media! server))))357 (start-media! server))))
@@ -541,17 +557,21 @@
541 Worth doing unconditionally: it says nothing at all without a `RUST_LOG`,557 Worth doing unconditionally: it says nothing at all without a `RUST_LOG`,
542 and when a call misbehaves it is the only thing that knows why — MoQ558 and when a call misbehaves it is the only thing that knows why — MoQ
543 subscription, codec negotiation and device open all happen on the far side of559 subscription, codec negotiation and device open all happen on the far side of
544- the boundary, where no jolt-level trace can see them."560+ the boundary, where no jolt-level trace can see them.
561+
562+ Asking whether the media plane is there is the same call, so this is it."
545 []563 []
546- (raw-init-logging))564+ (available?))
547 565
548 (defn install-pump!566 (defn install-pump!
549- "Start pumping the media plane every frame. Returns a timer id.567+ "Start pumping the media plane every frame. Returns a timer id, or nil where
568+ there is no media plane to pump.
550 569
551 Sixteen milliseconds rather than a longer gap because this is where video570 Sixteen milliseconds rather than a longer gap because this is where video
552 arrives: polling slower than the window paints would show every other frame."571 arrives: polling slower than the window paints would show every other frame."
553 []572 []
554- (vidya/every! 16 pump!))573+ (when (available?)
574+ (vidya/every! 16 pump!)))
555 575
556 (defn tiles576 (defn tiles
557 "Everyone with a picture in the current call, the self-view last.577 "Everyone with a picture in the current call, the self-view last.