Sora JavaScript SDK ドキュメント

このドキュメントは Sora JavaScript SDK バージョン 2024.2.2 に対応しています。

Sora 自体の製品お問い合わせは sora at shiguredo dot jp までお願い致します。 (このメールアドレスへの特定電子メールの送信を拒否いたします)

問い合わせについて

Sora JavaScript SDK の質問などについては Discord の #sora-sdk-faq をご利用ください。 ただし、 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。

https://discord.gg/shiguredo

Sora JavaScript SDK に対する有償のサポートについては提供しておりません。

注意事項

Sora JavaScript SDK 2024.2.0 以降は Compression Stream API を利用しています。 そのため、 Apple Safari の場合はバージョン 16.4 以降が必要です。

詳細は 対応ブラウザについて をご確認ください。

リリースノート

CHANGE

下位互換のない変更

UPDATE

下位互換がある変更

ADD

下位互換がある追加

FIX

バグ修正

2024.2.2

リリース日:

2024-11-29

  • [FIX] typesexport するように修正しました

2024.2.1

リリース日:

2024-11-29

  • [FIX] リリースミスを修正しました

2024.2.0

リリース日:

2024-11-29

  • [CHANGE] 廃止宣言から 4 年以上が経過したため addstream コールバックを削除しました

  • [CHANGE] 廃止宣言から 4 年以上が経過したため removestream コールバックを削除しました

  • [CHANGE] fflate を依存から削除しました

    • 依存ライブラリが 0 になりました

    • Compression Streams API を利用するように変更しました

      • Chrome/Edge 80 以降

      • Firefox 113 以降

      • Safari 16.4 以降

  • [CHANGE] メッセージを送信する sendMessage 関数を非同期に変更しました

    • void ではなく Promise<void> を返すようにしました

  • [CHANGE] forwardingFilter 項目の型を JSONType から ForwardingFilter に変更しました

    • ForwardingFilter 型を追加しました

    • ForwardingFilterAction 型を追加しました

    • ForwardingFilterRule 型を追加しました

    • ForwardingFilterRuleField 型を追加しました

    • ForwardingFilterRuleKindValue 型を追加しました

    • ForwardingFilterRuleOperator 型を追加しました

  • [CHANGE] E2EE 機能を削除しました

  • [UPDATE] メッセージングの圧縮と展開を fflate から Compression Streams API に変更しました

  • [ADD] メッセージングのみを利用する messaging を追加しました

  • [ADD] DataChannel シグナリングのみを利用した際の "type": "close" メッセージに対応しました

  • [ADD] シグナリング項目に forwarding_filters を追加しました

    • 将来的に forwarding_filter は廃止予定です

  • [FIX] Sora から API などで切断された場合の処理を改善しました

    • Sora から正常に切断された場合は SoraCloseEventtitleSHUTDOWN に変更しました

Sora JavaScript SDK 概要

Sora JavaScript SDK は 株式会社時雨堂 が開発、販売する WebRTC SFU Sora のブラウザ向け JavaScript ライブラリです。

主な仕様

Sora JavaScript SDK は Sora との WebRTC 接続部分の API を提供します。

依存ライブラリ

Sora JavaScript SDK は依存ライブラリが 0 の SDK です。

シグナリング処理

シグナリングとは WebRTC を利用する際にクライアント(SDK) とサーバー (Sora) の接続確立用のハンドシェイクの一種です。 WebRTC ではこのシグナリングの仕様が特に決まっていないため、すべて独自仕様となります。

Sora JavaScript SDK では Sora 独自のシグナリング部分をすべて SDK 側で吸収しているため、 SDK を利用したアプリケーション開発者が Sora 独自のシグナリングの仕組みを細かく意識する必要はありません。

WebRTC 接続処理

Sora との WebRTC 接続処理に対応しています。利用者が WebRTC 接続部分を意識する必要がなくなります。

問い合わせについて

Sora JavaScript SDK の質問などについては Discord の #sora-sdk-faq にお願い致します。

https://discord.gg/shiguredo

何か問題があり、相談したい場合に共有していただく情報
  • Sora WebRTC SFU のバージョン

  • Sora JavaScript SDK のバージョン

  • 利用ブラウザの種類

  • 利用ブラウザのバージョン

  • 利用 OS の種類

どのような問題が発生しており、何を解決したいのかを簡潔に教えてください。

問題の再現方法

問題を再現することができる最小限のコードを提供してください。

  • GitHub Gist

  • CodeSandbox

  • CodePen

  • StackBlitz

などを利用してコードを提供してください。

FAQ

対応ブラウザについて

Sora JavaScript SDK の 2024.2.0 以降を利用するには Compression Stream API をサポートしているブラウザのバージョンが必要になります。

  • Chrome / Chrome 80 以降

  • Firefox 113 以降

  • Safari 16.4 以降

Sora JavaScript SDK のサンプルについて

Sora JavaScript SDK のサンプル

Sora JavaScript SDK の最小限の書き方を確認できるサンプルです。

https://github.com/shiguredo/sora-js-sdk-examples

Sora JavaScript SDK ドキュメントのサンプル

Sora JavaScript SDK の解説を目的としたサンプルです。

サンプル

仕様

MediaStreamTrack と Connection ID の紐付け

Sora JavaScript SDK は MediaStreamTrack と Connection ID の紐付けを行う仕組みは提供していません。

ただし track コールバック時に、 RTCTrackEventstreams から MediaStream を取得できます。 MediaStreamstream.id が Connection ID となります。

client.on("track", (event: RTCTrackEvent) => {
  // Sora では必ず 1 クライアント から送られてくるのは 1 音声/ 1 映像に固定されています
  // そのため track.streams[0] でクライアントのメディアストリームを取得できます
  const stream = event.streams[0];

  // メディアストリームの ID はその音声と映像を配信しているクライアントの connectionId です
  // stream.id で取得できます
  console.log("connectionId: ", stream.id);
});
メディアストリームの扱い

Sora JavaScript SDK は音声や映像といったメディアストリームを SDK から扱うことはありません。

そのため音声や映像を扱う場合は MediaDevices.getUserMedia() API や MediaDevices.getDisplayMedia() API を利用し、 アプリケーション開発者がメディアストリームを取得し、Sora JavaScript SDK に渡す必要があります。

マルチトラック

Sora JavaScript SDK が配信可能なメディアストリームは 1 本で 1 音声トラック、1 映像トラックとなります。 これは Sora の仕様になります。

そのため、マルチトラックには対応しておりません。

もし複数の音声や映像を 1 クライアントで配信したい場合は複数のコネクションを張るようにしてください。

"type": "answer" の SDP 書き換えは SDK の挙動に影響はありますか?

Sora JS SDK では createAnswer が生成した SDP をそのまま利用するようにしています。 そのため、書き換え処理で SDK 側には基本的に影響することはありません。

もし SDP 書き換えをを行う場合は "type": "answer" だけでなく、 "type": "re-answer" も書き換えるようにしてください。

注釈

WebRTC API を利用せずに手動で SDP を変更する処理を "SDP Munging" と呼びます。

Sora への影響については Sora または Sora Cloud のサポートまでご連絡ください。

シグナリング

Sora との接続が完了したことを通知するコールバックはありますか?

Sora JavaScript SDK には Sora との接続完了を通知するには、 Sora のシグナリング通知機能を利用してください。

シグナリング通知機能の connection.createdconnection_id を利用してください。

// 色々省略
const sendrecv = soraConnection.sendrecv(channelId, metadata, options);
await sendrecv.connect(stream);

// シグナリング通知
sendrecv.on("notify", (event: SignalingNotifyMessage) => {
  console.log("notify", event.event_type);
  if (
    // connection.created が Sora とクライアントの間で WebRTC が確立した事を通知しています
      event.event_type === "connection.created" &&
      // 自分の connection_id と一致
      sendrecv.connectionId === event.connection_id
  ) {
      // 接続が成功
      console.log("self-connection_id: ", event.connection_id);
  }

  // 自分以外の参加者の connection_id の取得
  if (event.event_type === "connection.created") {
    console.log("connection_id", event.connection_id);
  }
});

データチャネルメッセージング

メッセージングのみを利用したいです

messaging() を利用する事でメッセージングのみを利用できます。

const options = {
  dataChannelSignaling: true,
  dataChannels: [
    {
      label: "#example",
      direction: "sendrecv" as DataChannelDirection,
    },
    {
      label: "#example2",
      direction: "recvonly" as DataChannelDirection,
    },
  ],
};
const messaging = soraConnection.messaging(channelId, metadata, options);
await messaging.connect();
maxPacketLifeTime や maxRetransmits が設定できません

Sora のシグナリング仕様では snake_case での指定ですが、 Sora JavaScript SDK では camelCase での指定となります。

const options = {
  dataChannelSignaling: true,
  dataChannels: [
    {
    label: "#example",
    direction: "sendrecv" as DataChannelDirection,
    maxPacketLifeTime: 60000,
    },
  ],
};
const options = {
  dataChannelSignaling: true,
  dataChannels: [
    {
      label: "#example",
      direction: "sendrecv" as DataChannelDirection,
      maxRetransmits: 0,
    },
  ],
};

WebRTC API

Sora JavaScript SDK には Sora との接続部分の機能のみを提供しています。

そのため、映像や音声、データなどを実際に処理する場合はすべて JavaScript の WebRTC API やライブラリなどを利用する必要があります。

WebRTC API - Web API | MDN

解像度を変更するにはどうしたらいいですか?

解像度の変更は MediaDevices.getUserMedia()MediaDevices.getDisplayMedia() API 側で行ってください。

背景をぼかすにはどうしたらいいですか?

時雨堂がオープンソースとして公開している @shiguredo/virtual-background - npm を利用することで簡単にブラウザで背景ぼかし機能を利用可能です。

以下で動作確認が可能です。 https://shiguredo.github.io/media-processors/virtual-background/

ライトを調整はできますか?

時雨堂がオープンソースとして公開している @shiguredo/light-adjustment - npm を利用することで簡単にブラウザでライト調整機能を利用可能です。

以下で動作確認が可能です。 https://shiguredo.github.io/media-processors/light-adjustment/

ノイズを抑制できますか?

時雨堂がオープンソースとして公開している @shiguredo/noise-suppression - npm を利用することで簡単にブラウザでノイズ抑制機能を利用可能です。

以下で動作確認が可能です。 https://shiguredo.github.io/media-processors/noise-suppression/

音声でステレオは利用できますか?

WebRTC の Opus はデフォルトで 2 チャンネル利用するためステレオに対応しています。

ただし、ステレオ音声を利用する場合はデフォルトで有効になっているエコーキャンセルを無効にする必要があります。

https://www.w3.org/TR/mediacapture-streams/#dom-mediatracksupportedconstraints-echocancellation

画面キャプチャはできますか?

MediaDevices.getDisplayMedia() を利用して画面のストリームを取得してください。

カメラを切り替えられますか?

トラックを切り替えたい場合は RTCRtpSender.replaceTrack() を利用して既存のトラックと置き換えを行ってください。

音声をミュートにできますか?

Sora JavaScript SDK はトラックのミュートは行いません。

