Baby Zzz's LogoBaby Zzz's
InicioFuncionesApp de escritorioGuíasPreguntasNosotrosContacto
Código abierto

Bibliotecas de código abierto para cámaras IP en Kotlin y Swift

kotlin2rtc y swift2rtc • licencia ISC • del equipo de Baby Zzz's

Baby Zzz's se comunica con las cámaras IP directamente desde el teléfono: las encuentra en su Wi-Fi, inicia sesión por ONVIF, reproduce su transmisión RTSP, mueve el giro y la inclinación, y envía la voz de los padres al altavoz de la cámara. Extrajimos ese código de nuestras apps de Android e iOS y lo publicamos como dos bibliotecas que cualquiera puede usar en sus propias apps o herramientas.

Kotlin · Android · JVMkotlin2rtcONVIF, PTZ, canal de retorno de audio RTSP, G.711 / G.726 / AAC / L16 en RTPgithub.com/mafischer/kotlin2rtc →Swift · iOS 17 · macOS 14swift2rtcONVIF, PTZ, cliente RTSP, desempaquetado RTP, decodificación con VideoToolbox / AudioToolboxgithub.com/mafischer/swift2rtc →

Protocolos de cámara al estilo de go2rtc, como bibliotecas

go2rtc es un servidor de transmisión muy conocido, escrito en Go, que habla una larga lista de protocolos de cámara. kotlin2rtc y swift2rtc llevan protocolos de cámara al estilo de go2rtc a Kotlin y Swift como bibliotecas integrables: no hay ningún servidor que ejecutar, el código vive dentro de su app y habla directamente con la cámara.

Son proyectos independientes. go2rtc y pytapo (una biblioteca de Python para cámaras TP-Link Tapo) fueron referencias de protocolo muy valiosas mientras las escribíamos, y agradecemos a sus autores. Ninguno de los dos proyectos está afiliado a Baby Zzz's ni lo respalda.

kotlin2rtc: ONVIF y RTSP para Android y la JVM

Kotlin puro con corrutinas, sin dependencias de Android, así que funciona en una app de Android y en cualquier JVM (bytecode para Java 17). Cuatro módulos:

  • kotlin2rtc-onvif: WS-Discovery, el cliente ONVIF de dispositivo, medios y PTZ (UsernameToken de WS-Security, HTTP Digest cuando la cámara lo pide), el nivel del altavoz de la cámara y una comprobación que verifica que la cámara responde y es el mismo dispositivo antes de enviar las credenciales.
  • kotlin2rtc-rtsp: el canal de retorno de audio RTSP (audio bidireccional ONVIF).
  • kotlin2rtc-codec: G.711 (ley µ y ley A), G.726, tramas AAC, L16, empaquetado RTP y RTCP.
  • kotlin2rtc-core: HTTP Digest, credenciales que nunca muestran su contraseña y una protección de red local: SOAP y RTSP van sin cifrar solo a direcciones de la propia red del dispositivo.

Instalación

La primera versión (0.1.0) se está preparando para Maven Central; hasta que se publique, compílela desde el repositorio.

// settings.gradle.kts: until 0.1.0 is on Maven Central, build it from a checkout next to your project
includeBuild("../kotlin2rtc")

// build.gradle.kts (group io.github.mafischer)
dependencies {
    implementation("io.github.mafischer:kotlin2rtc-onvif:0.1.0-SNAPSHOT")
    implementation("io.github.mafischer:kotlin2rtc-rtsp:0.1.0-SNAPSHOT")  // audio backchannel
    implementation("io.github.mafischer:kotlin2rtc-codec:0.1.0-SNAPSHOT") // G.711, G.726, AAC, L16, RTP
}

Encontrar una cámara y obtener su transmisión

import io.github.mafischer.kotlin2rtc.core.*
import io.github.mafischer.kotlin2rtc.onvif.*

// Only addresses on this device's subnets may be called (no cleartext SOAP to the internet)
val network = LocalNetwork(listOf(LinkSubnet.parse("192.168.1.20/24")))

// WS-Discovery: the ONVIF cameras that answer on this network
val cameras = WsDiscovery(accept = network::allows).discover(timeoutMillis = 3_000)

