llamadas: lo que hay de verdad; SSB_server.js como en la APK oficial

Revisado en el emulador: la APK oficial 1.3.3 del dev pide microfono y camara
y trae un puente nativo (.audio_bridge) que graba, reproduce, saca la camara y
emite. Nuestra app Android no lo tiene, asi que en esta APK el Telefono dice
que no hay llamadas.

- README, guia, android/README y los dos esquemas lo cuentan asi
- SSB_server.js queda identico al de la APK oficial (su version de movil
  enchufa ya phone_*_android.js); fuera el enganche duplicado de main.js
- el aviso de bienvenida va encima del lanzador: en el primer arranque
  quedaba a 1.300px y no se veia
This commit is contained in:
hacklab 2026-10-19 13:55:16 +02:00
parent e6ea3f4b58
commit 10e47f9bc1
9 changed files with 40 additions and 38 deletions

View file

@ -54,9 +54,15 @@ Ahora mismo hay enganches en `main_views.js`, `tribes_view.js`, `vote_view.js`,
## Llamadas: las del dev ## Llamadas: las del dev
La rama tuvo un módulo de salas y llamadas propio (Karvan). Se quitó el 19/10/2026 La rama tuvo un módulo de salas y llamadas propio (Karvan). Se quitó el 19/10/2026
porque el dev ya trae Teléfono y Salas. Lo nuestro es solo que funcionen en Android: porque el dev ya trae Teléfono y Salas. En Android el sonido y la cámara pasan por un
los permisos del envoltorio y el puente de audio y cámara. Si falta algo en las puente nativo de la app (`.audio_bridge`, ficheros `src/server/phone_*_android.js`,
llamadas, se arregla en ese puente o se le pide al dev, no se monta otro módulo. que son del dev). La APK oficial lo trae; nuestra app Android todavía no, y es lo
que falta para que las llamadas suenen. Si falta algo en las llamadas, se arregla en
ese puente o se le pide al dev, no se monta otro módulo.
Ojo al comparar con el dev: para el móvil la referencia es el `nodejs-project` de su
APK oficial, no su repositorio git. Hay ficheros, como `SSB_server.js` o
`phone_module.js`, cuya versión de móvil solo está en la APK.
Lo mismo vale para cualquier módulo: antes de hacer uno propio, mirad si el dev ya lo Lo mismo vale para cualquier módulo: antes de hacer uno propio, mirad si el dev ya lo
tiene o lo está haciendo. tiene o lo está haciendo.
@ -80,9 +86,6 @@ Aquí se puede hacer lo que haga falta.
- `src/backend/mobile_layer.js`: lo que el móvil necesita del backend (rutas que se - `src/backend/mobile_layer.js`: lo que el móvil necesita del backend (rutas que se
cortan, módulos que no van, avatar y lanzador, retoques del HTML, descargas de la cortan, módulos que no van, avatar y lanzador, retoques del HTML, descargas de la
copia de seguridad). La monta `fork_routes.js`. copia de seguridad). La monta `fork_routes.js`.
- `main.js`: arranca el backend en el móvil. Ahí se enchufan el audio, la cámara y la
emisión de Android (`src/server/phone_*_android.js`) en el Teléfono y las Salas del
dev, con `setAudioFactory` y compañía, sin tocar `SSB_server.js`.
- `src/models/fork_workflows.js`: nuestros workflows. - `src/models/fork_workflows.js`: nuestros workflows.
- `src/client/assets/translations/i18n_fork.js`: nuestros textos. - `src/client/assets/translations/i18n_fork.js`: nuestros textos.
- `src/client/assets/images/ux-*.svg`: nuestras imágenes. - `src/client/assets/images/ux-*.svg`: nuestras imágenes.

View file

