電話からビデオ会議への橋渡し

Vonage Video APIを使用すると、あらゆるビデオ体験を作成することができます。多くの場合、参加者は携帯電話ネットワークやISPの問題のために、インターネットのカバレッジが良くない地域にいるかもしれませんが、それでも会議に参加する必要があります。ビデオ会議に参加しない参加者が会議に電話をかけて参加する方法を紹介します。

このチュートリアルでは

Vonage Video API を使用すると、ユーザーがダイヤルしてビデオ会議に参加したり、ユーザーにダイヤル発信して直接参加したりすることができます。コードを書く必要がないように、既存のデモを使用してデモを立ち上げて実行する方法について説明します。

  1. デモを見る - コードを書かずにデモをチェックする
  2. デモの仕組み - クライアント側 - クライアント側のコードが行っていること
  3. デモの仕組み - サーバー・サイド - サーバーサイドのコードが行っていること

前提条件

チュートリアルを完了するには

デモを見る

コードを書く前にデモをチェックしたい場合は、基本的なビデオ通話がどのように見えるかを試すためのサンプルウェブサーバーとJavaScriptコードを用意しています。すべてのコードはオープンソースで公開されているので、デモを試してみてから、そのコードを使って独自の修正を加えることができます。

Node.jsサーバーの起動

ビデオ・デモでは、認証のためのクライアント・トークンの作成や一般的なセッション管理などを行うバックエンド・サーバーが必要です。好きな言語でこれを構築することができますが、私たちは事前に構築したサーバーを用意しています。 Vonage ビデオ学習サーバー (Node.js) on Code Hub.より 開発者向けドキュメント一番上のナビゲーション・バーで "Code Hub "をクリックし、下にスクロールして "Vonage Video Learning Server (Node.js) "のカードを見つける。それをクリックして開いてください。

このプロジェクトが何をするのかの説明が表示される。とりあえず、"Get code "をクリックして、Code Hubオンライン・エディターに読み込ませてみよう。Create a new development environment "をクリックしてください。ワークスペースに "Vonage Video Demo "という名前を付ける。学習サーバーはSIP経由の電話をサポートしているため、このデモには番号を割り当てる必要がある。このデモでは番号を使用しませんが、先に進み、"Assign a number "をクリックして、Vonageから既存の番号を割り当てるか、後のデモで使用するために新しい番号を購入してください。

Creating a new workspace

Code Hubがアプリケーションを自動的に作成し、アプリケーションが使用する公開鍵と秘密鍵の設定も行います。ワークスペースが作成されると、Visual Studio Codeのオンライン版であるコードエディターにドロップされます。このデモの後の部分でコードを見ることができますので、ご自身のプロジェクトに合わせてこのコードを編集してください。

Code editor

アプリケーションを実行するには、エディター上部の "View "をクリックし、次に "Terminal "をクリックする。これでコマンドラインを開き、コマンドを実行することができる。必要なのは vcr deploy するとコードがデプロイされます。コードがパッケージ化され、Vonage Code Hubサーバー上で実行されるため、しばらく時間がかかります。最後に出力される "インスタンスホストアドレス "をメモしておこう。

Deploying the project

すべてが正常に機能していれば、「インスタンス・ホスト・アドレス」にアクセスし、以下のページが表示されるはずだ:

Learning Server homepage

フロントエンドのテスト

バックエンドサーバーは、この1対1のデモを含む、私たちのすべてのビルド済みデモで直接動作します。次のサイトにアクセスしてください。 https://github.com/Vonage-Community/video-api-web-samples/tree/main/SIPこれは、このデモのフロントエンド部分のソースコードです。このサンプルでは、URLを持つ複数のユーザがビデオや電話番号を通してボイスチャットに参加したり、ホストが番号にダイヤル発信したりすることができます。

このデモを実行する最も簡単な方法は、READMEにある「Stackblitzで開く」ボタンをクリックすることだ。

SIP README