トラックのミュートを行いたい場合は MediaStreamTrack.enabled を利用して、ミュートを行ってください。

Electron で利用したいです

Sora JavaScript SDK は Electron でも利用可能です。

MediaStreamTrack から MediaStream の ID を取得したいです

MediaStreamTrack から MediaStream の ID は取得できません。 そのため、もし取得したい場合は何かしらの方法で ID を保持しておく必要があります。

ただし removetrack コールバックは MediaStream が発火させるため event.target で発火した MediaStream を取得可能です。

MediaStream: removetrack event - Web APIs | MDN

CPU や帯域による解像度やフレームレートの制限を無効にしたいです

無効にできません。

ブラウザで CPU 負荷が高まったと判断して、利用ビットレートを下げたことにより解像度やフレームレートが下がる場合、 Chrome 102 までは googCpuOveruseDetection という設定があり、 false にすることで、判定を無効にできていましたが、 その設定は Chrome 103 にて廃止されました。

Tip

制限の理由は qualityLimitationReason で確認できます。

映像を回転させたいです

getUserMedia で取得した映像を回転させるには Canvas API を利用してください。

<!doctype html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
</head>

<body>
  <video id="originalVideo" autoplay="" playsinline="" controls="" muted=""></video>
  <video id="rotatedVideo" autoplay="" playsinline="" controls="" muted=""></video>
  <hr />
  <script type="module" src="./main.ts"></script>

</body>

</html>
// getUserMedia で取得した映像を Canvas API を利用して 90 度回転する

document.addEventListener("DOMContentLoaded", async () => {
  const originalVideo = document.getElementById("originalVideo") as HTMLVideoElement;
  const rotatedVideo = document.getElementById("rotatedVideo") as HTMLVideoElement;

  const mediaStream = await navigator.mediaDevices.getUserMedia({
    video: true,
  });

  originalVideo.srcObject = mediaStream;

  const rotatedMediaStream = rotateMediaStream(mediaStream);
  rotatedVideo.srcObject = rotatedMediaStream;
});

const rotateMediaStream = (mediaStream: MediaStream): MediaStream => {
  // 元の映像トラックを取得
  const videoTrack = mediaStream.getVideoTracks()[0];

  // 映像の設定を取得
  const settings = videoTrack.getSettings();
  const width = settings.width || 640;
  const height = settings.height || 480;

  // Canvas要素を作成
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");

  // 90度回転させるため、幅と高さを入れ替える
  canvas.width = height;
  canvas.height = width;

  // Video要素を作成
  const video = document.createElement("video");
  video.srcObject = mediaStream;
  video.autoplay = true;

  // 映像フレームを描画して回転させる
  video.addEventListener("play", () => {
    const draw = () => {
      if (ctx) {
        // Canvasを90度回転
        ctx.save();
        ctx.translate(canvas.width, 0);
        ctx.rotate(Math.PI / 2);
        ctx.drawImage(video, 0, 0, width, height);
        ctx.restore();
      }
      requestAnimationFrame(draw);
    };
    draw();
  });

  // 回転した映像をMediaStreamとして取得
  return canvas.captureStream();
};

インストール

インストール方法

npm
$ npm add sora-js-sdk
pnpm
$ pnpm add sora-js-sdk

使用方法

import Sora from "sora-js-sdk";

チュートリアル

本章では 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 -E sora-js-sdk jose
jose について

joseSora LaboSora Cloud を利用する場合の JWT 生成に必要になります。

Vite と TypeScript を最新にする

$ pnpm up vite@latest typescript@latest

不要なファイルの削除

以下のファイルは利用しないため削除してください。

  • public/vite.svg

  • src/counter.ts

  • src/typescript.svg

  • src/style.css

index.html の変更

  • connect は接続ボタン

  • disconnect は切断ボタン

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

  • remote-videos は他の映像を表示する

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

<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="data:,">
  <title>Sora JS SDK Tutorial</title>
</head>

<body>
  <p>
    <button id="connect">Connect</button>
    <button id="disconnect" disabled>Disconnect</button>
  </p>
  <video id="local-video" autoplay playsInline controls muted style="transform: scaleX(-1)"></video>
  <div id="remote-videos"></div>
  <script type="module" src="./src/main.ts"></script>
</body>

</html>

.env.local の作成

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

$ touch .env.local

環境変数を設定してください。

Sora を自前で立てる場合
# Sora のシグナリング URL
VITE_SORA_SIGNALING_URL=wss://{host}/signaling
# 好きな文字列
VITE_SORA_CHANNEL_ID=tutorial
Sora Cloud
# Sora Cloud のシグナリング URL
VITE_SORA_SIGNALING_URL=wss://sora.sora-cloud.shiguredo.app/signaling
# 好きな文字列
VITE_SORA_CHANNEL_ID=tutorial
# Sora Cloud のダッシュボードから取得できる @ + プロジェクト ID
VITE_SORA_CHANNEL_ID_SUFFIX=@{project_id}
# Sora Cloud のダッシュボードから取得できる API キー
VITE_SECRET_KEY={api_key}
Sora Labo
# Sora Labo のシグナリング URL
VITE_SORA_SIGNALING_URL=wss://sora.sora-labo.shiguredo.app/signaling
# 好きな文字列
VITE_SORA_CHANNEL_ID=tutorial
# Sora Labo のダッシュボードから取得できるチャネル ID プレフィックス
# {GitHub ユーザ名}_{GitHub ID}_
VITE_SORA_CHANNEL_ID_PREFIX={github_username}_{github_id}_
# Sora Labo のダッシュボードから取得できるシークレットキー
VITE_SECRET_KEY={secret_key}

src/client.ts の追加

Sora JavaScript SDK を利用したクライアント、 Sora Client クラスを作成します。

import { SignJWT } from "jose";
import Sora, {
  type ConnectionOptions,
  type SoraConnection,
  type ConnectionPublisher,
} from "sora-js-sdk";

// Sora JavaScript SDK を利用した Sora クライアント
class SoraClient {
  private debug: boolean;

  private channelId: string;
  private options: ConnectionOptions;

  private secretKey: string;

  private sora: SoraConnection;
  private connection: ConnectionPublisher;

  constructor(
    signalingUrl: string,
    channelId: string,
    secretKey: string,
    options: ConnectionOptions = {},
  ) {
    this.debug = false;
    this.channelId = channelId;
    this.options = options;
    this.secretKey = secretKey;

    this.sora = Sora.connection(signalingUrl, this.debug);
    // metadata はここでは undefined にして connect 時に指定する
    this.connection = this.sora.sendrecv(this.channelId, undefined, this.options);
    this.connection.on("track", this.onTrack);
    this.connection.on("removetrack", this.removeTrack);
  }

  async connect(stream: MediaStream) {
    // SecretKey が指定されていたら JWT を生成して metadata に設定する
    if (this.secretKey) {
      const jwt = await this.generateJwt();
      this.connection.metadata = {
        access_token: jwt,
      };
    }
    // 接続する
    await this.connection.connect(stream);
  }

  async disconnect() {
    // 切断する
    await this.connection.disconnect();
  }

  private onTrack = (event: RTCTrackEvent) => {
    const stream = event.streams[0];
    const remoteVideoId = `remote-video-${stream.id}`;
    const remoteVideos = document.querySelector<HTMLDivElement>("#remote-videos");
    if (remoteVideos && !remoteVideos.querySelector<HTMLVideoElement>(`#${remoteVideoId}`)) {
      const remoteVideo = document.createElement("video");
      remoteVideo.id = remoteVideoId;
      remoteVideo.style.border = "1px solid red";
      remoteVideo.autoplay = true;
      remoteVideo.playsInline = true;
      remoteVideo.controls = true;
      remoteVideo.width = 320;
      remoteVideo.height = 240;
      remoteVideo.srcObject = stream;
      remoteVideos.appendChild(remoteVideo);
    }
  };

  private removeTrack = (event: MediaStreamTrackEvent) => {
    const target = event.target as MediaStream;
    const remoteVideo = document.getElementById(`remote-video-${target.id}`) as HTMLVideoElement;
    if (remoteVideo) {
      remoteVideo.remove();
    }
  };

  private generateJwt = (): Promise<string> => {
    return new SignJWT({
      channel_id: this.channelId,
    })
      .setProtectedHeader({ alg: "HS256", typ: "JWT" })
      .setExpirationTime("30s")
      .sign(new TextEncoder().encode(this.secretKey));
  };
}

export default SoraClient;

src/vite-env.d.ts の変更

/// <reference types="vite/client" />

interface ImportMetaEnv {
  VITE_SORA_SIGNALING_URL: string;
  VITE_SORA_CHANNEL_ID_PREFIX_PREFIX: string;
  VITE_SECRET_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

src/main.ts の変更

Sora Client クラスを利用したコードを追加します。

import SoraClient from "./client";

addEventListener("DOMContentLoaded", () => {
  // .env.local からシグナリング URL を取得する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  // .env.local からシークレットキーを取得する、無ければ空文字
  const secretKey = import.meta.env.VITE_SECRET_KEY || "";

  // チャネル ID を生成する
  const channelId = generateChannelId();

  // SoraClient を生成する
  const client = new SoraClient(signalingUrl, channelId, secretKey);

  // connect ボタンを押した時の処理
  document.getElementById("connect")?.addEventListener("click", async () => {
    // getUserMedia でカメラから映像を取得する
    const stream = await navigator.mediaDevices.getUserMedia({
      // 音声は無効
      audio: false,
      video: true,
    });

    await client.connect(stream);

    const localVideo = document.getElementById("local-video") as HTMLVideoElement;
    if (localVideo) {
      localVideo.srcObject = stream;
    }
  });

  document.getElementById("disconnect")?.addEventListener("click", async () => {
    if (client === undefined) {
      return;
    }

    // sendrecv があるかどうか確認する
    // 切断する
    await client.disconnect();
    const localVideo = document.getElementById("local-video") as HTMLVideoElement;
    if (localVideo) {
      localVideo.srcObject = null;
    }
    const remoteVideos = document.getElementById("remote-videos") as HTMLDivElement;
    while (remoteVideos?.firstChild) {
      remoteVideos.removeChild(remoteVideos.firstChild);
    }
  });
});

// 環境変数からチャネル ID を生成する
export const generateChannelId = (): string => {
  const channelId = import.meta.env.VITE_SORA_CHANNEL_ID || "";
  const channelIdPrefix = import.meta.env.VITE_SORA_CHANNEL_ID_PREFIX || "";
  const channelIdSuffix = import.meta.env.VITE_SORA_CHANNEL_ID_SUFFIX || "";

  // 環境変数の channelId が指定されていない場合はエラー
  if (!channelId) {
    throw new Error("VITE_SORA_CHANNEL_ID is not set");
  }

  // channelIdPrefix と channelIdSuffix が指定されている場合はそれを利用する
  if (channelIdPrefix && channelIdSuffix) {
    return `${channelIdPrefix}${channelId}${channelIdSuffix}`;
  }

  // channelIdPrefix が指定されている場合はそれを利用する
  if (channelIdPrefix) {
    return `${channelIdPrefix}${channelId}`;
  }

  // channelIdSuffix が指定されている場合はそれを利用する
  if (channelIdSuffix) {
    return `${channelId}${channelIdSuffix}`;
  }

  return channelId;
};

起動

$ pnpm run dev
VITE v6.0.7  ready in 232 ms

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

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

サンプル

概要

ここでは Sora JavaScript SDK を利用したサンプルを紹介します。

Vite

このサンプルでは Vite を使用して、環境変数から接続先の情報を取得するようにしています。

Env Variables and Modes | Vite

.env または .env.local
# Sora シグナリング URL
VITE_SORA_SIGNALING_URL=
# Sora チャネル ID
VITE_SORA_CHANNEL_ID=
# Sora チャネル ID プレフィックス
VITE_SORA_CHANNEL_ID_PREFIX=
# Sora チャネル ID サフィックス
VITE_SORA_CHANNEL_ID_SUFFIX=
# JWT 生成用のシークレットキー
VITE_SECRET_KEY=
VITE_SORA_SIGNALING_URL

Sora のシグナリング URL を指定してください。