@ -35,7 +35,8 @@ Android 7 o superior, 64 bits · se instala junto al Oasis oficial sin pisarlo
parlamento, votaciones y eventos. El resto se enciende en *Módulos* o en parlamento, votaciones y eventos. El resto se enciende en *Módulos* o en
*Ajustes → Workflows*. *Ajustes → Workflows*.
- Las llamadas son las de Oasis. Fuera Karvan, el módulo propio de salas: ahora se usan - Las llamadas son las de Oasis. Fuera Karvan, el módulo propio de salas: ahora se usan
el Teléfono y las Salas del dev, con el micrófono y la cámara del móvil enchufados. el Teléfono y las Salas del dev. Ojo: en esta APK todavía no suenan, porque a nuestra
app Android le falta el puente de audio nativo que sí trae la oficial (ver abajo).
- Votaciones como en asamblea: al crear una se elige Sí/No, semáforo (verde, amarillo, - Votaciones como en asamblea: al crear una se elige Sí/No, semáforo (verde, amarillo,
rojo) o termómetro (del 1 al 5). Los resultados salen en barras. rojo) o termómetro (del 1 al 5). Los resultados salen en barras.
- Borrar pide confirmación. Antes la X de una tribu la borraba de un toque. - Borrar pide confirmación. Antes la X de una tribu la borraba de un toque.
@ -58,12 +59,12 @@ Android 7 o superior, 64 bits · se instala junto al Oasis oficial sin pisarlo
| | Oasis oficial | Esta rama | | | Oasis oficial | Esta rama |
|---|---|---| |---|---|---|
| Llamadas y salas | Teléfono y Salas, pero sin micrófono ni cámara en Android | Los mismos, con el micrófono y la cámara del móvil | | Llamadas y salas | Teléfono y Salas, con micrófono y cámara | Los mismos; el puente de audio de Android todavía falta |
| Interfaz de móvil | El menú de escritorio en una pantalla pequeña | Tema Acampada, lanzador con iconos, fichas, barra de cuatro atajos | | Interfaz de móvil | El menú de escritorio en una pantalla pequeña | Tema Acampada, lanzador con iconos, fichas, barra de cuatro atajos |
| Primer arranque | Casi sesenta módulos encendidos | Modo acampada: lo justo para organizarse | | Primer arranque | Casi sesenta módulos encendidos | Modo acampada: lo justo para organizarse |
| Votaciones | Seis opciones fijas en una tabla | Sí/No, semáforo o termómetro, con barras | | Votaciones | Seis opciones fijas en una tabla | Sí/No, semáforo o termómetro, con barras |
| Varias identidades | Una por instalación | Varias en el mismo móvil, con aviso si dos comparten clave | | Varias identidades | Una por instalación | Varias en el mismo móvil, con aviso si dos comparten clave |
| Envoltorio Android | APK sin permisos de cámara ni micrófono | Proyecto Gradle propio: permisos, subida de ficheros, servicio que sobrevive | | Envoltorio Android | El del dev, sin código publicado | Proyecto Gradle propio y abierto: permisos, subida de ficheros, servicio que sobrevive |
| Metadatos de las fotos | Se quitan solo si está `sharp`; en Android nunca | Se quitan siempre: GPS, marca, modelo, número de serie | | Metadatos de las fotos | Se quitan solo si está `sharp`; en Android nunca | Se quitan siempre: GPS, marca, modelo, número de serie |
Los nombres de las categorías, los módulos y el resto de la aplicación son los de Los nombres de las categorías, los módulos y el resto de la aplicación son los de
@ -103,10 +104,13 @@ mensaje en tu nombre ni cambiar lo que dijiste.
![Llamadas: las del dev, con el móvil enchufado](docs/capturas/esquema-llamadas.png) ![Llamadas: las del dev, con el móvil enchufado](docs/capturas/esquema-llamadas.png)
El Teléfono (llamadas de uno a uno, con buzón de voz) y las Salas (hasta cincuenta El Teléfono (llamadas de uno a uno, con buzón de voz) y las Salas (hasta cincuenta
personas, con vídeo, grabación y emisión) son de Oasis. La APK oficial no pide personas, con vídeo, grabación y emisión) son de Oasis. En Android el sonido y la
permisos de micrófono ni de cámara, así que en Android no suenan. Esta rama trae su cámara no los maneja Node: el servidor se conecta a un puente nativo de la app
propio envoltorio, que sí los pide, y enchufa el audio y la cámara del móvil en los (`.audio_bridge`), que graba, reproduce, saca fotogramas de la cámara y emite ficheros.
puntos que el propio Oasis deja para eso. La rama no tiene llamadas propias.
La APK oficial del dev trae ese puente. La de esta rama todavía no: nuestra app
Android es otra (tiene el código publicado) y el puente hay que escribirlo. Hasta
entonces, en esta APK el Teléfono dice que las llamadas no están disponibles.
En la barra de arriba, junto al avatar, está el botón de *No molestar* del Teléfono. En la barra de arriba, junto al avatar, está el botón de *No molestar* del Teléfono.