val onvif = OnvifClient(
    transport = LanHttpTransport(allows = network::allowsCamera),
    deviceUrl = cameras.first().deviceUrl,
    credentials = Credentials("camera-user", "camera-password"),
)
onvif.syncClock() // WS-Security timestamps follow the camera's clock
val endpoints = onvif.endpoints()
val profile = onvif.profiles(endpoints.mediaUrl).first { it.hasVideo }
val rtspUrl = onvif.streamUri(endpoints.mediaUrl, profile.token)

Audio bidireccional ONVIF en Android e iOS

Muchas cámaras ONVIF con altavoz aceptan sonido de la app por RTSP: el canal de retorno de audio (backchannel) de la especificación de streaming de ONVIF, obligatorio en el Perfil T de ONVIF y disponible también en muchas otras cámaras. El cliente lo pide con un DESCRIBE que lleva Require: www.onvif.org/ver20/backchannel; la cámara indica su altavoz como un medio de audio sendonly; el cliente lo configura por TCP intercalado, lo inicia con PLAY y envía audio RTP en el códec de la cámara.

kotlin2rtc ya hace todo eso, en Android y en cualquier JVM: elige el mejor códec que ofrece la cámara (G.711, AAC-LC, G.726 de 40 a 16 kbit/s, L16), mantiene la sesión activa y la cierra correctamente. Es lo que hace funcionar el botón de pulsar para hablar y los sonidos para dormir en cámaras IP en la app de Baby Zzz's para Android. En iOS, el canal de retorno está previsto para swift2rtc.

Pulsar para hablar en Kotlin (canal de retorno RTSP)

import io.github.mafischer.kotlin2rtc.codec.BackchannelEncoder
import io.github.mafischer.kotlin2rtc.rtsp.RtspBackchannelClient

// Blocking calls: run them on an IO thread. The login rides in the URL (kept in memory only).
val client = RtspBackchannelClient(
    url = "rtsp://camera-user:[email protected]:554/stream1",
    allows = network::allowsCamera,
)
// DESCRIBE with "Require: www.onvif.org/ver20/backchannel"
val media = client.describe().media ?: return // no speaker kotlin2rtc can send to
val encoder = BackchannelEncoder(media)        // G.711, G.726, AAC or L16, as the camera asked
encoder.microphoneRate(16_000)
val link = client.open()                       // SETUP (TCP interleaved) + PLAY
try {
    while (talking) {
        val block: FloatArray = readMicrophone(16_000 / 50) // one 20-millisecond block, -1..1
        encoder.packets(sound = null, microphone = block).forEach(link::sendRtp)
    }
} finally {
    link.close() // TEARDOWN
}

swift2rtc: ONVIF y RTSP para iOS y macOS

Un paquete Swift (Swift 6, iOS 17 y macOS 14) con tres productos:

  • Swift2RTCOnvif: WS-Discovery, el cliente ONVIF de dispositivo, medios y PTZ, control PTZ con zoom óptico y la comprobación de la cámara.
  • Swift2RTCRTSP: un cliente RTSP: mensajes RTSP y SDP, desempaquetado RTP de H.264, H.265, AAC y G.711, y decodificación con VideoToolbox y AudioToolbox.
  • Swift2RTCCore: HTTP Digest, credenciales, un pequeño transporte HTTP sobre sockets y la misma protección de red local.

El canal de retorno de audio (audio bidireccional) está previsto.

Instalación con Swift Package Manager

// Package.swift
dependencies: [
    .package(url: "https://github.com/mafischer/swift2rtc.git", branch: "main"), // a version tag comes with 0.1.0
],
targets: [
    .target(name: "MyApp", dependencies: [
        .product(name: "Swift2RTCOnvif", package: "swift2rtc"),
        .product(name: "Swift2RTCRTSP", package: "swift2rtc"),
    ]),
]

Encontrar una cámara y obtener su transmisión

import Swift2RTCOnvif

// Only private (local) addresses may be called
let isLocal: @Sendable (InetAddress) -> Bool = { $0.isPrivate }

let cameras = try await WSDiscovery(accept: isLocal).discover(timeout: 3)
let onvif = OnvifClient(
    transport: SocketLanTransport(allows: isLocal),
    deviceURL: cameras[0].deviceURL,
    credentials: OnvifCredentials(username: "camera-user", password: "camera-password")
)
_ = try await onvif.syncClock()
let endpoints = try await onvif.endpoints()
let profiles = try await onvif.profiles(mediaURL: endpoints.mediaURL)
if let profile = profiles.first(where: { $0.hasVideo }) {
    let rtspURL = try await onvif.streamURI(mediaURL: endpoints.mediaURL, profileToken: profile.token)
}

