https://a.storyblok.com/f/270183/58906/a44612b863/callmemaybe_1200x627.png

WebRTCビデオセッションにSIPコールを追加する

最終更新日 February 8, 2021

所要時間:1 分

私たちはビデオ会議の時代に生きている。学校から職場、家族のイベントまで、ビデオ会議は多くの人にとって生活の一部となっていますが、コンピュータから参加できない場合もあります。このチュートリアルでは、Vonage Video API セッションに電話から参加できるようにする方法を説明します。

最後まで読み飛ばしたいですか?このチュートリアルのソースコードはすべて GitHub.

どのように機能するのか?

Video APIセッションからVoice APIに電話をかける。この呼び出しによって、アプリケーションの answer webhook がトリガーされ、音声会話が作成される。この会話は、別のストリームとして Video セッションに加わる。

ユーザーが会議番号にダイヤルすると、PINの入力を求められます。ユーザーが正しいPINを入力すると、音声会話に参加します。その時点で、ユーザーはVideoセッションの参加者全員の声を聞くことができ、他の参加者の声も聞くことができます。

セッションが終了したら、Voice APIまたはVideo APIの追加課金を避けるため、通話を切断する必要があります。

前提条件

このチュートリアルに従うには、以下のものが必要だ:

フロントエンドの構築

私たちのフロントエンドでは、Express と EJS テンプレートを使用します。この記事では、Video API セッションの作成方法は取り上げない。既存のセッションに SIP 呼び出しを追加する方法だけに焦点を当てます。

Videoセッションのテンプレートに、以下の2つのJavaScript関数を追加する:

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`);
    })
  };

これらの関数はどちらもExpressバックエンドのルートを呼び出している。この dialOutメソッドは、Voice カンファレンスを開始し、Video セッションのストリームとして追加します。この hangUp関数は、セッションの終了時に使用され、音声会議をセッションから切断します。HTML内に、これらの関数を呼び出すためのボタンを2つ追加します。

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

バックエンドへの高速レーン

フロントエンドの準備ができたので、SIP経由でVonage Voice APIに接続するためのバックエンドをセットアップしよう。

ヘルパー機能

ダイヤルアウトやハングアップを処理する前に、いくつかのヘルパー機能が必要だ。

/**
 * 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
});

この generatePin関数は、ビデオセッションごとに固有のPINを作成するために使用する、ランダムな4桁のPINを生成します。セッションに参加する発信者は、セッションに参加する前にこのPINの入力を求められます。

この generateToken関数を使用して Video API トークンを作成します。

この setSipOptions関数は、SIP接続にダイヤルするときに使用するオブジェクトを作成する。このオブジェクトには、音声会議に参加するために必要な認証情報が含まれています。

フロントエンドに答える

これらの関数を配置したら、フロントエンドに応答するルートを追加しよう。以下の dial-outルートは Video API を使って SIP 会議に接続する。後で、Voice API がこれらの呼び出しに応答する方法を知るように設定する。

/**
 * 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');
  }
});

この hang-upルートは、Video API セッションから音声会議を切断します。会議の終了時に通話を切断することは、非常に重要です。そうしないと、音声会議が開かれたまま、Video セッションに接続されたままになります。これにより、両方の料金が増加し続けることになる。

Voice API ウェブフック

Voice アプリケーションを作成する場合、Answer Url と Event Url を提供する必要があります。ローカルでアプリケーションを実行している場合は、ngrok を使用して外部エンドポイントを提供します。ngrok UrlかHeroku Urlのどちらかにルート /voice-answerを指定します。 /voice-eventsをイベント Url に指定します。

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)
})

この /voice-answerルートは、こちらがダイヤル発信することで会話が開始されます。他の参加者が電話をかけると、セッションの4桁のPINを入力するよう促される。発呼側からの入力はルートに転送され、セッションに参加する可能性があります。 /voice-dtmfルートに転送され、セッションに参加する可能性がある。

設定の構成

まず .envファイルを作りましょう。リポジトリ内の .env-sampleファイルをテンプレートとして使うことができます。中身はこうだ:

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

設定するには videoApiKeyvideoApiSecretを設定するには、Video API ダッシュボードから新しいプロジェクトを作成します。

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

作成されたら、API KeyとSecretをコピーし、それをあなたの .envファイルに videoApiKeyvideoApiSecretとしてファイルに貼り付ける。

音声アプリケーションを作成し、API KeyとSecretを voiceApiKeyvoiceApiSecret.番号を購入し、それを音声アプリケーションに関連付ける必要があります。その番号を conferenceNumber変数として使用します。

最後に、ngrokまたはHerokuのURLをserverUrlとして入力します。

これでビデオセッションに参加し、他の人があなたの番号にダイヤルしてPINコードを入力すればセッションに参加できます。ビデオセッションの終了時には、ビデオと音声の両方のアカウントが使用されないように、通話を切断する必要があることを強調しておくことが重要です。

さらに読む

Video API の SIP Interconnect 機能についてもっと知りたいですか?以下のリンクが役に立ちます。

シェア:

https://a.storyblok.com/f/270183/225x225/b0360f94ad/michaeljolley.png
Michael Jolleyヴォネージの卒業生

マイケルはハゲでヒゲのビルダー。ソフトウェア開発とDevOpsにおける20年の経験を生かし、他人の成功を助けることに集中する日々を送っている。