  • Sora 自前の場合は設定済のシグナリング URL を指定してください

    • VITE_SORA_SIGNALING_URL=wss://sora.example.com/signaling

  • Sora Labo の場合は wss://sora.sora-labo.shiguredo.app/signaling を指定してください

    • VITE_SORA_SIGNALING_URL=wss://sora.sora-labo.shiguredo.app/signaling

  • Sora Cloud の場合は wss://sora.sora-cloud.shiguredo.app/signaling を指定してください

    • VITE_SORA_SIGNALING_URL=wss://sora.sora-cloud.shiguredo.app/signaling

VITE_SORA_CHANNEL_ID

好きな文字列を指定してください。

VITE_SORA_CHANNEL_ID_PREFIX

Sora Labo はこちらの環境変数を設定してください

Sora のチャネル ID プレフィックスを指定してください。

{github_username}_{github_id}_ を指定してください。

例えば github_username が spam で github_id が 1234567890 の場合、 チャネル ID プレフィックスは spam_1234567890_ となります

# 例
# VITE_SORA_CHANNEL_ID_PREFIX=spam_1234567890_
VITE_SORA_CHANNEL_ID_PREFIX={github_username}_{github_id}_
VITE_SORA_CHANNEL_ID_SUFFIX

Sora Labo はこちらの環境変数を設定してください

Sora Cloud のチャネル ID サフィックスを指定してください。

  • @{project_id} を指定してください

    • VITE_SORA_CHANNEL_ID_SUFFIX=@{project_id}

VITE_SECRET_KEY

Sora Labo と Sora Cloud はこちらの環境変数を指定してください

JWT 生成用のシークレットキーを指定してください。

  • Sora Labo の場合はシークレットキーを指定してください

    • VITE_SECRET_KEY={secret_key}

  • Sora Cloud の場合は API キーを指定してください

    • VITE_SECRET_KEY={api_key}

vite-env.d.ts

https://vite.dev/guide/env-and-mode#intellisense-for-typescript

/// <reference types="vite/client" />

interface ImportMetaEnv {
  VITE_SORA_SIGNALING_URL: string;
  VITE_SORA_CHANNEL_ID: string;
  VITE_SORA_CHANNEL_ID_PREFIX: string;
  VITE_SORA_CHANNEL_ID_SUFFIX: string;
  VITE_SECRET_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

jose

Sora LaboSora Cloud では接続に JWT を利用しています。

このドキュメントでは JWT を生成するのに jose というライブラリを利用しています。

インストール
# npm
$ npm install jose

# pnpm
$ pnpm add jose
JWT 生成するコード
// jose をインストールしていることを前提としています
import { SignJWT } from "jose";

// channel_id と secret_key を指定して JWT を生成する
export const generateJwt = (channelId: string, secretKey: string): Promise<string> => {
  // HS256 を利用しています
  return (
    new SignJWT({
      // channel_id を Claim に設定しています
      channel_id: channelId,
    })
      // JWT のヘッダーを設定しています
      .setProtectedHeader({ alg: "HS256", typ: "JWT" })
      // JWT の期限を 30 秒に設定しています
      .setExpirationTime("30s")
      // JWT を生成しています
      .sign(new TextEncoder().encode(secretKey))
  );
};

チャネル ID の生成

環境変数を利用してチャネル ID を生成します。

export const generateChannelId = (): string => {
  // qs を確認する
  const urlParams = new URLSearchParams(window.location.search);
  const qsChannelId = urlParams.get("channelId") || "";
  const qsChannelIdPrefix = urlParams.get("channelIdPrefix") || "";
  const qsChannelIdSuffix = urlParams.get("channelIdSuffix") || "";

  // qs が指定されていればその値を優先するようにする
  const channelId = qsChannelId || import.meta.env.VITE_SORA_CHANNEL_ID || "";
  const channelIdPrefix = qsChannelIdPrefix || import.meta.env.VITE_SORA_CHANNEL_ID_PREFIX || "";
  const channelIdSuffix = qsChannelIdSuffix || import.meta.env.VITE_SORA_CHANNEL_ID_SUFFIX || "";

  // 環境変数の channelId が指定されていない場合はエラー
  if (!channelId) {
    throw new Error("VITE_SORA_CHANNEL_ID is not set");
  }

  // channelIdPrefix と channelIdSuffix が指定されている場合はそれを利用する
  if (channelIdPrefix && channelIdSuffix) {
    return `${channelIdPrefix}${channelId}${channelIdSuffix}`;
  }

  // channelIdPrefix が指定されている場合はそれを利用する
  if (channelIdPrefix) {
    return `${channelIdPrefix}${channelId}`;
  }

  // channelIdSuffix が指定されている場合はそれを利用する
  if (channelIdSuffix) {
    return `${channelId}${channelIdSuffix}`;
  }

  return channelId;
};

送受信で接続する

自分から音声、映像を配信し、他の参加者から音声、映像を受信する場合は sendrecv() を使用して接続します。

マルチストリームで接続した Connection オブジェクト は接続したチャネル ID に MediaStream が追加、削除されると track コールバックが呼ばれます。 コールバックを利用して追加、削除された MediaStream を処理します。

<!doctype html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
</head>

<body>
  <video id="localVideo" autoplay="" playsinline="" controls="" muted=""></video>
  <hr />
  <div id="remoteVideos"></div>

  <button id="connect">接続</button>
  <button id="disconnect">切断</button>

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

</body>

</html>
import Sora, { type SoraConnection, type ConnectionPublisher } from "sora-js-sdk";
import { generateJwt } from "../jwt";
import { generateChannelId } from "../sora";

document.addEventListener("DOMContentLoaded", (_event) => {
  // Vite を利用して env.local から取得
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const secretKey = import.meta.env.VITE_SECRET_KEY;

  const channelId = generateChannelId();

  const soraClient = new SoraClient(signalingUrl, channelId, secretKey);
  document.querySelector("#connect")?.addEventListener("click", () => soraClient.connect());
  document.querySelector("#disconnect")?.addEventListener("click", () => soraClient.disconnect());
});

class SoraClient {
  private debug = true;

  private signalingUrl: string;
  private channelId: string;

  private secretKey: string;

  private sora: SoraConnection;
  private connection: ConnectionPublisher;

  private streams: Record<string, MediaStream> = {};

  constructor(signalingUrl: string, channelId: string, secretKey: string) {
    this.signalingUrl = signalingUrl;
    this.channelId = channelId;
    this.secretKey = secretKey;

    // 接続先の Sora を設定する
    this.sora = Sora.connection(this.signalingUrl, this.debug);
    const options = {
      audio: true,
      video: true,
    };
    this.connection = this.sora.sendrecv(this.channelId, undefined, options);

    // ontrack イベント
    // メディアストリームトラック単位で発火する
    this.connection.on("track", this.onaddtrack.bind(this));

    // removetrack イベント (リモートメディアストリームが削除されたときに発生)
    this.connection.on("removetrack", this.onremovetrack.bind(this));
  }

  async connect() {
    // オーディオとビデオのストリームを取得
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: true,
      video: true,
    });

    const localVideElement = document.querySelector<HTMLVideoElement>("#localVideo");
    if (localVideElement !== null) {
      localVideElement.srcObject = stream;
    }

    // SecretKey があれば JWT を設定する
    if (this.secretKey) {
      const jwt = await generateJwt(this.channelId, this.secretKey);
      this.connection.metadata = {
        // Sora では特に "access_token" と決まっているわけではありません
        // access_token は Sora Labo や Sora Cloud の想定です
        access_token: jwt,
      };
    }

    // 接続
    await this.connection.connect(stream);
  }

  async disconnect() {
    // 切断
    await this.connection.disconnect();

    // ローカルビデオを削除
    const localVideo = document.querySelector<HTMLVideoElement>("#localVideo");
    if (localVideo !== null) {
      localVideo.srcObject = null;
    }

    // リモートビデオを削除
    const remoteVideos = document.querySelector<HTMLDivElement>("#remoteVideos");
    remoteVideos?.remove();
  }

  // 統計情報を取得できるようにする
  getStats(): Promise<RTCStatsReport | null> {
    if (!this.connection.pc) {
      return Promise.resolve(null);
    }

    return this.connection.pc.getStats();
  }

  private onaddtrack(event: RTCTrackEvent) {
    // 追加されたストリームを取得
    // 注: Sora では 1 クライアント 1 音声/ 1 映像と決まっているため、
    // ストリームが複数入ってこない
    const remoteStream = event.streams[0];

    // リモートビデオエレメントを取得
    const remoteVideos = document.querySelector("#remoteVideos");

    // リモートビデオエレメントのIDを生成
    const remoteVideoId = `remoteVideo-${remoteStream.id}`;

    // 既存のビデオエレメントが無ければ新たに作成
    if (!remoteVideos?.querySelector(`#${remoteVideoId}`)) {
      const remoteVideo = document.createElement("video");
      remoteVideo.id = remoteVideoId;
      remoteVideo.autoplay = true;
      remoteVideo.srcObject = remoteStream;
      remoteVideos?.appendChild(remoteVideo);
    }

    if (!this.streams[remoteStream.id]) {
      this.streams[remoteStream.id] = remoteStream;
    }
  }

  private onremovetrack(event: MediaStreamTrackEvent) {
    // target は removetrack が発火した MediaStream
    const target = event.target as MediaStream;
    const remoteVideo = document.querySelector(`#remoteVideo-${target.id}`);
    const remoteVideos = document.querySelector("#remoteVideos");
    if (remoteVideo) {
      remoteVideos?.removeChild(remoteVideo);
    }

    if (this.streams[target.id]) {
      delete this.streams[target.id];
    }
  }

  get getStreams(): Record<string, MediaStream> {
    return this.streams;
  }
}

送信のみで接続する

sendonly() を使用して接続します。

<!doctype html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
</head>

<body>
  <video id="localVideo" autoplay="" playsinline="" controls="" muted=""></video>
  <hr />

  <button id="connect">接続</button>
  <button id="disconnect">切断</button>

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

</body>