View file

@ -5,6 +5,10 @@ molde.
## Por que existe ## Por que existe
Nota (19/10/2026): desde la 1.3.x la APK oficial ya pide microfono y camara y trae un
puente nativo de audio y camara (`.audio_bridge`) para el Telefono y las Salas. Esta app
aun no lo tiene. Lo de abajo describe la situacion anterior.
El APK que se venia usando es el de epsylon re-firmado, y su `classes.dex` **no El APK que se venia usando es el de epsylon re-firmado, y su `classes.dex` **no
implementa `WebChromeClient.onPermissionRequest`**. Sin ese metodo el WebView de implementa `WebChromeClient.onPermissionRequest`**. Sin ese metodo el WebView de
Android deniega por defecto toda peticion de `getUserMedia()`, de modo que las Android deniega por defecto toda peticion de `getUserMedia()`, de modo que las

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Before After
Before After

View file

@ -163,7 +163,7 @@ def esquema_rama():
((740, 210, 1060, 400), "RUTAS", ((740, 210, 1060, 400), "RUTAS",
["fork_routes.js y", "mobile_layer.js, delante", "del router del dev: lo que", "no atienden pasa al suyo"], NEON), ["fork_routes.js y", "mobile_layer.js, delante", "del router del dev: lo que", "no atienden pasa al suyo"], NEON),
((1080, 210, 1340, 400), "ANDROID", ((1080, 210, 1340, 400), "ANDROID",
["envoltorio propio:", "permisos de micro y", "cámara, y el puente", "de audio del Teléfono"], NEON), ["envoltorio propio y", "abierto: permisos,", "ficheros y servicio.", "Falta el puente de audio"], NEON),
] ]
for box, t, l, r in capa: for box, t, l, r in capa:
caja(d, box, t, l, r) caja(d, box, t, l, r)
@ -178,29 +178,29 @@ def esquema_rama():
def esquema_llamadas(): def esquema_llamadas():
"""Las llamadas son las del dev; la rama solo enchufa el movil.""" """Las llamadas son las del dev; en Android pasan por un puente nativo de la app."""
W, H = 1400, 700 W, H = 1400, 700
out = Image.new("RGB", (W, H), BG) out = Image.new("RGB", (W, H), BG)
d = ImageDraw.Draw(out) d = ImageDraw.Draw(out)
titulo(d, "LLAMADAS: LAS DEL DEV, CON EL MÓVIL ENCHUFADO", titulo(d, "LLAMADAS: LAS DEL DEV",
"Teléfono y Salas son de Oasis. La rama no tiene llamadas propias: solo hace que suenen en Android.") "Teléfono y Salas son de Oasis. En Android el sonido y la cámara pasan por un puente nativo de la app.")
cajas = [ cajas = [
((50, 200, 360, 430), "TELÉFONO Y SALAS", ((50, 200, 360, 430), "TELÉFONO Y SALAS",
["De Oasis, tal cual.", "Llamadas de uno a uno", "con buzón de voz; salas", "de hasta 50, con vídeo,", "grabación y emisión."], BG), ["De Oasis, tal cual.", "Llamadas de uno a uno", "con buzón de voz; salas", "de hasta 50, con vídeo,", "grabación y emisión."], BG),
((400, 200, 700, 430), "LOS ENCHUFES", ((400, 200, 700, 430), "LOS ENCHUFES",
["setAudioFactory", "setVideoFactory", "setStreamFactory", "", "Los deja el propio dev."], BG), ["phone_*_android.js", "(del dev): se conectan", "a un puerto local que", "deja la app en", ".audio_bridge"], BG),
((740, 200, 1040, 430), "EL PUENTE", ((740, 200, 1040, 430), "EL PUENTE NATIVO",
["main.js enchufa ahí", "phone_*_android.js:", "el audio y la cámara", "pasan por la app de", "Android."], NEON), ["Dentro de la app:", "R graba el micro", "P reproduce", "V saca la cámara", "S emite un fichero"], NEON),
((1080, 200, 1350, 430), "EL MÓVIL", ((1080, 200, 1350, 430), "EL MÓVIL",
["Micrófono, cámara", "y altavoz. Los permisos", "se piden la primera vez", "que llamas o entras", "en una sala."], NEON), ["Micrófono, cámara", "y altavoz, con los", "permisos que se piden", "la primera vez."], BG),
] ]
for box, t, l, r in cajas: for box, t, l, r in cajas:
caja(d, box, t, l, r) caja(d, box, t, l, r)
for a, b in (((362, 315), (398, 315)), ((702, 315), (738, 315)), ((1042, 315), (1078, 315))): for a, b in (((362, 315), (398, 315)), ((702, 315), (738, 315)), ((1042, 315), (1078, 315))):
flecha(d, a, b) flecha(d, a, b)
caja(d, (50, 480, 1350, 630), "¿Y CON LA APK OFICIAL?", caja(d, (50, 480, 1350, 630), "DÓNDE ESTÁ CADA COSA",
["No declara micrófono ni cámara y su navegador interno deniega esas peticiones:", ["La APK oficial trae el puente: ahí las llamadas suenan. La app de esta rama todavía no lo tiene,",
"en Android las llamadas no pueden sonar. Por eso esta rama trae su propio envoltorio."], BG) "así que en ella el Teléfono dice que no hay llamadas. Escribir ese puente es lo siguiente."], BG)
out.save(HERE / "esquema-llamadas.png", optimize=True) out.save(HERE / "esquema-llamadas.png", optimize=True)

