
WebRTCビデオセッションにSIPコールを追加する
所要時間: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=設定するには videoApiKeyと videoApiSecretを設定するには、Video API ダッシュボードから新しいプロジェクトを作成します。
Project created dialog within the Vonage Video API dashboard
作成されたら、API KeyとSecretをコピーし、それをあなたの .envファイルに videoApiKeyと videoApiSecretとしてファイルに貼り付ける。
音声アプリケーションを作成し、API KeyとSecretを voiceApiKeyと voiceApiSecret.番号を購入し、それを音声アプリケーションに関連付ける必要があります。その番号を conferenceNumber変数として使用します。
最後に、ngrokまたはHerokuのURLをserverUrlとして入力します。
これでビデオセッションに参加し、他の人があなたの番号にダイヤルしてPINコードを入力すればセッションに参加できます。ビデオセッションの終了時には、ビデオと音声の両方のアカウントが使用されないように、通話を切断する必要があることを強調しておくことが重要です。
さらに読む
Video API の SIP Interconnect 機能についてもっと知りたいですか?以下のリンクが役に立ちます。