これでStackblitzでプロジェクトが開きます。バックエンドサーバーと同じように、コードを閲覧したり修正したりすることができます。このデモで必要なのは js/config.js ファイルを開き、Code HubインスタンスのURLを SAMPLE_SERVER_BASE_URL 変数である:

Stackblitz Demo Config

ファイルを保存したら、Stackblitzの右側にあるデモ・ビューを更新し、ブラウザがマイクとカメラの許可を求めるはずです。許可すると、サイドバーの下隅にあなたの画像が表示されるはずです。デモ・ペインの上にあるStackblitzのURLをコピーして、モバイル・デバイスや別のコンピューターで閲覧したり、友人に教えたりすれば、誰でもあなたのデモに接続できるはずです!

デモの仕組み

Vonageアプリケーションの設定

ビデオ・アプリケーションを動作させるには、クライアントとサーバーがVonageサーバーと通信する方法が必要です。Code Hub がこれを設定してくれますが、ローカルでコードを実行する場合や、Video API がどのようなものか知りたい場合は、他の API と同じように設定します。Vonageアプリケーションをセットアップして、アプリケーションのすべての設定を行い、認証に必要な項目を生成する必要があります。

に向かう。 Vonageカスタマーダッシュボード にログインしてください。ログインしたら

  1. "ビルド "の下にある "アプリケーション "をクリックする。
  2. "Create a new application "をクリックする。
  3. アプリケーションに "Basic Video Demo "のような名前をつけます。
  4. Generate public and private key(公開鍵と秘密鍵の生成)」をクリックし、ファイルをダウンロードする。 private.key.このファイルは後々のために記録しておくこと。
  5. 下にスクロールし、"Video "をオンに切り替えます。今はこれらの値を空にしておきます。
  6. Generate new application "をクリックしてアプリケーションを作成します。

アプリケーションを作成したら、アプリケーションIDを控えておいてください。ローカルでコードを実行する場合は、バックエンドを設定するためにこれが必要になります。Code Hubを使用している場合、サーバーコードはすでにアプリケーションIDと秘密鍵にアクセスしています。

クライアント側

デモのクライアント側部分は、いくつかの異なる部分から構成されている。ビデオ・フィードを置くためのいくつかのHTML要素、ログイン情報を取得し、Vonage Videoサーバーと話すためのいくつかのJavaScript、そしてダイヤルアウトするためにバックエンド・サーバーを呼び出すためのJavaScriptコードである。

これはブラウザのデモなので、次の場所にあるJavaScript SDKを使用します。 https://unpkg.com/@vonage/client-sdk-video@latest/dist/js/opentok.jsで、それをHTMLのscriptタグに含める。 index.html.

ルームに人を追加するには、2つの要素だけが必要です。例えば、現在のユーザー、あなたを "パブリッシャー "と呼びます。次に、あなたが "subscribe "する他の参加者を入れる場所が必要です。それらを "subscribers" 要素に入れます。

私たちは、以下の2つを作成する。 div のIDを1つ与える。 publisher もう一方のIDは subscriber.ページが訪問されたときや、他のユーザーがビデオ通話に参加したことを検出したときに、JavaScriptでこれらの要素を参照します。

// index.html
<div>
    <h2 class="font-black text-2xl">Your Camera</h2>
    <div class="h-80 w-80" id="publisher"></div>
</div>

<div>
    <h2 class="font-black text-2xl">Guests</h2>
    <div class="h-80 w-80" id="subscriber"></div>
</div>

次に、2組のコントロールがある。1つ目は、ビデオ会議でダイヤルイン機能を有効にするものです。この機能を有効にするために、2つのボタンを作成します。

<div><h2 class="font-black text-2xl">Dial Options</h2></div>
<div>
    <h3 class="font-black text-xl">Phone Conference</h3>
    <p>You can start a phone conference to let people dial in directly. They can call the following number to join once you have started the conference:</p>

    <p id="conference-number" class="text-center pb-4"></p>
</div>
<div>
    <button id="btn-dial-conference" class="bg-blue-500 bold text-white p-4 rounded">Create Phone Conference</button>
    <button id="btn-disconnect-conference" class="bg-red-500 bold text-white p-4 rounded">Disconnect Phone Conference</button>