</html>
import Sora, { type SoraConnection, type ConnectionPublisher } from "sora-js-sdk";
import { generateJwt } from "../jwt";
import { generateChannelId } from "../sora";
document.addEventListener("DOMContentLoaded", (_event) => {
  // Vite を利用して env.local から取得
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const secretKey = import.meta.env.VITE_SECRET_KEY;

  const channelId = generateChannelId();

  const soraClient = new SoraClient(signalingUrl, channelId, secretKey);
  document.querySelector("#connect")?.addEventListener("click", () => soraClient.connect());
  document.querySelector("#disconnect")?.addEventListener("click", () => soraClient.disconnect());
});

class SoraClient {
  private debug = true;

  private signalingUrl: string;
  private channelId: string;

  private secretKey: string;

  private sora: SoraConnection;
  private connection: ConnectionPublisher;

  constructor(signalingUrl: string, channelId: string, secretKey: string) {
    this.signalingUrl = signalingUrl;
    this.channelId = channelId;
    this.secretKey = secretKey;

    // 接続先の Sora を設定する
    this.sora = Sora.connection(this.signalingUrl, this.debug);
    const options = {};
    this.connection = this.sora.sendonly(this.channelId, undefined, options);

    // ontrack イベント
    // メディアストリームトラック単位で発火する
    this.connection.on("track", this.onaddtrack.bind(this));

    // removetrack イベント (リモートメディアストリームが削除されたときに発生)
    this.connection.on("removetrack", this.onremovetrack.bind(this));
  }

  async connect() {
    // オーディオとビデオのストリームを取得
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: true,
      video: true,
    });

    const localVideElement = document.querySelector<HTMLVideoElement>("#localVideo");
    if (localVideElement !== null) {
      localVideElement.srcObject = stream;
    }

    // SecretKey があれば JWT を設定する
    if (this.secretKey) {
      const accessToken = await generateJwt(this.channelId, this.secretKey);
      this.connection.metadata = {
        access_token: accessToken,
      };
    }

    // 接続
    await this.connection.connect(stream);
  }

  async disconnect() {
    // 切断
    await this.connection.disconnect();

    // ローカルビデオを削除
    const localVideElement = document.querySelector<HTMLVideoElement>("#localVideo");
    if (localVideElement !== null) {
      localVideElement.srcObject = null;
    }
  }

  private onaddtrack(event: RTCTrackEvent) {
    // 追加されたストリームを取得
    // 注: Sora では 1 クライアント 1 音声/ 1 映像と決まっているため、
    // ストリームが複数入ってこない
    const remoteStream = event.streams[0];

    // リモートビデオエレメントを取得
    const remoteVideos = document.querySelector("#remoteVideos");

    // リモートビデオエレメントのIDを生成
    const remoteVideoId = `remoteVideo-${remoteStream.id}`;

    // 既存のビデオエレメントが無ければ新たに作成
    if (!remoteVideos?.querySelector(`#${remoteVideoId}`)) {
      const remoteVideo = document.createElement("video");
      remoteVideo.id = remoteVideoId;
      remoteVideo.autoplay = true;
      remoteVideo.srcObject = remoteStream;
      remoteVideos?.appendChild(remoteVideo);
    }
  }

  private onremovetrack(event: MediaStreamTrackEvent) {
    // target は removetrack が発火した MediaStream
    const target = event.target as MediaStream;
    const remoteVideo = document.querySelector(`#remoteVideo-${target.id}`);
    const remoteVideos = document.querySelector("#remoteVideos");
    if (remoteVideo) {
      remoteVideos?.removeChild(remoteVideo);
    }
  }
}

受信のみで接続する

recvonly() を使用して接続します。

<!doctype html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
</head>

<body>
  <button id="connect">Connect</button>
  <button id="disconnect">Disconnect</button>

  <div id="remote-videos"></div>
  <script type="module" src="./main.ts"></script>

</body>

</html>
import Sora, {
  type SoraConnection,
  type ConnectionSubscriber,
  type ConnectionOptions,
} from "sora-js-sdk";
import { generateJwt } from "../jwt";
import { generateChannelId } from "../sora";

document.addEventListener("DOMContentLoaded", () => {
  // Vite を利用して env.local から取得
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const secretKey = import.meta.env.VITE_SECRET_KEY;

  const channelId = generateChannelId();

  const soraClient = new SoraClient(signalingUrl, channelId, secretKey);

  document.querySelector("#connect")?.addEventListener("click", () => soraClient.connect());
  document.querySelector("#disconnect")?.addEventListener("click", () => soraClient.disconnect());
});

class SoraClient {
  private debug = false;

  private channelId: string;
  private options: ConnectionOptions;
  private secretKey: string;

  private sora: SoraConnection;
  private connection: ConnectionSubscriber;

  private streams: Record<string, MediaStream> = {};

  constructor(
    signalingUrl: string,
    channelId: string,
    secretKey: string,
    options: ConnectionOptions = {},
  ) {
    this.channelId = channelId;
    this.secretKey = secretKey;
    this.options = options;

    // 接続先の Sora を設定する
    this.sora = Sora.connection(signalingUrl, this.debug);
    this.connection = this.sora.recvonly(this.channelId, undefined, this.options);
    // ontrack イベント
    // メディアストリームトラック単位で発火する
    this.connection.on("track", this.onaddtrack.bind(this));
    // removetrack イベント (リモートメディアストリームが削除されたときに発生)
    this.connection.on("removetrack", this.onremovetrack.bind(this));
  }

  async connect() {
    // SecretKey があれば JWT を設定する
    if (this.secretKey) {
      const jwt = await generateJwt(this.channelId, this.secretKey);
      this.connection.metadata = {
        // Sora では特に "access_token" と決まっているわけではありません
        // access_token は Sora Labo や Sora Cloud の想定です
        access_token: jwt,
      };
    }

    // 接続
    await this.connection.connect();
  }

  async disconnect() {
    // 切断
    await this.connection.disconnect();

    // リモートビデオを全て削除
    const remoteVideos = document.querySelector("#remote-videos");
    if (remoteVideos) {
      remoteVideos.innerHTML = "";
    }
  }

  async getStats(): Promise<RTCStatsReport | null> {
    if (!this.connection.pc) {
      throw new Error("missing pc");
    }

    return this.connection.pc.getStats();
  }

  private onaddtrack(event: RTCTrackEvent) {
    // 追加されたストリームを取得
    // 注: Sora では 1 クライアント 1 音声/ 1 映像と決まっているため、
    // ストリームが複数入ってこない
    const remoteStream = event.streams[0];

    // リモートビデオエレメントを取得
    const remoteVideos = document.querySelector("#remote-videos");

    // リモートビデオエレメントのIDを生成
    const remoteVideoId = `remote-video-${remoteStream.id}`;

    // 既存のビデオエレメントが無ければ新たに作成
    if (!remoteVideos?.querySelector(`#${remoteVideoId}`)) {
      const remoteVideo = document.createElement("video");
      remoteVideo.id = remoteVideoId;
      remoteVideo.autoplay = true;
      remoteVideo.srcObject = remoteStream;
      remoteVideos?.appendChild(remoteVideo);
    }

    if (!this.streams[remoteStream.id]) {
      this.streams[remoteStream.id] = remoteStream;
    }
  }

  private onremovetrack(event: MediaStreamTrackEvent) {
    // target は removetrack が発火した MediaStream
    const target = event.target as MediaStream;
    const remoteVideo = document.querySelector(`#remote-video-${target.id}`);
    const remoteVideos = document.querySelector("#remote-videos");
    if (remoteVideo) {
      remoteVideos?.removeChild(remoteVideo);
    }

    if (this.streams[target.id]) {
      delete this.streams[target.id];
    }
  }

  get getStreams(): Record<string, MediaStream> {
    return this.streams;
  }
}

接続して 5 秒後に切断する

disconnect() を使用して接続を切断します。

import Sora from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {};
  const client = sora.sendonly(channelId, undefined, options);

  // secretKey が指定されている場合は JWT を生成する
  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    client.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await client.connect(stream);

  // 5 秒後に切断する
  setTimeout(async () => {
    await client.disconnect();
  }, 5000);
};

export default connectToSora;

サイマルキャストを有効にして接続する

サイマルキャスト (Simulcast) は配信時に 1 つの RTCPeerConnection から複数種類のエンコードした映像を配信する機能です。 詳しくは Sora ドキュメント サイマルキャスト をご確認ください。

ConnectionBase オプションsimulcast: true を指定します

import Sora, { type VideoCodecType } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    simulcast: true,
    videoCodecType: "VP8" as VideoCodecType,
  };
  const sendonly = sora.sendonly(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendonly.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });

  await sendonly.connect(stream);
};

export default connectToSora;

スポットライトで接続する

スポットライト (Spotlight) は一定の音量を超えて音声を発している参加者の場合は音声や高画質映像を、それ以外の参加者は音声のない低画質映像を配信する機能です。 詳しくは Sora ドキュメント スポットライト をご確認ください。

ConnectionBase オプションspotlight: true multistream: true を指定します

import Sora, { type VideoCodecType } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    simulcast: true,
    // スポットライト機能を有効にする
    spotlight: true,
    videoCodecType: "VP8" as VideoCodecType,
  };
  const client = sora.sendonly(channelId, undefined, options);

  // シークレットキーが設定されている場合は JWT を設定する
  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    client.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await client.connect(stream);
};

export default connectToSora;

音声や映像コーデックを指定する

音声や映像のコーデックタイプは ConnectionBase オプション で指定します

import Sora, { type AudioCodecType, type VideoCodecType } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const soraConnection = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    // 音声コーデックに Opus を指定
    audioCodecType: "OPUS" as AudioCodecType,
    // 映像コーデックに VP9 を指定
    videoCodecType: "VP9" as VideoCodecType,
  };
  const sendrecv = soraConnection.sendrecv(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendrecv.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await sendrecv.connect(stream);
};

export default connectToSora;

音声や映像のビットレートを指定する

音声のビットレート指定は推奨しません

音声や映像のビットレートは ConnectionBase オプション で指定します

import Sora from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // Sora への接続を作成
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const soraConnection = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    audio: true,
    // オーディオのビットレートを 64 kbps に設定
    audioBitRate: 64,
    video: true,
    // ビデオのビットレートを 192 kbps に設定
    videoBitRate: 192,
  };
  const sendrecv = soraConnection.sendrecv(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendrecv.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await sendrecv.connect(stream);
};

export default connectToSora;
  • 音声ビットレートに指定できる範囲は 6-510 です

  • 映像ビットレートに指定できる範囲は 1-30000 です

映像コーデックパラメーターを指定する

ConnectionBase オプション で指定します。

import Sora, { type VideoCodecType } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const soraConnection = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    video: true,
    videoCodecType: "VP9" as VideoCodecType,
    // VP9 の 映像パラメーターで profile-id を 2 に指定
    // これを利用するには sora.conf にて signaling_vp9_params = true を設定する必要がある
    videoVp9Params: {
      profileId: 2,
    },
  };
  const sendonly = soraConnection.sendonly(channelId, undefined, options);

  // secretKey が設定されている場合は JWT を設定する
  const secretKey = import.meta.env.VITE_SECRET_KEY;
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendonly.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await sendonly.connect(stream);
};

export default connectToSora;

AV1 や H.264 や H.265 でも指定可能です。

映像と音声の可否を指定する

ConnectionBase オプション で指定します。

