Llamadas

**NOTA: esta página detalla el principio de las cuentas Jami.

¡Hagamos una llamada en Jami!

El lado del demonio

Cuando se crea una llamada entre dos compañeros, Jami utiliza principalmente protocolos conocidos como ICE, SIP o TLS. Sin embargo, para que se distribuya, el proceso de creación de una llamada es un poco diferente.

  1. Buscar la presencia de contactos en el DHT (para más detalles, véase -contact-management)

  2. Una vez que se encuentre el contacto, envíe una solicitud de llamada, anunciando los candidatos conocidos (la IP de cada interfaz de red + direcciones de retransmisión (TURN) + direcciones reflectivas (UPnP, públicas).

  3. Esperar la respuesta del contacto (reponerán sus direcciones conocidas).

  4. Negociar el enchufe a través de ICE. De hecho, se negocian dos sesiones de ICE. Una (preferida) en TCP, otra en UDP (como fallback).

  5. Luego, el enchufe se cifre en TLS (si TCP) o DTLS (si UDP).

  6. El contacto ahora puede aceptar o rechazar la llamada. Cuando aceptan, se negocia un transporte ICE (UDP sólo por ahora) para crear 4 nuevos enchufes para los medios (2 para audio, 2 para video).

  7. ¡La llamada está viva ahora!

Cambio de candidatos a ICE

Todo comienza realmente en jamiaccount.cpp (JamiAccount::startOutgoingCall). Una vez que ambos objetos ICE están listos y cuando se encuentra el contacto a través del DHT, se elabora la solicitud de llamada para el contacto. Esta solicitud contiene toda la información necesaria para la sesión remota ICE definida por:

dht::IceCandidates(callvid,  blob)

donde callvid es un número aleatorio utilizado para identificar la llamada y el blob contiene dos mensajes ICE concatenados (IceTransport::packIceMsg en ice_transport.cpp) que contienen la contraseña de la sesión, los candidatos ufrag e ICE.) como:

0d04b935
7c33834e7cf944bf0e367b42
H6e6ca382 1 UDP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 14133 typ host
H42c1g477 1 UDP 2130706431 fe80::9eb6:d0ff:fee7:1412 14133 typ host
Hc0a8027e 1 UDP 2130706431 192.168.0.123 34567 typ host
Sc0a8027e 1 UDP 1694498815 X.X.X.X 32589 typ srflx
0d04b932
7c33834e7cf944bf0e367b47
H6e6ca682 1 TCP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 50693 typ host tcptype passive
H6e6ca682 1 TCP 2130706431 2607:fad8:4:6:9eb6:d0ff:dead:c0de 9 typ host tcptype active
H42c1b577 1 TCP 2130706431 fe80::9eb6:d0ff:fee7:1412 50693 typ host tcptype passive
H42c1b577 1 TCP 2130706431 fe80::9eb6:d0ff:fee7:1412 9 typ host tcptype active
Hc0a8007e 1 TCP 2130706431 192.168.0.123 42751 typ host tcptype passive
Hc0a8007e 1 TCP 2130706431 192.168.0.123 9 typ host tcptype active
Sc0a8007e 1 TCP 1694498815 X.X.X.X 42751 typ srflx tcptype passive

y se envía a través del DHT en un mensaje cifrado para el dispositivo a hash(call:xxxxxx) donde xxxxxx es el id del dispositivo. El compañero responderá en el mismo lugar exacto (pero cifrado para el dispositivo remitente) su propio dht::IceCandidates. Ver JamiAccount::replyToIncomingIceMsg para más detalles.

La sesión ICE se crea en ambos lados cuando tienen todos los candidatos (por lo tanto, para el remitente, cuando se recibe la respuesta del contacto).

Negociación del ICE

Las llamadas pendientes son administradas por JamiAccount::handlePendingCallList() , que primero esperan que termine la negociación TCP (y si falla, espere a la UDP). El código para la negociación ICE es administrado principalmente por [pjproject]https://github.com/pjsip/pjproject) pero para Jami, la parte interesante se encuentra en ice_transport.cpp. Además, añadimos algunos parches/funciones importantes en la parte superior de pjproject que no se han fusionado en aguas arriba por ahora (por ejemplo, ICE sobre TCP). Estos parches están presentes en contrib/src/pjproject.

Encripta el control de la toma

Una vez que el enchufe es creado y administrado por una instancia de IceTransport, se envuelve en un SipTransport correspondiente a un TlsIceTransport. El código principal se encuentra en JamiAccount::handlePendingCall() y se envuelve en SipTransportBroker::getTlsIceTransport. Finalmente, nuestra sesión es administrada por TlsSession en daemon/src/security/tls_session.cpp y utiliza la biblioteca GnuTLS.

Así, el control de socket será un TLS (1.3 si su versión y sus gnutls de pares lo admiten) si se negocia un socket TCP. Si se negocia un socket UDP en su lugar (debido a restricciones de firewall / problema en la negociación / etc), el socket utilizará DTLS (todavía administrado por las mismas partes).

El socket de control se utiliza para transmitir paquetes SIP, como invitaciones, mensajes personalizados (Jami envía la VCard de su perfil en este socket al comienzo de la llamada, o la rotación de la cámara), mensajes de texto.