</div>

次に、ユーザーにダイヤル発信するためのコントロールセットを用意します。電話番号を入力し、システムがユーザーにダイヤル発信し、ユーザーが通話を受け入れると、会議にブリッジされます。

<div>
    <h3 class="font-black text-xl">Direct Dial</h3>
    <p>Directly dial a phone number and add them to the conference. They will appear as an additional guest and be automatically added to the conference call if you have already started one.</p>
</div>
<div>
    <label for="phone">Number to call:</label>
    <input name="phone" id="phone" type="text" placeholder="15554441234" class="border border-black p-4 w-full">
    <button id="btn-dial-number" class="bg-blue-500 bold text-white p-4 rounded">Call Number</button>
</div>

ハンドリング・ビデオ

JavaScript側では、まずビデオ通話自体の情報を取得する。ビデオ通話に接続するには、アプリケーションID、セッションID、トークンが必要です。

  • について アプリケーションID は、クライアントSDKがVonage側のビデオアプリのさまざまな設定を参照するために使用する識別子です。
  • について セッションID は、接続したい特定のビデオセッションです。1つのApplicationsは、同時に複数のビデオセッションを持つことができるからです。
  • について トークン は、特定のセッションに特定の権限で参加できるようにするJWT認証トークンです。

セッション ID とトークンを前もって生成することもできますが、現実の世界ではオンデマンドで生成することにな ります。このコードはその方法を表しています。この情報がどのように生成されるかは後ほど説明しますが、ここではデプロイしたバックエンドサーバから情報を取得します。

// src/app.js

// ...
} else if (SAMPLE_SERVER_BASE_URL) {
  // Make a GET request to get the Vonage Video Application ID, session ID, and token from the server
  fetch(SAMPLE_SERVER_BASE_URL + '/session')
  .then((response) => response.json())
  .then((json) => {
    applicationId = json.applicationId;
    sessionId = json.sessionId;
    token = json.token;
    // Initialize a Vonage Video Session object
    initializeSession();
  }).catch((error) => {
    handleError(error);
    alert('Failed to get Vonage Video sessionId and token. Make sure you have updated the config.js file.');
  });
}

接続情報がすべて揃ったら、Vonage Video JavaScript SDK を呼び出す。この SDK は、フロントエンドで Vonage Video API に接続するためのすべての処理を行う。まず OT.initSession().そして、私たちは streamCreated イベント session.on().これにより、他のパブリッシャーからのストリームが作成された時に実行されるコールバックを設定することができます。この場合 session.subscribe() にプッシュする。 subscriber HTMLで設定したdiv.また sessionDisconnected イベントで他のユーザーがいつ切断したかを知ることができるが、このデモでやっているのは、ユーザーが切断したことに気づいたというログを取ることだけだ。

そして publisher オブジェクトを OT.initPublisher().どの div にアタッチするかを指定します (publisher)、いくつかの基本的なフォーマット・オプションがあります。これは、カメラとマイクを Video API に接続します。

そして、次のように呼ぶ。 session.connect() で、サーバーから取得した接続JWTトークンを使ってセッションに接続します。これだけで、2人がルームに参加できる!

// src/app.js

function initializeSession() {
  const session = OT.initSession(applicationId, sessionId);

  // Subscribe to a newly created stream
  session.on('streamCreated', (event) => {
    const subscriberOptions = {
      insertMode: 'append',
      width: '100%',
      height: '100%'
    };
    session.subscribe(event.stream, 'subscriber', subscriberOptions, handleError);
  });

  session.on('sessionDisconnected', (event) => {
    console.log('You were disconnected from the session.', event.reason);
  });

  // initialize the publisher
  const publisherOptions = {
    insertMode: 'append',
    width: '100%',
    height: '100%',
    resolution: '1280x720'
  };
  const publisher = OT.initPublisher('publisher', publisherOptions, handleError);

  // Connect to the session
  session.connect(token, (error) => {
    if (error) {
      handleError(error);
    } else {
      // If the connection is successful, publish the publisher to the session
      session.publish(publisher, handleError);
    }
  });
}