音声なし

import Sora from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // Sora への接続を作成
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const soraConnection = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    // オーディオは不要
    audio: false,
  };
  const sendrecv = soraConnection.sendrecv(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY;
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendrecv.metadata = {
      access_token: jwt,
    };
  }

  // ユーザーメディア(ビデオのみ)を取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: false,
    video: true,
  });
  await sendrecv.connect(stream);
};

export default connectToSora;

映像なし

import Sora from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // ユーザーメディア(オーディオのみ)を取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: false,
  });

  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const soraConnection = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    // ビデオは不要
    video: false,
  };
  const sendonly = soraConnection.sendonly(channelId, undefined, options);

  // シークレットキーが設定されている場合は JWT を設定する
  const secretKey = import.meta.env.VITE_SECRET_KEY;
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendonly.metadata = {
      access_token: jwt,
    };
  }

  await sendonly.connect(stream);
};

export default connectToSora;

クライアントIDを指定する

接続時やサーバー認証成功時に任意の文字列を指定できる値です。 詳しくは Sora ドキュメント WebSocket 経由のシグナリング client_id を参照してください。

ConnectionBase オプション で指定します。

import Sora from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // Sora への接続を作成
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const soraConnection = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    // client-id に xyz を指定
    // client-id は重複可能
    clientId: "xyz",
  };
  const sendrecv = soraConnection.sendrecv(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendrecv.metadata = {
      access_token: jwt,
    };
  }

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await sendrecv.connect(stream);
};

export default connectToSora;

DataChannel 経由のシグナリングを使用する

WebRTC 接続確立後に、シグナリングを WebSocket 経由から DataChannel 経由に切り替える機能です。 詳しくは Sora ドキュメント DataChannel 経由のシグナリング を参照してください。

ConnectionBase オプション で指定します。

import Sora from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    // シグナリングを WebSocket 経由から DataChannel 経由に切り替えるかどうかを指定
    dataChannelSignaling: true,
    // シグナリングを DataChannel 経由に切り替えたあとに WebSocket を切断するかどうかを指定
    // true にした場合、 Sora JS SDK は自動で WebSocket を切断します
    ignoreDisconnectWebSocket: false,
  };
  const client = sora.sendrecv(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    client.metadata = {
      access_token: jwt,
    };
  }

  const mediaStream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await client.connect(mediaStream);
};

export default connectToSora;

メッセージング機能を使用する

DataChannel を利用したデータの送受信を行える機能です。 詳しくは Sora ドキュメントの リアルタイムメッセージング機能 をご確認ください。

ConnectionBase オプション で指定します。

import Sora, { type DataChannelDirection } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {
    // メッセージング機能を利用するには、データチャネルを利用したシグナリングを有効にする必要がある
    dataChannelSignaling: true,
    dataChannels: [
      {
        // メッセージングのラベルは # から始める必要がある
        label: "#example",
        // メッセージングの方向、sendrecv は送受信可能
        // sendonly の場合は送信のみ可能
        // recvonly の場合は受信のみ可能
        direction: "sendrecv" as DataChannelDirection,
        // https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/maxPacketLifeTime
        // https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/maxRetransmits
        // maxPacketLifeTime か maxResends のどちらかしか指定できない
        maxPacketLifeTime: 60000,

        // https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/ordered
        ordered: true,
      },
    ],
  };
  const sendrecv = sora.sendrecv(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendrecv.metadata = {
      access_token: jwt,
    };
  }

  // メッセージ送信が可能な datachannel との接続が確立した場合に on datachannel イベントが発火する
  sendrecv.on("datachannel", async (event) => {
    // event.datachannel にメッセージ送信可能な datachannel の情報が含まれる
    const label = event.datachannel.label; // #example
    console.log("ondatachannel", label);
    // メッセージを送信する
    await sendrecv.sendMessage(label, new TextEncoder().encode("Hello world."));
  });

  // メッセージを受信した際に on message イベントが発火する
  sendrecv.on("message", (event) => {
    const label = event.label;
    const data = event.data;
    console.log("onmessage", label, data);
  });

  const mediaStream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await sendrecv.connect(mediaStream);

  console.log("Connected to Sora");
};

// Soraへの接続とメッセージ送受信を開始
export default connectToSora;

メッセージングのみで接続することも可能です。

import Sora, { type DataChannelDirection } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  // ConnectionOptions の dataChannels を指定する
  const channelId = generateChannelId();
  const options = {
    // データチャネルメッセージオンリーを使う場合は設定が必要
    // https://sora-doc.shiguredo.jp/MESSAGING#3a3616
    audio: false,
    video: false,
    // データチャネルシグナリングを利用する
    dataChannelSignaling: true,
    // データチャネルメッセージングの定義を追加
    dataChannels: [
      {
        label: "#example",
        direction: "sendrecv" as DataChannelDirection,
      },
    ],
  };
  // Sora 2023.2.0 から role が sendrecv 以外でもメッセージングオンリーが利用可能になった
  const messaging = sora.messaging(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    messaging.metadata = {
      access_token: jwt,
    };
  }

  await messaging.connect();
  // Sora 2023.2.0 以前のバージョンでは sendrecv で接続する必要がある
  // もし sendrecv や sendonly を利用する場合は空のメディアストリームを渡す
  // await sendrecv.connect(new MediaStream());

  // メッセージを送信する
  messaging.sendMessage("#example", new TextEncoder().encode("Hello world."));
};

export default connectToSora;

シグナリング通知機能を使用する

シグナリング通知機能は自分の接続状況や他の接続の参加や離脱などの通知する仕組みです。

詳しくは Sora ドキュメント の シグナリング通知 をご確認ください。

import Sora, { type SignalingNotifyMessage } from "sora-js-sdk";
import { generateJwt } from "./jwt";
import { generateChannelId } from "./sora";

const connectToSora = async () => {
  // 接続先の Sora を設定する
  const signalingUrl = import.meta.env.VITE_SORA_SIGNALING_URL;
  const debug = true;
  const sora = Sora.connection(signalingUrl, debug);

  const channelId = generateChannelId();
  const options = {};
  const sendonly = sora.sendonly(channelId, undefined, options);

  const secretKey = import.meta.env.VITE_SECRET_KEY || "";
  if (secretKey) {
    const jwt = await generateJwt(channelId, secretKey);
    sendonly.metadata = {
      access_token: jwt,
    };
  }

  // シグナリング通知
  sendonly.on("notify", (event: SignalingNotifyMessage) => {
    console.log("notify", event.event_type);
    if (
      event.event_type === "connection.created" &&
      // 自分の connection_id と一致
      sendonly.connectionId === event.connection_id
    ) {
      // 接続が成功
      console.log("self-connection_id: ", event.connection_id);
    }

    if (event.event_type === "connection.created") {
      // 自分以外の参加者の connection_id
      console.log("connection_id", event.connection_id);
    }
  });

  // オーディオとビデオのストリームを取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  });
  await sendonly.connect(stream);
};

export default connectToSora;

API リファレンス

API リファレンスは apidoc を参照ください。

Sora

Sora JS SDK メインオブジェクトです。

API リファレンスは Sora を参照ください。

SoraConnection

Role、 ChannelId、 Metadata、Options を指定することにより Sora に接続するための SendRecv オブジェクトを作成します。

API リファレンスは SoraConnection を参照ください。

ConnectionPublisher / ConnectionSubscriber / ConnectionMessaging

Sora との接続/切断を管理するオブジェクトです。

コールバック

Sora JavaScript SDK には WebRTC API のイベントや Sora 固有の機能のイベントをハンドリングするためのコールバックを用意しています。

ここではそのコールバックの利用方法について説明します。

track

自分以外 の音声や映像のメディアストリームが追加、 または削除されたタイミングで発火するコールバックです。

このコールバックは RTCPeerConnectiontrack をラップしています。

Sora では RTCTrackEvent から MediaStream を取得する際、 streams には 1 つしか入ってきません。そのため streams[0] で取得することができます。