De paquetes RTP a imágenes

import Swift2RTCRTSP

let sdp = SDP.parse(describeAnswer)           // the camera's DESCRIBE body
var video = VideoDepacketizer(codec: .h264)    // or .h265
if let packet = RTPPacket.parse(interleavedPayload) {
    for unit in video.push(packet) {
        // unit.nalUnits: one picture, ready for a VideoToolbox decompression session
    }
}

Audio bidireccional Tapo sin la app Tapo (próximamente)

Las cámaras TP-Link Tapo, como la Tapo C210, ofrecen ONVIF y RTSP para el video, pero su altavoz no acepta sonido por el canal de retorno ONVIF: la app Tapo usa para ello un protocolo propio de TP-Link. La app de Baby Zzz's para Android y Baby Zzz's Desktop ya hablan con los altavoces Tapo mediante ese protocolo, con código propio, y tenemos previsto añadirlo a las dos bibliotecas.

Todavía no está publicado. El audio bidireccional Tapo no está hoy en kotlin2rtc ni en swift2rtc. Cuando se publique, será necesario activar Third-Party Compatibility (compatibilidad con terceros) para la cámara en la app Tapo.

Por qué bibliotecas y no un servidor

Los servidores como go2rtc son excelentes para quien tiene un laboratorio en casa: un equipo en la red habla con todas las cámaras y las retransmite. Una app de monitor de bebés tiene otras necesidades:

  • Ningún equipo adicional que configurar: el teléfono habla directamente con la cámara.
  • Las credenciales de la cámara se quedan en el dispositivo: no se entregan a otro servidor.
  • La app controla la sesión: abre la transmisión cuando alguien mira y la cierra al terminar, lo que importa para la batería y para el número limitado de conexiones de la cámara.
  • Poca superficie de ataque: nada escucha en la red, y la protección de red local se niega a enviar datos sin cifrar a cualquier dirección fuera de la propia red del dispositivo.

Se usan en Baby Zzz's

La app de Baby Zzz's para Android usa este código para añadir cámaras IP, reproducirlas junto a las cámaras de teléfono, mover cámaras PTZ y hablar o reproducir sonidos para dormir por el altavoz de la cámara. La app para iOS, que llegará pronto, usa el código Swift. Consulte cómo usar una cámara Tapo u ONVIF como monitor de bebés y las funciones de la app.

App para teléfono
Disponible enGoogle PlayPróximamenteiOS

Licencia y contribuciones

Las dos bibliotecas se publican con la licencia ISC. Los informes de errores, las notas de compatibilidad de cámaras y los pull requests son bienvenidos en GitHub: incidencias de kotlin2rtc e incidencias de swift2rtc.

Baby Zzz's LogoBaby Zzz's

Monitoreo de bebés privado y cifrado mediante WebRTC directo. Convierta teléfonos y tabletas Android de repuesto en un monitor de bebés, sin grabación de video en la nube.

App para teléfono
Disponible enGoogle PlayPróximamenteiOS

Navegación

  • Inicio
  • Funciones
  • App de escritorio
  • Guías
  • Preguntas
  • Nosotros
  • Código abierto

Guías y tutoriales

  • Guía de configuración de 2 dispositivos
  • Cámaras Wi‑Fi Tapo y ONVIF
  • Seguridad y privacidad WebRTC
  • Ubicación y seguridad de la cámara
  • Solución de problemas de Wi-Fi y NAT

Legal y soporte

  • Política de privacidad
  • Términos de servicio
  • Eliminación de cuenta y datos
  • Contactar soporte

Aviso: Baby Zzz's es una herramienta informativa de asistencia de monitoreo diseñada para padres y cuidadores. No es un dispositivo médico, no está diseñada para el diagnóstico, cura, mitigación, tratamiento o prevención de ninguna enfermedad o afección, y nunca debe reemplazar la supervisión directa y atenta de un adulto.

© 2026 Baby Zzz's LLC. Todos los derechos reservados.

Alojado de forma segura en Oracle Cloud Infrastructure (OCI) y Cloudflare.