電話対応

通話をサポートするための力仕事は、すべて Video API 自体とバックエンドサーバーによって処理されます。クライアント側のコードは、バックエンド・サーバーのいくつかのルートにアクセスして SIP コールを有効にし、終了したら電話会議を切断するだけです。テレフォニーを有効にするには /sip/session/dial ルートをバックエンドサーバーに追加する。

// js/index.js
document.getElementById('btn-dial-conference').addEventListener('click', async () => {
    const resp = await fetch(`${SAMPLE_SERVER_BASE_URL}/sip/session/dial`, {
        method: "POST"
    })
    .then(res => res.json())

    console.log(resp);
})

この同じルートを使って、特定のユーザーにダイヤル発信することができる。クライアントUIに入力された電話番号を渡すだけです:

// js/index.js
document.getElementById('btn-dial-number').addEventListener('click', async () => {
    const msisdn = document.getElementById('phone').value;
    const resp = await fetch(`${SAMPLE_SERVER_BASE_URL}/sip/session/dial`, {
        method: "POST",
        body: JSON.stringify({
            msisdn
        }),
        headers: {
            "Content-Type": "application/json"
        }
    })
    .then(res => res.json())

    console.log(resp);
})

ユーザーが電話会議に参加するか、直接ダイヤルして接続すると、新しい参加者が参加者リストに追加される。Video API は、SIP 接続からの音声を、ビデオセッションに接続している全員に自動的に転送します。

最後に、どちらのタイプの電話を終了させることもできます。 /sip/session/hangup ルートをバックエンドサーバーに作成します:

// js/index.js
 document.getElementById('btn-disconnect-conference').addEventListener('click', async () => {
    const resp = await fetch(`${SAMPLE_SERVER_BASE_URL}/sip/session/hangup`, {
        method: "POST"
    })
        .then(res => res.json())

    console.log(resp);
})

サーバーサイド

Vonage Videoアプリケーションのサーバーサイド部分は、セッションの作成、認証トークンの生成、アーカイブの開始や停止などの管理タスクを処理するために使用されます。このデモでは、ユーザがルームに参加できるようにセッションとトークンを作成することだけを考えています。API 自体は REST API であり、どのように呼び出してもかまいません。 Vonage Node SDK これは、すべての認証とHTTPコールを処理します。これを自分のアプリケーションにインストールするには、次のようにする:

npm install -s @vonage/server-sdk

デモ・コードにはすでにプリインストールされています。コードをローカルで実行する場合は、以下を実行する必要がある:

npm install

をコピーして、すべての依存関係をダウンロードします。 .envcopy という名前の新しいファイルに .env.に必要事項を記入してください。 .env アプリケーションID、ディスク上の秘密鍵の場所、Vonage API Key and Secretなど。

セッションの作成とセッションへの参加

最初にすることは、生成する部屋のセッションがすでにあるかどうかを調べることです。メモリ内の辞書を roomToSessionIdDictionaryもしその部屋にすでにセッションがあれば、辞書からセッションを引き出します。次に、Vonage Video Node SDK を使用して、クライアントトークンを作成します。 vonage.video.generateClientToken()セッションIDと設定を持つオブジェクトを渡す。現時点では、ユーザーを moderator ロールを設定する。そして、設定されたアプリケーションID、セッションID、トークンをフロントエンドに返します。

セッションが存在しない場合は、次のように新しいセッションを作成します。 vonage.video.createSession().これはVonage APIにコンタクトし、ユーザーが接続できるセッションを作成する。このセッションに対する特別な設定はありませんが、ここでアーカイブルールや、ルーティングやピアツーピアのようにセッションをどのように扱うべきかを設定します。そして先ほどと同じようにトークンを作成し、すべての情報をブラウザに送り返す。

// routes/index.js

