# SkyWay SDK Documentation - Full Content
> This file contains full documentation content for SkyWay SDK.
>
> SkyWay is a WebRTC platform that enables real-time communication
> for web and mobile applications.
This file includes the complete content of all documentation files for comprehensive reference.
## ユーザーガイド/はじめに
Path: user-guide_introduction.md
# はじめに
## SkyWayとは
SkyWayは、ビデオ・音声・データ通信機能をアプリケーションに簡単に実装できるSDK & APIです。
SDKには、Webやモバイル、IoTやゲームなど様々な利用シーンに合わせたものが存在します。SDKは通信を行うために様々なAPIを利用します。SDKと複数のサーバAPIの総体がSkyWayです。

## SkyWayをご利用になるには
SkyWayのご利用にあたっては、会員登録が必要となります。
まだお済みでない場合は、[こちらのリンク](https://console.skyway.ntt.com/signup)より登録をお願いします。
## SDK
アプリケーションのプラットフォームに合わせて、SDK を選択してくだい。
- [JavaScript SDK](./user-guide/javascript-sdk/overview) : Web アプリケーション用
- [iOS SDK](./user-guide/ios-sdk/overview) : iOS アプリケーション用
- [Android SDK](./user-guide/android-sdk/overview) : Android アプリケーション用
- [Linux®︎ SDK](./user-guide/linux-sdk/overview) : Linux アプリケーション用
- [Unity SDK](./user-guide/unity-sdk/overview) : Unity アプリケーション用
(ベータ版に関するお問い合わせは[こちら](https://support.skyway.ntt.com/hc/ja/requests/new?ticket_form_id=14615614124185))
## 開発にあたっての基礎知識
SkyWayの通信モデルは、複数の要素から成り立っています。各要素について、以下の図を用いて説明します。

- Roomという部屋のような要素があります。
- Roomの中にはMemberが複数存在できます。Room内に存在するMember同士が通信することができます。
- Member同士が通信を行う際は、まず片方のMember AがPublicationを作成します(これをpublishと言います)。
- このPublicationを、もう片方のMember BがsubscribeすることでSubscriptionが生成されます。これにより、Publication → Subscriptionへ音声・映像・データが流れ、Member Bはこれらを受信することができます。
## 認証・認可
正規のエンドユーザーがあらかじめ許可された操作のみを実行できるようにするために、SkyWay はトークンベースの認証・認可機能を提供しています。
ユーザーは、自身が認証したエンドユーザーに対して適切な権限を付与したトークン(SkyWay Auth Token)を発行することで、SkyWay に対するエンドユーザーの操作を制限できます。
詳しくは[こちら](./user-guide/authentication)
## TURN
TURNサーバーは、データを中継することで、企業ネットワークなど P2P 通信が利用できない特定のネットワーク環境での通信を可能にします。
詳しくは[こちら](./user-guide/turn)
## SFU
SFUサーバーは上りの通信の数、端末のエンコード負荷、上り帯域幅・通信量を削減し、P2P 方式よりも多人数での通信を可能にします。また、サイマルキャスト機能により、クライアントごとの通信環境に応じて自動的に品質を選択することで、快適な通信を実現できます。
SFUサーバーを利用するには、SFU Bot という特殊な Member を用いる必要があります。SkyWayのライブラリには RoomライブラリとCoreライブラリの2種類があり、SFU Bot を内包しているRoomライブラリでは、 Bot の存在を意識せずともオプション1つで簡単にSFUサーバーがご利用いただけます。
詳しくは[こちら](./user-guide/sfu)
## 商標
Linux®︎は、米国およびその他の国における Linus Torvalds の登録商標です。
---
## ユーザーガイド/認証・認可/SkyWay Auth Token(各種SDK用)
Path: user-guide_authentication_skyway-auth-token.md
# SkyWay Auth Token
正規のエンドユーザーがあらかじめ許可された操作のみを実行できるようにするために、SkyWay はトークンベースの認証・認可機能を提供しています。
ユーザーは、自身が認証したエンドユーザーに対して適切な権限を付与したトークン(SkyWay Auth Token)を発行することで、SkyWay に対するエンドユーザーの操作を制限できます。
次の図は、 SkyWay を利用した認証・認可のフローを示しています。

1. エンドユーザーに対応したセッショントークンやパスワードなどの認証情報を、ユーザーアプリケーションのバックエンドサーバーに送信する
2. バックエンドサーバーの認証基盤で認証する
3. エンドユーザーに応じて適切な権限を付与した SkyWay Auth Token を生成する
4. SkyWay Auth Token をフロントエンドアプリケーションに送信する
5. 取得した SkyWay Auth Token を SkyWay SDK に設定し、 SkyWay へのリクエストに用いる
悪意のある攻撃者によるトークンの改ざんを防ぐため、 SkyWay Auth Token にはシークレットキーによる署名が必要です。
シークレットキーは、 SkyWay コンソールにログイン後、アプリケーション一覧画面から取得できます。
> このドキュメントは、SkyWay Auth Tokenの最新版であるversion 3について記述されたドキュメントです。
> SkyWay Auth Tokenの `version` プロパティが `1` 、 `2` 、未指定の場合は、[旧バージョン SkyWay Auth Token(各種SDK用)](/ja/docs/user-guide/authentication/skyway-auth-token-legacy/)のページを参照してください。
> SkyWay Auth Token version 3は、各SDKのバージョンが以下のいずれかの場合に利用できます。
>
> JavaScript SDK: v1.11.0以降
>
> iOS SDK: v2.1.7以降
>
> Android SDK: v2.4.0以降
>
> Linux®︎ SDK: v2.0.0以降
## 認証・認可サンプル
GitHubで[SkyWay Auth Tokenを生成・取得するサンプルコード](https://github.com/skyway/authentication-samples)を公開しています。
このサンプルコードは、以下のような用途で利用できます。
- バックエンドサーバーにおける SkyWay Auth Token 生成の参考実装
- フロントエンド開発時の SkyWay Auth Token 払い出しサーバーのモックサーバー
## 基本仕様
SkyWay Auth Token は JWT(JSON Web Token)形式のトークンとして表されており、ヘッダー部・ペイロード部・署名部の 3 つから構成されます。ヘッダー部には署名の方式の情報、ペイロード部には発行する権限を示した情報、署名部には Base 64 URL 方式で変換されたヘッダとペイロードの署名が含まれます。
### ヘッダー部
ヘッダー部には、署名生成に利用するアルゴリズムを記述します。 JWT の仕様では、さまざまな署名アルゴリズムを指定できるよう規定されていますが、 SkyWay Auth Token ではアルゴリズムの指定に関するセキュリティ上の問題を回避するため HS256 にのみ対応しています。
```js
{
"alg" : "HS256",
"typ" : "JWT"
}
```
### ペイロード部
ペイロード部には JWT の仕様で定められるクレームの他、このトークンに付与する権限を定義する `scope` クレームを記述します。
| クレーム | 必須 | 形式 | 説明 |
| -------- | ---- | ------------------- | ----------------------------------------------------------------------- |
| iat | ✔️ | UNIX タイムスタンプ | トークンが発行された日時 |
| jti | ✔️ | string (UUID v4) | トークンのユニークな id |
| exp | ✔️ | UNIX タイムスタンプ | このトークンが無効になる時間を表すタイムスタンプ |
| version | ✔️ | number ( `3` ) | このトークンのバージョン。最新のバージョンである `3` を指定してください |
| scope | ✔️ | Object | このトークンに付与する権限を表すクレーム |
`iat` はトークンが発行された日時を示します。検証されるタイミングより後の時刻が `iat` として指定されているとエラーになります。ただし、時刻同期のズレを考慮して `+2分` まで許容されます。
`jti` は、トークンを一意に識別するための値です。トークン生成時に UUID v4 を生成し、設定する必要があります。
`exp` は、このトークンが無効になる時間を表すタイムスタンプです。この値を過ぎた時刻において、このトークンを用いたリクエストは失敗します。`iat` で示した時刻から `+3日` を超えた時刻を設定するとエラーになります。
`version` は、このトークンのバージョンです。最新のバージョンは `3` です。本ドキュメントでは、version 3 の SkyWay Auth Token について説明します。
`scope` は、このトークンに付与する権限を表すクレームです。
詳しくは「スコープによる権限の付与」を参照してください。
### 署名部
署名部には、悪意のある攻撃者によるトークンの改ざんを防ぐために HS256 による署名を記述します。署名は Base 64 URL 方式で変換されたヘッダとペイロードに対して行います。
ユーザー独自の方法で JWT の署名を行うことも可能ですが、SkyWay が公式に提供している [@skyway-sdk/token パッケージ](https://www.npmjs.com/package/@skyway-sdk/token) を用いることで、より簡単にトークンを作成することが可能です。
## スコープによる権限の付与
`scope` は、各リソースに対する操作の権限を定義するクレームです。
SDK のメソッド呼び出しに対応する各リソースの操作を許可するかどうかを設定します。
### リソースの階層構造
各リソースは次に示す階層構造となっています。
- TURN リソース
- Analytics リソース
- NoiseCancelling リソース
- Room リソース
- SFU リソース
- Member リソース
> SkyWay では Room ライブラリの利用をお勧めしているため、SkyWay Auth Token では、Room と記述する仕様となっています。
>
> Core ライブラリなど、Channel という名称を用いるライブラリを利用している場合は、本ドキュメントの説明文において Room と表記している箇所を Channel と読み替えてください。
> なお、Core ライブラリで SkyWay Auth Token を利用する場合であっても、 `scope` における指定は `rooms` である必要があります。
### Room / Memberリソースの指定方法
Room リソースと Member リソースは、`id` と `name` のプロパティを持ちます。
Room リソースや Member リソースを指定する際は、少なくとも `id` または `name` のどちらか一方のプロパティを指定する必要があります。
SkyWayでは `name` を利用してリソースを指定することを推奨しています。詳細は各 SDK の以下のドキュメントをご確認ください。
- [JavaScript SDK セキュアな運用のためのnameの指定の推奨について](/ja/docs/cookbook/javascript-sdk/recommendation-for-using-name)
- [iOS SDK セキュアな運用のためのnameの指定の推奨について](/ja/docs/cookbook/ios-sdk/recommendation-for-using-name)
- [Android SDK セキュアな運用のためのnameの指定の推奨について](/ja/docs/cookbook/android-sdk/recommendation-for-using-name)
#### プロパティにおけるワイルドカードの指定
`id` および `name` の各プロパティでは、ワイルドカードとして `*` を指定できます。
`*` を指定した場合、0 文字以上のあらゆる文字列にマッチします。
加えて、`name` に `*` を指定した場合は `name` を持たないリソースにもマッチします。
また、`name` のプロパティを `lesson-room-*` のように指定することにより、`lesson-room-1` や `lesson-room-a` にマッチさせることができます。
ワイルドカードは合計8個まで利用できます。
なお、nameに `*` を含む値をマッチさせたい場合は、バックスラッシュでエスケープして `\*` と記載する必要があります。
例えば、`lesson-room-\*` と指定することにより、`lesson-room-1` や `lesson-room-a` ではなく、`lesson-room-*` にマッチさせることができます。
`name` と `id` が両方指定された場合、指定された `id` と `name` の両方を持つリソースにマッチします。
片方のみが指定された場合、指定されていない方のプロパティは `*` が単体で指定されたとみなされます。
### メソッド
Room リソースと Member リソースに対する操作の権限はメソッド(`methods`)として定義します。
各リソースに対して指定可能なメソッドは以下の通りです。(各メソッドの詳細は後述します)
| リソース | メソッド |
| -------- | ---------------------------------- |
| Room | create, close, updateMetadata |
| Member | publish, subscribe, updateMetadata |
Member リソースの publish メソッドは、その Member が Publisher である Publication の unpublish 、および updateMetadata の操作も許可します。
Member リソースの subscribe メソッドは、その Member が Subscriber である Subscription の unsubscribe の操作も許可します。
なお、指定したリソースのプロパティの参照(読み取り)は、メソッドの指定に関わらず、リソースの指定がなされている場合は暗黙的に許可されます。
したがって、メソッドの指定を空にした場合は、指定したリソースの読み取り専用のトークンとして利用できます。
### Room リソースが複数指定されている場合の適用順
Room リソースの指定は、 `rooms` として複数を同時に指定することができます。
Room リソースが複数指定されている場合は、操作の対象となる Room と Member にマッチする最初の要素の指定のみが適用されます。
#### 例
`meeting-room-1` という name を持つ Room において、以下の操作を許可するための SkyWay Auth Token の例を示します。
- `manager` という name を持つ Member による publish の操作
- それ以外の Member による subscribe の操作
```ts
scope: {
// ...省略
rooms: [
{
id: "*",
name: "meeting-room-1",
methods: [],
member: {
id: "*",
name: "manager",
methods: ["publish"]
}
},
{
id: "*",
name: "meeting-room-1",
methods: [],
member: {
id: "*",
name: "*",
methods: ["subscribe"]
}
}
]
}
```
`manager` という name を持つ Member は先に 1 つ目の Room リソースの要素にマッチするため、subscribe の権限は付与されないことに注意してください。
この Member にも subscribe の権限を付与する場合は、 1 つ目の要素の Member リソースの指定において、subscribe のメソッドを明示的に指定するようにしてください。
### SkyWay Auth Token の例
例として、すべてのリソースについて権限を指定したスコープを以下に示します。
このスコープはトークンに以下の権限を付与します。
- App(id: `sample-app-id`)において、
- TURN を有効化
- Analytics を有効化
- NoiseCancelling を有効化
- Room(name: `lesson-room-1`)の作成・削除、metadataの更新ができる。
- Room(name: `lesson-room-1`)において SFU を有効化
- SFU サーバーを介して publish されている Publication に同時に紐づけられる Subscription の数を最大 99 に制限
- Room(name: `lesson-room-1`)について、
- `alice` という名前の Member として入室できる。
- `alice` という名前の Member のmetadataの更新ができる。
- `alice` が Publisher である Publication を作成・削除できる。
- `alice` が Subscriber となる Subscription を作成・削除できる。
```js
scope: {
appId: "sample-app-id",
turn: {
enabled: true
},
analytics: {
enabled: true
},
noiseCancelling: {
enabled: true
},
rooms: [
{
id: "*",
name: "lesson-room-1",
methods: ["create", "close", "updateMetadata"],
sfu: {
enabled: true,
maxSubscribersLimit: 99,
},
member: {
id: "*",
name: "alice",
methods: ["publish", "subscribe", "updateMetadata"]
}
}
]
}
```
また、Room リソースは、複数の定義を含めることができます。
例えば、 2 つの Room に同時に join し、それぞれの Room で実行可能な操作の権限を個別に設定したい場合は以下の例のようになります。
- App(id: `sample-app-id`)において、
- TURN を有効化
- Analytics を有効化
- NoiseCancelling を有効化
- Room(name: `lesson-room-1`)の作成・削除、metadataの更新ができる。
- Room(name: `lesson-room-1`)において SFU を有効化
- SFU サーバーを介して publish されている Publication に同時に紐づけられる Subscription の数を最大 99 に制限
- Room(name: `lesson-room-1`)について、
- `alice` という名前の Member として入室できる。
- `alice` という名前の Member のmetadataの更新ができる。
- `alice` が Publisher である Publication を作成・削除できる。
- `alice` が Subscriber となる Subscription を作成・削除できる。
- Room(name: `lesson-room-2`)の参照ができる。
- Room(name: `lesson-room-2`)において SFU を有効化
- SFU サーバーを介して publish されている Publication に同時に紐づけられる Subscription の数を最大 99 に制限
- Room(name: `lesson-room-2`)について、
- `bob` という名前の Member として入室できる。
- `bob` が Subscriber となる Subscription を作成・削除できる。
```js
scope: {
appId: "sample-app-id",
turn: {
enabled: true
},
analytics: {
enabled: true
},
noiseCancelling: {
enabled: true
},
rooms: [
{
id: "*",
name: "lesson-room-1",
methods: ["create", "close", "updateMetadata"],
sfu: {
enabled: true,
maxSubscribersLimit: 99,
},
member: {
id: "*",
name: "alice",
methods: ["publish", "subscribe", "updateMetadata"]
}
},
{
id: "*",
name: "lesson-room-2",
methods: [],
sfu: {
enabled: true,
maxSubscribersLimit: 99,
},
member: {
id: "*",
name: "bob",
methods: ["subscribe"]
}
}
]
}
```
### TURN リソース
TURN サーバーの利用可否を設定するためのオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | ------- | ---- | ---------------------------------------------------------------------------------------- |
| enabled | boolean | ✔️ | TURN サーバーの利用可否。true の場合、 TURN サーバーを経由して通信することも可能となる。 |
なお、TURN リソースの指定が省略された場合は、 `enabled` に `true` が指定されたものとみなされます。
### Analytics リソース
Analytics 機能の利用有無を設定するためのオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | ------- | ---- | --------------------------------------------------------------------- |
| enabled | boolean | ✔️ | Analytics 機能の利用有無。true の場合、通信ログをサーバーに送信する。 |
なお、Analytics リソースの指定が省略された場合は、 `enabled` に `true` が指定されたものとみなされます。
> SkyWay Auth Token version 1、2 と異なり、 version 3 では `analytics` を省略した場合は `true` となります。
### NoiseCancelling リソース
AI Noise Canceller の利用有無を設定するためのオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | ------- | ---- | --------------------------------------------------------------------- |
| enabled | boolean | ✔️ | AI Noise Canceller の利用有無。true の場合、AI Noise Cancellerが利用可能になる。 |
なお、NoiseCancelling リソースの指定が省略された場合は、 `enabled` に `true` が指定されたものとみなされます。
### Room リソース
Room を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | --------------------------------------- | ---- | ------------------------------------------------ |
| id | string (UUID v4)\| `*` | ※ | 指定する Room の id。`*` を指定可能。 |
| name | string \| `*` | ※ | 指定する Room の name。`*` を指定可能。 |
| methods | ( create \| close \| updateMetadata )[] | ✔️ | Room メソッドを配列で指定する。 |
| sfu | SFU Resource | | SFU リソースに関するオブジェクトを指定する。 |
| member | Member Resource | | Member リソース に関するオブジェクトを指定する。 |
※: 上記「Room / Memberリソースの指定方法」を参照
member プロパティが指定されている場合は、そのトークンを用いた Room への入室(join)と退室(leave)が暗黙的に許可されます。
#### Room メソッド
Room リソースの `methods` には、以下の値が指定可能
- create: Room の作成ができる
- close: Room の削除ができる
- updateMetadata: Room の metadata の編集ができる
なお、Room リソースの指定がなされている場合は、メソッドの指定内容に関わらず暗黙的に参照(読み取り)が許可されます。
### SFU リソース
SFU サーバーの利用可否を設定するためのオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ------------------- | ------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| enabled | boolean | ✔️ | SFU サーバーの利用有無。true の場合、P2P での通信に加えて SFU サーバーを利用した通信も可能になる。 |
| maxSubscribersLimit | number | | SFU サーバーを介して publish されている Publication に同時に紐づけられる Subscription の数の上限。値は0から99まで指定可能。publish時に引数で指定した `maxSubscribers` の値がこの値よりも大きい場合、 publish 時にエラーとなる。|
なお、SFU リソースの指定が省略された場合は、 `enabled` に `true` が、 `maxSubscribersLimit` に `99` が指定されたものとみなされます。
### Member リソース
Member を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | -------------------------------------------- | ---- | ----------------------------------------- |
| id | string (UUID v4)\| `*` | ※ | 指定する Member の id。`*` を指定可能。 |
| name | string \| `*` | ※ | 指定する Member の name。`*` を指定可能。 |
| methods | ( publish \| subscribe \| updateMetadata )[] | ✔️ | Member メソッドを配列で指定する。 |
※: 上記「Room / Memberリソースの指定方法」を参照
#### Member メソッド
Member リソースの `methods` には、以下の値が指定可能
- publish: publish・unpublish、Publication の metadata の編集ができる
- subscribe: subscribe・unsubscribe ができる
- updateMetadata: Member の metadata の編集ができる
なお、Member リソースの指定がなされている場合は、メソッドの指定内容に関わらず、その Member リソースが指定されている Room に対する参照(読み取り)、および Room への入室(join)と退室(leave)が暗黙的に許可されます。
## 商標
Linux®︎は、米国およびその他の国における Linus Torvalds の登録商標です。
---
## ユーザーガイド/認証・認可/旧バージョン SkyWay Auth Token(各種SDK用)
Path: user-guide_authentication_skyway-auth-token-legacy.md
# 旧バージョン SkyWay Auth Token
> このドキュメントは、SkyWay Auth Tokenの version 1(version未指定も含む)、または version 2 について記述されたドキュメントです。
> SkyWay Auth Tokenの `version` プロパティが `3` となっているSkyWay Auth Tokenをご利用の場合は、[SkyWay Auth Token(各種SDK用)](/ja/docs/user-guide/authentication/skyway-auth-token/)のページを参照してください。
> また、現在 version 1、または 2 の SkyWay Auth Token をご利用中の方は、 version 3 への移行をご検討ください。
SkyWay は、ユーザーが認証していないエンドユーザーによる SkyWay の不正利用を防ぐため、トークンベースの認証・認可機能を提供しています。
ユーザーは、自身が認証したエンドユーザーに対して適切な権限を付与したトークン(SkyWay Auth Token)を発行することで、エンドユーザーによる SkyWay の不正な利用を防ぐことができます。
次の図は、 SkyWay を利用した認証・認可のフローを示しています。

1. エンドユーザーに対応したセッショントークンやパスワードなどの認証情報を、ユーザーアプリケーションのバックエンドサーバーに送信する
2. バックエンドサーバーの認証基盤で認証する
3. エンドユーザーに応じて適切な権限を付与した SkyWay Auth Token を生成する
4. SkyWay Auth Token をフロントエンドアプリケーションに送信する
5. 取得した SkyWay Auth Token を SkyWay SDK に設定し、 SkyWay へのリクエストに用いる
悪意のある攻撃者によるトークンの改ざんを防ぐため、 SkyWay Auth Token にはシークレットキーによる署名が必要です。
シークレットキーは、 SkyWay コンソールにログイン後、アプリケーション一覧画面から取得できます。
## 認証・認可サンプル
GitHubで[SkyWay Auth Tokenを生成・取得するサンプルコード](https://github.com/skyway/authentication-samples/tree/version-1-2)を公開しています。
このサンプルコードは、以下のような用途で利用できます。
- バックエンドサーバーにおける SkyWay Auth Token 生成の参考実装
- フロントエンド開発時の SkyWay Auth Token 払い出しサーバーのモックサーバー
## 基本仕様
SkyWay Auth Token は JWT(JSON Web Token)形式のトークンとして表されており、ヘッダー部・ペイロード部・署名部の 3 つから構成されます。ヘッダー部には署名の方式の情報、ペイロード部には発行する権限を示した情報、署名部には Base 64 URL に変換されたヘッダとペイロードの署名が含まれます。
### ヘッダー部
ヘッダー部には、署名生成に利用するアルゴリズムを記述します。 JWT の仕様では、さまざまな署名アルゴリズムを指定できるよう規定されていますが、 SkyWay Auth Token ではアルゴリズムの指定に関するセキュリティ上の問題を回避するため HS256 にのみ対応しています。
```js
{
"alg" : "HS256",
"typ" : "JWT"
}
```
### ペイロード部
ペイロード部には JWT の仕様で定められるクレームの他、このトークンに付与する権限を定義する `scope` クレームを記述します。
| クレーム | 必須 | 形式 | 説明 |
| -------- | ---- | ------------------- | ------------------------------------------------ |
| iat | ✔️ | UNIX タイムスタンプ | トークンが発行された日時 |
| jti | ✔️ | string (UUID v4) | トークンのユニークな id |
| exp | ✔️ | UNIX タイムスタンプ | このトークンが無効になる時間を表すタイムスタンプ |
| version | | number | このトークンのバージョン |
| scope | ✔️ | Object | このトークンに付与する権限を表すクレーム |
`iat` はトークンが発行された日時を示します。検証されるタイミングより後の時刻が `iat` として指定されているとエラーになります。ただし、時刻同期のズレを考慮して `+2分` まで許容されます。
`jti` は、トークンを一意に識別するための値です。トークン生成時に UUID v4 を生成し、設定する必要があります。
`exp` は、このトークンが無効になる時間を表すタイムスタンプです。この値を過ぎた時刻において、このトークンを用いたリクエストは失敗します。`iat` で示した時刻から `+3日` を超えた時刻を設定するとエラーになります。
`version` は、このトークンのバージョンです。指定していなければ`1`となります。`2`以上を指定することで、ChannelおよびMemberのNameにワイルドカードが利用できます。(後述)
`scope` は、このトークンに付与する権限を表すクレームです。
詳しくは「スコープによる権限の付与」を参照してください。
### 署名部
署名部には、悪意のある攻撃者によるトークンの改ざんを防ぐために HS256 による署名を記述します。署名は Base 64 URL エンコードに変換されたヘッダとペイロードに対して行います。
ユーザー独自の方法で JWT の署名を行うことも可能ですが、SkyWay が公式に提供している [@skyway-sdk/token](https://www.npmjs.com/package/@skyway-sdk/token) パッケージを用いることで、より簡単にトークンを作成することが可能です。
## スコープによる権限の付与
`scope` は、各リソースに対する操作に関する権限を定義するクレームです。どのリソースについてどのような操作を可能とするか、を定義することができます。
### リソースの階層構造
各リソースは次に示す階層構造となっております。
- App リソース
- Channel リソース
- Member リソース
- Publication リソース
- Subscription リソース
- SFU Bot リソース
- Forwarding リソース
### Channel / Memberリソースの指定方法
ChannelリソースとMemberリソースは、`id`と`name`を持ちます。
`scope` クレームでは、これらのリソースの指定のため少なくとも `id` または `name` のどちらか一方を指定する必要があります。
SkyWayでは `name` を利用してリソースを指定することを推奨しています。詳細は各 SDK の以下のドキュメントをご確認ください。
- [JavaScript SDK セキュアな運用のためのnameの指定の推奨について](/ja/docs/cookbook/javascript-sdk/recommendation-for-using-name)
- [iOS SDK セキュアな運用のためのnameの指定の推奨について](/ja/docs/cookbook/ios-sdk/recommendation-for-using-name)
- [Android SDK セキュアな運用のためのnameの指定の推奨について](/ja/docs/cookbook/android-sdk/recommendation-for-using-name)
#### `*`の利用について
`id`および`name`には、`*`のみを指定可能です。
`*`のみを指定した場合、あらゆる文字列にマッチします。
また、`name`に`*`のみを指定した場合、`name`を持たないリソースにもマッチします。
また、`version`に`2`以上を指定すると、nameに対して、ワイルドカードとしての`*`を利用可能です。
例えば、`lesson-room-*`と指定することにより、`lesson-room-1`や`lesson-room-a`にマッチさせることができます。
ワイルドカードは合計8個まで利用できます。
なお、version2でnameに`*`を含む値をマッチさせたい場合は、バックスラッシュでエスケープして`\*`と記載する必要があります。
例えば、`lesson-room-\*`と指定することにより、`lesson-room-1`や`lesson-room-a`ではなく、`lesson-room-*`にマッチさせることができます。
`name`と`id`が両方指定された場合、指定された`id`と`name`の両方を持つリソースにマッチします。
片方のみが指定された場合、指定されていない方が `*`のみとして扱われます。
### アクション
リソースに対する操作の権限はアクション(`actions`)として定義します。
各リソースに対して指定可能なアクションは以下の通りです。(各アクションの詳細は後述します)
| リソース | アクション |
| ------------ | ------------------------------------------------------ |
| App | read |
| Channel | write, read, create, delete, updateMetadata |
| Member | write, create, delete, signal, updateMetadata |
| Publication | write, create, delete, updateMetadata, enable, disable |
| Subscription | write, create, delete |
| SFU Bot | write, create, delete |
| Forwarding | write, create, delete |
### 例
例として、すべてのリソースについて権限を指定したスコープを以下に示します。
このスコープはトークンに以下の権限を付与します。
- App(id: `sample-app-id`)において、
- Channel(Name: `lesson-room-1`)を作成・削除できる。
- Channel(Name: `lesson-room-1`)について、
- `alice` という名前の Member を作成・削除できる。
- `alice` が Publisher である Publication を作成・削除できる。
- `alice` が Subscriber となる Subscription を作成・削除できる。
- SFU Bot を Channel に作成・削除できる。
- SFU Bot に `Forwarding` の作成・削除をさせることができる。
```js
scope: {
app: {
id: "sample-app-id",
actions: ["read"],
channels: [
{
name: "lesson-room-1",
actions: ["create", "delete"],
members: [
{
name: "alice",
actions: ["create", "delete"],
publication: {
actions: ["create", "delete"]
},
subscription: {
actions: ["create", "delete"]
}
},
],
sfuBots: [
{
actions: ["write"],
forwardings: [
{
actions: ["create", "delete"]
}
]
}
]
},
]
}
}
```
また、一部のリソースは、複数のリソースを下位の階層に含めることができます。
例えば、 1 つの Channel に複数の Member を含め、次のようなスコープを定義できます。
- App(ID: `sample-app-id`)において、
- Channel(Name: `lesson-room-1`)を作成・削除できる。
- Channel(Name: `lesson-room-1`)について、
- `alice` という名前の Member を作成・削除できる。
- `alice` が Publisher である Publication を作成・削除できる。
- `alice` が Subscriber となる Subscription を作成・削除できる。
- (`*`を使用しているので) すべての Member を削除できる。
```js
scope: {
app: {
id: "sample-app-id",
actions: ["read"],
channels: [
{
name: "lesson-room-1",
actions: ["create", "delete"],
members: [
{
name: "alice",
actions: ["create", "delete"],
publication: {
actions: ["create", "delete"]
},
subscription: {
actions: ["create", "delete"]
}
},
{
name: "*",
actions: ["delete"],
publication: {
actions: []
},
subscription: {
actions: []
}
}
],
},
]
}
}
```
### App リソース
あるアプリケーションを表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | ----------------- | ---- | ---------------------------------------------------------------------------------------------------------------------- |
| id | string (UUID v4) | ✔️ | アプリケーションの id。 `*` は指定できない。 |
| turn | boolean | | TURN サーバーの利用可否。true の場合、 TURN サーバーを経由して通信することが可能となる。省略された場合は true となる。 |
| analytics | boolean | | Analytics の利用有無。true の場合、通信ログをサーバーに送信する。省略された場合は false となる。 |
| actions | read [] | ✔️ | アプリケーション自体に対する権限を配列で指定する。`read` のみ指定可能。 |
| channels | ChannelResource[] | ✔️ | Channel リソース に関するオブジェクトを配列で指定する。 |
### Channel リソース
Channel を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | --------------------------------------------------------- | ---- | ------------------------------------------------------ |
| id | string (UUID v4)\| `*` | ※ | 指定する Channel の id。`*` を指定可能。 |
| name | string \| `*` | ※ | 指定する Channel の name。`*` を指定可能。 |
| actions | ( write \| read \| create \| delete \| updateMetadata )[] | ✔️ | Channel アクションを配列で指定する。 |
| members | Member Resource[] | | Member リソース に関するオブジェクトを配列で指定する。 |
| sfuBots | SFU Bot Resource[] | | SFUbot リソース に関するオブジェクトを配列で指定する。 |
※: 上記「Channel / Memberリソースの指定方法」を参照
#### Channel アクション
Channel リソースの `actions` には、以下の値が指定可能
- read: Channel の取得
- write: Channel のすべての操作
- create: Channel の作成
- delete: Channel の削除
- updateMetadata: metadata の編集
ただし、書き込み権限(write | create | delete | updateMetadata)のいずれかが設定されている場合、暗黙的に読み込み権限(read)も付与される。
### Member リソース
Member を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ------------ | ----------------------------------------------------------- | ---- | ----------------------------------------------------- |
| id | string (UUID v4)\| `*` | ※ | 指定する Member の id。`*` を指定可能。 |
| name | string \| `*` | ※ | 指定する Member の name。`*` を指定可能。 |
| actions | ( write \| create \| delete \| updateMetadata \| signal )[] | ✔️ | Member アクションを配列で指定する。 |
| publication | Publication Resource | | Publication リソースに関するオブジェクトを指定する。 |
| subscription | Subscription Resource | | Subscription リソースに関するオブジェクトを指定する。 |
※: 上記「Channel / Memberリソースの指定方法」を参照
#### Member アクション
Member リソースの `actions` には、以下の値が指定可能
- write: Member のすべての操作
- create: Member の作成、MemberTtl の Update
- delete: Member の削除
- updateMetadata: metadata の編集
- signal: シグナリング情報のやり取り ※3
※3: Pub/Sub を行う場合に必要
### Publication リソース
親リソースである Member リソースによって表される Member を Publisher とする Publication を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | ---------------------------------------------------------------------- | ---- | ---------------------------------------- |
| actions | ( write \| create \| delete \| updateMetadata \| enable \| disable )[] | ✔️ | Publication アクションを配列で指定する。 |
#### Publication アクション
Publication リソースの `actions` には、以下の値が指定可能
- write: Publication のすべての操作
- create: Publication の作成
- delete: Publication の削除
- updateMetadata: metadata の編集
- enable: Publication の有効化
- disable: Publication の無効化
### Subscription リソース
親リソースである Member リソースによって表される Member を Subscriber とする Subscription を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | ------------------------------- | ---- | ----------------------------------------- |
| actions | ( write \| create \| delete )[] | ✔️ | Subscription アクションを配列で指定する。 |
#### Subscription アクション
Subscription リソースの `actions` には、以下の値が指定可能
- write: Subscription のすべての操作
- create: Subscription の作成
- delete: Subscription の削除
### SFU Bot リソース
SFU Bot を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ----------- | -------------------------------- | ---- | --------------------------------------------------------- |
| actions | ( write \| create \| delete ) [] | ✔️ | SFU Bot アクション を配列で指定する。 |
| forwardings | Forwarding Resource[] | | Forwarding リソースに関するオブジェクトを配列で指定する。 |
#### SFU Bot アクション
SFU Bot リソースの `actions` には、以下の値が指定可能
- write: SFU Bot のすべての操作
- create: SFU Bot の作成
- delete: SFU Bot の削除
### Forwarding リソース
Forwarding を表すオブジェクト
| プロパティ | 形式 | 必須 | 説明 |
| ---------- | -------------------------------- | ---- | --------------------------------------- |
| actions | ( write \| create \| delete ) [] | ✔️ | Forwarding アクションを配列で指定する。 |
#### Forwarding アクション
Forwarding リソースの `actions` には、以下の値が指定可能
- write: Forwarding のすべての操作
- create: Forwarding の作成
- delete: Forwarding の削除
---
## ユーザーガイド/認証・認可/SkyWay Admin Auth Token(SkyWay Channel API, SkyWay Recording API用)
Path: user-guide_authentication_skyway-admin-auth-token.md
# SkyWay Admin Auth Token
SkyWay Admin Auth Tokenは、SkyWay Channel APIやSkyWay Recording APIなどのアプリケーションの管理者(サーバー)用APIを利用する際に必要な、認証のためのトークンです。
トークン検証の際、ペイロードに記載された有効期限確認が行われます。
> 本トークンをクライアントアプリケーションに提供しないよう注意してください。管理者(サーバー)用APIを利用されてしまう恐れがあります。
## 形式
SkyWay Admin Auth TokenはJWT形式です。
ペイロード部は以下の通りです。
| クレーム | 必須 | 形式 | 説明 |
| ------- | ---- | --------------- | ------------------------------------------------- |
| iat | ✔️ | UNIX タイムスタンプ | トークンが発行された日時 |
| jti | ✔️ | string (UUID v4) | トークンのユニークな id |
| exp | ✔️ | UNIX タイムスタンプ | このトークンが無効になる時間を表すタイムスタンプ |
| appId | ✔️ | string(UUID v4) | アプリケーションID |
`iat` はトークンが発行された日時を示します。検証されるタイミングより後の時刻が `iat` として指定されているとエラーになります。ただし、時刻同期のズレを考慮して `+2分` まで許容されます。
`jti` は、トークンを一意に識別するための値です。トークン生成時に UUID v4 を生成し、設定する必要があります。
`exp` は、このトークンが無効になる時間を表すタイムスタンプです。この値を過ぎた時刻において、このトークンを用いたリクエストは失敗します。`iat` で示した時刻から `+3日` を超えた時刻を設定するとエラーになります。
例
```js
{
"iat": 1706754878,
"jti": "ba51311f-599d-47ca-a51d-df371fa750e7",
"exp": 1706854878,
"appId": "ac8adbc8-a2ff-4c41-9f5e-fdaed5e1e65e"
}
```
## 作成方法の例
Node.jsでの作成方法を以下に示します。
```js
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const payload = {
iat: Date.now() / 1000,
jti: crypto.randomUUID(),
exp: Date.now() / 1000 + 60 * 60 * 24 * 3,
appId: "アプリケーションIDを記載します",
};
const SECRET_KEY = "シークレットキーを記載します";
const token = jwt.sign(payload, SECRET_KEY);
console.log(token)
```
---
## ユーザーガイド/Analytics/概要
Path: user-guide_analytics_overview.md
# 概要
Analyticsは、SkyWayの通信状況と品質を分析するための機能です。通信ログを収集・可視化することにより、エンドユーザーの通信品質の正確な把握が可能となり、迅速な問い合わせ対応や、ユーザーエクスペリエンスの向上に役立てることができます。
### Analyticsの利用シーン
エンドユーザーから不具合の申告があった際、対応者はエンドユーザーの利用環境(ブラウザやOSのバージョン、使用機器の名称、等)と、通信状態をAnalyticsの画面で確認します。そうすることで、ブラウザアップデートが必要、マイクがオフになっている、ネットワーク環境の改善が必要、等の適切な案内を行うことができます。
### Analyticsが収集する通信ログ
Analyticsが収集する通信ログには2種類あります。サーバ通信ログとクライアント通信ログです。クライアント通信ログは主にグラフで可視化する通信状態に関する情報です。サーバ通信ログは主にチャンネルやメンバーの基本情報ですが、SFU利用時にはSFUサーバ上の通信ログも含まれます。いずれも通話内容や個人を特定するような情報は収集しません。

> クライアント通信ログの送信は、以下のバージョンでの利用を推奨します。
>
> - JavaScript SDK: v1.7.0以降
> - iOS SDK: v2.0.0以降
> - Android SDK: v2.0.0以降
> - Linux®︎ SDK: v1.0.0以降 (Linux®︎ は、米国およびその他の国における Linus Torvalds の登録商標です。)
## 通信ログの送信について
クライアント通信ログはSkyWayコンソールでAnalyticsを有効化していない場合でも送信されます。これは何らかのトラブルが生じた際のサポート時に利用するためです。
もし送信しないようにする場合は、SkyWayAuthToken で analytics の enabled プロパティを `false` にします。
```javascript
{
version: 3,
scope: {
appId: "sample-app-id",
analytics: {
enabled: false, // false を指定
},
rooms: [
...以下省略
```
SkyWayAuthToken v1, v2 を使用する場合の指定方法は [旧バージョン SkyWayAuthToken(各種SDK用)](https://skyway.ntt.com/ja/docs/user-guide/authentication/skyway-auth-token-legacy/) を参照してください。
なお、この設定を行った場合でも、サーバ通信ログは収集されます。
---
## ユーザーガイド/Analytics/クイックスタート
Path: user-guide_analytics_quickstart.md
# クイックスタート
### 始め方
Analytics を始めるには、SkyWay コンソールへログインし、プロジェクト詳細画面より Analytics を有効化していただく必要があります。
まず、SkyWay コンソールへログインし、プロジェクト詳細画面を開くと以下のボタンが確認できます。

こちらを押して、Analyticsを有効化します。Enterpriseプランの場合は、料金に関する案内が表示されるので、内容をご確認いただいた上で利用開始してください。
> SkyWayAuthToken v1, v2を利用する場合、analytics の enabled プロパティを `true` に設定する必要があります。
> 詳細は [旧バージョン SkyWayAuthToken(各種SDK用)](https://skyway.ntt.com/ja/docs/user-guide/authentication/skyway-auth-token-legacy/) を参照ください。
### コンソールの使い方
**Analytics画面の表示**
アプリケーション一覧画面に「Analytics」というボタンがあります。こちらを押すと、次項のチャンネル・メンバー検索画面に移動します。または、アプリケーション詳細画面のサイドメニューから「Analytics」を選択しても同様です。

**チャンネル・メンバー検索**
通信状況を調べたいチャンネル、またはメンバーを検索する画面です。(「チャンネル」、「メンバー」については[こちら](./user-guide/introduction/#26))
画面を表示した時点では、直近1週間の間に存在していたチャンネル一覧が表示されます。
検索条件を指定し、検索ボタンをクリックします。その後、結果リストのいずれかの項目をクリックすることで、チャンネル詳細、またはメンバー詳細の画面に移動します。

**チャンネル詳細**
チャンネルの詳細な情報を確認できます。
チャンネルに参加したメンバーの一覧と、メンバー数の推移が確認できます。メンバー一覧は、期間やキーワード(ID, Name)で検索することができます。メンバーのリストのいずれかをクリックすると、メンバー詳細の画面に移動します。

**メンバー詳細**
メンバーの詳細な情報を確認できます。
SDKプラットフォームやデバイス名などの環境情報は、SkyWayAuthTokenに`analytics: true` を加えていない場合は表示されません。
画面下の通話履歴では、SubscriptionとPublicationの一覧が確認できます。(「Subscription」、「Publication」については[こちら](./user-guide/introduction/#12))
Subscriptionのいずれかの項目を押すと、通信詳細の画面に移動します。

**通信詳細**
指定したPublicationとSubscriptionの間での通信について、詳細を確認する画面です。
通信品質の分析において、もっとも重要な画面です。以下、画面のエリアごとに説明します。
- 画面上段では、通信の両端となるPublicationとSubscriptionの情報が確認できます。
- 画面中段の時系列データでは、ある時点での通信の状態を確認できます。
- 上部のバー
- 両端の青いピンを移動することで、画面下段のグラフで表示する範囲を指定できます。
- バーの上にある白い丸は、カメラデバイス、エンコード設定、metadataの変更のイベントです。これをクリックすると、その時刻における通信の状態が表示されます。
- Publication / Subscription の状態
- ネットワーク種別
- 有線接続、無線(モバイル)接続など
- TURN利用
- TURNを経由した通信かどうか
- ハードウェア アクセラレーション
- ON or OFF
- メディア(Publicationのみ)
- ビデオ・マイクデバイスの機種名、または画面共有時にはディスプレイ、ウィンドウ、タブいずれか
- コーデック(Publicationのみ)
- コーデック名(H264、VP8、Opusなど)
- metadata(Publicationのみ)
- メタデータの内容が表示される。全文表示可能。
- 画面下段では、通信品質をグラフで確認することができます。ドラッグで拡大することができます。各グラフの見方は次の章で説明します。

---
## ユーザーガイド/Analytics/グラフの読み取り方
Path: user-guide_analytics_graph.md
# グラフの読み取り方
このページでは、通信詳細画面における各種グラフの読み取り方について説明します。
## ネットワーク情報
### ジッター
ジッターとは、パケットの伝送時間の揺らぎ、振れ幅を表します。ネットワークが混雑すると大きくなり、映像・音声の遅延や欠損が起きやすくなります。
一般的に、ジッターは10ms未満が正常とされています。
WebRTCは自動で画質やフレームレートを下げることでネットワークの詰まりを解消するように動作するため、ジッターが10msを超えた場合、数秒程度で回復します。
回復しなかった場合、 **利用しているルータやネットワーク回線の過負荷・不具合(後述)** が予想されます。
### ジッターバッファー遅延
ジッターバッファー遅延は、ジッターが高い場合に発生し、映像・音声の遅延が起きやすくなっていることを示します。また、乱高下するような状況では映像や音声の途切れが目立つ可能性が高いとされています。
WebRTCは自動で画質やフレームレートを下げることでジッターが10ms未満に回復するように動作するため、ジッターバッファー遅延もそれに伴い回復します。
回復しなかった場合、 **利用しているルータやネットワーク回線の負荷・不具合(後述)** が予想されます。
### パケットロス率
パケットロス率は、publisherから送信されたパケットのうち、subscriberが受信するまでの間に欠損した割合を示します。
一般的に、パケットロス率が20%を超えると映像・音声の途切れが目立ち、50%を超えると通話が困難になるとされています。
パケットロス率が10%を超えると、WebRTCは自動で画質やフレームレートを下げてパケットロス率の回復を試みます。多くの場合、数秒程度でパケットロス率は10%未満に回復します。
回復しなかった場合、 **利用しているルータやネットワーク回線の過負荷・不具合(後述)** が予想されます。
### ビットレート
ビットレートは、映像・音声・データ通信の、1秒あたりに受信したデータ量です。
映像・音声の場合は、データ量が大きければ大きいほど、高い品質であることを示します。データ通信の場合は、データ量が大きければ大きいほど、多くのデータ通信が行われたことを示します
- 音声の場合、ビットレートは一般的に32kbps前後であり、32kbpsより低い場合には、音声の途切れや品質の低下を感じる可能性があります。
- 映像の場合、ビットレートはネットワーク品質に応じて200kbps~1Mbps前後となり、200kbpsより低い場合には画質やフレームレートの低下が目立つ可能性があります。
- データ通信の場合、ビットレートは受信するデータに応じて変化します。データ通信で多くのデータを送受信(publish、subscribe)してしまうと、映像・音声で利用できる通信帯域幅が減り、映像・音声の品質が低下する可能性があります。
受信した音声・映像のビットレートが低い場合、 **利用しているルータやネットワーク回線の過負荷・不具合(後述)** が予想されます。
### 往復遅延時間(RTT)
往復遅延時間(RTT)はRoundTripTimeの略であり、パケットがpublisherとsubscriberの間を往復するのに要した時間を示します。
一般的に、RTTが300ms以上の場合、ほとんどのユーザーが遅延を感じ、通話が困難になると言われています。
RTTが高い場合、主に **通信相手との物理的な距離が離れている(後述)** ことが予想されます。
## メディア情報
### 音量レベル(音声のみ)
音量レベルは、送信・受信した音声の大きさを示します。
送信側の音量レベルが0の場合、複数の原因が考えられます。
- マイクがミュート状態になっている
- 別のマイクを選択している
- マイクが故障している
マイクがミュート状態になっていないか、マイクの選択が適切か、マイクが故障していないかを確認する必要があります。
### フレームレート(映像のみ)
フレームレートは、送信・受信した映像の滑らかさを示します。
WebRTCは幅広いフレームレートをサポートしており、ネットワーク品質に応じて自動でフレームレートを調整します。
一般的に、カメラ映像の場合は15\~30fps、画面共有の場合は5\~10fpsになります。
これらの数値より低い場合には、映像の途切れが目立つようになります。
フレームレートが低い場合、 **利用しているルータやネットワーク回線の過負荷・不具合(後述)** が予想されます。
### 解像度(映像のみ)
解像度は、送信・受信した映像の鮮明さを示します。
WebRTCは幅広い解像度をサポートしており、ネットワーク品質に応じて自動で解像度を調整します。
映像の体感品質は、解像度だけではなく描画サイズも影響するため、解像度のみで品質を評価することは困難です。しかし、320x240(QVGA)よりも小さい画質の場合は、ボヤけて見える可能性が高くなります。
品質が低いと感じる場合には、 **利用しているルータやネットワーク回線の過負荷・不具合(後述)** が予想されます。
### 1秒間のうちエンコード/デコードに要した時間(映像のみ)
この項目は、映像を圧縮(エンコード)・復元(デコード)するのに要した時間を示します。
一般的に、1000msを超える値の場合は、デバイス負荷が高まっており、映像の送信や描画がリアルタイムに行えなくなっていることを示します。
1000msを超える場合は、 **デバイスの過負荷(後述)** が予想されます。
また、デバイスによってはハードウェアアクセラレーションがサポートされている場合もあり、この場合は専用のチップにエンコード・デコード処理を任せることで、デバイス負荷を軽減できます。ハードウェアアクセラレーションが有効になっているかは、通信詳細画面において、「 **Publication / Subscription の状態** 」で確認できます。
## 各種グラフ共通
### Disabled状態
各種グラフにおいて、Publicationが `Disabled` 状態になっている時間帯は、灰色の領域で表現されます。
`Disabled` 状態は、Publicationが映像や音声の送信を停止している状態を示します。
例えば下記のような状態は`Disabled` 状態とは異なるためご注意ください。
- マイクの物理的なミュートボタン等によるハードウェアミュートの状態
- **[MediaStreamTrack](https://developer.mozilla.org/ja/docs/Web/API/MediaStreamTrack)** の`enabled`プロパティが`false`の状態
## 通話不具合に対する対処法
通話不具合のケースに応じた、対処法の例を説明します。
### 利用しているルータやネットワーク回線の過負荷・不具合が予想されるケース
- 有線LAN接続の利用(例: Wi-Fiから有線LAN接続への変更)
- デバイスからWi-Fiルータへの距離が遠い場合に、有線LAN接続へ切り替えることで、ジッターの減少、パケットロスの減少、RTTの低下により、より安定した通話が行える可能性があります。
- 多くのデータを送受信(publish、subscribe)しないようにアプリケーションを修正する
- 不要な映像・音声・データ通信を送受信(publish、subscribe)しないようにアプリケーションを修正することで、映像や音声一つ一つに利用できる通信帯域幅が増え、より高品質な通話が行える可能性があります。
- ルーター・モデムの再起動
- ルータ・モデムの不調が解消する可能性があります
- 通信端末で動作している不要なアプリケーションの停止
- データ通信量が削減され、WebRTCで利用できる通信帯域幅が増え、より高品質な通話が行える可能性があります。
- 同一ルーターに接続する他の端末の通信を停止する
- データ通信量が削減され、WebRTCで利用できる通信帯域幅が増え、より高品質な通話が行える可能性があります。
- ネットワーク回線の変更(例:テザリングの利用)
- 混雑しているネットワーク回線を利用しないことで、ジッター、パケットロス率、RTTなどの品質が改善し、より安定した通話が行える可能性があります。
- テザリングを利用する場合、WebRTCでは大量のデータ通信を行うため、速度制限や追加料金にご注意ください。
### 通信相手との物理的な距離が離れていることが予想されるケース
以下の対処によって、問題が解消する可能性があります。
- ネットワーク回線の変更(例:テザリングの利用)
- 経由するネットワーク機器の数が減り、RTTの高まりを解消でき、より遅延の少ない通話が行える可能性があります。
- テザリングを利用する場合、WebRTCでは大量のデータ通信を行うため、速度制限や追加料金にご注意ください。
### 通信端末の過負荷が予想されるケース
以下の対処によって、問題が解消する可能性があります。
- 送信・描画する映像や音声の数の削減
- エンコード・デコード処理の数を減らすことで、通信端末のCPU負荷が削減され、より安定した通話が行える可能性があります。
- バックグラウンドで動作しているアプリケーションの停止
- 動作中のアプリケーションを停止することで、通信端末のCPU負荷が削減され、より安定した通話が行える可能性があります。
---
## ユーザーガイド/JavaScript SDK/概要
Path: user-guide_javascript-sdk_overview.md
# 概要
## JavaScript SDK について
JavaScript SDK は Web アプリケーションで SkyWay を利用するための SDK です。
この SDK は複数のライブラリで構成されています。
現在提供されているライブラリは以下の通りです。
**Room**
- SkyWay の全機能を利用できるライブラリ
- メディア通信毎に P2P と SFU の方式を選択できます
- また事前に Room 内での通信方式を定めておくことも可能です
- P2P Room は少人数向け
- 上限人数に制限はありませんが、ユーザーが快適に通話できる人数は 4 人までです
- SFU Room は多人数向け
- SFU サーバーを経由してメディア通信を行います
**Token**
- 認証認可のためのトークンを生成する際に利用できるユーティリティライブラリ
- シークレットキーを利用するため、フロントエンドで利用する際には注意してください
## ライブラリの仕様
SkyWay を利用する上で理解する必要のある基本的な仕様について説明します。
### Room
通話を行うグループの単位であり、ユーザーは共通の Room に参加したユーザー同士で通話を行います。
Room に参加しているユーザーのことを Member と呼びます。
### Stream
Room 上で送受信できるメディアのことを Stream といいます。以下の 3 種類の Stream を利用できます。
- AudioStream
- ユーザーのマイク音声など
- VideoStream
- ユーザーのカメラ映像など
- DataStream
- 任意のメッセージ
- SFU を用いた通信では利用できません
### Publish
Member が Stream を Room に公開することを Publish といいます。
Stream を Publish すると Room 上に Stream に対応する Publication というリソースが作成されます。
### Subscribe
Member が Room 上の Publication を受信することを Subscribe といいます。
Subscribe をすると Room 上に Subscription というリソースが作成されます。
Publication を Subscribe した Member は Subscription を通じて Stream にアクセスし映像や音声を受信できます。
### SkyWay Auth Token
SkyWay Auth Token は、SkyWay を利用するために必要な JWT(JSON Web Token)形式のトークンです。
ユーザー毎に権限を細かく設定することでき、例えば Room ごとの入室を特定ユーザーに制限する、といったことができます。
SkyWay Auth Token を利用するためには、これを払い出すアプリケーションサーバーを構築する必要があります。SkyWay SDK を利用したクライアントアプリは、アプリケーションサーバーから SkyWay Auth Token を取得し、これを用いて SkyWay の各種機能を利用します。
なお、サーバーを構築せずにフロントエンドで SkyWay Auth Token を生成した場合、シークレットキーをエンドユーザーが取得できるため、権限の制限が機能せず注意する必要があります。
GitHub で公開している[SkyWay Auth Tokenを生成・取得するサンプルコード](https://github.com/skyway/authentication-samples)は SkyWay Auth Token 払い出しサーバーのモックサーバーとしても活用できるため、開発時はこちらの利用もご検討ください。
## SDK のインストール方法
基本的には NPM パッケージとして提供しています。
なお、Room ライブラリはプロトタイピングや記事の執筆、学習など、手軽に試していただくために CDN にホストしたライブラリを用意していますが、SkyWay としてお客様の環境での CDN 経由での利用はおすすめしておりません。
CDN にホストされたライブラリは SkyWay の SDK バージョンアップに伴い自動的に更新されるため、お客様が意図しないところで、商用環境に更新版がリリースされてしまう可能性があるためです。
大変お手数ではございますが、NPM 経由での利用をお願い致します。
### NPM を利用する場合
npm がインストールされている環境下で以下のコマンドを実行します。
**Room ライブラリ**
```sh
npm install @skyway-sdk/room
```
**その他のプラグインやユーティリティライブラリ**
```sh
npm install @skyway-sdk/token
```
### CDN を利用する場合
CDN を介して利用できるのは Room ライブラリのみとなっています。それ以外のライブラリは NPM を利用ください。
なお、CDN にホストされているライブラリはアップデートに伴い自動的に最新版に更新されるため、商用環境での利用はおすすめしておりません。
以下のスクリプト要素を HTML に追加します。
**Room ライブラリ**
```html
```
モジュールはグローバル変数の `skyway_room` に格納されるので以下のようにモジュールを取得できます。
```js
const { SkyWayAuthToken, SkyWayContext, SkyWayStreamFactory, SkyWayRoom } = skyway_room;
```
## リリース
### NPM
- Room ライブラリ: https://www.npmjs.com/package/@skyway-sdk/room
### GitHub
- リポジトリ: https://github.com/skyway/js-sdk
- リリースノート: https://github.com/skyway/js-sdk/releases
---
## ユーザーガイド/JavaScript SDK/クイックスタート
Path: user-guide_javascript-sdk_quickstart.md
# 🚀 クイックスタート
## チュートリアルを始めるにあたって
本チュートリアルは、JavaScript の基本的な知識、及び、npm の利用経験を前提としています。
JavaScript の言語仕様や開発環境の構築手順は記載していないため、必要に応じて他の Web サイト等を参考にしてください。
## チュートリアル
SkyWay のメディア通信を体験できるシンプルなサンプルアプリケーションを作成します。
本チュートリアルでは Room ライブラリを使用します。
完成品(NPM パッケージ利用)は [https://github.com/skyway/js-sdk/tree/main/examples/tutorial](https://github.com/skyway/js-sdk/tree/main/examples/tutorial) にあります。
SDK を CDN 経由で利用する場合と、NPM 経由で利用する場合の 2 パターンの環境構築方法を紹介します。
なお、CDN にホストされているライブラリはアップデートに伴い自動的に最新版に更新されるため、商用環境での利用はおすすめしておりません。また、CDN を介して利用できるのは Room ライブラリのみとなっています。
### 環境構築 [CDN を利用する場合]
#### HTML 作成
index.html というファイルを作成し、以下の内容にします。
_index.html_
```html
SkyWay Tutorial
ID:
room name:
```
#### JavaScript ファイル作成
index.html と同じディレクトリで main.js というファイルを作成してください。
チュートリアルのプログラムはこのファイルの中に記述します。
#### 各種モジュールの取得
main.js ファイルの先頭に以下の内容を入力し、これから用いる各種モジュールをライブラリより取得します。
_main.js_
```js
const { nowInSec, SkyWayAuthToken, SkyWayContext, SkyWayRoom, SkyWayStreamFactory, uuidV4 } = skyway_room;
```
#### アプリケーションの起動方法
以下に、ローカルサーバーを用意するいくつかの方法を記載します。
- Visual Studio Code の拡張機能 Live Server
- 各種プログラミング言語での起動コマンド
```bash
# python 2.X
$ python -m SimpleHTTPServer 8080
# python 3.X
$ python -m http.server 8080
# ruby
$ ruby -run -e httpd . -p 8080
# php
$ php -S localhost:8080
# Node.js
$ npx http-server -p 8080
```
ブラウザからローカルサーバーのアドレス経由で index.html ファイルを開くとアプリケーションが起動します。
### 環境構築 [NPM を利用する場合]
#### 事前準備
1. Node.js のバージョン 20 以降をインストールする
2. 任意の作業ディレクトリに tutorial フォルダを作成する
3. tutorial フォルダ直下で次の作業をする
3-1. `npm init` を実行し、対話画面が終了するまで Enter キーをクリックする
3-2. `npm i @skyway-sdk/room` を実行する
3-3. `npm i -D parcel` を実行する
3-4. src フォルダを作成する
3-5. package.json ファイルを開き、scripts の階層に `"dev": "parcel ./src/index.html",` を追記する
#### HTML 作成
src フォルダの下に index.html というファイルを作成し、以下の内容を入力します。
_index.html_
```html
SkyWay Tutorial
ID:
room name:
```
#### JavaScript ファイル作成
src フォルダの下に main.js というファイルを作成してください。
チュートリアルのプログラムはこのファイルの中に記述します。
#### 各種モジュールの取得
main.js ファイルの先頭に以下の内容を入力し、これから用いる各種モジュールをライブラリより取得します。
_main.js_
```js
import { nowInSec, SkyWayAuthToken, SkyWayContext, SkyWayRoom, SkyWayStreamFactory, uuidV4 } from "@skyway-sdk/room";
```
#### アプリケーションの起動方法
tutorial ディレクトリで以下のコマンドを実行するとローカルサーバーが起動します。
```sh
npm run dev
```
ローカルサーバーのアドレスをブラウザで開くとアプリケーションが起動します。
### アプリケーション ID とシークレットキーの取得
※SkyWay への登録がまだの方は[こちら](https://console.skyway.ntt.com/login/)から
SkyWay コンソールへログインし、以下の 3 つを行います。
1. 「アプリケーションを作成」ボタンを押す

2. アプリケーション名を入力して作成ボタンを押す
3. アプリケーション一覧からアプリケーション ID とシークレットキーをコピーする
### SkyWay Auth Token を作る
SkyWay Auth Token とは、SkyWay を利用するための JWT 形式のトークンです。
トークンごとに権限を細かく設定することでき、例えば room ごとの入室を特定ユーザーに制限する、といったことができます。
ここでは細かい SkyWay Auth Token の設定方法に関する説明は省きます([SkyWay Auth Token についてはこちら](/ja/docs/user-guide/authentication))。
> 本チュートリアルでは、すぐに通信を試していただくために、トークン生成をクライアントアプリケーションで実装していますが、
本来、 **SkyWay Auth Token はサーバーアプリケーションで生成してクライアントアプリケーションに渡すようにするべきです。**
クライアントアプリケーションでトークン生成を行った場合、任意の Room に入ることができるようなトークンを第三者が作成する可能性があります。
SkyWay では、[SkyWay Auth Tokenを生成するためのサーバーアプリケーションのサンプル](https://github.com/skyway/authentication-samples)を提供しています。
サーバーアプリケーションを実装する際は、こちらも参考にしてください。
---
main.js に以下の内容を入力してください。先ほど取得したアプリケーション ID とシークレットキーを置換する必要があります。
_main.js_
```js
const token = new SkyWayAuthToken({
jti: uuidV4(),
iat: nowInSec(),
exp: nowInSec() + 60 * 60 * 24,
version: 3,
scope: {
appId: "ここにアプリケーションIDをペーストしてください",
rooms: [
{
name: "*",
methods: ["create", "close", "updateMetadata"],
member: {
name: "*",
methods: ["publish", "subscribe", "updateMetadata"],
},
},
],
},
}).encode("ここにシークレットキーをペーストしてください");
```
### カメラ映像、マイク音声の取得
main.js 内に、カメラから映像を取得して、video タグにセットするコードを追加します。
1. 即時実行の async 関数で全体を囲みます。これにより、非同期処理を await で記述できるようになります。**以降の JavaScript の処理はこの即時実行関数内に記述します。**
2. マイク音声とカメラ映像を取得し、それぞれを変数に分割代入します。
3. video 要素に映像(video)をセットします(audio は後ほど利用します)。
4. セットした映像を再生します。
_main.js_
```js
(async () => {
// 1
const localVideo = document.getElementById("local-video");
const { audio, video } = await SkyWayStreamFactory.createMicrophoneAudioAndCameraStream(); // 2
video.attach(localVideo); // 3
await localVideo.play(); // 4
})(); // 1
```
ここで、一度アプリケーションを起動して、カメラ映像が表示されるか確かめてみましょう。
環境構築のアプリケーションの起動方法の項目に従ってアプリケーションを起動してください。
### 通信処理の追加
相手との通信を行うための処理を追加していきます。
#### HTML 要素の取得
後ほど利用するため、要素を JavaScript 側で変数に格納しておきます。
_main.js_
```js
const buttonArea = document.getElementById("button-area");
const remoteMediaArea = document.getElementById("remote-media-area");
const roomNameInput = document.getElementById("room-name");
const myId = document.getElementById("my-id");
const joinButton = document.getElementById("join");
const leaveButton = document.getElementById('leave');
```
#### room の作成と入室
join ボタンを押した際に実行されるイベントハンドラを作成し、この中に以降の処理を記載していきます。
先ほど生成した SkyWay Auth Token を用いて、`context` を作ります。
`context` とは、グローバルな情報を管理するオブジェクトです。認証・認可や、ログの設定などの情報を管理します。
また、このとき、`roomNameInput` が空の場合には、以降の処理が実行できないため、空かどうかのチェックを入れています。
_main.js_
```js
joinButton.onclick = async () => {
if (roomNameInput.value === "") return;
const context = await SkyWayContext.Create(token);
};
```
次に `SkyWayRoom.FindOrCreate` という関数の第一引数に、先ほど作成した `context` を渡して、`room` を作成します。
この関数は、もしすでに同じ name の room が存在しなければ作成し、存在する場合にはその room を取得するという関数です。
第2引数のオブジェクトで name には、ユーザーが input 要素に入力した値を用います。
_main.js_
```js
const room = await SkyWayRoom.FindOrCreate(context, {
name: roomNameInput.value,
});
```
次に、先ほど作成(or 取得)した `room` に入室します。 すると `Member` オブジェクトが返ってきます。ここでは `me` という変数名とします。
自分の ID を表示するために、me.id を span 要素に格納します。
_main.js_
```js
const me = await room.join();
myId.textContent = me.id;
```
#### 自分の映像と音声を publish する
`Member` オブジェクトの `publish` 関数の引数に、先ほど取得した audio と video を渡して、音声・映像を publish します。
第2引数のオブジェクトにて通信方式を指定します。今回は P2P 方式を利用するため `type` には”p2p”を指定します。
- ”sfu”を指定すると SFU を利用した通信になり、 `type` を定義しない場合(デフォルト値)は ”p2p” となります
_main.js_
```js
await me.publish(audio, { type: "p2p" });
await me.publish(video, { type: "p2p" });
```
#### 相手の映像と音声を subscribe する
相手の映像と音声を subscribe し、audio, video 要素にセットする処理を追加します。
_main.js_
```js
const subscribeAndAttach = (publication) => {
// 3
if (publication.publisher.id === me.id) return;
const subscribeButton = document.createElement("button"); // 3-1
subscribeButton.id = `subscribe-button-${publication.id}`;
subscribeButton.textContent = `${publication.publisher.id}: ${publication.contentType}`;
buttonArea.appendChild(subscribeButton);
subscribeButton.onclick = async () => {
// 3-2
const { stream } = await me.subscribe(publication.id); // 3-2-1
let newMedia; // 3-2-2
switch (stream.track.kind) {
case "video":
newMedia = document.createElement("video");
newMedia.playsInline = true;
newMedia.autoplay = true;
break;
case "audio":
newMedia = document.createElement("audio");
newMedia.controls = true;
newMedia.autoplay = true;
break;
default:
return;
}
newMedia.id = `media-${publication.id}`;
stream.attach(newMedia); // 3-2-3
remoteMediaArea.appendChild(newMedia);
};
};
room.publications.forEach(subscribeAndAttach); // 1
room.onStreamPublished.add((e) => {
// 2
subscribeAndAttach(e.publication);
});
```
1. `room` の `publications` プロパティに、room に存在する `publication` の配列が入っています。この配列の各要素を、`subscribeAndAttach` 関数の引数に与えています。この関数については後ほど説明します。
2. `room` の `onStreamPublished` は `Event` 型のプロパティです。`Event` には、`add` という関数があります。この関数の引数にコールバック関数を渡すと、その room 内で誰かが publish された時点でコールバック関数が実行されます。コールバック関数の引数に入っているオブジェクトの `publication` プロパティに、publish された `publication` が存在していますので、これを `subscribeAndAttach` 関数に渡します。
3. `subscribeAndAttach` 関数を作成します。引数に publication を取ります。この publication が自分(me)が publish したものでない場合に、以降の処理を実行します。
3-1. publisher.id と publication の contentType(video or audio)をラベルにしたボタンを、ボタンエリアに追加します。
3-2. 3-1 で作成したボタンのイベントハンドラを作成します。
3-2-1. publication を subscribe します。すると `stream` が返却されます。
3-2-2. audio 要素 or video 要素を作成します。`newMedia` という名前の変数を作成し、 `stream.track.kind` が video であれば video 要素を、audio であれば audio 要素を作成し、それぞれ適切な属性を設定します。
3-2-3. `stream` を、先ほど作成した `newMedia`(audio 要素 or video 要素)にセットし、その後、`remoteMediaArea`(div 要素)に追加します。
#### 自分の退室処理を実装する
`Member` オブジェクトの `leave` 関数で `room` から退室します。退室後は `room` についての処理を行わないため、`dispose` 関数で `room` に関連するリソースを解放・破棄します。
```js
leaveButton.onclick = async () => {
await me.leave();
await room.dispose();
myId.textContent = "";
buttonArea.replaceChildren();
remoteMediaArea.replaceChildren();
};
```
#### 相手の退室処理を実装する
`onStreamPublished` と同様に、`room` の `onStreamUnublished` は `Event` 型のプロパティです。この関数の引数にコールバック関数を渡すと、その room 内で誰かの publication が unpublish された時点でコールバック関数が実行されます。相手が退室すると自動的に相手の publication が unpublish されるため、退室時もこのコールバック関数が実行されます。コールバック関数の引数に入っているオブジェクトの `publication` プロパティには unpublish された `publication` が存在しています。
```js
room.onStreamUnpublished.add((e) => {
document.getElementById(`subscribe-button-${e.publication.id}`)?.remove();
document.getElementById(`media-${e.publication.id}`)?.remove();
});
```
これで完成です。
アプリケーションの起動方法に従ってアプリケーションを起動して、複数の window で表示しましょう。
それぞれで同じルーム名を入力し `join` ボタンを押すと、room 内に存在する publication のボタンが表示されます。そのボタンを押すと、相手の映像と音声が表示されるはずです。
完成したアプリケーションを、[GitHub Pages](https://docs.github.com/ja/pages/getting-started-with-github-pages/about-github-pages)や[Netlify](https://www.netlify.com/)など、ホスティングサービスを利用してアップロードし、複数の端末からの接続を試してみましょう。
ライブラリの取得部分を除いたコード全体はこちら
_main.js_
```js
const token = new SkyWayAuthToken({
jti: uuidV4(),
iat: nowInSec(),
exp: nowInSec() + 60 * 60 * 24,
version: 3,
scope: {
appId: "ここにアプリケーションIDをペーストしてください",
rooms: [
{
name: "*",
methods: ["create", "close", "updateMetadata"],
member: {
name: "*",
methods: ["publish", "subscribe", "updateMetadata"],
},
},
],
},
}).encode("ここにシークレットキーをペーストしてください");
(async () => {
const localVideo = document.getElementById("local-video");
const buttonArea = document.getElementById("button-area");
const remoteMediaArea = document.getElementById("remote-media-area");
const roomNameInput = document.getElementById("room-name");
const myId = document.getElementById("my-id");
const joinButton = document.getElementById("join");
const leaveButton = document.getElementById("leave");
const { audio, video } =
await SkyWayStreamFactory.createMicrophoneAudioAndCameraStream();
video.attach(localVideo);
await localVideo.play();
joinButton.onclick = async () => {
if (roomNameInput.value === "") return;
const context = await SkyWayContext.Create(token);
const room = await SkyWayRoom.FindOrCreate(context, {
name: roomNameInput.value,
});
const me = await room.join();
myId.textContent = me.id;
await me.publish(audio, { type: "p2p" });
await me.publish(video, { type: "p2p" });
const subscribeAndAttach = (publication) => {
if (publication.publisher.id === me.id) return;
const subscribeButton = document.createElement("button");
subscribeButton.id = `subscribe-button-${publication.id}`;
subscribeButton.textContent = `${publication.publisher.id}: ${publication.contentType}`;
buttonArea.appendChild(subscribeButton);
subscribeButton.onclick = async () => {
const { stream } = await me.subscribe(publication.id);
let newMedia;
switch (stream.track.kind) {
case "video":
newMedia = document.createElement("video");
newMedia.playsInline = true;
newMedia.autoplay = true;
break;
case "audio":
newMedia = document.createElement("audio");
newMedia.controls = true;
newMedia.autoplay = true;
break;
default:
return;
}
newMedia.id = `media-${publication.id}`;
stream.attach(newMedia);
remoteMediaArea.appendChild(newMedia);
};
};
room.publications.forEach(subscribeAndAttach);
room.onStreamPublished.add((e) => subscribeAndAttach(e.publication));
leaveButton.onclick = async () => {
await me.leave();
await room.dispose();
myId.textContent = "";
buttonArea.replaceChildren();
remoteMediaArea.replaceChildren();
};
room.onStreamUnpublished.add((e) => {
document.getElementById(`subscribe-button-${e.publication.id}`)?.remove();
document.getElementById(`media-${e.publication.id}`)?.remove();
});
};
})();
```
---
## ユーザーガイド/JavaScript SDK/解放・破棄処理
Path: user-guide_javascript-sdk_release-and-dispose.md
# 解放・破棄処理
Room インスタンスおよび SkyWayContext インスタンスの利用を終了してリソースを解放するには、 [Room.dispose メソッド](https://javascript-sdk.api-reference.skyway.ntt.com/room/interfaces/Room.html#dispose) および [SkyWayContext.dispose メソッド](https://javascript-sdk.api-reference.skyway.ntt.com/core/classes/SkyWayContext.html#dispose) を使用します。
Room.dispose メソッドはその Room インスタンスに関するイベントリスナーや LocalMember のインスタンス、サーバとの通信を解放・破棄し、SkyWayContext.dispose メソッドは SkyWay SDK で使用しているすべてのイベントリスナーや Room インスタンス、サーバとの通信を解放・破棄します。
```js
const context = await SkyWayContext.Create(token);
const room = await SkyWayRoom.FindOrCreate(context, {
name: roomNameInput.value,
});
// 入室
const me = await room.join();
...
// 退出
await me.leave();
// Roomを含むリソースが不要になった
await room.dispose();
// SkyWay SDKに関するすべての操作が不要になった
context.dispose();
```
---
## ユーザーガイド/JavaScript SDK/バーチャル背景と背景ぼかし処理の実装
Path: user-guide_javascript-sdk_video-processing.md
# バーチャル背景と背景ぼかし処理の実装
SkyWay では、JavaScript/TypeScript を用いてブラウザ上でカメラから取得した映像の背景を加工するライブラリを提供しています。
カメラから取得した映像の背景を任意の画像に差し替えたり(以下では背景差し替え処理と呼びます)、背景へのぼかし処理(以下では背景ぼかし処理と呼びます)を行うことができます。
## 対応ブラウザ
以下ブラウザの直近 2 バージョンに対応しています。
- Chrome
- Edge
## インストール
以下のコマンドでインストールを行います。
```
npm install skyway-video-processors
```
## 使い方
以下の使い方の詳細は[Sample](https://github.com/skyway/skyway-video-processors/tree/main/example/simple)を参照してください。
任意の画像を利用して背景差し替え処理を行う `VirtualBackground` と、任意の強度で背景ぼかし処理を適用する `BlurBackground` の 2 つのクラスが存在します。
### VirtualBackground の使い方
`VirtualBackground` のインスタンスを作成します。
```ts
import { VirtualBackground } from "skyway-video-processors";
const backgroundProcessor = new VirtualBackground({ image: "green.png" });
```
インスタンスの初期化を行います。
```ts
await backgroundProcessor.initialize();
```
`createProcessedStream` によって、デバイスからの映像に対して背景差し替え処理を行った映像の `ProcessedStream` を取得できます。
`ProcessedStream` の track を用いて、背景差し替え処理を行った映像の `MediaStream` を作成できます。
```ts
const result = await backgroundProcessor.createProcessedStream();
const stream = new MediaStream([result.track]);
```
作成した `MediaStream` を `videoElement` の `srcObject` に割り当てることで映像を再生できます。
```ts
videoElement.srcObject = stream;
await videoElement.play();
```
### BlurBackground の使い方
`BlurBackground` のインスタンスを作成します。
```ts
import { BlurBackground } from "skyway-video-processors";
const backgroundProcessor = new BlurBackground();
```
インスタンスの初期化を行います。
```ts
await backgroundProcessor.initialize();
```
`createProcessedStream` によって、デバイスからの映像に対して背景ぼかし処理を行った映像の `ProcessedStream` を取得できます。
`ProcessedStream` の `track` を用いて、背景ぼかし処理を行った映像の `MediaStream` を作成できます。
```ts
const result = await backgroundProcessor.createProcessedStream();
const stream = new MediaStream([result.track]);
```
作成した `ProcessedStream` を `videoElement` の `srcObject` に割り当てることで映像を再生できます。
```ts
videoElement.srcObject = stream;
await videoElement.play();
```
## JavaScript SDKとの連携方法
バーチャル背景による加工を行った映像を SkyWay で送信する映像として利用することができます。
`VirtualBackground`, もしくは `BlurBackground` の初期化を行い、そのインスタンスを JavaScript SDK に引数として渡します。
```ts
const backgroundProcessor = new BlurBackground();
await backgroundProcessor.initialize();
const video = await SkyWayStreamFactory.createCustomVideoStream(backgroundProcessor, {
stopTrackWhenDisabled: true,
});
const me = await room.join();
await me.publish(video);
```
## API リファレンス
こちらに API リファレンスを公開しています。
- [API リファレンス](https://github.com/skyway/skyway-video-processors/tree/main#api)
## サンプル
こちらにサンプルアプリを公開しています。
- [バーチャル背景を利用したカメラ映像を取得するアプリケーション](https://github.com/skyway/skyway-video-processors/tree/main/example/simple)
- [バーチャル背景を利用してSkyWayで通話するアプリケーション](https://github.com/skyway/skyway-video-processors/tree/main/example/skyway-js-sdk)
---
## ユーザーガイド/JavaScript SDK/サポートブラウザ
Path: user-guide_javascript-sdk_browser.md
# サポートブラウザ
- PC
- Chrome
- Firefox
- Safari
- Edge
- スマートフォン/タブレット
- iOS/iPadOS
- Safari
- Chrome
- Firefox
- Edge
- Android
- Chrome
- Firefox
- Edge
- WebView
- SFSafariViewController
- WKWebView
- 標準ブラウザの機能外のカスタムを行う場合には必ずしも動作保証しない
- AndroidWebView
- 標準ブラウザの機能外のカスタムを行う場合には必ずしも動作保証しない
**サポートバージョン**
上記サポートブラウザ全てについて「安定版の最新 2 メジャーバージョン」とします。
---
## ユーザーガイド/JavaScript SDK/既知の問題
Path: user-guide_javascript-sdk_issues.md
# 既知の問題
## Bluetooth イヤホンを利用している際に Audio を扱う Publication の Disable/Enable を行うと再生中の音声が一瞬途切れる
SDK では Publication の Disable をする際に Stream と紐付いているメディアデバイスを解放し、Enable する際にメディアデバイスを再取得します。
これにより Publication を Disable している間は、PC のカメラインジゲータやマイクインジゲータを消灯することが出来ます。
Bluetooth イヤホンを利用している環境では音声デバイスの取得/解放時に Bluetooth イヤホン上の音声が途切れる場合があります。
この音声の途切れが許容できない場合は、SkyWayStreamFactory で LocalAudioStream を作成する際に次のオプションを指定してください。
ただし、このオプションを指定すると Publication の Disable 時にメディアデバイスの解放処理が行われなくなるのでご注意ください。
```ts
await SkyWayStreamFactory.createMicrophoneAudioStream({ stopTrackWhenDisabled: false });
```
## iOS Safari でブラウザのウィンドウやタブを閉じたとき、またはページを更新したとき Member が Room から leave しない
SDK ではブラウザのウィンドウやタブを閉じたとき、またはページを更新したときに [beforeunload イベント](https://developer.mozilla.org/ja/docs/Web/API/Window/beforeunload_event) を検知して Member を自動的に leave させます。しかし、iOS Safari は beforeunload イベントに対応していないため、これによる Member の leave が行われません。
代替手段として、[LocalMemberConfig](https://javascript-sdk.api-reference.skyway.ntt.com/room/types/LocalMemberConfig.html) の keepaliveIntervalSec(デフォルト値 30)と keepaliveIntervalGapSec(デフォルト値 30)を適切な値に設定することで Member が自動的に leave するタイミングをある程度コントロールできます。
Member の生存確認は keepaliveIntervalSec 秒ごとにクライアントからサーバーへの応答の有無で行われており、keepaliveIntervalSec 秒応答がないまま keepaliveIntervalGapSec 秒経過した場合 Member の leave が行われます。
そのため、例えば keepaliveIntervalSec を 30 秒、keepaliveIntervalGapSec を 5 秒とすることで、ブラウザのウィンドウを閉じたとき最短で 5 秒後、最長で 35 秒後に Member を自動的に leave させることができます。
Room ライブラリの場合
```ts
const context = await SkyWayContext.Create(token);
const room = await SkyWayRoom.FindOrCreate(context, {
name: 'sample-room',
});
const me = await room.join({
keepaliveIntervalSec: 30,
keepaliveIntervalGapSec: 5,
});
```
---
## ユーザーガイド/iOS SDK/概要
Path: user-guide_ios-sdk_overview.md
# SkyWay iOS SDK の概要
SkyWay iOS SDK (以下、iOS SDK )は iOS デバイス用のアプリケーションから SkyWay を利用するための SDK です。
iOS のネイティブなアプリケーションに SkyWay を組み込むことで、デバイス同士やブラウザとのリアルタイム通信を実現できます。
## 対応環境
| 項目 | iOS SDKの対応状況 |
| ----------------- | ---------------------------------------- |
| OS | iOS 14, iPadOS 14 以降 |
| CPUアーキテクチャ | arm64, x86_64※ |
| IDE | Xcode 16 以降 |
※iPhone Simulator 環境でのビルドも対応はしていますが、動作未保証です。
## アプリケーション開発言語
Swift
## ライブラリの仕様
SkyWay を利用する上で理解する必要のある基本的な仕様について説明します。
### Room
通話を行うグループの単位であり、ユーザーは共通の Room に参加したユーザー同士で通話を行います。
メディア通信毎に P2P と SFU の方式を選択できます。
また事前に Room 内での通信方式を定めておくことも可能です。
- P2P は少人数向け
- 上限人数に制限はありませんが、ユーザーが快適に通話できる人数は 4 人までです
- SFU は多人数向け
- SFU サーバーを経由してメディア通信を行います
### Member
Room に参加しているユーザーのことを Member と呼びます。
### Stream
Room 上で送受信できるメディアのことを Stream といいます。以下の 3 種類の Stream を利用できます。
- AudioStream
- ユーザーのマイク音声など
- VideoStream
- ユーザーのカメラ映像など
- DataStream
- 任意のメッセージ
- SFUを用いた通信では利用できません
### Publish
Member が Stream を Room に公開することを Publish といいます。
Stream を Publish すると Room 上に Stream に対応する Publication というリソースが作成されます。
### Subscribe
Member が Room 上の Publication を受信することを Subscribe といいます。
Subscribe をすると Room 上に Subscription というリソースが作成されます。
Publication を Subscribe した Member は Subscription を通じて Stream にアクセスし映像や音声を受信できます。
### SkyWay Auth Token
SkyWay Auth Token は、SkyWay を利用するために必要な JWT(JSON Web Token)形式のトークンです。
ユーザー毎に権限を細かく設定することでき、例えば Room ごとの入室を特定ユーザーに制限する、といったことができます。
SkyWay Auth Token を利用するためには、これを払い出すアプリケーションサーバーを構築する必要があります。SkyWay SDK を利用したクライアントアプリは、アプリケーションサーバーから SkyWay Auth Token を取得し、これを用いて各種 SkyWay の機能を利用します。
なお、サーバーを構築せずにフロントエンドで SkyWay Auth Token を生成した場合、シークレットキーをエンドユーザーが取得できるため、権限の制限が機能せず注意する必要があります。
## SDK のダウンロード
Swift Package Manager と CocoaPods 、 GitHub のリリースで配布を行なっています。
### Swift Package Manager
以下のリポジトリで公開しています。
- https://github.com/skyway/ios-sdk.git
### CocoaPods
Pod Specs は独自に管理しています。
CocoaPodsがインストールされている環境でリポジトリを追加してください
```
$ pod repo add skyway-ios-sdk-specs https://github.com/skyway/skyway-ios-sdk-specs.git
$ pod repo add skyway-ios-webrtc-specs https://github.com/skyway/skyway-ios-webrtc-specs.git
$ pod repo update
```
`Podfile` に以下のソースを追加してください。
```
source 'https://github.com/skyway/skyway-ios-sdk-specs.git'
source 'https://github.com/skyway/skyway-ios-webrtc-specs.git'
source 'https://github.com/CocoaPods/Specs.git'
```
インストールするライブラリを以下のように記述します。
```
pod 'SkyWayRoom'
```
`Podfile` の全体は以下のようになります。
```
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
source 'https://github.com/skyway/skyway-ios-sdk-specs.git'
source 'https://github.com/skyway/skyway-ios-webrtc-specs.git'
source 'https://github.com/CocoaPods/Specs.git'
target 'CocoaPodSample' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for CocoaPodSample
pod 'SkyWayRoom'
end
```
`pod install` でインストールします。
```
$ pod install
```
### GitHub のリリース
以下のリポジトリでリリースノートと xcframework を公開しています。
- https://github.com/skyway/ios-sdk/releases/latest
ダウンロード後、 zip ファイルを解凍し、 xcframework をプロジェクトに配置してください。
## 旧iOS SDK(SkyWay.framework)との互換性と共存
互換性はありません。
1つのアプリで新旧 SDK を共存(リンク)することは v1.2.1 から可能です。
---
## ユーザーガイド/iOS SDK/クイックスタート
Path: user-guide_ios-sdk_quickstart.md
# 🚀 クイックスタート
SkyWay のメディア通信を体験できるシンプルなサンプルアプリケーションを作成します。
本チュートリアルでは SFU でのメディア通信を使用します。
ここでは、iPhone のマイク音源とカメラ映像を SFU サーバーに送信し、それぞれを自分が受信して音声を再生と映像の描画するというアプリケーションを作ります。
このクイックスタートの実行には iPhone 実機が必要です。
完成品は https://github.com/skyway/ios-sdk/tree/main/Tutorial にあります。
## 開発環境
- Xcode 26.0.1
- iOS 26.0.1
## アプリケーション ID とシークレットキーの取得
※SkyWay への登録がまだの方は[こちら](https://console.skyway.ntt.com/login/)から
SkyWay コンソールへログインし、以下の 3 つを行います。
1. 「アプリケーションを作成」ボタンを押す

2. アプリケーション名を入力して作成ボタンを押す
3. アプリケーション一覧からアプリケーション ID とシークレットキーをコピーする
## SkyWay Auth Token の作成
SkyWay を利用するためには、初めに JWT(JSON Web Token)を用いて `Context` を初期化します。
SkyWay Auth Token は本来サーバーサイドで生成するため、 iOS SDK にはトークンの生成機能はございません。
クイックスタートでは、 Dev 環境専用の API である `Context.setupForDev(withAppId:secretKey:options:completion:)` を用いて初期化するため、 SkyWay Auth Token の作成は省略します。
認証認可について、詳しくは[こちら](/ja/docs/user-guide/authentication/)をご覧ください。
## XcodeProjectの作成・フレームワークの設定
新規で Xcodeproject を作成してください。
作成時、Interface は `Storyboard` を選択してください。

## パーミッションの設定
`info.plist` の `Privacy - Microphone Usage Description` と `Privacy - Camera Usage Description` を追加して、value にはユーザーに利用許可を確認するプロンプトのメッセージを登録してください。
ここでは、`マイクを利用します` と `カメラを利用します` と登録します。

## SDKのダウンロード
今回は Swift Package Manager にてダウンロードします。
Xcode から Project を選択し、 Package Dependencies を選択します。
左下 `+` ボタンからパッケージ検索のモーダルを表示させ、右上の URL 検索ボックスに `https://github.com/skyway/ios-sdk.git` と入力します。
Package Product `SkyWayRoom` がチェックされていることを確認し、 Add Package を押下します。
## 映像ビューのセットアップ
今回は、カメラからキャプチャしている Local の View (プレビュー)と SFU サーバーから受信した Remote の View を描画します。
Storyboard を使って解説します。
まず、View コンポーネントを作成し、ViewController 直下の View に追加します。

View の名前を `Local View` にリネームします。

この View の Custom Class の設定で Class 名を `SKWCameraPreviewView` に設定します。
この View を複製して、`Remote View` にリネームします。

この View の Custom Class の設定で Class 名を `SKWVideoView` に設定します。
適宜 Auto Layout を利用して View の constraint を設定します。
上側を LocalView, 下側を RemoteView に配置します。

IBOutlet を利用して `Local View` と `Remote View` をそれぞれ変数宣言します。この時、Type は `SKW` を消した `CameraPreviewView` と `VideoView` 宣言してください。
```
デフォルトでは`SKW`プレフィックスがついているのでご注意ください。
```


## Contextのセットアップ
ここでは、簡易的に Initial ViewController の `viewDidLoad` に SkyWay のロジックを記述していきます。
```swift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Impl here
}
}
```
`import SkyWayRoom` でフレームワークを import してください。
```swift
import UIKit
import SkyWayRoom
class ViewController: UIViewController {
```
アプリケーション ID とシークレットキーをメンバー変数で宣言します。
`Context.setupForDev(withAppId:secretKey:options:completion:)` で SkyWay のセットアップを行います。
`completion` にて失敗した場合は Error が返ります。ここでは async/await 形式で記述します。
> `Context.setupForDev(withAppId:secretKey:options:completion:)` は Dev 環境での利用が想定されている API です。
> 本番環境では、SecretKeyを秘匿するため `Context.setup(withToken:options:completion:)` をご利用ください。
```swift
override func viewDidLoad() {
super.viewDidLoad()
Task {
let appId = "アプリケーションIDを入力してください"
let secretKey = "シークレットキーを入力してください"
// SkyWayのセットアップ
try? await Context.setupForDev(withAppId: appId, secretKey: secretKey, options: contextOpt)
```
## Roomの作成
SkyWay のセットアップが完了したら Room を作成します。
`Room.create(with:completion:)` で Room を作成できます。
```swift
let roomInit: Room.InitOptions = .init()
guard let room: Room = try? await .create(with: roomInit) else {
print("[Tutorial] Creating room failed.")
return
}
```
## Roomへの参加
`Room.join(with:completion:)` でルームに参加し、メンバーを作成します。
```swift
let memberInit: Room.MemberInitOptions = .init()
memberInit.name = "Alice" // Memberに名前を付けることができます
guard let member = try? await room.join(with: memberInit) else {
print("[Tutorial] Join failed.")
return
}
```
## マイク音源のAudioStreamの作成とRoomへのPublish
マイクを音声入力として Stream を作成します。
Publish をするための LocalStream を作成するためには、Source が必要です。
`MicrophoneAudioSource` のイニシャライザから Source を作成し、`createStream()` で LocalStream を作成します。
通信方式は P2P とメディアサーバーを介する SFU がありますが、今回は SFU を利用します。
通信方式は `RoomPublicationOptions` の `type` プロパティで指定できます。
`LocalRoomMember.publish(_:options:completion:)` で Room に Publish します。
```swift
// AudioStreamの作成
let audioSource: MicrophoneAudioSource = .init()
let audioStream = audioSource.createStream()
let audioPublicationOptions: RoomPublicationOptions = .init()
audioPublicationOptions.type = .SFU
guard let audioPublication = try? await member.publish(audioStream, options: audioPublicationOptions) else {
print("[Tutorial] Publishing failed.")
return
}
```
## AudioStreamのSubscribe
先ほど Publish した Stream を `LocalRoomMember.subscribe(publicationId:options:completion:)` を利用して、Subscribe して Stream を受け取ります。
PublicationID は `RoomPublication` の `id` で取得できます。
```
※P2P方式では、自分のPublishしたStreamをSubscribeできませんのでご注意ください
```
```swift
// Audioの場合、subscribeした時から音声が流れます
guard let _ = try? await member.subscribe(publicationId: audioPublication.id, options: nil) else {
print("[Tutorial] Subscribing failed.")
return
}
print("🎉Subscribing audio stream successfully.")
```
## カメラの設定とプレビューの描画
カメラ映像ソースの場合は**カメラの設定とキャプチャ操作が必要です。**
`CameraVideoSource.supportedCameras()` で SkyWay がサポートしているカメラの一覧を取得できます。
今回は前面カメラデバイスを取得します。
```swift
// Cameraの設定
guard let camera = CameraVideoSource.supportedCameras().first(where: { $0.position == .front }) else {
print("Supported cameras is not found.");
return
}
```
`CameraVideoSource.shared().startCapturing(with:options:completion:)` でキャプチャーを開始します。
```swift
// キャプチャーの開始
try! await CameraVideoSource.shared().startCapturing(with: camera, options: nil)
```
確認用に `CameraVideoSource.shared().attach(localView)` でキャプチャリングをしているカメラ映像を描画します。
```swift
// Previewの描画
CameraVideoSource.shared().attach(localView)
```
## カメラ映像ソースのVideoStreamの作成とRoomへのPublish
Stream は `CameraVideoSource.shared().createStream()` で作成できます。
AudioStream 同様、`publish(_:options:completion:)` で Publish を行います。
```swift
// VideoStreamの作成
let localVideoStream = CameraVideoSource.shared().createStream()
let videoPublicationOptions: RoomPublicationOptions = .init()
videoPublicationOptions.type = .SFU
guard let videoPublication = try? await member.publish(localVideoStream, options: videoPublicationOptions) else {
print("[Tutorial] Publishing failed.")
return
}
```
## VideoStreamのSubscribe
AudioStream 同様、`subscribe(publicationId:completion:)` を利用して、Subscribe して Stream を受け取ります。
```swift
guard let videoSubscription = try? await member.subscribe(publicationId: videoPublication.id, options: nil) else {
print("[Tutorial] Subscribing failed.")
return
}
print("🎉Subscribing video stream successfully.")
```
## RemoteViewの描画
Subscription の `stream` を取得し、`RemoteVideoStream` にキャストします。
`attach(_)` で `remoteView` を指定することで、SFU から受信した映像を描画できます。
```swift
let remoteVideoStream = videoSubscription.stream as! RemoteVideoStream
remoteVideoStream.attach(remoteView)
```
## Tutorial完成コード
```swift
import UIKit
import SkyWayRoom
class ViewController: UIViewController {
@IBOutlet weak var localView: CameraPreviewView!
@IBOutlet weak var remoteView: VideoView!
override func viewDidLoad() {
super.viewDidLoad()
Task {
let appId = "アプリケーションIDを入力してください"
let secretKey = "シークレットキーを入力してください"
// SkyWayのセットアップ
let contextOpt: ContextOptions = .init()
contextOpt.logLevel = .trace
try? await Context.setupForDev(withAppId: appId, secretKey: secretKey, options: contextOpt)
let roomInit: Room.InitOptions = .init()
guard let room: Room = try? await .create(with: roomInit) else {
print("[Tutorial] Creating room failed.")
return
}
let memberInit: Room.MemberInitOptions = .init()
memberInit.name = "Alice" // Memberに名前を付けることができます
guard let member = try? await room.join(with: memberInit) else {
print("[Tutorial] Join failed.")
return
}
// AudioStreamの作成
let auidoSource: MicrophoneAudioSource = .init()
let audioStream = auidoSource.createStream()
let audioPublicationOptions: RoomPublicationOptions = .init()
audioPublicationOptions.type = .SFU
guard let audioPublication = try? await member.publish(audioStream, options: audioPublicationOptions) else {
print("[Tutorial] Publishing failed.")
return
}
// Audioの場合、subscribeした時から音声が流れます
guard let _ = try? await member.subscribe(publicationId: audioPublication.id, options: nil) else {
print("[Tutorial] Subscribing failed.")
return
}
print("🎉Subscribing audio stream successfully.")
// Cameraの設定
guard let camera = CameraVideoSource.supportedCameras().first(where: { $0.position == .front }) else {
print("Supported cameras is not found.");
return
}
// キャプチャーの開始
try! await CameraVideoSource.shared().startCapturing(with: camera, options: nil)
// Previewの描画
CameraVideoSource.shared().attach(localView)
// VideoStreamの作成
let localVideoStream = CameraVideoSource.shared().createStream()
let videoPublicationOptions: RoomPublicationOptions = .init()
videoPublicationOptions.type = .SFU
guard let videoPublication = try? await member.publish(localVideoStream, options: videoPublicationOptions) else {
print("[Tutorial] Publishing failed.")
return
}
guard let videoSubscription = try? await member.subscribe(publicationId: videoPublication.id, options: nil) else {
print("[Tutorial] Subscribing failed.")
return
}
print("🎉Subscribing video stream successfully.")
let remoteVideoStream = videoSubscription.stream as! RemoteVideoStream
remoteVideoStream.attach(remoteView)
}
}
}
```
## 実行
iPhone(実機)にて Run します。
```
iPhone Simulatorではカメラが利用できないので実機にて実行してください。
```
iPhone 実機に声をかけたり音声を鳴らしてみてください。音声が出力され、LocalView と RemoteView に映像が描画されれば成功です。
## 次のステップ
今回は SFU サーバーを介して自分が Publish したメディアを Subscribe するというシンプルなものでした。
次は、他のクライアントと映像・音声・データをやりとりしてみましょう。他のクライアントと疎通できるサンプルアプリケーションを用意しています。
[サンプルコード](/ja/docs/sample-code/ios-sdk/)
また、開発の前に開発ドキュメントもご一読ください。
[iOS SDKの開発ドキュメント](/ja/docs/user-guide/ios-sdk/)
---
## ユーザーガイド/iOS SDK/音声・映像入力ソースと LocalStream の作成方法
Path: user-guide_ios-sdk_media-source-and-stream.md
# 音声・映像入力ソースと LocalStream の作成方法
Publish をするためには、音声・映像入力ソースまたはデータソースと紐付いた LocalStream が必要です。
ここでは、音声・映像入力ソースに対して LocalStream をどのように作るか説明します。
## 概要
LocalStream を作る操作は以下の流れで行います。
1. ソースの作成
2. (一部ソースのみ)ソースのキャプチャ処理開始
3. ソースから LocalStream を作成
## 音声ソース
### マイク入力ソース
現在、マイク入力ソースのみ対応しています。
マイクを利用する場合は `info.plist` の `Privacy - Microphone Usage Description` を追加して、value にはユーザーにマイク利用許可を確認するプロンプトのメッセージを登録してください。
マイク入力ソースは `MicrophoneAudioSource.init()` で作成できます。
このソースから `createStream()` で LocalStream を作成できます。
```swift
let audioSource: MicrophoneAudioSource = .init()
let localSteam: LocalAudioStream = audioSource.createStream()
```
**後述の映像ソースで必要なキャプチャの操作は不要です。**
Subscribe され次第、マイクから音声がキャプチャされます。
## 映像ソース
### カメラソース
本体のカメラ(前面・背面)入力から LocalStream を作成します。
カメラを利用する場合は `info.plist` の `Privacy - Camera Usage Description` を追加して、value にはユーザーにカメラ利用許可を確認するプロンプトのメッセージを登録してください。
カメラ入力ソースは、`CameraVideoSource.shared()` で取得できます。
このソースはキャプチャが同時に1つしかできないため、シングルトンインスタンスで管理しています。
次に、カメラの設定を行います。
SkyWay SDK がサポートしているカメラの一覧から、キャプチャを行うカメラを設定できます。
`supportedCameras()` から一覧取得できます。
例えば、前面カメラの場合は以下のようなコードで取得できます。
```swift
let frontCam: AVCaptureDevice? = CameraVideoSource.supportedCameras().first(where: { $0.position == .front })
```
```
※iPhone Simulatorでは利用できるカメラが存在しないことに注意してください。
```
`startCapturing(with:options:completion:)` でキャプチャを開始する必要があります。
```swift
try? await CameraVideoSource.shared().startCapturing(with:frontCam, options:nil)
```
このソースから `createStream()` で LocalStream を作成できます。
```swift
let stream = CameraVideoSource.shared().createStream()
```
```
※キャプチャ開始は、`createStream()`の後に任意のタイミングで開始させることもできますが、キャプチャを開始し忘れた場合、SubscriberがStreamを受け取っても映像が描画されませんので注意してください。
```
#### カメラデバイスの変更による映像切り替え
カメラデバイスの変更は Unpublish->新しいソースの LocalStream の作成->Subscribe といったことをさせず、ソースのみ切り替えることができます。
`CameraVideoSource` の `change(_:)` をコールすることで、映像描画中でもカメラデバイス変更できます。
#### カメラ映像のプレビュー
自分自身がカメラ映像を Publish する前にプレビューを確認したいユースケースの場合などの場合は、`CameraVideoSource.shared().attach(_:)` で `CameraPreviewView` に描画できます。
### 動画ファイルソース
アプリ内のアセットにある動画ファイルの映像から、LocalStream を作成します。
`FileVideoSource.init(filename:)` から拡張子まで含めたファイル名でインスタンスを生成します。
```swift
let fileSource: FileVideoSource = .init(filename: "hoge.mp4")
```
`startCapturing(onError:)` でキャプチャを開始する必要があります。
```swift
fileSource.startCapturing(onError: nil)
```
このソースから `createStream()` で LocalStream を作成できます。
```swift
let stream = fileSource.createStream()
```
### 任意の画像フレームソース
`CMSampleBuffer` 型の画像データを連続的に更新し、その映像ソースから LocalStream を作成します。
`CustomFrameVideoSource.init()` でインスタンスを作成します。
```swift
let frameSource: CustomFrameVideoSource = .init()
```
このソースから `createStream()` で LocalStream を作成できます。
```swift
let stream = frameSource.createStream()
```
キャプチャループ内などで `updateFrame(with:)` をコールして画像を更新します。
```
{
// フレーム更新ループ内などで
frameSource.updateFrame(with:buffer)
}
```
#### 画面共有
ReplayKit と組み合わせることで、アプリ内の画面共有を行うことができます。
```swift
let source: CustomFrameVideoSource = .init()
RPScreenRecorder.shared().startCapture { buffer, _, err in
guard err == nil else {
return
}
source.updateFrame(with: buffer)
} completionHandler: { _ in }
stream = source.createStream()
```
---
## ユーザーガイド/iOS SDK/解放・破棄処理
Path: user-guide_ios-sdk_release-and-dispose.md
# 解放・破棄処理
リソースとは、SDK で生成される全てのインスタンスおよびそのメモリを指します。
## Room の管理
Room インスタンスは操作不要な状態になるまでアプリケーションで管理してください。
OK
```swift
let room: Room? = try? await .find(by: query)
// 入室
let member: LocalRoomMember = try? await room?.join(with: nil)
...
// 退出
try? await member.leave()
// Roomを含むリソースが不要になった
await room.dispose()
room = nil
```
NG
```swift
let room: Room? = try? await .find(by: query)
// 入室
let member: LocalRoomMember = try? await room?.join(with: nil)
...
// 破棄
room = nil
// 危険: クラッシュする可能性があります
try? await member.publsh(stream, options: nil)
```
### Room を閉じた後の挙動
誰かが明示的に Room を閉じたときに Member が入室していた場合、 Publish と Subscribe を中止して退出します。
Room を閉じた後にそこで生成されたリソースの操作はエラーになります。
### SkyWayを終了する
アプリケーションにおいて SkyWay の機能を利用しなくなった場合、`Context.dispose()` をコールすることで SkyWay サーバーとの通信を切断し、SDK で管理している全てのリソースを破棄します。
事前に、Member の Room 退出処理を行ってください。
また、`Context.dispose()` をコールした後、それまで生成したリソース(インスタンス)にアクセスしないでください。
アクセスした場合の挙動は未定義でアプリケーションがクラッシュする可能性があります。
`dispose()` 後に再度 `setup(withToken:options:completion:)` することで再度 SkyWay サーバーと接続できます。
---
## ユーザーガイド/iOS SDK/Tips
Path: user-guide_ios-sdk_tips.md
# Tips
開発に関するヒント、注意点を掲載しています。
## SKWプレフィックスについて
一部 API は Objective-C++ 言語で実装されているためコーディング規約として `SKW` プレフィックスを付与しています。
Swift アプリケーションからは `NS_SWIFT_NAME` で `SKW` プレフィックスなしで設定していますが、Storyboard や Interface Builder などをご利用いただく際などに `SKW` プレフィックスで設定するケースがあります。
---
## ユーザーガイド/iOS SDK/既知の問題
Path: user-guide_ios-sdk_issues.md
# 既知の問題
## Xcode14以上において、Context.setup(withToken:options:completion) をするとThread Performance Checkerのログが表示される
```
v1.2.1 にて修正されました。
```
依存ライブラリである Socket Rocket によるものです。
https://github.com/facebookincubator/SocketRocket/issues/648
## Class XXX is implemented in both...のログが表示される
```
v1.2.0 にて修正されました。
```
内部で利用している WebRTC ライブラリのシンボルが衝突していることによるものです。
動作には影響ありません。
---
## ユーザーガイド/Android SDK/概要
Path: user-guide_android-sdk_overview.md
# SkyWay Android SDK の概要
SkyWay Android SDK(以下、Android SDK)は Android デバイス用のアプリケーションから SkyWay を利用するための SDK です。
Android のネイティブなアプリケーションに SkyWay を組み込むことで、デバイス同士やブラウザとのリアルタイム通信を実現できます。
このセクションでは、Android SDK の動作環境や入手方法を掲載しています。
Android SDK の採用を検討する際の参考情報としてください。
## 対応環境
| 項目 | SkyWay Android SDKの対応状況 |
| ----------------- | ---------------------------------------- |
| OS | Android 5.0 Lollipop(API Level 21)以降 |
| CPUアーキテクチャ | arm64-v8a、armeabi-v7a、x86_64、x86 |
| 推奨するIDE | Android Studio |
`Android SDK v2.2.1 から 64-bit アーキテクチャ(arm64v8a & x86_64) における 16KB Page Sizeに対応済です。`
※原則として、一般のスマートフォン上での動作、またはエミュレータによる動作検証を想定しています。
## アプリケーション開発言語
- Kotlin
Kotlin は Android アプリケーション開発の公式でサポート言語であり(2023年現在)、Android Studio のような開発環境で利用できます。
## ライブラリの仕様
SkyWay を利用する上で理解する必要のある基本的な仕様について説明します。
### Room
通話を行うグループの単位であり、ユーザーは共通の Room に参加したユーザー同士で通話を行います。
メディア通信毎に P2P と SFU の方式を選択できます。
また事前に Room 内での通信方式を定めておくことも可能です。
- P2P は少人数向け
- 上限人数に制限はありませんが、ユーザーが快適に通話できる人数は 4 人までです
- SFU は多人数向け
- SFU サーバーを経由してメディア通信を行います
### Member
Room に参加しているユーザーのことを Member と呼びます。
### Stream
Room 上で送受信できるメディアのことを Stream といいます。以下の 3 種類の Stream を利用できます。
- AudioStream
- ユーザーのマイク音声など
- VideoStream
- ユーザーのカメラ映像など
- DataStream
- 任意のメッセージ
- SFU を用いた通信では利用できません
### Publish
Member が Stream を Room に公開することを Publish といいます。
Stream を Publish すると Room 上に Stream に対応する Publication というリソースが作成されます。
### Subscribe
Member が Room 上の Publication を受信することを Subscribe といいます。
Subscribe をすると Room 上に Subscription というリソースが作成されます。
Publication を Subscribe した Member は Subscription を通じて Stream にアクセスし映像や音声を受信できます。
### SkyWay Auth Token
SkyWay Auth Token は、SkyWay を利用するために必要な JWT(JSON Web Token)形式のトークンです。
ユーザー毎に権限を細かく設定することでき、例えば Room ごとの入室を特定ユーザーに制限する、といったことができます。
SkyWay Auth Token を利用するためには、これを払い出すアプリケーションサーバーを構築する必要があります。SkyWay SDK を利用したクライアントアプリは、アプリケーションサーバーから SkyWay Auth Token を取得し、これを用いて各種 SkyWay の機能を利用します。
なお、サーバーを構築せずにフロントエンドで SkyWay Auth Token を生成した場合、シークレットキーをエンドユーザーが取得できるため、権限の制限が機能せず注意する必要があります。
## SDK のダウンロード
Maven Central Repository にて配布を行なっています。
導入先の app/build.gradle にて、以下の依存関係を追記してください。
```
// 最新の SDK バージョンに差し替えてください
// 最新の SDK バージョン情報は以下のリンクより、Maven Central Repository にて確認できます
// https://central.sonatype.com/search?q=skyway
def skywayVersion = 'x.x.x'
dependencies {
implementation "com.ntt.skyway:room:$skywayVersion"
}
```
## 旧Android SDK(skyway.aar)との互換性と共存
互換性はありません。
1つのアプリで新旧 SDK を共存することは v4.0.2 から可能です。
---
## ユーザーガイド/Android SDK/クイックスタート(Android View)
Path: user-guide_android-sdk_quickstart.md
# 🚀 クイックスタート(Android View)
このセクションでは、SkyWay Android SDK を利用した最小限の Android View をベースとするアプリケーションを開発する方法について掲載しています。
はじめて Android SDK を利用する方はこちらを参考に導入してください。
完成品は [公式リポジトリ](https://github.com/skyway/android-sdk/tree/main/examples/AndroidView/QuickStart) にて公開しています。
尚、この記事は以下を前提に構成しています。
- Activity を用いたアプリ開発経験があること
- Kotlin の文法(関数、変数定義、呼び出し、コルーチンなど)がわかること
上記については Android Developers などを参考にしてください。
## アプリの概要
このアプリには以下のシンプルな通話機能をP2Pによって実装します。
1) ユーザーはルーム名を指定して入室できる
2) ユーザーがパーミッションの要求を許可すれば、入室と同時に同じルームのメンバーに対してカメラ映像とマイク音声を配信する
3) ユーザーは入室時から同じルームに入室しているユーザーのマイク音声とカメラ映像を視聴できる
## Android プロジェクト の作成
Android Developers の公式ウェブサイトを参考に、Android プロジェクトを作成します。
https://developer.android.com/training/basics/firstapp/creating-project?hl=ja
「Language」は kotlin を選択してください。また、「Minimum SDK」は Android 6.0(API Level: 23) 以降を選択してください。
## Android SDK のインストール
`app/build.gradle` に以下の依存関係を追加するだけでSDKのインストールは完了です。
> このセクションではgradleファイルをGroovyによって記述しています。
> Kotlin DSLによる記述方法は[クイックスタート(JetPack Compose)](https://skyway.ntt.com/ja/docs/user-guide/android-sdk/quickstart-compose/)をご参照ください。
```java
// 最新の SDK バージョンに差し替えてください
// 最新の SDK バージョン情報は以下のリンクより、Maven Central Repository にて確認できます
// https://central.sonatype.com/search?q=skyway
def skywayVersion = 'x.x.x'
dependencies {
// ... 省略
implementation 'com.ntt.skyway:room:$skywayVersion'
}
```
## パーミッションの設定
Android SDK の動作に必要なパーミッションを `app/src/main/AndroidManifest.xml` に記述します。
以下に、映像・音声の通信をする際に必要なパーミッションの例を示します。
```xml
```
## レイアウトの設定
`res/layout/activity_main.xml` に表示したいコンポーネントを記述します。
### Video 表示コンポーネントの配置する
"ローカルのビデオ"には自身の映像、"リモートのビデオ"には通話相手の映像を映します。
初期状態から以下のように変更します。
```xml
```
### ルーム名の表示枠と参加ボタンを作成する
Video 表示コンポーネントの下にルーム名の表示枠と参加ボタンを追加します。
```xml
```
## SkyWay Auth Token の作成
SkyWay を利用するためには、初めに JWT(JSON Web Token) を用いて `SkyWayContext` を初期化します。
SkyWay Auth Token は本来サーバーサイドで生成するため、Android SDK にはトークンの生成機能はございません。
クイックスタートでは、Dev環境専用のAPIである `SkyWayContext.setupForDev` を用いて初期化するため、SkyWay Auth Tokenの作成は省略します。
認証認可について、詳しくは[こちら](/ja/docs/user-guide/authentication/)をご覧ください。
## 機能の実装
`MainActivity` クラスを編集します。
```kotlin
//プロジェクト作成時に決めたパッケージ名にしてください
package YOUR.SKYWAY.QUICKSTART
import ... //省略
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
```
以降は `MainActivity` クラスに機能を実装します。
### SkyWayContext, メンバの初期化
`MainActivity` クラスから `SkyWayContext.Options` を設定します。
また、後ほど必要になるメンバをまとめて宣言しておきます。
```kotlin
class MainActivity : AppCompatActivity() {
// SkyWayContext.Optionsの設定
private val option = SkyWayContext.Options(
logLevel = Logger.LogLevel.VERBOSE
)
// メンバの宣言
private val appId = "YOUR_APP_ID"
private val secretKey = "YOUR_SECRET_KEY"
private val scope = CoroutineScope(Dispatchers.IO)
private var localRoomMember : LocalRoomMember? = null
private var room : Room? = null
private var localVideoStream : LocalVideoStream? = null
private var localAudioStream : LocalAudioStream? = null
override fun onCreate(savedInstanceState: Bundle?) {
}
}
```
### UIの初期化
`initUI()` 関数を作成し、 `onCreate()` から呼び出します。
この関数は `activity_main.xml` で記述したレイアウトの初期値を設定します。
```kotlin
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// UIの初期化
initUI()
}
// roomNameの初期値を生成する
private fun initUI() {
val roomName = findViewById(R.id.roomName)
roomName.text = UUID.randomUUID().toString()
}
}
```
### パーミッションの要求
カメラやマイクから入力を受け取る前に、アプリケーションにはデバイスを使う権限が必要です。
`onCreate()` に以下を追記して権限を要求します。
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
// ... 省略
// UIの初期化
initUI()
// 権限の要求
if (ContextCompat.checkSelfPermission(
applicationContext,
Manifest.permission.CAMERA
) != PermissionChecker.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(
applicationContext,
Manifest.permission.RECORD_AUDIO
) != PermissionChecker.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
),
0
)
}
}
```
### JOINボタンのハンドラを作成する
`onCreate()` で `activity_main.xml` で定義したJOINボタンの動作を設定し、`joinAndPublish()` 関数を作成します。
以降の項目では `JoinAndPublish()` に機能を実装しています。
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
// ... 省略
// JOINボタンの動作を設定
val btnJoinRoom = findViewById