import Sora from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
// track で上がってくるのは RTCTrackEvent
client.on("track", (event: RTCTrackEvent) => {
  // Sora では必ず 1 クライアント から送られてくるのは 1 音声/ 1 映像に固定されています
  // そのため track.streams[0] でクライアントのメディアストリームを取得できます
  const _stream = event.streams[0];

  // メディアストリームの ID はその音声と映像を配信しているクライアントの connectionId になります
  // stream.id で取得できます

  // ここにストリームを表示したりする処理を書く
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);

重要

track コールバックは audiovideo2 回 発火します。

removetrack

自分以外 の音声や映像のメディアストリームが削除されたタイミングで発火するコールバックです。

このコールバックは MediaStreamremovetrack をラップしています。

MediaStreamTrackEvent から MediaStream をする場合は target を利用してください。 target はイベントが送出されたオブジェクトへの参照で、 MediaStream を取得できます。

import Sora from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
// removetrack で上がってくるのは MediaStreamTrackEvent
client.on("removetrack", (event: MediaStreamTrackEvent) => {
  // ここにトラック削除イベントの処理を書く
  // event.target は MediaStream
  if (event.target instanceof MediaStream) {
    // ここにトラック削除イベントの処理を書く
  }
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);

disconnect

Sora からクライアントが切断したタイミングで発火するコールバックです。

  • disconnect メソッドが呼ばれた場合

  • PeerConnection の state が正常な状態では無くなった場合に強制終了する場合

  • 上記以外で何かしらの異常があった場合

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

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
// SoraCloseEvent が上がってくる
client.on("disconnect", (_event: SoraCloseEvent) => {
  // ここに切断処理イベントの処理を書く
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);

push

Sora のシグナリングで利用している通信経路経由でプッシュ通知が送られてきたタイミングで発火するコールバックです

  • WebSocket 経由でのシグナリングのプッシュ通知

  • DataChannel 経由でのシグナリングのプッシュ通知

import Sora, { type SignalingPushMessage, type TransportType } from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
client.on("push", (_message: SignalingPushMessage, _transportType: TransportType) => {
  // ここにシグナリング経由のプッシュ通知の処理を書く
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);
参考

notify

Sora のシグナリングで利用している通信経路経由での通知が送られてきた場合に発火するコールバックです。

import Sora, { type SignalingNotifyMessage, type TransportType } from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
client.on("notify", (_message: SignalingNotifyMessage, _transportType: TransportType) => {
  // ここにシグナリング通知の処理を書く
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);
参考

timeout

Sora との接続でシグナリングは成功したが、WebRTC 接続が成功せずタイムアウトしたタイミングで発火するコールバックです。

シグナリングの開始には WebSocket over TLS を利用するため、多くの環境で接続が成功します。 ただし、その後の WebRTC の接続が失敗する場合があります。

その場合は Sora 側から WebSocket を切断するのですが、 ネットワークの問題などでクライアントがそれに気付けない状況への対策となります。

import Sora from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const connection = conn.sendrecv("sora", undefined, {});
connection.on("timeout", () => {
  // ここに接続がタイムアウトした時の処理を書く
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await connection.connect(mediaStream);

message

データチャネルメッセージング機能を利用した際に、メッセージを受信したタイミングで発火するコールバックです。

このコールバックは RTCDataChannelmessage をラップしています。

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

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});

client.on("message", (_event: DataChannelMessageEvent) => {
  // ここにデータチャネルメッセージイベントを処理する
  // event.label と event.data が取れる
  // https://sora-js-sdk.shiguredo.jp/apidoc/interfaces/DataChannelMessageEvent
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);
参考

datachannel

DataChannel 経由シグナリングを利用した際に、利用可能な各データチャネルが利用に可能になったタイミングで発火するコールバックです。

メッセージング機能などを利用している場合はこちらのコールバックを利用して、メッセージングが送れるようになったかどうかを判断してください。

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

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});

// RTCDataChannelEvent ではなく Sora 独自の DataChannelEvent
client.on("datachannel", (_event: DataChannelEvent) => {
  // ここにデータチャネルが利用可能になった際の処理を書く
  // event.datachannel.direction や event.datachannel.label が取れる
});

// メディアストリームを取得
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

// Sora に繫ぐ
await client.connect(mediaStream);

このコールバックは RTCPeerConnectiondatachannel と同じタイミングで発火しません。 Sora JavaScript SDK が独自に発火させています。

参考

signaling

注釈

この機能はログ出力用のコールバックです

Sora とのシグナリングメッセージを送受信した際に発火するコールバックです。

WebSocket と DataChannel 経由でのシグナリングメッセージが取得可能です。

log

注意

この機能はデバッグ用のトレースログ出力用のコールバックです

SDK のトレースログを出力した際に発火するコールバックです。

このコールバックは debugfalse でも発火します。

timeline

注意

この機能はデバッグ用のタイムラインログ出力用のコールバックです

クライアントの主要なイベントが発生した際に発火するコールバックです。

主に、クライアントの挙動を時系列に確認するために利用するためのデバッグ向けコールバックになっています。

シーケンス図

        sequenceDiagram
   participant client1 as クライアント1<br>sendrecv
   participant client2 as クライアント2<br>sendrecv
   participant sora as WebRTC SFU Sora
   participant app as アプリケーションサーバー
   note over client1: getUserMedia
   client1->>+sora: 接続要求
   sora-->>-client1: 接続成功
   note over client1,sora: WebRTC 確立

   sora-)client1: シグナリング通知<br>connection.created (クライアント1)
   client1->>client1: notify コールバックが発火

   note over client1: 1 分経過

   sora-)client1: シグナリング通知<br>connection.updated
   client1->>client1: notify コールバックが発火

   note over client2: getUserMedia
   client2->>+sora: 接続要求
   par
      sora-->>-client2: 接続成功
      note over client2,sora: WebRTC 確立
      sora-)client2: シグナリング通知<br>connection.created (クライアント2)
      client2->>client2: notify コールバックが発火
      client2->>client2: track コールバックが発火
   and
      sora-)client1: シグナリング通知<br>connection.created (クライアント2)
      client1->>client1: notify コールバックが発火
      client1->>client1: track コールバックが発火
   end
   app->>sora: PushChannel API<br>{"mute": true}
   par
      sora-)client1: プッシュ通知<br>{"mute": true}
      client1->>client1: push コールバックが発火
   and
      sora-)client2: プッシュ通知<br>{"mute": true}
      client2->>client2: push コールバックが発火
   end
   client1->>+sora: 切断要求
   par
      sora-->>-client1: シグナリング切断
      note over client1: 切断完了
      client1->>client1: disconnect コールバックが発火
   and
      sora-)client2: シグナリング通知<br>connection.destroyed (クライアント1)
      client2->>client2: notify コールバックが発火
      client2->>client2: removetrack コールバックが発火
   end
   app->>sora: DisconnectChannel API
   sora->>client2: シグナリング切断
   note over client2: 切断完了
   client2->>client2: disconnect コールバックが発火
    

typedocs

Sora Labo

時雨堂の WebRTC SFU Sora を無料で検証できる Sora Labo で Sora JavaScript SDK を利用する方法を紹介します。

Sora Labo にサインアップする

Sora Labo にサインアップするには GitHub のアカウントが必須です。

アカウント取得後 Sora Labo にアクセスしてサインアップしてください。

Sora JavaScript SDK のサンプルを動かしてみる

Sora JavaScript SDK を Git Clone して、 pnpm install を実行してください。

注釈

pnpm のインストールについては https://pnpm.io/ja/installation をご確認ください。

git clone [email protected]:shiguredo/sora-js-sdk-examples.git
cd sora-js-sdk-examples
pnpm install

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

cp .env.template .env.local

Sora Labo 向けの設定を追加していきます。

  • VITE_SORA_SIGNALING_URL には wss://sora.sora-labo.shiguredo.app/signaling を指定してください

  • VITE_SORA_CHANNEL_ID_PREFIX_PREFIX には Sora Labo ダッシュボードで生成したチャンネル ID プレフィックスを指定してください

    • {github_username}_{github_id}_ を指定してください

  • VITE_SECRET_KEY には Sora Labo ダッシュボードで生成した JWT のシークレットキーを指定してください

VITE_SORA_SIGNALING_URL=wss://sora.sora-labo.shiguredo.app/signaling
VITE_SORA_CHANNEL_ID_PREFIX_PREFIX={github_username}_{github_id}_
VITE_SECRET_KEY={secret_key}

あとはサンプルを起動するだけです。 pnpm run dev を実行する事でサンプルが起動します。

pnpm run dev

以下を二つ開いて connect ボタンを押して、音声と映像が双方向で表示されれば WebRTC SFU Sora 経由で Sora JavaScript SDK を利用できています。

古いリリースノート

UPDATE

下位互換がある変更

ADD

下位互換がある追加

CHANGE

下位互換のない変更

FIX

バグ修正

2024.1.2

リリース日:

2024-07-09

  • [FIX] "type": "offer"simulcast の値が反映されていない問題を修正しました

    • @voluntas

2024.1.1

リリース日:

2024-06-17

  • [FIX] 内部バージョンが canary になっていたリリースミスを修正しました

    • @voluntas

2024.1.0

リリース日:

2024-06-07

  • [CHANGE] オーディオコーデック LYRA のサポートを削除しました

  • [CHANGE] シグナリングオプションの multistream は false の時のみレガシーストリームを使用するようにしました - レガシーストリームを使用したい場合は multistream: false の指定をしてください

  • [CHANGE] 挙動と関数名が一致しないため stopAudioTrackstopVideoTrack を非推奨にしました - 今後は removeAudioTrackremoveVideoTrack を利用してください

  • [CHANGE] examples を Vite を利用して動かすように変更しました

  • [CHANGE] examples を クラスベースに変更しました

  • [ADD] removeAudioTrackremoveVideoTrack を追加しました - stopAudioTrackstopVideoTrack の名前を変更しただけの関数です

詳細な変更履歴は https://github.com/shiguredo/sora-js-sdk/releases/tag/2024.1.0 をご確認ください。

2023.2.0

リリース日:

2023-12-12

  • [CHANGE] Nodejs の対応バージョンから 16 系を落としました

  • [CHANGE] フォーマッター/リンターを Biome に変更しました

  • [CHANGE] テストツールを Vitest に変更しました

  • [CHANGE] パッケージ管理ツールを pnpm に変更しました

  • [CHANGE] dist/ 以下をリポジトリに含めるないようにしました

  • [ADD] "type": "offer" で受け取った session_id を保持するようにしました

  • [ADD] Sora 2023.2.0 で対応した H.265 のパラメータ指定に対応しました

    • ConnectionOptions 型に videoH265Params フィールドを追加しました

  • [FIX] ユーザが直接使わない型には @internal を指定して .d.ts に含まれないようにしました

  • [FIX] stopVideoTrack で例外を掴んでしまっていたのを修正しました

2023.1.0

リリース日:

2023-06-21

  • [UPDATE] Sora 2023.1.0 で入った転送フィルター機能を接続オプションで指定できるようにしました

    • ConnectionOptions 型に forwardingFilter フィールドを追加しました

  • [UPDATE] Sora 2023.1.0 で入った SDP 再利用機能に対応しました

  • [UPDATE] オファー SDP のメディアポートに 0 を指定することで古いトランシーバーを解放できるようにしました

    • Firefox は 0 ポートを指定するとエラーになるため、 SDK 側で従来の 9 に置換しています

  • [ADD] 最新版の Safari / Mobile Safari で Lyra コーデックを使用可能にしました

  • [ADD] 接続オプションとしてビデオコーデック用パラメータの送信を追加しました

    • ConnectionOptions 型に videoVP9Params videoH264Params videoAV1Params フィールドを追加しました

2022.3.3

2022.3.2 からバージョン情報以外の変更点はありません

  • [FIX] npm 最新バージョンへのリリースミスを修正しました。

2022.3.2

リリース日:

2023-02-10

  • [FIX] ミュート状態で接続すると、replace(Video|Audio)Track した場合に画像・音声データが送信されない問題を修正しました

2022.3.1

リリース日:

2022-12-21

  • [FIX] E2EE が有効かどうかの判定を undefined ではなく null で行うよう修正しました

2022.3.0

リリース日:

2022-12-20

  • [UPDATE] E2EE 有効時に Lyra コーデックを使用できるようにしました

2022.2.0

リリース日:

2022-12-13

  • [CHANGE] ts-jest を @swc/jest に変更しました

  • [CHANGE] サンプルの sora-e2ee-wasm のダウンロード先を変更しました

  • [CHANGE] sora.min.js を削除しました

  • [ADD] audioCodecType に "LYRA" を追加しました

    • 注意: 現時点では Lyra コーデックと E2EE の併用はできず、両方が指定された場合には E2EE が優先されます

  • [ADD] Sora.initLyra() 関数を追加しました

    • Lyra でエンコードされた音声を送信ないし受信する場合には、事前にこの関数を呼び出しておく必要があります

    • wasm やモデルファイルのダウンロードは実際に必要になったタイミングで遅延して行われます

  • [ADD] ConnectOptions に audioLyraParamsUsedtx を追加しました

  • [ADD] ConnectOptions に audioLyraParamsBitrate を追加しました

  • [ADD] audio_streaming_language_code を追加しました

  • [FIX] 廃止になった opus_params の clock_rate を削除しました

2022.1.0

リリース日:

2022-6-19

  • [CHANGE] 切断処理時に MediaStream の停止処理をしないように変更しました

  • [CHANGE] ConnectionOptions からシグナリング type: connect メッセージを生成する仕組みを変更しました

    • multistream オプションが false の場合、シグナリングメッセージに multistream: false を含めるよう変更しました

    • multistream フラグの値に関係なく spotlight オプションをシグナリングメッセージに含めるよう変更しました

    • spotlight フラグの値に関係なく spotlightFocusRid オプションをシグナリングメッセージに含めるよう変更しました

    • spotlight フラグの値に関係なく spotlightUnfocusRid オプションをシグナリングメッセージに含めるよう変更しました

    • spotlight フラグの値に関係なく spotlightNumber オプションをシグナリングメッセージに含めるよう変更しました

    • simulcast フラグの値に関係なく spotlightNumber オプションをシグナリングメッセージに含めるよう変更しました

  • [ADD] sendrecv オブジェクトのオプションに bundle_id を追加しました

  • [UPDATE] sendrecv API を使用して接続する場合に multistream option の初期値が true になるよう修正しました

  • [UPDATE] sendrecv API を使用して multistream: false で接続した場合、Sora との接続前に例外が発生するように修正しました

  • [CHANGE] connectedSignalingUrl は現在接続中の WebSocket の URL ではなく type offer メッセージを受信した URL を返すようにしました

    • ignoreDisconnectWebSocket を使用して WebSocket を切断した場合にも URL を返すように修正しました

  • [UPDATE] SendRecv オブジェクト に contactSignalingUrl プロパティを追加しました