async function createSession(response, roomName, sessionProperties = {}, role = 'moderator') {
  let sessionId;
  let token;
  console.log(`Creating ${role} creds for ${roomName}`);

  if (roomToSessionIdDictionary[roomName]) {
    sessionId = roomToSessionIdDictionary[roomName];
    // generate token for user
    token = vonage.video.generateClientToken(sessionId, { role })
    response.setHeader('Content-Type', 'application/json');
    response.send({
      applicationId: appId,
      sessionId: sessionId,
      token: token
    });
  } else {
    try {
      // Create the session
      const session = await vonage.video.createSession(sessionProperties);
      roomToSessionIdDictionary[roomName] = session.sessionId;

      // generate token for user
      token = vonage.video.generateClientToken(session.sessionId, { role });
      response.setHeader('Content-Type', 'application/json');
      response.send({
        applicationId: appId,
        sessionId: session.sessionId,
        token: token
      });
    } catch(error) {
      console.error("Error creating session: ", error);
      response.status(500).send({ error: 'createSession error:' + error });
    }
  }
}

SIPブリッジへの接続

VonageはVideo APIを利用するためのSIPブリッジを提供しています。必要なのは、Vonage Customer Dashboardで登録した電話番号だけです。その電話番号を着信用のSIPインターフェースとして使用することができます。また 会話機能 Vonage Voice APIを使用して、複数のユーザーを1つの音声会議にブリッジすることができます。

最初に行う必要があるのは、ビデオセッションを電話会議にダイヤルすることで ある。ビデオセッションに参加するために、SIP接続用のクライアントトークンを作成し、次に vonage.video.initiateSIPCall() をSIPコンフィギュレーションと組み合わせて、すべてを橋渡ししている。

// routes/index.js
const { msisdn } = req.body;
const sessionId = findSessionIdForRoom(req.params.room);
const conversation = findConversationFromSessionId(sessionId);
const token = vonage.video.generateClientToken(sessionId, {
  data: JSON.stringify({
    sip: true,
    role: 'client',
    name: conversation.conversationName,
  })
})

const options = {
  token, 
  sip: {
    auth: {
      username: process.env.VCR_API_ACCOUNT_ID, // Your Vonage API Key
      password: process.env.VCR_API_ACCOUNT_SECRET, // Your Vonage API Secret
    },
    uri: `sip:${process.env.CONFERENCE_NUMBER}@sip.nexmo.com;transport=tls`,
    secure: false,
  }
}

// ...

await vonage.video.intiateSIPCall(sessionId, options)
  .then(data => {
    // Update the conversation with connection data
    conversation.connectionId = data.connectionId;
    conversation.streamId = data.streamId;
    sipConversationToSessionIdDictionary[sessionId] = conversation;

    res.send(data)
  })

Conversationはどこで設定するのですか?SIPコールを開始すると、SIPブリッジからVoice APIを通じて会議番号にダイヤル発信されます。会議番号は、Customer Dashboardで設定されます。 /sip/vapi/answer ルートを設定する必要があります。Cloud Runtimeを使用している場合、これは自動的に設定されますが、手作業で設定する場合は、このアプリケーションのアプリケーション設定に入り、"Answer URL "を https://your-domain.com/sip/vapi/answerここで your-domain は、デモがデプロイされるドメイン名である。

ルートは NCCO対談アクション これは、Voice API Conversationを作成し、すべての人の架け橋となるものです。

// routes/index.js
router.get('/sip/vapi/answer', async function (req, res) {
  const ncco = new NCCOBuilder();
  const conversation = findConversationFromSessionId(findSessionIdForRoom('session'));

  // If the call is not from the SIP connector, then announce we are connecting
  // to the conference call
  if (!req.query['SipHeader_X-OpenTok-SessionId']) {
    ncco.addAction(new Talk('Please wait while we connect you'));
  }

  // Call an individual user
  if (req.query['SipHeader_X-learningserver-msisdn']) {
    ncco.addAction(new Connect({type: 'phone', number: req.query['SipHeader_X-learningserver-msisdn']}, process.env.CONFERENCE_NUMBER));
  } else {
    ncco.addAction(new Conversation(conversation.conversationName, null, true, true, false, null, null, false));
  }

  res.send(ncco.build());
});