Artículos relacionados:

  • El programa de trabajo de la Comisión de Educación y Tecnología de la Unión Europea (CEDEFOP)

  • El proyecto de ley de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea) de la Unión Europea (UE) de la Unión Europea) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea) de los Estados Unidos) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea) de la Unión Europea (UE) de la Unión Europea) de la Unión Europea (UE) de la Unión Europea (UE) de la Unión Europea) de los Estados Unidos) de las Naciones Unidas) de las Naciones Unidas) en el 15 de las Naciones Unidas (UE) en el 15 de las Naciones Unidas) en el 15 de las Partes.

Sockets de medios

Los sockets de medios son sockets SRTP donde la clave se negocia a través de la sesión TLS previamente creada. ** TODO**

Arquitectura

¿Qué es esto?

El sistema de transmisión de datos

Desde la versión 13.3.0 de Daemon, multi-stream es totalmente compatible. Esta función permite a los usuarios compartir varios videos durante una llamada al mismo tiempo. En las siguientes partes, describiremos todos los cambios relacionados.

el agua

La primera parte es negociar suficientes flujos de medios. De hecho, cada flujo de medios utiliza 2 tomas UDP. Consideramos tres escenarios:

  1. Si es el anfitrión de una conferencia que quiere agregar medios, no hay nada más que negociar, porque ya mezclamos los vídeos en una corriente. Así que, añadimos los nuevos medios directamente al videomixer sin negociaciones.

  2. Si estamos en 1:1, por ahora, ya que no hay información de conferencia, multi-stream no es compatible.

  3. De lo contrario, se negocian dos nuevos sockets para nuevos medios.

Para que pjsip pueda generar más sockets por sesión de ICE, PJ_ICE_COMP_BITS fue modificado a 5 (que corresponde a 2^5, por lo que 32 flujos).

Deprecar el interruptorInputo, solicitud de soporteMediaCambio

En el daemon, la antigua API switchInput ahora es DEPRECATED; igual para switchSecondaryInput:

<method name="switchInput" tp:name-for-bindings="switchInput">
    <tp:docstring>
        Switch input for the specified call
    </tp:docstring>
    <arg type="s" name="accountId" direction="in"/>
    <arg type="s" name="callId" direction="in"/>
    <arg type="s" name="input" direction="in"/>
    <arg type="b" direction="out" />
</method>

<method name="switchSecondaryInput" tp:name-for-bindings="switchSecondaryInput">
    <tp:added version="11.0.0"/>
    <tp:docstring>
        Switch secondary input for the specified conference
    </tp:docstring>
    <arg type="s" name="accountId" direction="in" />
    <arg type="s" name="conferenceId" direction="in"/>
    <arg type="s" name="input" direction="in"/>
    <arg type="b" direction="out" />
</method>

requestMediaChange sustituye a esto, tanto para las llamadas como para las conferencias:

<method name="requestMediaChange" tp:name-for-bindings="requestMediaChange">
    <tp:added version="11.0.0"/>
    <tp:docstring>
        <p>Request changes in the media of the specified call.</p>
    </tp:docstring>
    <arg type="s" name="accountId" direction="in" />
    <arg type="s" name="callId" direction="in">
        <tp:docstring>
        The ID of the call.
        </tp:docstring>
    </arg>
    <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="VectorMapStringString"/>
    <arg type="aa{ss}" name="mediaList" direction="in">
        <tp:docstring>
        A list of media attributes to apply.
        </tp:docstring>
    </arg>
    <arg type="b" name="requestMediaChangeSucceeded" direction="out"/>
</method>

Compatibilidad

Si se realiza una llamada con un peer donde la versión del daemon es < 13.3.0, no se habilita el multi-stream y se utiliza el comportamiento antiguo (sólo 1 video).

Identificación de las corrientes

Debido a que ahora puede haber múltiples flujos, cada flujo de medios se identifica por su identificador, y el formato es «_»; por ejemplo: «audio_0», «video_2», etc.

Rotación

El XML se actualizó para agregar el flujo buscado:

<?xml version="1.0" encoding="utf-8" ?>
<media_control>
  <vc_primitive>
    <stream_id>{}</stream_id>
    <to_encoder>
      <device_orientation>0</device_orientation>
    </to_encoder>
  </vc_primitive>
</media_control>

Cuadro de teclas

El XML se actualizó para agregar el flujo buscado:

<?xml version="1.0" encoding="utf-8" ?>
<media_control>
  <vc_primitive>
    <stream_id>{}</stream_id>
    <to_encoder><picture_fast_update/></to_encoder>
  </vc_primitive>
</media_control>

Actividad de voz

El XML se actualizó para agregar el flujo buscado:

<?xml version="1.0" encoding="utf-8" ?>
<media_control>
  <vc_primitive>
    <stream_id>{}</stream_id>
    <to_encoder>
      <voice_activity>true</voice_activity>
    </to_encoder>
  </vc_primitive>
</media_control>

Conferencia

Reflected changes are documented here.

Cliente

Incluso si el back-end admite hasta 32 medios al mismo tiempo, excepto para clientes personalizados, actualmente recomendamos que solo se dé la capacidad de compartir una cámara y un video al mismo tiempo.

En el cliente-qt, la parte interesante es en AvAdapter (métodos como isCapturing, shareAllScreens, stopSharing). En la lógica de la biblioteca, addMedia y removeMedia en el callModel utilizan directamente el requestMediaChange y se pueden utilizar como referencia de diseño.