古いリリースノート はこちら

2021.2.3

リリース日:

2022-02-10

  • [FIX] メッセージング機能で文字列データが送信されてきた場合にそのまま message callback に渡していた問題を修正しました

2021.2.2

リリース日:

2022-02-02

  • [FIX] fflate package のバージョンを 0.7.1 から 0.7.3 に更新しました

2021.2.1

リリース日:

2022-01-27

  • [FIX] type redirect 時のシグナリングで接続エラーになった場合、例外が発火しなかった問題を修正しました

2021.2.0

リリース日:

2021-12-15

  • [UPDATE] simulcast 時の transceiver 判定条件に offer.mids.video での分岐を追加しました

  • [UPDATE] 複数パッケージの管理を lerna から npm workspace に変更しました

  • [ADD] メッセージング機能を追加しました

    • sendrecv オブジェクトのオプションに datachannels を追加しました

    • sendrecv オブジェクトに sendMessage API を追加しました

    • sendrecv オブジェクトに datachannels プロパティを追加しました

    • on callback に "message" を追加しました

    • on callback に "datachannel" を追加しました

  • [CHANGE] 複数 Signaling URL への接続に対応しました

    • Connection オブジェクト第一引数の type を string から string | string[] に変更しました

    • Connection オブジェクト signalingUrl プロパティの戻り値の type を string から string | string[] に変更しました

    • Connection オブジェクトに signalingUrlCandidates プロパティを追加しました

    • SendRecv オブジェクト signalingUrl プロパティの戻り値の type を string から string | string[] に変更しました

    • SendRecv オブジェクト に signalingUrlCandidates プロパティを追加しました

    • SendRecv オブジェクト に connectedSignalingUrl プロパティを追加しました

    • SendRecv オブジェクト に signalingCandidateTimeout オプションを追加しました

  • [UPDATE] type redirect 対応を追加しました

  • [CHANGE] spotlight_legacy 対応を削除しました
    • ConnectionOptions の spotlight オプションの型を boolean のみに変更しました

2021.1.7

リリース日:

2021-9-13

  • [ADD] SoraCloseEvent 関連の type を export しました

2021.1.6

リリース日:

2021-8-10

  • [FIX] timeline ログに re-answer のログが出力されていなかったので修正しました

  • [UPDATE] timeline ログの ontrack ログに詳細情報を追加しました

2021.1.5

リリース日:

2021-8-5

  • [FIX] dataChannelSignaling false の場合に Disconnect API 経由で切断すると disconnect callback が発火しない問題を修正しました

  • [UPDATE] 非同期で disconnect を複数回呼んだ場合の処理を修正しました

2021.1.4

リリース日:

2021-8-3

  • [FIX] DataChannel 切断のタイムアウト処理中に WebSocket が切断すると Uncaught (in promise) が発生する問題を修正しました

  • [UPDATE] 切断処理中の WebSocket の onclose タイムラインログに code と reason を入れるようにしました

2021.1.3

リリース日:

2021-7-30

  • [FIX] DataChannel 切断処理を修正しました

    • 切断タイムアウト処理時にすでに DataChannel の readyState が closed 状態であれば onclose を待たないように修正しました

2021.1.2

注意

2021.1.3 をご利用ください

リリース日:

2021-7-30

  • [CHANGE] disconnect API を修正しました

    • type: disconnect メッセージに reason を追加するように修正しました

  • [CHANGE] disconnect callback を修正しました

    • disconnect callback が受け取る event を CloseEvent から SoraCloseEvent に変更しました

    • disconnect callback が受け取る event の type は "close" のみから "normal" か "abend" のどちらかが返るように変更しました

    • disconnect callback が受け取る event の code, reason は undefined のパターンを追加しました

    • disconnect callback が受け取る event に title を追加しました

    • disconnect callback が受け取る event に params を追加しました

  • [CHANGE] connect signaling 時の意図しない WebSocket の切断時のメッセージを統一しました

    • "Signaling failed. {reason}" に統一しました

  • [CHANGE] timeline callback Event の property を変更しました

    • transportType を logType に変更しました

  • [CHANGE] signaling callback Event の property を変更しました

    • transportType は必須項目にしました

  • [UPDATE] PeerConnecion の状態が不正な場合に切断処理に入るようにしました

    • PeerConnecion connectionState が "failed" になった場合は切断するようにしました

    • PeerConnecion connectionState が undefined の場合 iceConnectionState が disconnect になって 1000ms 変化がない場合は切断するようにしました

  • [UPDATE] 型を export しました

2021.1.1

リリース日:

2021-6-29

  • [FIX] 接続処理が途中で失敗した場合の timeline ログに connected のログが出力されていた問題を修正しました

2021.1.0

リリース日:

2021-6-18

  • [CHANGE] fflate を導入して Signaling zlib 対応を追加しました

  • [CHANGE] timeout option を connectionTimeout option に名前を変更しました

    • timeout option を使用している場合は deprecated warning が出るように変更

  • [CHANGE] Notify callback, Push callback の第二引数に TransportType を追加しました

  • [CHANGE] role から upstream と downstream を削除しました

  • [CHANGE] publisher と subscriber を削除しました

  • [CHANGE] シグナリングメッセージに型定義を追加しました

  • [CHANGE] 型定義の修正しました

    • Callbacks の各 callback 型定義を修正しました

    • on メソッドに渡す第2引数の型定義を修正しました

    • trace メソッドに渡す第3引数の型定義を any から unknown に変更しました

  • [CHANGE] packages 以下の npm*client を yarn に変更しました

  • [UPDATE] TypeScript を3系から4系に変更しました

  • [UPDATE] サイマルキャストのサンプルを low / middle / high から r0 / r1 / r2 へ変更しました

  • [ADD] ConnectionOptions に spotlightFocusRid / spotlightUnfocusRid を追加しました

  • [ADD] get audio, get video を追加して接続がそれぞれに対応しているかを返すようにしました

  • [ADD] stopAudioTrack, stopVideoTrack, replaceAudioTrack, replaceVideoTrack を追加しました

  • [ADD] helper メソッドを追加しました

  • [ADD] packages:upgrade コマンドを追加しました

  • [ADD] Switch DataChannel を実装しました

    • ConnectionOptions に dataChannelSignaling を追加しました

    • ConnectionOptions に ignoreDisconnectWebSocket を追加しました

2020.6.2

リリース日:

2021-1-28

  • [FIX] simulcast が使用できるかどうかの判定を修正しました

    • UserAgent を用いた判定から RTCRtpSender.getCapabilities を用いた判定に変更

2020.6.1

リリース日:

2020-12-22

  • [FIX] simulcast 時に setParameters するための RTCRtpTransceiver 検索条件を変更しました

    • getUserMedia constraints の audio/video と Sora signaling の audio/video が一致しなかった場合に DOMException: Read-only field modified in setParameters(). が発生します

    • encodings が readonly な RTCRtpSender を持つ RTCRtpTransceiver を検索条件から除外して対応しました

2020.6.0

リリース日:

2020-12-10

  • [UPDATE] e2ee 処理で signaling notify 時に metadata / authn_metadata どちらでも動作するように修正しました

  • [UPDATE] connect 時の例外に code と reason を含めるようにしました

    • WebSocket の onclose が発火した場合のみ Error オブジェクトに close event の code と reason を含めました

  • [FIX] type offer 時に受け取った encodings を type update 時にも setParametes するように修正しました

2020.5.0

リリース日:

2020-12-07

  • [CHANGE] simulcastQuality を simulcastRid に変更しました

  • [CHANGE] simulcast を bool のみに変更しました

  • [CHANGE] simulcast_rid を追加しました

  • [CHANGE] オプションの e2ee を boolean のみに変更しました

  • [UPDATE] clientId option に空文字列を渡せるように修正しました

  • [UPDATE] sora-e2ee パッケージを内包するように変更しました

    • lerna を使って複数 package を管理するようにしました

    • sdk package を作成して既存コードを sdk package 内へ移動しました

    • e2ee package を作成して sora-e2ee コードを移植しました

    • go-wasm package を作成して wasm_exec.js コードを内包しました

2020.4.2

リリース日:

2020-11-30

  • [FIX] metadata に直接 undefined を渡せるように修正しました

2020.4.1

リリース日:

2020-11-18

  • [FIX] timeout option を設定時に特定の条件で正しく動かない問題を修正しました

    • peerconnection connectionState が undefined の場合に timeout error が強制的に発動してしまう

    • peerconnection 接続前に timeout の時間に到達した場合 timeout error が発動しない

2020.4.0

リリース日:

2020-10-30

  • [CHANGE] signaling 時に処理に失敗した場合の reject の引数を CloseEvent オブジェクトから Error オブジェクトに変更しました

  • [CHANGE] connect() のタイムアウト処理にデフォルト値を設定しました

    • 60000 ms でタイムアウトするように設定しました

  • [UPDATE] connect() 実行時 PeerConnection connectionState が 'connected' になったら処理が完了するように変更しました

  • [UPDATE] disconnect 処理を修正しました

    • WebSocket で type: "disconnect" を send するように変更しました

    • WebSocket の readyState の監視をやめました

    • peerConnection の切断監視を signalingState から connectionState に変更しました

  • [UPDATE] sora-e2ee のバージョンを 2020.3.0 に更新しました

  • [FIX] package.json に定義されているモジュールの向き先を dist/sora.mjs に変更し、対象ファイルがビルドされるよう Rollup の設定を追加しました

  • [UPDATE] simulcast で active パラメータを有効にするための実装を追加しました

2020.3.0

リリース日:

2020-09-30

  • [UPDATE] Safari 14 以降で Simulcast が使えるように変更しました

2020.2.0

リリース日:

2020-09-08

  • [UPDATE] sora-e2ee を 2020.2.0 にアップデートしました

  • [UPDATE] 新スポットライトに対応しました

    • ConnectionOptions に spotlightNumber を追加しました

    • ConnectionOptions の spotlight に boolean を受け取れるよう修正しました

  • [FIX] disconnect() を複数回実行した場合に例外が発生しないように修正しました

2020.1.5

リリース日:

2020-07-20

  • [FIX] metadata が undefined の場合以外は signaling connect message に metadata を含めるように変更しました

2020.1.4

リリース日:

2020-07-08

  • [UPDATE] type.ts にある type Json のインデックスシグネチャに undefined を許可しました

2020.1.3

リリース日:

2020-06-22

  • [CHANGE] type.ts にある Audio, Video をそれぞれ SignalingAudio, SignalingVideo に名前変更しました

  • [ADD] SoraConnection の型定義を export しました

  • [ADD] sendrecv, sendonly, recvonly の引数 options に signalingNotifyMetadata を追加しました

