チュートリアル

本章では Sora JavaScript SDK を使って音声と映像を送受信できる簡単なサンプルを作成します。

プロジェクトの作成

開発環境ツールとして Vite を利用します。 無理に Vite を利用する必要は無く、慣れたツールを利用してください。

パッケージマネージャーとしては pnpm を利用していますが、 npm または yarn でも問題ありません。

$ pnpm create vite@latest
✔ Project name: … sora-js-sdk-tutorial
✔ Select a framework: › Vanilla
✔ Select a variant: › TypeScript

Scaffolding project in /private/tmp/sora-js-sdk-tutorial...

Done. Now run:

  cd sora-js-sdk-tutorial
  pnpm install
  pnpm run dev
tree
.
├── index.html
├── package.json
├── public
│   └── vite.svg
├── src
│   ├── counter.ts
│   ├── main.ts
│   ├── style.css
│   ├── typescript.svg
│   └── vite-env.d.ts
└── tsconfig.json

sora-js-sdk の追加

$ pnpm add -D -E sora-js-sdk

vite と typescript を最新にする

$ pnpm up vite@latest typescript@latest

index.html の変更

  • connectButton は接続ボタン

  • disconnectButton は切断ボタン

  • localVideo は自分が取得した映像を出力する

  • remoteVideos は他の映像を表示する

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Vite + TS + Sora JS SDK</title>
</head>

<body>
  <button id="connectButton">Connect</button>
  <button id="disconnectButton" disabled>Disconnect</button>
  <hr />
  <video id="localVideo" autoplay="" playsInline="" controls="" muted=""></video>
  <hr />
  <div id="remoteVideos"></div>

  <script type="module" src="./src/main.ts"></script>
</body>

</html>

.env.local の作成

.env.local ファイルを作成してください。

$ touch .env.local

その後 Sora のシグナリング URL やチャネル ID、必要があればアクセストークンを指定してください。

VITE_SORA_SIGNALING_URL=wss://sora.example.com/signaling
VITE_SORA_CHANNEL_ID=sora-js-sdk
VITE_ACCESS_TOKEN=

main.ts の変更

import Sora from "sora-js-sdk";
import type { ConnectionPublisher } from "sora-js-sdk";

addEventListener("DOMContentLoaded", () => {
  // .env からシグナリング URL を取得する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  // .env からチャネル ID を取得する
  const channelId = import.meta.env.VITE_SORA_CHANNEL_ID;
  const metadata = {
    // sora-labo や sora-cloud のアクセストークン
    access_token: import.meta.env.VITE_ACCESS_TOKEN,
  };

  const connectButton = document.getElementById(
    "connectButton",
  ) as HTMLButtonElement;
  const disconnectButton = document.getElementById(
    "disconnectButton",
  ) as HTMLButtonElement;
  const localVideo = document.getElementById("localVideo") as HTMLVideoElement;
  const remoteVideos = document.getElementById(
    "remoteVideos",
  ) as HTMLDivElement;

  let sendrecv: ConnectionPublisher;

  connectButton.addEventListener("click", async () => {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: false,
      video: true,
    });
    const debug = true;
    const options = {
      multistream: true,
    };
    const soraConnection = Sora.connection(signalingUrl, debug);
    sendrecv = soraConnection.sendrecv(channelId, metadata, options);
    sendrecv.on("track", (event) => {
      const stream = event.streams[0];
      const remoteVideoId = `remoteVideo-${stream.id}`;
      if (!document.getElementById(remoteVideoId)) {
        const video = document.createElement("video");
        video.id = remoteVideoId;
        video.autoplay = true;
        video.playsInline = true;
        video.srcObject = stream;
        remoteVideos?.appendChild(video);
      }
    });
    sendrecv.on("removetrack", (event) => {
      // removetrack は MediaStream で発火する
      const target = event.target as MediaStream;
      const remoteVideo = document.getElementById(
        `remoteVideo-${target.id}`,
      ) as HTMLVideoElement;
      if (remoteVideo) {
        // target は mediaStream なので target.id は mediaStream.id と同じ
        remoteVideo.remove();
      }
    });
    await sendrecv.connect(stream);
    if (localVideo) {
      localVideo.srcObject = stream;

      connectButton.disabled = true;
    }
    disconnectButton.disabled = false;
  });

  disconnectButton.addEventListener("click", async () => {
    // sendrecv があるかどうか確認する
    if (sendrecv) {
      // 切断する
      await sendrecv.disconnect();
      if (localVideo) {
        localVideo.srcObject = null;
      }
      while (remoteVideos?.firstChild) {
        remoteVideos.removeChild(remoteVideos.firstChild);
      }
    }
    connectButton.disabled = false;
    disconnectButton.disabled = true;
  });
});

起動

$ pnpm run dev
VITE v6.0.5  ready in 223 ms

➜  Local:   http://localhost:5173/
➜  Network: use --host to expose
➜  press h + enter to show help

http://localhost:5173/ へアクセスして、ブラウザのタブをふたつ以上開いて、 Connect ボタン を押して、双方向で配信ができていれば成功です。

© Copyright 2024, Shiguredo Inc. Created using Sphinx 8.1.3