2024年11月25日
Astroを用いたクラウドレコーディングの実装
※この投稿は、Agoraの日本代理店であるブイキューブが、Agoraブログを翻訳した記事です。
この記事は、高速なWebサイトを構築するためのWebフレームワークであるAstroを用いたバックエンド構築に関するシリーズのパート2です。
パート1
Astroを用いたトークン生成システムの構築
今回はトークン生成システムの構築に続き、ビデオ通話にクラウド録画を追加します。
目次
[非表示]前提条件
- NodeJSとAstroがインストールされていること
- Agoraの開発者アカウント
- Astroで構築されたトークンジェネレータ
- AWS S3 Storage Bucket
プロジェクトセットアップ
このガイドは、パート1のトークンジェネレータガイドをベースに構築します。 トークン生成ガイドでは、api/tokens.json エンドポイントを構築するプロセスを説明します。 このエンドポイントは、トークン生成ロジックを処理する handleGenerateToken 関数を使用します。 同じバックエンドサーバーにあるので、クラウド録画エンドポイント内でこの関数を直接使用します。
前回のガイドで、環境変数にAPP_IDとAPP_CERTIFICATEがあるはずです。 このガイドを通して、さらに環境変数を追加していきます。
クラウド録画の概要
クラウド録画は Agora が提供する RESTful API で、ビデオ通話を任意のストレージプロバイダに録画することができます。 バックエンドは、機密データがアプリケーションと直接やり取りされないように、この録画をトリガーする必要があります。 クラウド録画セッションのフローは以下の通りです。
- Agora クラウド録画リソースを取得します。
- カスタムストレージ設定を使用してクラウド録画を開始します。これには、ストレージプロバイダへのフイルの書き込みを許可するために必要なキーが含まれます。
- 30秒ごとにクラウド録画のステータスを問い合わせ、正しく実行されていることを確認します。
- クラウド録画を停止します。
Agora RESTful API を有効にする
このガイド全体は、Agora RESTful API への接続に依存しています。 接続するには、Customer ID と Customer Secret が必要です。 これらは、Agora コンソールに入り、Developer Toolkit の下の RESTful API タブを選択し、"Add a Secret" ボタンをクリックすることで見つけることができます。 そして、これらの値をコピーし、CUSTOMER_ID と CUSTOMER_SECRET 環境変数に格納します。
AWS S3 バケットへの接続
Agora は、ほとんどの一般的なストレージソリューションへのレコーディングをサポートしています。 このガイドでは、AWS S3を使用します。 さて、AWSは複雑なバックエンド設定の塊です。 このガイドでは、Agoraの実装にフォーカスしているので、弾力性のあるAWSインフラを構築する代わりに、ルートユーザのアクセスキーとパブリックバケットを使用します。
IAMの "My security credentials "から "Create access key "ボタンをクリックして、新しいルートユーザのアクセスキーを作成します。 そして、この情報をACCESS_KEYとSECRET_KEY環境変数に保存します。
次に、S3にアクセスして新しいバケットを作成します。 今回はテスト用に作っているので、"Block all public access "のチェックを外します。 環境変数BUCKET_NAMEにバケット名を保存します。
エンドポイントの定義
api/recording/start.json、api/recording/query.json、api/recording/stop.jsonの3つのエンドポイントを用意します。 エンドポイントは入力情報を必要とするので、POSTリクエストを使ってリクエストボディとして入力を渡します。 これらの入力が空でないことをチェックします。 もし空であれば、utils/sendResponse.tsのヘルパー関数を使用してBad Requestレスポンスを返します。 エンドポイントはボディに以下の情報を必要とします:
- api/recording/start.json は channel を必要とします
- api/recording/query.json は sid と resourceId を必要とします
- api/recording/stop.json は channel、sid、resourceId を必要とします
すべてが正しく実行されれば、ヘルパー関数を使用して成功したレスポンスを送信します。
import type { APIContext } from "astro";
export async function POST({ request }: APIContext) {
const { channel } = await request.json()
if (!channel) {
return sendBadRequest("channel is required")
}
return sendSuccessfulResponse("<return data>")
}
ヘルパー関数の作成
このガイドの残りは、Agora API の呼び出しを含む Cloud Recording の実装に焦点を当てます。 コードを単純化し、統一されたリクエスト構造を持つために、utils/makeRequest.ts でヘルパー関数をセットアップします。
makeRequest 関数は、すべてのヘッダーを定義し、リクエストを実行し、レスポンスを返します。
入力には、メソッド(GET と POST を使用します)、url、body、およびクレデンシャルが必要です。
export const makeRequest = async (method: string, url: string, credential: string, body?: string) => {
const headers = new Headers({
"Authorization": "basic " + credential,
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": `${method}, OPTIONS`,
});
const res = await fetch(url, {
method: method,
headers: headers,
body: body
})
if (!res.ok) {
console.log(await res.text())
throw new Error("Failed to make request")
}
return res
}
utils/generateCredential.tsの別のヘルパー関数がこのクレデンシャルを生成します。 これは、Customer IDとCustomer Secretを使用してBase-64エンコードされたクレデンシャルです。
export const generateCredential = () => {
const credential = import.meta.env.CUSTOMER_ID + ":" + import.meta.env.CUSTOMER_SECRET
const base64_credential = btoa(credential)
return base64_credential
}
リソースの生成
ビデオ通話を録画するための最初のステップは、録画用のリソースを生成することです。 これにより、これはビデオ通話を録画できるバックエンドのAgoraサービスをスピンアップします。
クラウド録画はこのタイミングから5分以内に開始する必要があります。
このリソースを生成するために、Agora サービスに最初のリクエストを行います。 これには acquire 関数を使用します。
この関数は、同じバックエンドサーバー内でクラウド録画セッションを開始するときにのみ使用されるため、エンドポイントを作成する必要はありません。
このため、コードを整理しておくために、utils/generateResource.tsファイルでこの関数を定義します。
import { makeRequest } from "./makeRequest"
export const generateCloudRecordingResource = async (channel: string, credential: string, uid: string, appId: string) => {
const body = {
"cname": channel,
"uid": uid,
"clientRequest": {}
}
const url = `https://api.agora.io/v1/apps/${appId}/cloud_recording/acquire`
const res = await makeRequest("POST", url, credential, JSON.stringify(body))
const data = await res.json()
const resourceId = data["resourceId"]
return resourceId
}
クラウドレコーディングの開始
前のセクションを組み合わせると、api/recording/start.json.ts ファイルの POST 関数内で録画を開始することができます。 クレデンシャルを生成し、そのクレデンシャルを使ってリソースを生成し、トークンを作成します。
その後、Agora start エンドポイント URL でリクエストを行い、リクエストボディを渡します。 このボディはAgoraクラウド録画サービスが必要とする全ての情報を定義します。
リクエストボディのプロパティの完全なリストはAgoraのドキュメントにあります。 このデモでは、AWS をベンダーとして定義し、US_EAST_2 をリージョンとして定義します。 そして、ストレージバケットにアクセスするために必要なすべての情報を提供し、最後にファイルパスとファイル出力タイプを定義します。
const recordingUid = "1"
const credential = generateCredential()
const resourceId = await generateCloudRecordingResource(channel, credential, recordingUid, APP_ID)
const token = await handleGenerateToken({ channel: channel, role: 1, uid: recordingUid, expireTime: 3600 })
const url = `https://api.agora.io/v1/apps/${APP_ID}/cloud_recording/resourceid/${resourceId}/mode/mix/start`
const body = {
"cname": channel,
"uid": recordingUid,
"clientRequest": {
"token": token,
"storageConfig": {
"secretKey": SECRET_KEY,
"vendor": 1,
"region": 1,
"bucket": BUCKET_NAME,
"accessKey": ACCESS_KEY,
"fileNamePrefix": [
"recording",
Date.now().toString()
]
},
"recordingFileConfig": {
"avFileType": [
"hls",
"mp4"
]
},
},
}
const res = await makeRequest("POST", url, credential, JSON.stringify(body))
const data = await res.json()
const sid = data.sid
return sendSuccessfulResponse({
resourceId: resourceId,
sid: sid
})
レスポンスに成功すると、sidが返されます。 sidとresourceIdはどちらも録画の停止やクエリに使う必要があるので、呼び出し元に返す必要があります。
これをテストするには、npm run devを使ってバックエンドを実行します。 ターミナルで cURL を使って、channel をボディに含む POST リクエストを送ることができます。
curl -X POST http://localhost:4321/api/recording/start.json \
-H "Content-Type: application/json" \
-d '{
"channel": "test"
}'
POSTリクエストに情報が欠けている場合、何が欠けているかを伝えるBad Requestレスポンスが返されます。 適切なリクエストであれば、次のような正常なレスポンスが返ってきます。
{"resourceId":"<long string>","sid":"<another long string>"}
ステータスの確認
クラウド録画が実行されている間、すべてが適切に実行されていることを確認するために、定期的にクエリを実行します。 Agoraのquery APIを使用し、GETメソッドを使って呼び出す。
const credential = generateCredential()
const url = `https://api.agora.io/v1/apps/${APP_ID}/cloud_recording/resourceid/${resourceId}/sid/${sid}/mode/mix/query`
const res = await makeRequest("GET", url, credential)
const data = await res.json()
return sendSuccessfulResponse(data)
これをテストするには、cURL を使用し、開始エンドポイントの戻り値から sid と resourceId を渡します。
注意: この App ID とチャンネルに関連付けられたビデオ通話に誰かが参加している必要があります。 録画するものがない場合、Agora バックエンドは録画を開始しません。
curl -X POST http://localhost:4321/api/recording/query.json \
-H "Content-Type: application/json" \
-d '{
"sid": "<from start command return>",
"resourceId": "<from start command return>"
}'
クラウドレコーディングの停止
最後に、クラウド録画を停止する必要があります。 これはstartコマンドやqueryコマンドと非常に似ているが、Agora stop URLを使う点が異なります。
const recordingUid = "1"
const credential = generateCredential()
const url = `https://api.agora.io/v1/apps/${APP_ID}/cloud_recording/resourceid/${resourceId}/sid/${sid}/mode/mix/stop`
const body = {
"cname": channel,
"uid": recordingUid,
"clientRequest": {
}
}
const res = await makeRequest("POST", url, credential, JSON.stringify(body))
const data = await res.json()
return sendSuccessfulResponse(data)
cURLでのテストも行うことができます。
curl -X POST http://localhost:4321/api/recording/stop.json \
-H "Content-Type: application/json" \
-d '{
"channel": "test"
"sid": "<from start command return>",
"resourceId": "<from start command return>"
}'
以上でAstroで完全に動作するクラウド録画バックエンドの構築は完了です。
トークンジェネレーターとクラウド録画バックエンドがAstroに組み込まれたので、以下の記事も参考にフロントエンドを追加して、1つのコードベースですべて録画できる安全なビデオ通話を実現することが可能です。
話題の最新フロントエンドフレームワーク「Astro」とReactJSを使用してビデオ通話アプリを構築する。
Agoraの開発者アカウントを作る(無料トライアル)
Agoraの無料トライアルは利用時間10,000分/月で、開発期間中はずっと無料となっています。(リリース後から料金が発生)Agoraは株式会社ブイキューブが日本代理店となっており、料金など不明点は日本語での対応が可能です。
Agoraの導入について、お気軽にお問い合わせ下さい。
執筆者ブイキューブ