{"id":25117867,"url":"https://github.com/openayame/ayame-spec","last_synced_at":"2025-06-30T06:08:36.942Z","repository":{"id":98588189,"uuid":"311018296","full_name":"OpenAyame/ayame-spec","owner":"OpenAyame","description":"WebRTC Signaling Server Ayame Spec","archived":false,"fork":false,"pushed_at":"2025-04-21T01:05:18.000Z","size":20,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-22T17:11:10.795Z","etag":null,"topics":["p2p","webrtc","websocket"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenAyame.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-08T08:35:25.000Z","updated_at":"2025-04-21T01:05:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"d12ceb9e-c9a5-496c-91ee-18e816c1207c","html_url":"https://github.com/OpenAyame/ayame-spec","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/OpenAyame/ayame-spec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAyame%2Fayame-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAyame%2Fayame-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAyame%2Fayame-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAyame%2Fayame-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenAyame","download_url":"https://codeload.github.com/OpenAyame/ayame-spec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenAyame%2Fayame-spec/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262720641,"owners_count":23353450,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["p2p","webrtc","websocket"],"created_at":"2025-02-08T03:34:48.478Z","updated_at":"2025-06-30T06:08:36.922Z","avatar_url":"https://github.com/OpenAyame.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebRTC Signaling Server Ayame 仕様\n\n## 概要\n\nこれは WebRTC P2P で利用するためのシグナリングサーバ向けの仕様です。\nオープンソースとして公開されている https://github.com/OpenAyame/ayame はこの仕様に準拠して実装されています\n\n## 注意\n\n- 開発者向けの仕様書です\n\n## シグナリング\n\nAyame の `ws://192.0.2.100:3000/signaling` がクライアントからの WebSocket 接続を確立し、管理するエンドポイントとなります。\n\nこのエンドポイントに WebSocket で接続すると、Ayame は接続したクライアントの接続を保持します。\n\nこのシグナリングサーバは 1 対 1 専用のため、3 つ以上のクライアントの接続要求は拒否します。\n\nAyame は WebSocket で接続しているクライアントのうちどれかからデータが来ると、\n送信元のクライアント以外の接続済みのクライアントにデータを *そのまま* WebSocket で送信します。これらはすべて非同期で行われます。\n\n### 接続確立までのシーケンス図\n\n- Ayame が互いのSDP 交換や peer connection の接続をシグナリングによってやり取りします。\n- SDP とは WebRTC の接続に必要な peer connection の 内部情報です。\n    - [RFC 4566 \\- SDP: Session Description Protocol](https://tools.ietf.org/html/rfc4566)\n    - [Annotated Example SDP for WebRTC](https://tools.ietf.org/html/draft-ietf-rtcweb-sdp-11)\n\n\n```\n                  +-------------+          +-------------------+         +-------------+                      +-----------------------+\n                  |   client1   |          |      Ayame        |         |   client2   |                      | authentication server |\n                  +-----+-------+          +--------+----------+         +------+------+                      +-----------+-----------+\n                        |                           |                           |                                         |\n                        |                           |                           |                                         |\n                ============================= WebSocket 接続 =============================                                |\n                        |                           |                           |                                         |\n                        |GET /signaling             |                           |                                         |\n                        |--------------------------\u003e|                           |                                         |\n                        |    101 Switching Protocols|                           |                                         |\n                        |\u003c--------------------------|                           |                                         |\n                     +--|                           |             GET /signaling|                                         |\n                     |  |                           |\u003c--------------------------|                                         |\n  Stream の取得      |  |                           |101 Switching Protocols    |                                         |\n  PeerConnection の初期化等                         |--------------------------\u003e|                                         |\n                     |  |                           |                           |--+                                      |\n                     |  |                           |                           |  |                                      |\n                     |  |                           |                           |  | Stream の取得                        |\n                     |  |                           |                           |  | PeerConnection の初期化等            |\n                     |  |                           |                           |  |                                      |\n         ============== ここからは WebSockets の Data フレームでの JSON の送受信 =================                        |\n                     |  |                           |                           |  |                                      |\n                ========================== クライアントの登録 =============================                               |\n                     |  |{\"type\":\"register\",        |                           |  |                                      |\n                     |  | \"roomId\": \"...\",          |                           |  |                                      |\n                     |  | \"clientId\":\"...\",         |                           |  |                                      |\n                     |  | \"key\":\"...\",              |                           |  |                                      |\n                     |  | \"authnMetadata\": \"...\"}   |                           |  |                                      |\n                     +-\u003e|                           |                           |  |                                      |\n                        |--------------------------\u003e|                           |  |                                      |\n                        |                           |POST /ayame/webhook/authn  |  |                                      |\n                        |                           |{\"roomId\":\"...\",           |  |                                      |\n                        |                           | \"clientId\":\"...\",         |  |                                      |\n                        |                           | \"signalingKey\":\"...\",     |  |                                      |\n                        |                           | \"authnMetadata\":\"...\"}    |  |                                      |\n                        |                           |--------------------------------------------------------------------\u003e|\n                        |                           |                           |  |                                      |--+\n                        |                           |                           |  |               200 OK                 |  |\n                        |                           |                           |  |               {\"allowed\":true,       |  | 認証処理\n                        |                           |                           |  |                \"iceServers\":[],      |  |\n                        |                           |                           |  |                \"authzMetadata\":\"...\"}|\u003c-+\n                        |                           |\u003c--------------------------------------------------------------------|\n                        |                           |                           |  |                                      |\n  認証ウェブフックで    |   {\"type\":\"accept\",       |                           |  |                                      |\n  認証拒否の場合は      |    \"iceServers\": [],      |                           |  |                                      |\n  type は reject です   |    \"isExistUser\": false,  |                           |  |                                      |\n                        |    \"isExistClient\": false,|                           |  |                                      |\n                        |    \"authzMetadata\": \"...\"}|                           |  |                                      |\n                        |\u003c--------------------------|    {\"type\":\"register\",    |  |                                      |\n  isExistClient が false の場合は、                 |     \"roomId\": \"...\",      |  |                                      |\n  offer を送らずに相手クライアントの                |     \"clientId\":\"...\",     |  |                                      |\n  登録を待ちます        |                           |     \"key\":\"...\",          |  |                                      |\n                        |                           |     \"authnMetadata\":\"...\"}|\u003c-+                                      |\n                        |                           |\u003c--------------------------|                                         |\n                        |                           |POST /ayame/webhook/authn  |                                         |\n                        |                           |{\"roomId\":\"...\",           |                                         |\n                        |                           | \"clientId\":\"...\",         |                                         |\n                        |                           | \"signalingKey\":\"...\",     |                                         |\n                        |                           | \"authnMetadata\":\"...\"}    |                                         |\n                        |                           |--------------------------------------------------------------------\u003e|\n                        |                           |                           |                                         |--+\n                        |                           |                           |                  200 OK                 |  |\n                        |                           |                           |                  {\"allowed\":true,       |  | 認証処理\n                        |                           |                           |                   \"iceServers\":[],      |  |\n                        |                           |                           |                   \"authzMetadata\":\"...\"}|\u003c-+\n                        |                           |\u003c--------------------------------------------------------------------|\n                        |                           |{\"type\":\"accept\",          |                                         |\n                        |                           | \"iceServers\": [],         |                                         |\n                        |                           | \"isExistUser\": true,      |                                         |\n                        |                           | \"isExistClient\": true}    | isExistClient が true のため、          |\n                        |                           |--------------------------\u003e| offer を作成します                      |\n                        |                           |                           |--+                                      |\n                        |                           |                           |  |                                      |\n                        |                           |                           |  | 作成した offer の SDP を             |\n                        |                           |                           |  | setLocalDescription で               |\n                        |                           |                           |  | PeerConnection に適用させます        |\n                =================== SDP および ICE Candidate の交換 =======================                               |\n                        |                           |           {\"type\":\"offer\",|  | offer を Ayame 経由で                |\n                        |                           |            \"sdp\":\"...\"}   |\u003c-+ 相手クライアントへ送ります           |\n                        |                           |\u003c--------------------------|                                         |\n                        |           {\"type\":\"offer\",|                           |                                         |\n                        |            \"sdp\":\"...\"}   |                           |                                         |\n                        |\u003c--------------------------|                           |                                         |\n                     +--|                           |                           |                                         |\n                     |  |                           |                           |                                         |\n  受信した offer を  |  |                           |                           |                                         |\n  setRemoteDescription で                           |                           |                                         |\n  PeerConnection に適用させます                     |                           |                                         |\n                     |  |                           |                           |                                         |\n                     |  |                           |                           |                                         |\n                     |  |                           |{\"type\":\"candidate\",       |                                         |\n                     |  |                           | \"ice\":{\"candidate\":\"...\"} |                                         |\n                     |  |                           |\u003c--------------------------|                                         |\n                     |  | {\"type\":\"candidate\",      |                           |                                         |\n                     |  |  \"ice\":{\"candidate\":\"...\"}|                           |                                         |\n                     |  |\u003c--------------------------|                           |                                         |\n  answer を作成します|  |                           |                           |                                         |\n  作成した answer の SDP を                         |                           |                                         |\n  PeerConnection に適用させます                     |                           |                                         |\n  Answer を Ayame 経由で|                           |                           |                                         |\n  相手クライアントへ送ります                        |                           |                                         |\n                     |  |                           |                           |                                         |\n                     +-\u003e|                           |                           |                                         |\n                        |                           |                           |                                         |\n                        | {\"type\":\"answer\",         |                           |                                         |\n                        |  \"sdp\":\"...\"}             |                           |                                         |\n                        |--------------------------\u003e|                           |                                         |\n                        |                           |                           |                                         |\n                        |                           |{\"type\":\"answer\",          |                                         |\n                        |                           | \"sdp\":\"...\"}              |                                         |\n                        |                           |--------------------------\u003e|                                         |\n                        |                           |                           |                                         |\n                        |                           |                           |                                         |\n                  ======================== Trickle ICE の場合 ===========================                                 |\n  ICE candidate イベント発火時に                    |                           |                                         |\n  ICE candidate を Ayame 経由で                     |                           |                                         |\n  相手クライアントへ送ります                        |                           |                                         |\n                        |{\"type\":\"candidate\",       |                           |                                         |\n                        | \"ice\":{\"candidate\":\"...\"} |                           |                                         |\n                        |--------------------------\u003e|                           |                                         |\n                        |                           |                           |                                         |\n                        |                           |{\"type\":\"candidate\",       |                                         |\n                        |                           | \"ice\":{\"candidate\":\"...\"} |                                         |\n                        |                           |--------------------------\u003e|                                         |\n                        |                           |                           | 受信した ICE candidate を               |\n                        |                           |                           | addIceCandidate で                      |\n                        |                           |                           | PeerConnection に追加します             |\n                        |                           | {\"type\":\"candidate\",      |                                         |\n                        |                           |  \"ice\":{\"candidate\":\"...\"}|                                         |\n                        |                           |\u003c--------------------------|                                         |\n                        | {\"type\":\"candidate\",      |                           |                                         |\n                        |  \"ice\":{\"candidate\":\"...\"}|                           |                                         |\n                        |\u003c--------------------------|                           |                                         |\n                        |                           |                           |                                         |\n                        |                           | {\"type\":\"candidate\",      |                                         |\n                        |                           |  \"ice\":{\"candidate\":\"...\"}|                                         |\n                        |                           |\u003c--------------------------|                                         |\n                        | {\"type\":\"candidate\",      |                           |                                         |\n                        |  \"ice\":{\"candidate\":\"...\"}|                           |                                         |\n                        |\u003c--------------------------|                           |                                         |\n                        |                           |                           |                                         |\n                        |{\"type\":\"candidate\",       |                           |                                         |\n                        | \"ice\":{\"candidate\":\"...\"} |                           |                                         |\n                        |--------------------------\u003e|                           |                                         |\n                        |                           |                           |                                         |\n                        |                           |{\"type\":\"candidate\",       |                                         |\n                        |                           | \"ice\":{\"candidate\":\"...\"} |                                         |\n                        |                           |--------------------------\u003e|                                         |\n                        |                           |                           |                                         |\n                        |                           |                           |                                         |\n                        |                           |                           |                                         |\n                        |                           |                           |                                         |\n```\n\n### プロトコル\n\nWS のメッセージはJSONフォーマットでやり取りします。\nすべてのメッセージはプロパティに `type` を持ちます。\n`type` は以下の5つです。\n\n- register\n- accept\n- reject\n- offer\n- answer\n- candidate\n- bye\n\n#### type: register\n\nクライアントが Ayame に対して roomId, clientId を登録するために利用するメッセージです。\n\n```\n{type: \"register\", \"roomId\" \"\u003cstring\u003e\", \"clientId\": \"\u003cstring\u003e\"}\n```\n\nAyame は register メッセージを受け取ったら、\nそのクライアントが指定した room に入室可能か検査して、可能であれば accept, 不可であれば reject を返却します。\n\nもし認証ウェブフックが有効になっている場合は、まずは認証を行います。\n\n#### type: accept\n\nAyame が register に込められている情報を検査し、\n入室が可能であることをクライアントに知らせるメッセージです。\n\n```\n{type: \"accept\", isExistClient: \"\u003cboolean\u003e\"}\n```\n\nクライアントが accept を受け取った際、 isExistClient が true の場合は offer メッセージを送信します。\nisExsistClient が false の場合は answer メッセージを待ちます。\n\n#### type: reject\n\nAyame が register メッセージで指定した roomId に入室が **不可能** であることをクライアントに知らせるメッセージです。\n\n```\n{type: \"reject\", \"reason\": \"\u003cstring\u003e\"}\n```\n\nこれを受け取ったらクライアントは RTCPeerConnection や WebSocket を閉じて初期化する必要があります。\n\n#### type: offer\n\naccept を受け取り isExistClient: true を受け取ったクライアントは offer メッセージを Ayame に送信します。\n\n```\n{type: \"offer\", sdp: \"v=0\\r\\no=- 4765067307885144980...\"}\n```\n\nこれを受け取ったクライアントはこの SDP を remoteDescription をセットします。\nまた、このタイミングで answer メッセージを生成し、localDescription にセットした後、anwser メッセージ を送信します。\n\n#### type: answer\n\naccept を受け取り isExistClient: false を受け取ったクライアントは offer メッセージを待ち、\noffer メッセージを受け取ったら answer メッセージを送信します。\n\n```\n{type: \"answer\", sdp: \"v=0\\r\\no=- 4765067307885144980...\"}\n```\n\n#### type: candidate\n\nice candidate を交換するメッセージです。\n\n```\n{type: \"candidate\", ice: {candidate: \"....\"}}\n```\n\nこれを受け取ったクライアントは ice candidate を追加します。\n\n#### type: bye\n\nシグナリング用の WebSocket を切断したことを知らせるメッセージです。\n\n```\n{type: \"bye\"}\n```\n\nこれを受け取ったクライアントは RTCPeerConnection を閉じて、\nリモート(受信側)の video element を破棄する必要があります。\n\n### シグナリング詳細\n\n- 積極的に拡張する\n\n- 登録\n    - type: register\n        - roomId\n            - 必須\n            - string\n        - clientId\n            - オプション\n                - 要検討\n            - string\n        - authnMetadata\n            - 拡張\n            - オプション\n            - any\n        - signalingKey\n            - 拡張\n            - オプション\n            - string\n            - 互換性のため key も許可する\n                - 2020.2 で互換性はなくす\n            - signalingKey と key 両方飛んできたら signalingKey を優先する\n- 切断\n    - type: bye\n        - 1:1 のどちらかが切断したら飛ばす\n- 認証成功\n    - 拡張\n    - type: accept\n        - authzMetadata\n            - any\n        - iceServers:\n            - stun/turn の払い出し\n        - isExistClient\n            - bool\n            - isExistUser も 2020.2 までは飛ばす\n\n- 認証拒否\n    - 拡張\n    - type: reject\n        - reason\n            - string\n- ピンポン\n    - 拡張\n    - type: ping\n    - type: pong\n    - ping を 5 秒間隔でなげて 60 秒 pong が返ってこなかったら切断する\n\n## ウェブフック\n\n- URL の設定は yaml に設定可能にする\n\n### 認証サーバへ飛ばす情報\n\n- clientId\n    - 必須\n    - string\n- roomId\n    - 必須\n    - string\n- authnMetadata\n    - オプション\n    - any\n- signalingKey\n    - オプション\n    - string\n- ayameClient\n    - オプション\n    - string\n- environment\n    - オプション\n    - string\n- libwebrtc\n    - オプション\n    - string\n\n### 認証サーバから払い出す情報\n\n- allowed\n    - 必須\n    - boolean\n- reason\n    - オプション\n    - allowed が false のときのみ必須となる\n    - string\n- authzMetadata\n    - オプション\n    - クライアントまで届く\n    - any\n- iceServers:\n    - オプション\n    - 構成は考える\n\n### シグナリング切断時に飛ばす情報\n\n- roomId\n    - 必須\n    - string\n- clientId\n    - 必須\n    - string\n- reason\n    - オプション\n    - any\n\n\n## 設定ファイル\n\n**config.ini**\n\n```ini\ndebug = true\n\nlog_dir = .\nlog_name = ayame.log\n\nsignaling_log_name = signaling.log\nwebhook_log_name = webhook.log\n\ntype_message = false\n\nlisten_ipv4_address = 127.0.0.1\nlisten_port_number = 3000\n\n# authn_webhook_url = http://127.0.0.1:3001/authn_webhook_url\n# disconnect_webhook_url = http://127.0.0.1:3001/disconnect_webhook_url\n# webhook_request_timeout = 5\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenayame%2Fayame-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenayame%2Fayame-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenayame%2Fayame-spec/lists"}