https://d226lax1qjow5r.cloudfront.net/blog/blogposts/add-sip-calls-to-webrtc-video-sessions/callmemaybe_1200x627.png

Ajouter des appels SIP à des sessions Video WebRTC

Publié le February 8, 2021

Temps de lecture : 4 minutes

Nous vivons à l'heure de la vidéoconférence. De l'école au travail en passant par les événements familiaux, la vidéoconférence est devenue un mode de vie pour beaucoup, mais il arrive que la participation à partir d'un ordinateur ne soit pas possible. Dans ce tutoriel, nous verrons comment permettre aux participants de se joindre à vos sessions Video API de Vonage par téléphone.

Vous voulez sauter à la fin ? Vous pouvez trouver tout le code source de ce tutoriel sur GitHub.

Comment cela fonctionne-t-il ?

À partir de la session Video API, nous lançons un appel à Voice API. Cet appel déclenchera le webhook de réponse dans notre application qui créera une conversation vocale. Cette conversation rejoindra la session Video en tant que flux supplémentaire.

Lorsque les utilisateurs composent le numéro de la conférence, un code PIN leur est demandé. Si l'utilisateur fournit le code PIN correct, il rejoindra la conversation Voice. À ce moment-là, l'utilisateur pourra entendre tous les participants à la session Video et ceux-ci pourront à leur tour entendre la voix des autres participants.

Une fois la session terminée, l'appel doit être raccroché pour éviter des frais supplémentaires liés à l'API Voice ou Video.

Conditions préalables

Pour suivre ce tutoriel, vous aurez besoin de :

  • Un compte Video API de Vonage. Cliquez ici pour en obtenir un gratuitement.

  • Optionnel : Ngrok pour les tests locaux

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

Construire le Frontend

Notre frontend utilisera Express avec un modèle EJS. Pour cet article, nous ne couvrirons pas la création d'une session Video API, mais vous pouvez consulter le code dans le référentiel pour voir comment nous procédons. Nous nous concentrerons uniquement sur l'ajout d'un appel SIP à une session existante.

Dans le modèle de la session vidéo, ajoutez les deux fonctions JavaScript ci-dessous :

const dialOut = () => {
  fetch(`/dial-out?roomId=${roomId}`)
    .then(response => response.json())
    .then((sipData) => {
      connectionId = sipData.connectionId;
    }).catch((error) => {
      alert(`There was an error dialing-out`);
    })
};
const hangUp = () => {
  fetch(`/hang-up?roomId=${roomId}`)
    .then(response => response)
    .then((data) => {
      console.log('dial-out-hang-up-complete');
    }).catch((error) => {
      alert(`There was an error hanging up`);
    })
  };

Ces deux fonctions appellent des routes sur notre backend Express. La méthode dialOut lance la conférence vocale et l'ajoute en tant que flux dans la session Video. La fonction hangUp sera utilisée à la fin de la session pour déconnecter la conférence vocale de la session. Dans notre code HTML, nous ajouterons deux boutons pour appeler ces fonctions.

<button onclick="dialOut()">Click here to dial-out to the Vonage Conference</button>
<button onclick="hangUp()">Click here to hang-up</button>

Voie express vers le backend

Notre frontend étant prêt à fonctionner, configurons notre backend pour qu'il se connecte à l'API Voice de Vonage via SIP.

Fonctions d'assistance

Nous aurons besoin de quelques fonctions d'aide avant de gérer les appels sortants et les raccrochages.

/**
 * Generates a random 4 digit PIN
 */
const generatePin = () => {
  const pin = Math.floor(Math.random() * 9000) + 1000;
  if (app.get(pin)) {
    return generatePin();
  }
  return pin;
};

/**
 * Creates a Video API user token
 * @param {String} sessionId Id of the Video API session the user wishes to join
 * @param {String} sipTokenData Data associated with the SIP connection
*/
const generateToken = (sessionId, sipTokenData = '') => OT.generateToken(sessionId, {
  role: 'publisher',
  data: sipTokenData,
});

/**
 * Properties for the OT.dial API call
 * @returns {Object}
*/
const setSipOptions = () => ({
  auth: {
    username: config.voiceApiKey,
    password: config.voiceApiSecret,
  },
  secure: false
});

La fonction generatePin génère un code PIN aléatoire à 4 chiffres que nous utiliserons pour créer un code PIN unique pour chaque session Video. Les personnes appelant la session seront invitées à saisir ce code PIN avant d'être autorisées à participer à la session.

La fonction generateToken est utilisée pour créer un jeton d'API Video avec le SIP

La fonction setSipOptions crée un objet que nous utiliserons pour établir la connexion SIP. Il contient les informations d'authentification nécessaires pour rejoindre la conférence vocale.

Répondre au Frontend

Avec ces fonctions en place, ajoutons des routes pour répondre à notre frontend. La route dial-out ci-dessous utilisera l'API Video pour se connecter à une conférence SIP. Plus tard, nous configurerons l'API Voice pour qu'elle sache comment répondre à ces appels.

