# コールバック

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

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


## connected

Sora との接続が確立したタイミングで発火するコールバックです。

```typescript
import Sora, { type SignalingNotifyConnectionCreated } from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
client.on("connected", (_event: SignalingNotifyConnectionCreated) => {
  // ここに connected コールバック発火時の処理を記述します
});

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

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

RTCPeerConnection が `connected` かつシグナリング通知でかつ、自身の `connection_id` の connection.created を受信したタイミングで **一回のみ** 発火するコールバックです。

### 注意点

- シグナリング通知を無効にしている場合は発火しません
- `connected` コールバック発火後に `connecting` から `connected` に状態が変化した場合は発火しません


## switched

Sora とのシグナリングが WebSocket 経由から DataChannel 経由に切り替わったタイミングで発火するコールバックです。

```typescript
import Sora, { type SignalingSwitchedMessage } from "sora-js-sdk";

const conn = Sora.connection("wss://sora.example.com/signaling", true);
const client = conn.sendrecv("sora", undefined, {});
client.on("switched", (_event: SignalingSwitchedMessage) => {
  // ここに switched コールバック発火時の処理を記述します
});

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

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

## track

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

このコールバックは [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) の [track](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/track_event) をラップしています。

Sora では [RTCTrackEvent](https://developer.mozilla.org/en-US/docs/Web/API/RTCTrackEvent) から [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) を取得する際、
[streams](https://developer.mozilla.org/en-US/docs/Web/API/RTCTrackEvent/streams) には 1 つしか入ってきません。そのため `streams[0]` で取得することができます。

```typescript
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] でクライアントのメディアストリームを取得できます
  // メディアストリームの ID はその音声と映像を配信しているクライアントの connectionId になります
  // stream.id で取得できます
  // ここにストリームを表示したりする処理を書く
});

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

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

> **重要**
>
> track コールバックは `audio` と `video` の **2 回** 発火します。

## removetrack

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

このコールバックは [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) の [removetrack](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/removetrack_event) をラップしています。

[MediaStreamTrackEvent](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrackEvent) から [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) をする場合は [target](https://developer.mozilla.org/en-US/docs/Web/API/Event/target) を利用してください。
[target](https://developer.mozilla.org/en-US/docs/Web/API/Event/target) はイベントが送出されたオブジェクトへの参照で、 [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) を取得できます。

```typescript
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 が正常な状態では無くなった場合に強制終了する場合
- 上記以外で何かしらの異常があった場合

```typescript
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 経由でのシグナリングのプッシュ通知

```typescript
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);
```

### 参考

- [Sora ドキュメント プッシュ API](https://sora-doc.shiguredo.jp/API_PUSH)

## notify

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

```typescript
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);
```

### 参考

- [Sora ドキュメント シグナリング通知](https://sora-doc.shiguredo.jp/SIGNALING_NOTIFY)

## timeout

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

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

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

```typescript
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

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

このコールバックは [RTCDataChannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel) の [message](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/message_event) をラップしています。

```typescript
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://shiguredo.github.io/sora-js-sdk/interfaces/DataChannelMessageEvent.html
});

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

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

### 参考

- [Sora ドキュメント メッセージング機能](https://sora-doc.shiguredo.jp/MESSAGING)

## datachannel

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

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

```typescript
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);
```

このコールバックは [RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) の [datachannel](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event) と同じタイミングで発火しません。
Sora JavaScript SDK が独自に発火させています。

### 参考

- [Sora ドキュメント データチャネル経由のシグナリング](https://sora-doc.shiguredo.jp/DATA_CHANNEL_SIGNALING)
- [Sora ドキュメント メッセージング機能](https://sora-doc.shiguredo.jp/MESSAGING)

## signaling

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

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

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

## log

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

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

このコールバックは `debug` が `false` でも発火します。

## timeline

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

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

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

## シーケンス図

```mermaid
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














