payfri-video-sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -90
- package/dist/plugin/withVideoSdk.cjs +2 -1
- package/dist/plugin/withVideoSdk.cjs.map +1 -1
- package/dist/plugin/withVideoSdk.d.cts +5 -1
- package/dist/plugin/withVideoSdk.d.ts +5 -1
- package/dist/plugin/withVideoSdk.js +2 -1
- package/dist/plugin/withVideoSdk.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,91 +1,112 @@
|
|
|
1
1
|
# payfri-video-sdk
|
|
2
2
|
|
|
3
|
-
SDK del **servicio de video de Payfri**. Integra videollamadas en tu producto
|
|
4
|
-
|
|
5
|
-
WebRTC ni montar infraestructura de medios propia. Tres entry points con una **separación estricta
|
|
6
|
-
de seguridad**:
|
|
3
|
+
SDK oficial del **servicio de video de Payfri**. Integra videollamadas en tu producto sin
|
|
4
|
+
implementar WebRTC ni montar infraestructura de medios.
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
| --- | --- | --- | --- |
|
|
10
|
-
| `payfri-video-sdk/server` | Tu **backend** | **API key** del tenant (secreta) | Crear salas y emitir tokens |
|
|
11
|
-
| `payfri-video-sdk/client` | **Navegador** | Solo un **token** de corta duración | Unirse a la llamada (web) |
|
|
12
|
-
| `payfri-video-sdk/native` | **React Native** | Solo un **token** de corta duración | Unirse a la llamada (móvil) |
|
|
6
|
+
## La idea en 30 segundos
|
|
13
7
|
|
|
14
|
-
|
|
15
|
-
> `/native` hacen **imposible** pasarla (no compila), y además hay una verificación en runtime.
|
|
8
|
+
Una videollamada son dos pasos, en dos lugares distintos:
|
|
16
9
|
|
|
17
|
-
|
|
10
|
+
1. **Tu backend** pide un token de acceso al servicio (aquí vive tu **API key**, que es secreta).
|
|
11
|
+
2. **Tu frontend** (web o móvil) se une a la llamada con ese token (expira; default 1 hora).
|
|
18
12
|
|
|
19
13
|
```
|
|
20
14
|
Tu backend ──(API key)──▶ API de video ──▶ { token, livekitUrl }
|
|
21
|
-
│
|
|
22
|
-
|
|
23
|
-
▼
|
|
24
|
-
Navegador / app móvil se une a la llamada con el token
|
|
15
|
+
│
|
|
16
|
+
└──▶ tu frontend se une a la llamada con { token, livekitUrl }
|
|
25
17
|
```
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
2. Le pasas `{ token, livekitUrl }` a tu frontend (respuesta de tu propio endpoint).
|
|
29
|
-
3. El frontend se une a la sala con `/client` (web) o `/native` (React Native).
|
|
30
|
-
|
|
31
|
-
Los tokens expiran (default **1 hora**, configurable de 60 s a 12 h), así que emite uno nuevo por
|
|
32
|
-
participante y por sesión.
|
|
33
|
-
|
|
34
|
-
## Qué necesitas antes de empezar
|
|
35
|
-
|
|
36
|
-
Te lo entrega el equipo que administra el servicio de video:
|
|
37
|
-
|
|
38
|
-
- **`baseUrl`** — URL de la API de video, p. ej. `https://api.video.tuempresa.com`
|
|
39
|
-
- **`apiKey`** — API key de tu tenant (formato `{prefijo}_live_{aleatorio}`). Se muestra **una sola
|
|
40
|
-
vez** al crearla: guárdala en un gestor de secretos, nunca en el código.
|
|
41
|
-
- **`embedBaseUrl`** (solo para `/native`) — URL de la página embebible, p. ej.
|
|
42
|
-
`https://embed.tuempresa.com`
|
|
43
|
-
- **Alta de CORS** — pide que agreguen el dominio de tu frontend a los orígenes permitidos de la API.
|
|
44
|
-
|
|
45
|
-
Requisitos técnicos: Node 18+ en el backend (usa `fetch` global; en runtimes sin él puedes inyectar
|
|
46
|
-
uno propio). El paquete se distribuye en **ESM + CJS con tipos incluidos**.
|
|
47
|
-
|
|
48
|
-
## Instalación
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
# Backend (emitir tokens) — sin dependencias extra
|
|
52
|
-
npm install payfri-video-sdk
|
|
53
|
-
|
|
54
|
-
# Navegador (unirse a la llamada) — livekit-client es peer dependency
|
|
55
|
-
npm install payfri-video-sdk livekit-client
|
|
19
|
+
El SDK trae un entry point para cada lugar:
|
|
56
20
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
21
|
+
| Entry | Dónde corre | Recibe | Para qué |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `payfri-video-sdk/server` | Tu backend | API key (secreta) | Emitir tokens, administrar salas |
|
|
24
|
+
| `payfri-video-sdk/client` | Navegador | Solo el token | Unirse a la llamada (web, tú pones la UI) |
|
|
25
|
+
| `payfri-video-sdk/native` | React Native | Solo el token | Unirse a la llamada (móvil, UI lista) |
|
|
60
26
|
|
|
61
|
-
|
|
27
|
+
Dos cosas que conviene saber desde ya:
|
|
62
28
|
|
|
63
|
-
|
|
64
|
-
|
|
29
|
+
- **Regla de oro:** la API key jamás sale de tu servidor. `/client` y `/native` ni siquiera
|
|
30
|
+
compilan si intentas pasarles una (y lo verifican también en runtime).
|
|
31
|
+
- **El SDK de backend es opcional.** `/server` es un wrapper de conveniencia sobre la API REST del
|
|
32
|
+
servicio. Si prefieres, llama a la API directo con cualquier HTTP client —
|
|
33
|
+
[ejemplo abajo](#sin-sdk-rest-directo).
|
|
65
34
|
|
|
66
|
-
|
|
35
|
+
## Inicio rápido
|
|
67
36
|
|
|
68
|
-
|
|
37
|
+
**1. En tu backend — emite el token:**
|
|
69
38
|
|
|
70
39
|
```ts
|
|
71
40
|
import { createVideoClient } from "payfri-video-sdk/server";
|
|
72
41
|
|
|
73
42
|
const video = createVideoClient({
|
|
74
43
|
baseUrl: process.env.VIDEO_API_BASE_URL!, // https://api.video.tuempresa.com
|
|
75
|
-
apiKey: process.env.VIDEO_API_KEY!, // secreta, SOLO
|
|
44
|
+
apiKey: process.env.VIDEO_API_KEY!, // secreta, SOLO aquí
|
|
76
45
|
});
|
|
77
46
|
|
|
78
|
-
//
|
|
47
|
+
// En tu endpoint (protegido con TU auth):
|
|
79
48
|
const { token, livekitUrl } = await video.tokens.issue({
|
|
80
49
|
roomName: "consulta-123",
|
|
81
|
-
identity: "doctor-45",
|
|
50
|
+
identity: "doctor-45", // id único de TU usuario
|
|
82
51
|
displayName: "Dra. López",
|
|
83
|
-
createIfMissing: true,
|
|
52
|
+
createIfMissing: true, // crea la sala si no existe
|
|
84
53
|
});
|
|
54
|
+
// devuelve { token, livekitUrl } a tu frontend
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**2a. En el navegador — únete:**
|
|
85
58
|
|
|
86
|
-
|
|
59
|
+
```ts
|
|
60
|
+
import { joinRoom } from "payfri-video-sdk/client";
|
|
61
|
+
|
|
62
|
+
const handle = await joinRoom({
|
|
63
|
+
token, // desde tu backend
|
|
64
|
+
livekitUrl, // desde tu backend
|
|
65
|
+
container: document.getElementById("call")!,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await handle.toggleMic();
|
|
69
|
+
await handle.leave();
|
|
87
70
|
```
|
|
88
71
|
|
|
72
|
+
**2b. O en React Native — únete:**
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { VideoCall } from "payfri-video-sdk/native";
|
|
76
|
+
|
|
77
|
+
<VideoCall token={token} livekitUrl={livekitUrl} embedBaseUrl="https://embed.tuempresa.com" style={{ flex: 1 }} />;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Eso es todo el flujo. Lo demás es referencia.
|
|
81
|
+
|
|
82
|
+
## Qué necesitas
|
|
83
|
+
|
|
84
|
+
Te lo entrega el equipo que administra el servicio:
|
|
85
|
+
|
|
86
|
+
- **`baseUrl`** — URL de la API de video
|
|
87
|
+
- **`apiKey`** — la key de tu tenant. Se muestra **una sola vez** al crearla: guárdala en un gestor
|
|
88
|
+
de secretos, nunca en el código
|
|
89
|
+
- **`embedBaseUrl`** — URL de la página de llamada (solo si usas `/native`)
|
|
90
|
+
|
|
91
|
+
Técnico: Node 18+ en el backend (o inyecta tu propio `fetch`). El paquete es ESM + CJS con tipos
|
|
92
|
+
TypeScript incluidos.
|
|
93
|
+
|
|
94
|
+
## Instalación
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm install payfri-video-sdk # backend: suficiente para /server
|
|
98
|
+
npm install payfri-video-sdk livekit-client # web: /client necesita livekit-client
|
|
99
|
+
npm install payfri-video-sdk react-native-webview # móvil: /native necesita el WebView
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Las peer dependencies son opcionales: instala solo lo que exige el entry que uses. (`livekit-client`
|
|
103
|
+
aparece porque el motor de medios del servicio es [LiveKit](https://livekit.io) — detalle interno;
|
|
104
|
+
tú solo interactúas con este SDK.)
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Referencia: `/server` (backend)
|
|
109
|
+
|
|
89
110
|
### `createVideoClient(options)`
|
|
90
111
|
|
|
91
112
|
| Opción | Tipo | Requerido | Descripción |
|
|
@@ -148,23 +169,39 @@ try {
|
|
|
148
169
|
|
|
149
170
|
| `status` | Causa típica |
|
|
150
171
|
| --- | --- |
|
|
172
|
+
| 400 | Body inválido (revisa `message`) |
|
|
151
173
|
| 401 | API key inválida o revocada |
|
|
152
174
|
| 403 | Tenant suspendido |
|
|
153
175
|
| 404 | Sala inexistente (usa `createIfMissing: true` si aplica) |
|
|
154
|
-
|
|
176
|
+
|
|
177
|
+
### Sin SDK: REST directo
|
|
178
|
+
|
|
179
|
+
`/server` solo envuelve la API REST. El mismo token del inicio rápido, con `curl`:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
curl -X POST "$VIDEO_API_BASE_URL/v1/tokens" \
|
|
183
|
+
-H "Authorization: Bearer $VIDEO_API_KEY" \
|
|
184
|
+
-H "Content-Type: application/json" \
|
|
185
|
+
-d '{"roomName":"consulta-123","identity":"doctor-45","displayName":"Dra. López","createIfMissing":true}'
|
|
186
|
+
# → { "token": "...", "livekitUrl": "wss://...", "roomName": "...", "identity": "...", "expiresAt": "..." }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Endpoints equivalentes: `POST /v1/tokens`, `POST /v1/rooms`, `GET /v1/rooms/:roomName`,
|
|
190
|
+
`DELETE /v1/rooms/:roomName`. Los errores tienen la forma `{ error: { code, message } }`. La
|
|
191
|
+
documentación completa (Swagger) vive en `<baseUrl>/docs`. Úsalo desde cualquier lenguaje —
|
|
192
|
+
el SDK solo es obligatorio si quieres los tipos y el manejo de errores ya resueltos.
|
|
155
193
|
|
|
156
194
|
---
|
|
157
195
|
|
|
158
|
-
##
|
|
196
|
+
## Referencia: `/client` (navegador)
|
|
197
|
+
|
|
198
|
+
`joinRoom` conecta a la sala y monta los `<video>` en tu contenedor. **La UI es tuya**: tú pones
|
|
199
|
+
los botones y llamas a los métodos del handle.
|
|
159
200
|
|
|
160
201
|
```ts
|
|
161
202
|
import { joinRoom } from "payfri-video-sdk/client";
|
|
162
203
|
|
|
163
|
-
const handle = await joinRoom({
|
|
164
|
-
token, // recibido desde TU backend
|
|
165
|
-
livekitUrl, // recibido desde TU backend
|
|
166
|
-
container: document.getElementById("call")!,
|
|
167
|
-
});
|
|
204
|
+
const handle = await joinRoom({ token, livekitUrl, container: document.getElementById("call")! });
|
|
168
205
|
|
|
169
206
|
handle.on("participantJoined", (p) => console.log("entró", p.identity));
|
|
170
207
|
handle.on("error", (e) => console.error(e));
|
|
@@ -178,8 +215,8 @@ await handle.leave(); // salir y liberar recursos
|
|
|
178
215
|
|
|
179
216
|
| Opción | Tipo | Default | Descripción |
|
|
180
217
|
| --- | --- | --- | --- |
|
|
181
|
-
| `token` | `string` | requerido | Token
|
|
182
|
-
| `livekitUrl` | `string` | requerido | URL `wss` del servidor de medios (
|
|
218
|
+
| `token` | `string` | requerido | Token emitido por tu backend |
|
|
219
|
+
| `livekitUrl` | `string` | requerido | URL `wss` del servidor de medios (viene con el token; pásala tal cual) |
|
|
183
220
|
| `container` | `HTMLElement` | requerido | Elemento donde se montan los videos |
|
|
184
221
|
| `enableCamera` | `boolean` | `true` | Publicar cámara al conectar |
|
|
185
222
|
| `enableMicrophone` | `boolean` | `true` | Publicar micrófono al conectar |
|
|
@@ -198,30 +235,22 @@ await handle.leave(); // salir y liberar recursos
|
|
|
198
235
|
|
|
199
236
|
Para casos avanzados, `handle.room` expone el `Room` de `livekit-client` subyacente.
|
|
200
237
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
`joinRoom` **no tiene** campo para la API key. Esto no compila:
|
|
204
|
-
|
|
205
|
-
```ts
|
|
206
|
-
// @ts-expect-error — apiKey no existe en JoinRoomOptions
|
|
207
|
-
joinRoom({ token, livekitUrl, container, apiKey: "..." });
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
Y en runtime, `joinRoom` lanza si detecta `apiKey`/`apiSecret`/`secret` en las opciones.
|
|
238
|
+
> Seguridad: `joinRoom` no tiene campo para la API key — pasarla no compila, y en runtime lanza si
|
|
239
|
+
> detecta `apiKey`/`apiSecret`/`secret` en las opciones.
|
|
211
240
|
|
|
212
241
|
---
|
|
213
242
|
|
|
214
|
-
## React Native
|
|
243
|
+
## Referencia: `/native` (React Native)
|
|
215
244
|
|
|
216
|
-
|
|
217
|
-
|
|
245
|
+
`<VideoCall>` incrusta la llamada **con UI lista** (la página del servicio dentro de un `WebView`).
|
|
246
|
+
No requiere `react-native-webrtc` ni código nativo propio.
|
|
218
247
|
|
|
219
248
|
```tsx
|
|
220
249
|
import { VideoCall } from "payfri-video-sdk/native";
|
|
221
250
|
|
|
222
251
|
<VideoCall
|
|
223
|
-
token={token} //
|
|
224
|
-
livekitUrl={livekitUrl} //
|
|
252
|
+
token={token} // desde tu backend
|
|
253
|
+
livekitUrl={livekitUrl} // desde tu backend
|
|
225
254
|
embedBaseUrl="https://embed.tuempresa.com"
|
|
226
255
|
onConnected={() => console.log("conectado")}
|
|
227
256
|
onLeave={() => navigation.goBack()}
|
|
@@ -234,9 +263,9 @@ import { VideoCall } from "payfri-video-sdk/native";
|
|
|
234
263
|
|
|
235
264
|
| Prop | Tipo | Requerido | Descripción |
|
|
236
265
|
| --- | --- | --- | --- |
|
|
237
|
-
| `token` | `string` | ✅ | Token
|
|
238
|
-
| `livekitUrl` | `string` | ✅ | URL `wss` del servidor de medios (
|
|
239
|
-
| `embedBaseUrl` | `string` | ✅ | Base de la página
|
|
266
|
+
| `token` | `string` | ✅ | Token emitido por tu backend |
|
|
267
|
+
| `livekitUrl` | `string` | ✅ | URL `wss` del servidor de medios (viene con el token; pásala tal cual) |
|
|
268
|
+
| `embedBaseUrl` | `string` | ✅ | Base de la página de llamada (**HTTPS obligatorio**) |
|
|
240
269
|
| `theme` | `string` | — | Color de acento para branding (ej. `#4f7cff`) |
|
|
241
270
|
| `onConnected` | `() => void` | — | La videollamada conectó |
|
|
242
271
|
| `onDisconnected` | `() => void` | — | El usuario se desconectó o se cerró la sala |
|
|
@@ -246,7 +275,7 @@ import { VideoCall } from "payfri-video-sdk/native";
|
|
|
246
275
|
| `onError` | `(error: Error) => void` | — | Permisos denegados, token inválido, fallo de sala |
|
|
247
276
|
| `style` | `StyleProp<ViewStyle>` | — | Estilo del contenedor (default: ocupa todo) |
|
|
248
277
|
|
|
249
|
-
Igual que `/client`,
|
|
278
|
+
Igual que `/client`, no existe campo para la API key (no compila si la pasas).
|
|
250
279
|
|
|
251
280
|
### Permisos de cámara y micrófono
|
|
252
281
|
|
|
@@ -262,10 +291,15 @@ Igual que `/client`, `VideoCallProps` **no tiene** campo para la API key (no com
|
|
|
262
291
|
}
|
|
263
292
|
```
|
|
264
293
|
|
|
265
|
-
El plugin inyecta
|
|
266
|
-
|
|
294
|
+
El plugin inyecta `NSCameraUsageDescription` / `NSMicrophoneUsageDescription` (iOS) y
|
|
295
|
+
`CAMERA` / `RECORD_AUDIO` / `MODIFY_AUDIO_SETTINGS` (Android).
|
|
267
296
|
|
|
268
297
|
**React Native "bare"** (sin Expo) — agrégalos a mano en `Info.plist` y `AndroidManifest.xml`.
|
|
298
|
+
En Android, `MODIFY_AUDIO_SETTINGS` es obligatorio: el WebView lo exige junto a `RECORD_AUDIO`;
|
|
299
|
+
sin él el micrófono falla con "Could not start audio source".
|
|
300
|
+
|
|
301
|
+
**Prueba en un dev build en teléfono real** (`npx expo run:android` / `run:ios`) — Expo Go no
|
|
302
|
+
aplica config plugins, así que los permisos no existen ahí.
|
|
269
303
|
|
|
270
304
|
> App de ejemplo completa (Expo):
|
|
271
305
|
> [`examples/expo-videocall`](https://github.com/Payfri/VideoCallsGateway/tree/main/examples/expo-videocall)
|
|
@@ -277,10 +311,9 @@ y `CAMERA` / `RECORD_AUDIO` (Android).
|
|
|
277
311
|
| Síntoma | Causa probable | Solución |
|
|
278
312
|
| --- | --- | --- |
|
|
279
313
|
| `401 UNAUTHORIZED` desde `/server` | API key mal copiada o revocada | Verifica la env var; pide una key nueva si fue revocada |
|
|
280
|
-
| CORS bloquea la petición del navegador | Tu dominio no está en la lista de orígenes | Pide el alta de tu dominio al equipo de la plataforma |
|
|
281
314
|
| "token inválido o expirado" al unirse | El token venció (default 1 h) | Emite un token nuevo por sesión; sube `ttlSeconds` si aplica |
|
|
282
315
|
| Cámara/micrófono no arrancan (web) | Contexto no seguro | Sirve tu página por **HTTPS** (`getUserMedia` lo exige) |
|
|
283
|
-
| Cámara/micrófono no arrancan (RN) | Permisos no declarados | Config plugin (Expo) o permisos manuales (bare)
|
|
316
|
+
| Cámara/micrófono no arrancan (RN) | Permisos no declarados, o Expo Go | Config plugin + dev build (Expo) o permisos manuales (bare) |
|
|
284
317
|
| `No hay fetch disponible` en `/server` | Node < 18 o runtime sin fetch | Usa Node 18+ o pasa `fetch` en las opciones |
|
|
285
318
|
| Pantalla en blanco en `<VideoCall>` | `embedBaseUrl` en HTTP o mal apuntada | Debe ser HTTPS y responder la página `/room` |
|
|
286
319
|
|
|
@@ -15,7 +15,8 @@ var withVideoSdk = (config, props) => {
|
|
|
15
15
|
});
|
|
16
16
|
return configPlugins.AndroidConfig.Permissions.withPermissions(withIos, [
|
|
17
17
|
"android.permission.CAMERA",
|
|
18
|
-
"android.permission.RECORD_AUDIO"
|
|
18
|
+
"android.permission.RECORD_AUDIO",
|
|
19
|
+
"android.permission.MODIFY_AUDIO_SETTINGS"
|
|
19
20
|
]);
|
|
20
21
|
};
|
|
21
22
|
var withVideoSdk_default = withVideoSdk;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/withVideoSdk.ts"],"names":["withInfoPlist","AndroidConfig"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/withVideoSdk.ts"],"names":["withInfoPlist","AndroidConfig"],"mappings":";;;;;AA6BA,IAAM,mBAAA,GAAsB,mDAAA;AAC5B,IAAM,uBAAA,GAA0B,sDAAA;AAEhC,IAAM,YAAA,GAAyD,CAAC,MAAA,EAAQ,KAAA,KAAU;AAChF,EAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,mBAAA;AACxC,EAAA,MAAM,cAAA,GAAiB,OAAO,cAAA,IAAkB,uBAAA;AAGhD,EAAA,MAAM,OAAA,GAAUA,2BAAA,CAAc,MAAA,EAAQ,CAAC,GAAA,KAAQ;AAC7C,IAAA,GAAA,CAAI,UAAA,CAAW,wBAAA,GACb,GAAA,CAAI,UAAA,CAAW,wBAAA,IAA4B,UAAA;AAC7C,IAAA,GAAA,CAAI,UAAA,CAAW,4BAAA,GACb,GAAA,CAAI,UAAA,CAAW,4BAAA,IAAgC,cAAA;AACjD,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,OAAOC,2BAAA,CAAc,WAAA,CAAY,eAAA,CAAgB,OAAA,EAAS;AAAA,IACxD,2BAAA;AAAA,IACA,iCAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH,CAAA;AAEA,IAAO,oBAAA,GAAQ","file":"withVideoSdk.cjs","sourcesContent":["import {\n AndroidConfig,\n withInfoPlist,\n type ConfigPlugin,\n} from \"@expo/config-plugins\";\n\n/**\n * Config plugin de Expo para `payfri-video-sdk`. Inyecta en el prebuild los permisos\n * de cámara y micrófono que exige el sistema operativo para usar getUserMedia\n * dentro del WebView de `<VideoCall>`:\n *\n * - iOS: NSCameraUsageDescription, NSMicrophoneUsageDescription (Info.plist)\n * - Android: CAMERA, RECORD_AUDIO, MODIFY_AUDIO_SETTINGS (AndroidManifest)\n *\n * MODIFY_AUDIO_SETTINGS es obligatorio: Chromium (el WebView) lo exige junto a\n * RECORD_AUDIO para abrir dispositivos de captura; sin él getUserMedia falla con\n * \"Could not start audio source\" aunque el usuario haya concedido el micrófono.\n *\n * El tenant lo activa en su `app.json` y no toca ningún archivo nativo:\n *\n * { \"plugins\": [[\"payfri-video-sdk\", { \"cameraText\": \"Para videollamadas\" }]] }\n */\nexport interface VideoSdkPluginProps {\n /** Texto del permiso de cámara mostrado por iOS. */\n cameraText?: string;\n /** Texto del permiso de micrófono mostrado por iOS. */\n microphoneText?: string;\n}\n\nconst DEFAULT_CAMERA_TEXT = \"Esta app usa la cámara para las videollamadas.\";\nconst DEFAULT_MICROPHONE_TEXT = \"Esta app usa el micrófono para las videollamadas.\";\n\nconst withVideoSdk: ConfigPlugin<VideoSdkPluginProps | void> = (config, props) => {\n const cameraText = props?.cameraText ?? DEFAULT_CAMERA_TEXT;\n const microphoneText = props?.microphoneText ?? DEFAULT_MICROPHONE_TEXT;\n\n // iOS: no pisar valores que el proyecto ya haya definido.\n const withIos = withInfoPlist(config, (cfg) => {\n cfg.modResults.NSCameraUsageDescription =\n cfg.modResults.NSCameraUsageDescription ?? cameraText;\n cfg.modResults.NSMicrophoneUsageDescription =\n cfg.modResults.NSMicrophoneUsageDescription ?? microphoneText;\n return cfg;\n });\n\n // Android: withPermissions deduplica, así que es seguro re-declararlos.\n return AndroidConfig.Permissions.withPermissions(withIos, [\n \"android.permission.CAMERA\",\n \"android.permission.RECORD_AUDIO\",\n \"android.permission.MODIFY_AUDIO_SETTINGS\",\n ]);\n};\n\nexport default withVideoSdk;\n"]}
|
|
@@ -6,7 +6,11 @@ import { ConfigPlugin } from '@expo/config-plugins';
|
|
|
6
6
|
* dentro del WebView de `<VideoCall>`:
|
|
7
7
|
*
|
|
8
8
|
* - iOS: NSCameraUsageDescription, NSMicrophoneUsageDescription (Info.plist)
|
|
9
|
-
* - Android: CAMERA, RECORD_AUDIO (AndroidManifest)
|
|
9
|
+
* - Android: CAMERA, RECORD_AUDIO, MODIFY_AUDIO_SETTINGS (AndroidManifest)
|
|
10
|
+
*
|
|
11
|
+
* MODIFY_AUDIO_SETTINGS es obligatorio: Chromium (el WebView) lo exige junto a
|
|
12
|
+
* RECORD_AUDIO para abrir dispositivos de captura; sin él getUserMedia falla con
|
|
13
|
+
* "Could not start audio source" aunque el usuario haya concedido el micrófono.
|
|
10
14
|
*
|
|
11
15
|
* El tenant lo activa en su `app.json` y no toca ningún archivo nativo:
|
|
12
16
|
*
|
|
@@ -6,7 +6,11 @@ import { ConfigPlugin } from '@expo/config-plugins';
|
|
|
6
6
|
* dentro del WebView de `<VideoCall>`:
|
|
7
7
|
*
|
|
8
8
|
* - iOS: NSCameraUsageDescription, NSMicrophoneUsageDescription (Info.plist)
|
|
9
|
-
* - Android: CAMERA, RECORD_AUDIO (AndroidManifest)
|
|
9
|
+
* - Android: CAMERA, RECORD_AUDIO, MODIFY_AUDIO_SETTINGS (AndroidManifest)
|
|
10
|
+
*
|
|
11
|
+
* MODIFY_AUDIO_SETTINGS es obligatorio: Chromium (el WebView) lo exige junto a
|
|
12
|
+
* RECORD_AUDIO para abrir dispositivos de captura; sin él getUserMedia falla con
|
|
13
|
+
* "Could not start audio source" aunque el usuario haya concedido el micrófono.
|
|
10
14
|
*
|
|
11
15
|
* El tenant lo activa en su `app.json` y no toca ningún archivo nativo:
|
|
12
16
|
*
|
|
@@ -13,7 +13,8 @@ var withVideoSdk = (config, props) => {
|
|
|
13
13
|
});
|
|
14
14
|
return AndroidConfig.Permissions.withPermissions(withIos, [
|
|
15
15
|
"android.permission.CAMERA",
|
|
16
|
-
"android.permission.RECORD_AUDIO"
|
|
16
|
+
"android.permission.RECORD_AUDIO",
|
|
17
|
+
"android.permission.MODIFY_AUDIO_SETTINGS"
|
|
17
18
|
]);
|
|
18
19
|
};
|
|
19
20
|
var withVideoSdk_default = withVideoSdk;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/withVideoSdk.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/withVideoSdk.ts"],"names":[],"mappings":";;;AA6BA,IAAM,mBAAA,GAAsB,mDAAA;AAC5B,IAAM,uBAAA,GAA0B,sDAAA;AAEhC,IAAM,YAAA,GAAyD,CAAC,MAAA,EAAQ,KAAA,KAAU;AAChF,EAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,mBAAA;AACxC,EAAA,MAAM,cAAA,GAAiB,OAAO,cAAA,IAAkB,uBAAA;AAGhD,EAAA,MAAM,OAAA,GAAU,aAAA,CAAc,MAAA,EAAQ,CAAC,GAAA,KAAQ;AAC7C,IAAA,GAAA,CAAI,UAAA,CAAW,wBAAA,GACb,GAAA,CAAI,UAAA,CAAW,wBAAA,IAA4B,UAAA;AAC7C,IAAA,GAAA,CAAI,UAAA,CAAW,4BAAA,GACb,GAAA,CAAI,UAAA,CAAW,4BAAA,IAAgC,cAAA;AACjD,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,OAAO,aAAA,CAAc,WAAA,CAAY,eAAA,CAAgB,OAAA,EAAS;AAAA,IACxD,2BAAA;AAAA,IACA,iCAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH,CAAA;AAEA,IAAO,oBAAA,GAAQ","file":"withVideoSdk.js","sourcesContent":["import {\n AndroidConfig,\n withInfoPlist,\n type ConfigPlugin,\n} from \"@expo/config-plugins\";\n\n/**\n * Config plugin de Expo para `payfri-video-sdk`. Inyecta en el prebuild los permisos\n * de cámara y micrófono que exige el sistema operativo para usar getUserMedia\n * dentro del WebView de `<VideoCall>`:\n *\n * - iOS: NSCameraUsageDescription, NSMicrophoneUsageDescription (Info.plist)\n * - Android: CAMERA, RECORD_AUDIO, MODIFY_AUDIO_SETTINGS (AndroidManifest)\n *\n * MODIFY_AUDIO_SETTINGS es obligatorio: Chromium (el WebView) lo exige junto a\n * RECORD_AUDIO para abrir dispositivos de captura; sin él getUserMedia falla con\n * \"Could not start audio source\" aunque el usuario haya concedido el micrófono.\n *\n * El tenant lo activa en su `app.json` y no toca ningún archivo nativo:\n *\n * { \"plugins\": [[\"payfri-video-sdk\", { \"cameraText\": \"Para videollamadas\" }]] }\n */\nexport interface VideoSdkPluginProps {\n /** Texto del permiso de cámara mostrado por iOS. */\n cameraText?: string;\n /** Texto del permiso de micrófono mostrado por iOS. */\n microphoneText?: string;\n}\n\nconst DEFAULT_CAMERA_TEXT = \"Esta app usa la cámara para las videollamadas.\";\nconst DEFAULT_MICROPHONE_TEXT = \"Esta app usa el micrófono para las videollamadas.\";\n\nconst withVideoSdk: ConfigPlugin<VideoSdkPluginProps | void> = (config, props) => {\n const cameraText = props?.cameraText ?? DEFAULT_CAMERA_TEXT;\n const microphoneText = props?.microphoneText ?? DEFAULT_MICROPHONE_TEXT;\n\n // iOS: no pisar valores que el proyecto ya haya definido.\n const withIos = withInfoPlist(config, (cfg) => {\n cfg.modResults.NSCameraUsageDescription =\n cfg.modResults.NSCameraUsageDescription ?? cameraText;\n cfg.modResults.NSMicrophoneUsageDescription =\n cfg.modResults.NSMicrophoneUsageDescription ?? microphoneText;\n return cfg;\n });\n\n // Android: withPermissions deduplica, así que es seguro re-declararlos.\n return AndroidConfig.Permissions.withPermissions(withIos, [\n \"android.permission.CAMERA\",\n \"android.permission.RECORD_AUDIO\",\n \"android.permission.MODIFY_AUDIO_SETTINGS\",\n ]);\n};\n\nexport default withVideoSdk;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payfri-video-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "SDK del microservicio de video: entry /server (apiKey, backend), /client (token, navegador) y /native (token, React Native)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": ["livekit", "video", "webrtc", "react-native", "expo", "sdk"],
|