nandi/jolt-nativepublic Fork 0
258bbc5161b93d580a4c84363acabe63b0624e88
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

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

jolt_main.c · 231 lines · 8.6 KBC Blame HistoryRaw
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago1/*
2 * The Jolt half of the Android app: an embedded Chez runtime and the boot image
3 * built from the Jolt sources, reached from `libvidya.so`'s `android_main`.
4 *
5 * This is not the NativeActivity. On Android the activity's library must be the
6 * one holding android-activity's glue, which is `libvidya.so` — see
7 * `crates/jolt-vidya/src/android.rs`. That glue dlopens this library and calls
8 * `vidya_jolt_main`, so the entry point below is an ordinary C function rather
9 * than a `main`.
10 *
Let the media plane cross to the phone, camera and all fd0e21a nandi 18d ago11 * Every foreign symbol is registered with Chez explicitly. Jolt resolves a
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago12 * `defcfn` through Chez's foreign-entry table, and on Android nothing populates
Let the media plane cross to the phone, camera and all fd0e21a nandi 18d ago13 * that table from the dynamic loader: the symbols live in *different* shared
14 * objects (`libvidya.so` and `libjoltmoq.so`, both DT_NEEDEDs of this one),
15 * which is exactly the case the loader will not answer for. Registering them by
16 * hand is what makes all three ABIs — the push/pop one, the retained tree one
17 * glimmer binds, and the media plane — reachable.
18 *
19 * The media plane needs one thing more than a symbol table. Its camera is
20 * Camera2, reached over JNI, and the handles that takes only arrive in
21 * android-activity's glue inside libvidya. This file is the only place both
22 * objects are in scope, so it is where they are handed across.
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago23 */
24
25#include <stddef.h>
26#include <stdio.h>
27#include <unistd.h>
28
29#include <android/log.h>
30#include <pthread.h>
31
Let the media plane cross to the phone, camera and all fd0e21a nandi 18d ago32#include "joltmoq.h"
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago33#include "scheme.h"
34#include "vidya.h"
35#include "vidya_tree.h"
36
37/* The boot image, linked in as a binary blob by llvm-objcopy. */
38extern const unsigned char _binary_jolt_boot_start[];
39extern const unsigned char _binary_jolt_boot_end[];
40
41#define REGISTER_VIDYA(name) Sregister_symbol(#name, (void *)&name)
Let the media plane cross to the phone, camera and all fd0e21a nandi 18d ago42#define REGISTER_JOLTMOQ(name) Sregister_symbol(#name, (void *)&name)
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago43
44static void register_vidya_api(void) {
45 /* vidya.h */
46 REGISTER_VIDYA(vidya_open);
47 REGISTER_VIDYA(vidya_close);
48 REGISTER_VIDYA(vidya_should_close);
49 REGISTER_VIDYA(vidya_set_target_fps);
50 REGISTER_VIDYA(vidya_set_mode);
51 REGISTER_VIDYA(vidya_get_mode);
52 REGISTER_VIDYA(vidya_load_font);
53 REGISTER_VIDYA(vidya_begin_frame);
54 REGISTER_VIDYA(vidya_end_frame);
55 REGISTER_VIDYA(vidya_page_begin);
56 REGISTER_VIDYA(vidya_page_end);
57 REGISTER_VIDYA(vidya_card_begin);
58 REGISTER_VIDYA(vidya_card_end);
59 REGISTER_VIDYA(vidya_gap);
60 REGISTER_VIDYA(vidya_separator);
61 REGISTER_VIDYA(vidya_title);
62 REGISTER_VIDYA(vidya_title_2);
63 REGISTER_VIDYA(vidya_body);
64 REGISTER_VIDYA(vidya_dim_label);
65 REGISTER_VIDYA(vidya_button);
66 REGISTER_VIDYA(vidya_checkbox);
67 REGISTER_VIDYA(vidya_checkbox_value);
68 REGISTER_VIDYA(vidya_status);
69 REGISTER_VIDYA(vidya_text_field);
70
71 /* vidya_tree.h */
72 REGISTER_VIDYA(vidya_tree_root);
73 REGISTER_VIDYA(vidya_node_new);
74 REGISTER_VIDYA(vidya_node_free);
75 REGISTER_VIDYA(vidya_node_exists);
76 REGISTER_VIDYA(vidya_node_set_str);
77 REGISTER_VIDYA(vidya_node_set_num);
78 REGISTER_VIDYA(vidya_node_set_bool);
79 REGISTER_VIDYA(vidya_node_clear_props);
80 REGISTER_VIDYA(vidya_node_get_str);
81 REGISTER_VIDYA(vidya_node_get_num);
82 REGISTER_VIDYA(vidya_node_get_bool);
83 REGISTER_VIDYA(vidya_node_tag);
84 REGISTER_VIDYA(vidya_node_child_count);
85 REGISTER_VIDYA(vidya_node_child_at);
86 REGISTER_VIDYA(vidya_node_append);
87 REGISTER_VIDYA(vidya_node_remove);
88 REGISTER_VIDYA(vidya_node_insert_after);
89 REGISTER_VIDYA(vidya_node_replace);
90 REGISTER_VIDYA(vidya_tree_frame);
91 REGISTER_VIDYA(vidya_tree_poll_event);
92 REGISTER_VIDYA(vidya_tree_event_node);
93 REGISTER_VIDYA(vidya_tree_event_name);
94 REGISTER_VIDYA(vidya_tree_event_text);
95 REGISTER_VIDYA(vidya_tree_event_num);
96
97 /* Neither of these paints anything; they are the platform reached through
98 the same ABI. `vidya_open_url` is the one that matters here — signing in
99 leaves for a browser and comes back. */
100 REGISTER_VIDYA(vidya_clipboard_image_png);
101 REGISTER_VIDYA(vidya_open_url);
102 REGISTER_VIDYA(vidya_pick_image);
103 REGISTER_VIDYA(vidya_picked_image);
104
105 /* Live pixels, the window's own size, and the tree dump. Nothing here is
106 Android-specific; they are on this list because the list is the whole of
107 what an application can reach on Android, and a symbol left off it is not
108 a link error but a call that fails at the moment a screen needs it. */
Register vidya_set_title, which the phone cannot call without it 726f7c6 nandi 18d ago109 REGISTER_VIDYA(vidya_set_title);
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago110 REGISTER_VIDYA(vidya_frame_rgba);
111 REGISTER_VIDYA(vidya_frame_drop);
112 REGISTER_VIDYA(vidya_screen_width);
113 REGISTER_VIDYA(vidya_screen_height);
114 REGISTER_VIDYA(vidya_tree_dump);
115}
116
Let the media plane cross to the phone, camera and all fd0e21a nandi 18d ago117/*
118 * The media plane's symbols, registered for the same reason the Vidya ones
119 * above are: they live in libjoltmoq.so, a third object, and Android's loader
120 * will not answer a foreign-entry lookup that crosses one.
121 *
122 * A call reaches none of this without it — `joltmoq_start` would be a defcfn
123 * that resolves to nothing at the moment someone dials.
124 */
125static void register_joltmoq_api(void) {
126 REGISTER_JOLTMOQ(joltmoq_init_logging);
127
128 /* Lifecycle. */
129 REGISTER_JOLTMOQ(joltmoq_start);
130 REGISTER_JOLTMOQ(joltmoq_stop);
131 REGISTER_JOLTMOQ(joltmoq_is_live);
132
133 /* In-call controls. */
134 REGISTER_JOLTMOQ(joltmoq_set_muted);
135 REGISTER_JOLTMOQ(joltmoq_set_speaker_muted);
136 REGISTER_JOLTMOQ(joltmoq_set_camera);
137 REGISTER_JOLTMOQ(joltmoq_set_camera_device);
138 REGISTER_JOLTMOQ(joltmoq_set_mic_device);
139 REGISTER_JOLTMOQ(joltmoq_set_speaker_device);
140 REGISTER_JOLTMOQ(joltmoq_mic_level);
141
142 /* Status, drained rather than delivered. */
143 REGISTER_JOLTMOQ(joltmoq_poll_status);
144 REGISTER_JOLTMOQ(joltmoq_status_text);
145 REGISTER_JOLTMOQ(joltmoq_status_has_camera);
146 REGISTER_JOLTMOQ(joltmoq_status_has_mic);
147
148 /* Remote video, borrowed a frame at a time. */
149 REGISTER_JOLTMOQ(joltmoq_frame_poll);
150 REGISTER_JOLTMOQ(joltmoq_frame_key);
151 REGISTER_JOLTMOQ(joltmoq_frame_width);
152 REGISTER_JOLTMOQ(joltmoq_frame_height);
153 REGISTER_JOLTMOQ(joltmoq_frame_rgba);
154 REGISTER_JOLTMOQ(joltmoq_video_keys);
155
156 /* Devices. On the phone the cameras come from Camera2 and the microphone
157 and speaker lists are empty — the platform picks those itself. */
158 REGISTER_JOLTMOQ(joltmoq_cameras);
159 REGISTER_JOLTMOQ(joltmoq_microphones);
160 REGISTER_JOLTMOQ(joltmoq_speakers);
161
162 /* Dialling. */
163 REGISTER_JOLTMOQ(joltmoq_sfu_url);
164 REGISTER_JOLTMOQ(joltmoq_can_dial);
165 REGISTER_JOLTMOQ(joltmoq_new_instance);
166}
167
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago168/*
169 * Chez writes to stdout/stderr, which on Android goes nowhere. Pump both into
170 * logcat so a Scheme-level error is visible rather than a silent exit.
171 */
172static void *log_scheme_output(void *context) {
173 int fd = *(int *)context;
174 char buffer[1024];
175 FILE *stream = fdopen(fd, "r");
176 if (stream == NULL) return NULL;
177
178 while (fgets(buffer, sizeof(buffer), stream) != NULL) {
179 __android_log_write(ANDROID_LOG_ERROR, "VidyaJolt", buffer);
180 }
181 fclose(stream);
182 return NULL;
183}
184
185int vidya_jolt_main(void) {
186 static const char *argv[] = {"vidya", NULL};
187 int output_pipe[2];
188 pthread_t logger;
189
190 if (pipe(output_pipe) == 0) {
191 dup2(output_pipe[1], STDOUT_FILENO);
192 dup2(output_pipe[1], STDERR_FILENO);
193 close(output_pipe[1]);
194 pthread_create(&logger, NULL, log_scheme_output, &output_pipe[0]);
195 pthread_detach(logger);
196 }
197
198 __android_log_print(ANDROID_LOG_INFO, "VidyaJolt",
199 "initializing embedded Chez runtime");
200 Sscheme_init(NULL);
201 Sregister_boot_file_bytes(
202 "jolt",
203 (void *)_binary_jolt_boot_start,
204 (iptr)(_binary_jolt_boot_end - _binary_jolt_boot_start));
205 Sbuild_heap(NULL, NULL);
206 register_vidya_api();
Let the media plane cross to the phone, camera and all fd0e21a nandi 18d ago207 register_joltmoq_api();
208
209 /* The media plane's own handles, which it cannot get for itself: they arrive
210 in android-activity's glue, and the glue is in libvidya.so. This is the
211 only place both objects are in scope. Before Scheme starts, so no call can
212 reach the camera ahead of it.
213
214 Logged because there is otherwise no way to see it happen: joltmoq's own
215 logging goes through env_logger, which nothing has initialised this early,
216 so a failure here would be silent until a camera failed to open much later
217 for reasons that would look like anything but this. */
218 void *moq_vm = vidya_android_vm();
219 void *moq_activity = vidya_android_activity();
220 __android_log_print(moq_vm && moq_activity ? ANDROID_LOG_INFO : ANDROID_LOG_ERROR,
221 "VidyaJolt", "media plane JNI handles: vm=%p activity=%p",
222 moq_vm, moq_activity);
223 joltmoq_android_init(moq_vm, moq_activity);
Build libvidya for the phone, and hold the glue that boots it d942053 nandi 19d ago224
225 __android_log_print(ANDROID_LOG_INFO, "VidyaJolt", "starting Jolt application");
226 int status = Sscheme_start(1, argv);
227 __android_log_print(ANDROID_LOG_ERROR, "VidyaJolt",
228 "Jolt application exited with status %d", status);
229 Sscheme_deinit();
230 return status;
231}