2020.1.2

リリース日:

2020-06-18

  • [FIX] sendrecv, sendonly, recvonly の引数に渡す metadata の型を Json に変更しました

  • [FIX] authMetadata の型を Json に変更しました

2020.1.1

リリース日:

2020-06-17

  • [UPDATE] type export を追加しました

    • 以下の型定義を export しました

    • AudioCodecType

    • Callbacks

    • ConnectionBase

    • ConnectionOptions

    • ConnectionPublisher

    • ConnectionSubscriber

    • Role

    • SimulcastQuality

    • VideoCodecType

2020.1.0

リリース日:

2020-06-01

  • [CHANGE] @deprecated メッセージを追加しました

    • publisher/subscriber を使用している場合に warning を出すように変更しました

    • addstream/removestream を使用している場合に warning を出すように変更しました

    • debug: true 時に disconnect の MediaStream close 処理で warning を出すように変更しました

  • [CHANGE] property 名の変更とアクセス制限の追加しました

    • _pcpc に名前変更しました

    • _wsws に名前変更してアクセス制限を protected に変更しました

    • _callbackscallbacks に名前変更してアクセス制限を protected に変更しました

  • [CHANGE] method 名の変更とアクセス制限の追加しました

    • _ がついているメソッド名から _ を削除してアクセス制限を追加しました

  • [UPDATE] E2EE 対応しました

  • [UPDATE] TypeScript 化しました

  • [UPDATE] async / await 化しました

  • [ADD] Sora から type: ping が送られてきた際に stats: true だった場合 type: pong 送信時に stats に getStats の結果を入れました

1.16.0

日時: 2020-01-20

  • [ADD] タイムアウトを指定可能にしました

    • デフォルトではタイムアウトは有効にはなっていません

  • [ADD] 新しい role である sendrecv / sendonly / sendrecv を利用できるようにしました

  • [ADD] サンプルに multsitream_sendonly.html を追加しました

  • [UPDATE] サンプルで利用する role を新しいものに変更しました

  • [CHANGE] サンプルの multistream.html を multistream_sendrecv.html に変更しました

  • [CHANGE] サンプルの multistream_down.html を multistream_recvonly.html に変更しました

  • [CHANGE] サンプルの spotlight.html を spotlight_sendrecv.html に変更しました

  • [CHANGE] サンプルの spotlight_down.html を spotlight_recvonly.html に変更しました

  • [CHANGE] サンプルの updown.html を sendonly_recvonly.html に変更しました

  • [CHANGE] sdk_version と sdk_type を廃止し sora_client を追加しました

  • [CHANGE] user_agent を廃止し sora_client を追加しました

  • [FIX] README から simulcast_rid を削除しました

1.15.0

日時: 2019-10-10

  • [CHANGE] Plan B のコードをすべて削除しました

  • [CHANGE] ssrc group simulcast のコードをすべて削除しました

  • [UPDATE] タスクランナーを webpack から rollupjs に変更しました

  • [UPDATE] babel core を 6 から 7 へアップデートしました

  • [CHANGE] signaling message 作成時のチェックを修正しました

    • role が 'upstream' または 'downstream' でない場合はエラーになるように修正しました

    • channelId が null または undefined な場合はエラーになるように修正しました

    • metadata が null または undefined な場合は signaling message に metadata を含めないように修正しました

  • [ADD] multistream + simulcast に対応しました

  • [ADD] opus params 関連のオプションを追加しました

1.14.0

日時: 2019-07-08

  • [FIX] rid ベース simulcast で音声がでない問題を修正しました

  • [UPDATE] rid ベース simulcast で replaceTrack を使用しないで addTrack のみで実装しました

1.13.0

日時: 2019-06-10

  • [CHANGE] userAgent を user_agent に変更しました

  • [ADD] rid ベース simulcast への対応をしました

    • Firefox と Safari では利用できないようにしました

1.12.0

日時: 2019-04-15

  • [UPDATE] example の整理をしました

  • [UPDATE] development build 時に sora-js-sdk の version に '-dev' をつけるように変更しました

  • [ADD] Signaling Option に client_id を追加しました

1.11.0

日時: 2019-03-27

  • [UPDATE] Safari の Unified Plan, Plan B 両方に対応しました

  • [UPDATE] Simulcast option が使えるブラウザ判定を変更しました

1.10.2

日時: 2019-01-21

  • [FIX] マルチストリームで Safari 12.0 と 12.1 両方に対応しました

1.10.1

日時: 2019-01-17

  • [UPDATE] Firefox の Media Panel addon の Media-Webrtc が動作するよう RTCPeerConnection の変数格納を削除しました

  • [ADD] ConnectionOptions の新しいプロパティに型を追加しました

  • [FIX] マルチストリームで Safari 12.1 に対応しました

1.10.0

日時: 2018-10-29

  • [UPDATE] simulcast, simulcastQuality オプションを追加しました

1.9.3

日時: 2018-10-19

  • [FIX] Single Stream の subscriber で on('addstream', callback) が発火しない問題を修正しました

1.9.2

日時: 2018-5-20

  • [UPDATE] package json の文言修正を修正しました

1.9.1

日時: 2018-5-13

  • [UPDATE] Unified Plan の適応を Chrome M71 以降のバージョンに変更しました

1.9.0

日時: 2018-5-28

  • [ADD] Chrome M68 以降のバージョンの動作変更しました

    • RTCPeerConnection の config に sdpSemantics: 'unified-plan' を追加しました

    • signaling message に plan_b: true オプションを渡さないように修正しました

  • [CHANGE] snapshot 関連を削除しました

  • [FIX] ontrack で stream が取得できなかった場合のエラーを修正しました

1.8.2

日時: 2018-4-27

  • [CHANGE] vad を spotlight に変更しました

1.8.1

日時: 2018-3-15

  • [FIX] addTransceiver を使うのは safari の場合だけにしました

  • [FIX] pc が null の場合は reject するように修正しました

1.8.0

日時: 2018-2-21

  • [ADD] 認証ウェブフックで払い出された metadata を参照できるように修正しました

  • [UPDATE] Sora のプレビュー機能向けのパラメータ vad を signaling connect 時に指定できるように修正しました

1.7.7

日時: 2018-1-12

  • [UPDATE] example を修正しました。 動作に変更はありません

  • [FIX] disconnect 時 Safari では PeerConnection Closing Error で失敗していたので、正常に disconnect するように修正しました

  • [FIX] subscriber multistream 時に Chrome では remoteClientIds が更新されていなかった問題を修正しました

  • [FIX] websocket 切断時に特定の条件で remote clientId のリストが更新されない問題があったため、disconnect 時に初期化するように修正しました

  • [FIX] disconnect 時に特定の条件で peerConnection 切断処理中に oniceconnectionstatechange イベントが発火することがあるため peerConnection の oniceconnectionstatechange を明示的に初期化するように修正しました

1.7.6

日時: 2017-12-29

  • [FIX] multistream subscriber 利用時に ontrack が video でしか発火しなかったのを修正しました

  • [FIX] multistream subscriber 利用時に onremovestream を ontrack の動作に合わせました

1.7.5

日時: 2017-12-27

  • [CHANGE] offer 作成用の peerConnection を close するように修正しました

1.7.4

日時: 2017-11-29

  • [UPDATE] signaling connect 時のパラメータに UserAgent を追加しました

  • [CHANGE] publisher, subscriber の引数の options に渡したオブジェクトの value 値が null の場合は処理しないように修正しました

1.7.3

日時: 2017-11-15

  • [UPDATE] Firefox で icecandidate に時間がかかる問題を修正しました

1.7.2

日時: 2017-11-06

  • [UPDATE] 最新の Edge に対応しました

  • [FIX] signaling offer 時の message に config が含まれていないとエラーになる問題を修正しました

1.7.1

日時: 2017-11-01

  • [UPDATE] signaling connect 時のパラメータに sdp を追加しました

1.7.0

日時: 2017-10-30

  • [ADD] event type に log を追加しました

  • [FIX] disconnect を同時に複数回呼ぶとエラーになる問題を修正しました

1.6.1

日時: 2017-10-18

  • [ADD] RTCPeerConnection の引数に MediaConstraints を渡せる機能を追加しました

1.6.0

日時: 2017-10-03

  • [ADD] Publisher と Subscriber の options に AudioBitRate を追加しました

1.5.0

日時: 2017-8-29

  • [CHANGE] Signaling 時の WebSocket onerror では reject しないように修正しました

  • [FIX] multistream audio only の場合に addstream イベントが動作しなかったので修正しました

1.4.1

日時: 2017-7-3

  • [FIX] Signaling message の metadata が旧仕様(access_token)のままだったので修正しました

1.4.0

日時: 2017-6-16

  • [ADD] Signaling notify 用の callback を追加できるように変更しました

1.3.0

日時: 2017-6-14

  • [ADD] Signaling notify 用の callback を追加できるように変更しました

1.3.0

日時: 2017-6-9

  • [UPDATE] Safari に対応しました

    • 現時点で確認できているのは Safari Technology Preview 32 での動作のみです

1.2.0

日時: 2017-5-29

  • [ADD] Subscriber の multistream に対応しました

  • [CHANGE] iceServers が指定されていない場合に 'stun:stun.l.google.com:19302' を使用していたのをやめました

1.1.0

日時: 2017-4-18

  • [UPDATE] Microsoft Edge に対応しました

1.0.0

日時: 2017-4-11

  • [CHANGE] PeerConnection まで含めた処理を SDK で実行するように変更しました

  • [CHANGE] multistream をパラメータに追加しました

  • [CHANGE] videoSnapshot をパラメータに追加しました

  • [CHANGE] videoBitRate をパラメータに追加しました

  • [CHANGE] audioCodecType をパラメータに追加しました

  • [CHANGE] codecType を videoCodecType に変更しました

0.5.0

日時: 2016-5-13

  • [CHANGE] codecType のチェックをしないようにしました

  • [UPDATE] シグナリングメッセージのキー名を変更しました

0.4.2

日時: 2016-4-8

  • [UPDATE] ドキュメントを修正しました

0.4.1

日時: 2016-3-31

  • [UPDATE] ドキュメントを修正しました

0.4.0

日時: 2016-3-22

  • [UPDATE] codecType が選択できるように修正しました

  • [UPDATE] パッケージの更新をしました

  • [UPDATE] ビルドのしくみを変更しました

0.3.2

日時: 2016-3-1

  • [UPDATE] パッケージの更新をしました

0.3.1

日時: 2016-2-2

  • [UPDATE] signaling 時に WS が切断した場合、ステータスコードが 440x だったら Promise.reject するように変更しました

0.3.0

日時: 2016-1-18

  • [UPDATE] disconnect を追加しました

0.2.0

日時: 2015-12-15

  • [CHANGE] constructor の引数に URL 文字列を受け取る用に修正しました

  • [CHANGE] package name を sora.js から sora-js-sdk に変更しました

  • [CHANGE] Promise 化しました

  • [FIX] PeerConnection Object が GC の対象にならないように修正しました

0.1.0

日時: 2015-11-19

© Copyright 2024, Shiguredo Inc. Created using Sphinx 8.2.1