LoginSignup
5
1

Tencent RTC Web SDK と Next.js を組み合わせてビデオ通話アプリをサクッと作ってみた

Last updated at Posted at 2023-12-22

この記事は↓のアドベントカレンダーの参加記事です。

TRTC Web SDK を使うと、サクッとビデオ通話を行うアプリケーションが作れる、という話を聞いたので、試しにドキュメント (https://web.sdk.qcloud.com/trtc/webrtc/doc/en/index.html) を読んでみてサンプルアプリ (tomoasleep/hello-trtc) を作ってみました。

スクリーンショット 2023-12-22 16.40.51.png

こういう感じのビデオ通話アプリを作ってみたのですが、バックエンドは基本 Tencent 側がやってくれて、フロントエンドを書くだけで簡単に動かせました :v: どういう感じで作れるか紹介していこうと思います。

1. Tencent Cloud 上でアプリケーションを設定する

ビデオ通話のバックエンドは Tencent Cloud を用いるのでまずはそれの設定を行います。

↓ からアカウントの作成やログインが行えるので、まずはアカウントを作成します。

https://www.tencentcloud.com/en/account/register?

アカウントを作成したら、 https://console.tencentcloud.com/trtc/app からアプリケーションを作成します。
package type は RTC Engine で、 application name は適当でOKです。

image.png

作成したら、アプリケーションの内容が表示されるので、 SDKAppID, SecretKey の値を覚えておきます。
Tencent Cloud 上ではこれだけで OK です。

2023/12 時点だと、アカウント作成時から1年間は毎月10000分無料利用できるようです。
Ref: https://www.tencentcloud.com/campaign/freetier

(※ https://console.trtc.io/overview からも設定等が可能です。こっちは RTC 関連に絞られているので分かりやすい)

2. Web フロントエンドの実装を行う

ということで、フロントエンドの実装を行います。公式で (非 React ですが) チュートリアルがあるので、これを参考にしつつ、 Next.js 向けに書いてみます。

今回は create-next-app で作った Next.js 14 アプリケーションをベースに作ります。

今回実装したサンプルコードは、↓にあります。

2-1. ユーザーの signature を計算する Server Action を作る

TRTC アプリケーションに接続するコードは大まかに以下の通りになっています。

TRTC 側では Room とそれに参加している User の管理を行ってくれるので、クライアント側では User として Room に参加する、という形で接続が行えます。

const client = TRTC.createClient({
  mode: "rtc",
  sdkAppId, // アプリケーションの SDKAppID
  userId, // ユーザーID
  userSig, // ユーザーの署名データ
  useStringRoomId: true,
});

await client.join({
  roomId // 部屋 ID
});

User の情報として必要なのが、 id と sig (署名) です。 TRTC 側では全 User の管理や登録は行わないので、 User の認証に sig を利用します。

image.png
https://www.tencentcloud.com/document/product/647/35166 より

sig の生成には SecretKey を使うので、別でサーバーを立てて…ということになるのですが、ここでは Server Action を使ってみます。

今回は userId, roomId はユーザーに入力してもらって、それを元に Server Action で userSig を計算します。

"use server";

import { Api } from "tls-sig-api-v2";

// sdkAppId はクライアントに公開してしまって OK
const sdkAppId = Number(process.env.NEXT_PUBLIC_TRTC_SDK_APP_ID);

export async function generateSig(userId: string): Promise<string> {
  // SecretKey は sig の生成に使うので、クライアントへの公開は NG
  const sdkSecretKey = process.env.TRTC_SECRET_KEY;
  if (!sdkSecretKey) {
    throw new Error("secret key is not given");
  }

  const api = new Api(sdkAppId, sdkSecretKey);

  return api.genSig(userId, 86400 /* 1day */);
}
export default function Home() {
  // ...

  return (
    <LoginForm
      onSubmit={async ({ roomId, userId }) => {
        const userSig = await generateSig(userId);
        setUserSession({ userId, userSig });
        setRoomId(roomId);
      }}
    />
  );

2-2. 通話画面を作る

2-1 で作成した usersig と userId, roomId を元に接続と通話を行います。

接続に必要なコードは、チュートリアル (https://web.sdk.qcloud.com/trtc/webrtc/doc/en/tutorial-11-basic-video-call.html) などを参考にすると以下の通りになります。

function connectTRTC({ userId, userSig, roomId, localStreamContainerId, remoteStreamContainerId }) {
  const client = TRTC.createClient({
    mode: "rtc",
    sdkAppId, // アプリケーションの SDKAppID
    userId, // ユーザーID
    userSig, // ユーザーの署名データ
    useStringRoomId: true,
  });

  client.on("stream-added", (event) => {
    const remoteStream = event.stream;
    client.subscribe(remoteStream);
  });

  client.on("stream-subscribed", (event) => {
    const remoteStream = event.stream;
    remoteStream.play(remoteStreamContainerId); // 指定した id の HTML 要素に、他の参加者を表示する
  });

  await client.join({ roomId });

  const localStream = TRTC.createStream({
    userId,
    audio: true,
    video: true,
  });
  await localStream.initialize();
  localStream.play(localStreamContainerId);  // 指定した id の HTML 要素に、自分を表示する
  await client.publish(localStream);
}

これを React 環境で使えるように useEffect などを用いて Hook 化して、 React コンポーネントから接続するようにします。

export function VideoChat({ roomId, userId, userSig }) {
  const remoteStreamContainerId = useId();
  const localStreamContainerId = useId();

  const useTRTC({
    roomId,
    userId,
    userSig,
    localStreamContainerId,
    remoteStreamContainerId,
  });

  return (
    <div className="container mx-auto">
      <div id={localStreamContainerId} />
      <div id={remoteStreamContainerId} />
    </div>
  );
}

2-3. 接続デバイスを変更できるようにする

実際のビデオ通話では、通話に使いたいカメラやマイクを変更したいことがあります。
TRTC Web SDK では、デバイスのリストの取得や、変更も簡単に行うことが可能です。

以下のようなコードで接続デバイスを変更する機能を実装できます

export function Selector({
  localStream,
  kind,
}: {
  localStream: LocalStream | null;
  kind: MediaDeviceKind;
}) {
  const { data: devices } = useAsyncValue(async () => {
    const devices = await TRTC.getDevices(); // デバイス一覧を取得
    return devices.filter((device) => device.kind === kind);
  });

  if (!devices || !localStream) {
    return <div>loading...</div>;
  }

  return (
    <div>
      <select
        onChange={(event) => {
          if (event.target.value) {
            localStream.switchDevice(
              kind === "videoinput" ? "video" : "audio",
              event.target.value
            ); // 通話に使うデバイスを設定
          }
        }}
      >
        {devices.map((device) => {
          return (
            <option key={device.deviceId} value={device.deviceId}>
              {device.label}
            </option>
          );
        })}
      </select>
    </div>
  );
}

という感じで作ったのが以下の画面です。 (アイコンで隠している部分が、実際にはカメラで録画している内容になります。)

スクリーンショット 2023-12-22 16.40.51.png

2-4. 他にも色々な設定を簡単に行える

他にも色々設定が簡単に行なえます。公式チュートリアルに色々載っているので参考になると思います。

おわりに

今回試しに Tencent RTC Web SDK を触ってみたのですが、ビデオ通話アプリをバックエンド構築がほぼ不要で作れるので、通話機能だったりストリーミング機能を高速でサービスインのに非常に向いているなと感じました。

今回のサンプルアプリは、何も知らない状態から半日ぐらいで作ったのですが、設定もわかりやすく、殆どの時間をフロントエンドの実装に集中することができたので、開発体験としては結構良いんじゃないかと思います。
サンプル実装は↓で作ってみたので、興味がある人はそちらも見てみてください。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1