13
main.js
View file

@ -102,19 +102,6 @@ try {
} }
} catch (e) {} } catch (e) {}
// Telefono y Salas del dev: en Android el audio, la camara y la emision van por el
// puente de la app (src/server/phone_*_android.js). El modulo del dev deja enchufarlos
// con setAudioFactory y compania; se hace aqui, antes de arrancar, para no tocar
// SSB_server.js. Ver GUIA_DE_DESARROLLO.md.
try {
const phone = require('./src/server/phone_module');
phone.setAudioFactory(require('./src/server/phone_audio_android'));
phone.setVideoFactory(require('./src/server/phone_video_android'));
phone.setStreamFactory(require('./src/server/phone_stream_android'));
} catch (e) {
console.error('[Oasis] Phone bridge not available:', e && e.message);
}
const backendPath = path.join(__dirname, 'src', 'backend', 'backend.js'); const backendPath = path.join(__dirname, 'src', 'backend', 'backend.js');
console.log('[Oasis] Launching Oasis Social Network Utopia...'); console.log('[Oasis] Launching Oasis Social Network Utopia...');

View file

@ -506,3 +506,7 @@ form.oasis-phone-state .oasis-phone-state-btn {
.main-column .bb-manage h3, .main-column .bb-manage-add h3 { font-size: 20px !important; margin: 18px 0 10px !important; } .main-column .bb-manage h3, .main-column .bb-manage-add h3 { font-size: 20px !important; margin: 18px 0 10px !important; }
.main-column a.bb-manage-done { display: block !important; width: 100% !important; margin-top: 18px !important; text-align: center; } .main-column a.bb-manage-done { display: block !important; width: 100% !important; margin-top: 18px !important; text-align: center; }
.main-column div.bb-manage, .main-column div.bb-manage-add, .main-column div.bb-manage-list, .main-column div.bb-pick-grid { padding: 0 !important; margin: 0 !important; border: 0 !important; } .main-column div.bb-manage, .main-column div.bb-manage-add, .main-column div.bb-manage-list, .main-column div.bb-pick-grid { padding: 0 !important; margin: 0 !important; border: 0 !important; }
/* el aviso de bienvenida, encima del lanzador: debajo quedaba a 1.300px y quien
abria la app por primera vez no lo veia */
body > .welcome-banner { order: -1; margin-top: 10px !important; }

View file

@ -80,7 +80,7 @@ const Server = SecretStack({ caps })
.use(require('ssb-unix-socket')) .use(require('ssb-unix-socket'))
.use(require('ssb-no-auth')) .use(require('ssb-no-auth'))
.use(require('./snapshot_plugin')) .use(require('./snapshot_plugin'))
.use(require('./phone_module')) .use((() => { const pm = require('./phone_module'); try { if (process.env.OASIS_MOBILE === '1') { pm.setAudioFactory(require('./phone_audio_android')); pm.setVideoFactory(require('./phone_video_android')); pm.setStreamFactory(require('./phone_stream_android')); } } catch (_) {} return pm; })())
.use(require('./network_pause')); .use(require('./network_pause'));
if (!config.pub) { if (!config.pub) {