この時点で、ユーザーは会議番号にダイヤルして会議に参加することができ、Voice APIがすべてを橋渡しする。ユーザーが会議番号にダイヤルすると、その番号は /sip/vapi/answer エンドポイントに接続される。発信者に会議に接続していることを伝えるアクションを追加し、ブリッジ接続する。

ユーザーへのダイヤル発信

全体として、ユーザーへのダイヤル発信のプロセスは、電話会議の設定と同じです。唯一の違いは、ダイヤルするためのナンバーを /sip/:room/dial ルートに、その番号をオプションとしてSIPヘッダーに追加する。

// routes/index.js
router.post("/sip/:room/dial", async function (req, res) {
  // Set up client token and SIP options as before

  // Add a header that will get passed to the Voice API
  if (msisdn) {
    options.sip.headers = {
      "X-learningserver-msisdn": msisdn
    }
  }

  //Initiate the call as before
  await vonage.video.intiateSIPCall(sessionId, options)
    .then(data => {
      // Update the conversation with connection data
      conversation.connectionId = data.connectionId;
      conversation.streamId = data.streamId;
      sipConversationToSessionIdDictionary[sessionId] = conversation;

      res.send(data)
    })
});

SIPコールが発信されると、その追加の X-learningserver-msisdn ヘッダーは、バックエンドサーバーが受け入れる Voice API 呼び出しの一部として渡されます。このヘッダがトリガーとなり、NCCOのステップが追加されます。 NCCOのアクションをつなぐそして、相手が答えたら、会話の橋渡しをする。

// routes/index.js

router.get('/sip/vapi/answer', async function (req, res) {
  // Find the conversation info as before

  // If this header exists, call the user to bridge them in
  if (req.query['SipHeader_X-learningserver-msisdn']) {
    ncco.addAction(new Connect({type: 'phone', number: req.query['SipHeader_X-learningserver-msisdn']}, process.env.CONFERENCE_NUMBER));
  } else {
    ncco.addAction(new Conversation(conversation.conversationName, null, true, true, false, null, null, false));
  }

  res.send(ncco.build());
});

吊るす

終了すると、UIはSIPコールを直接切断するオプションを提供する。これは /sip/:room/hangup ルートからSIPコールの接続を単に切断する。

// routes/index.js

router.post("/sip/:room/hangup", async function (req, res) {
  // Get the session ID
  // Look up the connection from calls ID
  const sessionId = findSessionIdForRoom(req.params.room)
  const conversation = findConversationFromSessionId(sessionId);
  await vonage.video.disconnectClient(sessionId, conversation.connectionId)
    .then(data => 
      res.send(data)
    )
    .catch(error => res.status(500).send(error));
});

手動で電話を切らない場合は、会話が完了したことを知らせるVoice APIイベントを監視する。参加者全員が切断されると、会話は自動的に完了する。私たちは completed その際、上記と同じようにセッションからの切断を行う。

// routes/index.js

// This must be all because VAPI sometimes sends events as POST no matter what
// your event URL config is set to. This is a known bug.
router.all('/sip/vapi/events', async function (req, res) {
  if (req.query.status === "completed") {
    const conversation = findConversationFromSessionId(findSessionIdForRoom('session'));
    await vonage.video.disconnectClient(findSessionIdForRoom('session'), conversation.connectionId)
      .then(data => res.send(data))
      .catch(error => res.status(500).send(error));
  } else {
    res.send();
  }
})

結論

このチュートリアルでは、SIP経由でテレフォニーコールをハンドリングするためのバックエンドサーバーで何が行われているのか、ユーザーがセッションに参加し、お互いを見たり聞いたりするためのウェブクライアントを作成する方法、そしてサンプルを素早くテストするためにVonage Code HubとStack Blitzを使用するのがいかに簡単かを覗いてみた。

さらに読む