/**
 * When the dial-out get request is made, the dial method of the 
 * OpenTok Dial API is invoked
*/
app.get('/dial-out', (req, res) => {
  const { roomId } = req.query;
  const { conferenceNumber } = config;
  const sipTokenData = `{"sip":true, "role":"client", "name":"'${conferenceNumber}'"}`;
  const sessionId = app.get(roomId);
  const token = generateToken(sessionId, sipTokenData);
  const options = setSipOptions();
  const sipUri = `sip:${conferenceNumber}@sip.nexmo.com;transport=tls`;
  OT.dial(sessionId, token, sipUri, options, (error, sipCall) => {
    if (error) {
      console.dir(error)
      res.status(500).send('There was an error dialing out');
    } else {
      app.set(conferenceNumber + roomId, sipCall.connectionId);
      res.json(sipCall);
    }
  });
});

/**
 * When the hang-up get request is made, the forceDisconnect method 
 * of the OpenTok API is invoked
*/
app.get('/hang-up', (req, res) => {
  const { roomId } = req.query;
  const { conferenceNumber } = config;
  if (app.get(roomId) + app.get(conferenceNumber + roomId)) {
    const sessionId = app.get(roomId);
    const connectionId = app.get(conferenceNumber + roomId);
    OT.forceDisconnect(sessionId, connectionId, (error) => {
      if (error) {
        res.status(500).send('There was an error hanging up');
      } else {
        res.status(200).send('Ok');
      }
    });
  } else {
    res.status(400).send('There was an error hanging up');
  }
});

L'itinéraire hang-up déconnecte la conférence vocale de la session Video API. Il est essentiel de raccrocher l'appel à la fin d'une réunion. Sinon, la conférence vocale restera ouverte et connectée à la session Video. Dans ce cas, les deux sessions continueront d'augmenter les frais.

Crochets Web de l'API Voice

Lorsque vous créez une application vocale, vous devez fournir une Url de réponse et une Url d'événement. Si vous exécutez l'application localement, vous voudrez utiliser ngrok pour fournir un point de terminaison externe. Fournissez votre Url ngrok ou votre Url Heroku avec des routes /voice-answer pour l'Url de réponse et /voice-events pour l'Url d'événement.

app.get('/voice-events', (req, res) => {
  res.status(200).send();
});

app.post('/voice-answer', (req, res) => {
  const { serverUrl } = config;
  const ncco = [];
  if (req.body['SipHeader_X-OpenTok-SessionId']) {
    ncco.push({
      action: 'conversation',
      name: req.body['SipHeader_X-OpenTok-SessionId'],
    });
  } else {
    ncco.push(
      {
        action: 'talk',
        text: 'Please enter a pin code to join the session'
      },
      {
        action: 'input',
        eventUrl: [`${serverUrl}/voice-dtmf`]
      }
    )
  }

  res.json(ncco);
});

app.post('/voice-dtmf', (req, res) => {
  const { dtmf } = req.body;
  let sessionId;

  if (app.get(dtmf)) {
    sessionId = app.get(dtmf);
  }

  const ncco = [
    {
      action: 'conversation',
      name: sessionId,
    }];

  res.json(ncco)
})

L'itinéraire /voice-answer créera une conversation lorsqu'elle sera déclenchée en raison de notre numérotation. Lorsque d'autres participants appellent, ils sont invités à fournir le code PIN à quatre chiffres de la session. Les entrées de l'appelant seront transmises à l'itinéraire /voice-dtmf pour qu'il puisse éventuellement rejoindre la session.

Configuration des paramètres

Commençons par créer un fichier .env fichier. Vous pouvez utiliser le fichier .env-sample dans le repo comme modèle. Son contenu doit être le suivant :

videoApiKey=
videoApiSecret=
voiceApiKey=
voiceApiSecret=
conferenceNumber=
serverUrl=

Pour régler videoApiKey et videoApiSecret, créez un nouveau projet à partir du tableau de bord Video API.

Project created dialog within the Vonage Video API dashboardProject created dialog within the Vonage Video API dashboard

Une fois qu'il est créé, copiez la clé et le secret de l'API et collez-les dans votre fichier .env en tant que videoApiKey et videoApiSecret respectivement.

Créez maintenant une application vocale et utilisez la clé et le secret de l'API en tant qu'entrées voiceApiKey et voiceApiSecret. Vous devrez acheter un numéro et l'associer à votre application vocale. Utilisez ce numéro comme variable conferenceNumber variable.

Enfin, entrez l'url de ngrok ou Heroku comme serverUrl.

Vous pouvez désormais participer à une session Video et d'autres personnes peuvent composer votre numéro et entrer un code PIN pour participer à la session. Il est important de souligner que vous devez raccrocher l'appel à la fin de la session Video afin d'éviter l'utilisation des comptes vidéo et vocaux lorsque vous avez terminé.

Pour en savoir plus

Vous souhaitez en savoir plus sur la fonction d'interconnexion SIP de l'API Video ? Voici quelques liens qui pourraient vous être utiles.

Partager:

https://a.storyblok.com/f/270183/225x225/b0360f94ad/michaeljolley.png
Michael JolleyAnciens de Vonage

Michael est le bâtisseur chauve et barbu. Fort de ses 20 ans d'expérience dans le développement de logiciels et DevOps, ce développeur aux prises avec des difficultés folliculaires passe ses journées à aider les autres à réussir.