Skip to content

JSON RPC API メモ

Yoteichi edited this page Aug 23, 2017 · 10 revisions

概要

PeerCastStation の HTML UI では Ajax を使用しており、ページ全体のリロー ドや遷移をさせずにブラウザに表示されるページの情報を更新したり、チャン ネル操作や設定の変更などができる。

具体的には、ブラウザで動いている JavaScript が JSON RPC プロトコル に従って作 成されたリモートプロシージャコールを表す JSON [RFC4627] テキストを所定 の URL に POST し、それに対する応答がサーバーから POST の応答本文とし て返ってくる。

この API を使うと、別のプログラム(別のマシンで動いていても良い)が PeerCastStation から情報を取得したり、PeerCastStation を操作することが できる。

JSON

JSON は構造化データをテキストで表わすフォーマットだということは知って いると思う。セキュリティの問題を無視して、やろうと思えば JavaScript パー サーでパースすることができるが、許されている値の種類は JavaScript のサ ブセットになる。

数値 1.0、文字列 "abc"、配列 [A, B, C, ...]、オブジェクト {A:B, ...}。その他の値として false, true, null が使える。「オブジェク ト」というのは、JavaScript の用語から来ていて、波括弧で囲まれたキー・ 値の組が並んだ「オブジェクト記法」のデータのことだ。

JSON RPC

JSON RPC では JSON で要求・応答が行なわれる。

リモートプロシージャ(JSON RPC では「メソッド」と言う)の呼び出しは、以 下のような形式で行なわれる(要求オブジェクト)。

{
    "jsonrpc": "2.0",
    "id": 6412,
    "method": "getVersionInfo",
    "params": []
}

method が呼び出したいメソッドの名前、params はメソッドに対する引数 だ。

引数を取らないメソッドに対しては、params キーは省略できるが、存 在する場合は配列かオブジェクトでなければならない。

引数は配列で順番に指定することもできるし、個々の引数にも名前が付いてい るので、オブジェクトで指定することもできる。f(x) というメソッドに対 して [1.0] と 引数を指定するのと {"x": 1.0} と引数を指定するのは、 同じことだ。

id は個々の呼び出しを区別するための数値で、対応する応答オブジェクト に同じ id が入っている。我々の場合では、複数の要求に対する応答が同じ 経路で順不同で返ってくるような状況は想定していないので、ID の唯一性に 気を配る必要はない。(…と思う。どうなん?)

応答オブジェクトは、成功時には "result" というキーを含み、値がメソッ ドの返り値になっている。失敗時には "error" というキーを含む。詳しく は JSON RPC の仕様書などを見てください。

HTTP 要求のフォーマット

PeerCastStation が JSON RPC を受け付ける URL は、 http://localhost:7144/api/1 だ。ここに要求を POST する。

curl コマンドで getVersionInfo メソッドを呼び出してみる。

$ curl -H "X-Requested-With: XMLHttpRequest" -H "Content-Type: application/json" -X POST -d '{"jsonrpc": "2.0","id": 6412,"method":"getVersionInfo"}' http://localhost:7144/api/1
{
  "jsonrpc": "2.0",
  "id": 6412,
  "result": {
    "agentName": "PeerCastStation/2.3.6.0",
    "apiVersion": "1.0.0",
    "jsonrpc": "2.0"
  }
}

-H オプションはヘッダーを、-d は POST の本文データを指定している。 このマシンでは バージョン 2.3.6 の PeerCastStation が動いていることが わかる。

X-Requested-With ヘッダーを指定する必要があったことに注意して欲しい。 このヘッダーは、本来ブラウザが Ajax リクエストを発行する時に付くものだ。 PeerCastStation バージョン 1.9 から、JSON RPC の呼び出しにはこのヘッダー が必要になった。

遠隔での呼び出し

ローカルマシン以外の PeerCastStation に要求を送る場合には、HTTP Basic 認証で認証する必要が(普通は)ある。

認証が必要であることは、/api/1 への POST に対して 401 Unauthorized 応答が返ってくることでわかる。

HTTP Basic 認証は user:pass のようなログイン情報を Base64 でエンコー ドしたものを HTTP ヘッダーで送る方式である。(盗聴されたら簡単にログイ ン情報を復元できるので一般に推奨されない)

認証情報は Authorization ヘッダーで次のように送る。

Authorization: Basic dXNlcjpwYXNz

dXNlcjpwYXNzuser:pass を Base64 エンコードしたもの。Linux では 以下のようにすればコマンドラインから文字列を Base64 エンコードすること ができる。

$ echo -n "user:pass" | base64
dXNlcjpwYXNz

もちろん暗号ではないので簡単にデコードできる。

$ echo -n "dXNlcjpwYXNz" | base64 -d
user:pass

どのようなメソッドが定義されているかの調べ方

こんなものを読むよりソースに当たるのが確実(ぉぃ。 APIHost.cs で定義されている APIContext クラスのメソッドのうち、 [RPCMethod("getVersionInfo")]のように RPCMethod 属性が付与されている ものが、リフレクション魔法により JSON RPC で利用できるようになっている。

APIレファレンス

C# 風の記法でメソッドのシグネチャを示す。型名 void は値 null だけから なる型。bool は true あるいは false。number? 等は number あるいは null であることを表わす。

ところどころサンプルデータが Ruby 表記でごめんなさい。

void addBroadcastHistory(object info)

チャンネル作成時の詳細を履歴に保存。

object addListener(string address, number port, number localAccepts, number globalAccepts, bool localAuthorizationRequired=false, bool globalAuthorizationRequired=true)

新しく待ち受けポートを追加。

object addYellowPage(string protocol, string name, string uri=null, string announceUri=null, string channelsUri=null)

イエローページを追加。YPビューアの機能が追加されたバージョン 1.9.2 からは、addYellowPage(protocol, name, uri, announceUri, channelsUri) 。(uri は null で良い?)

string broadcastChannel(number? yellowPageId, string sourceUri, string contentReader, object info, object track, string sourceStream=null)

チャンネルを開始。チャンネルIDを返す。contentReader は getContentReaders メソッドで得られる名前を指定する。

void bumpChannel(string channelId)

チャンネルに再接続。

number? checkBandWidth()

帯域測定をして帯域幅を Kbps 単位で返す。測定に失敗した場合は null を返す。

466

array checkPorts()

ポート開放状態をチェックする。

[7144]

void checkUpdate()

新バージョンのチェックを開始する。

void clearLog()

ログをクリア。

string? getAuthToken()

パスワードを入力せずに設定画面を開いたり、ダイレクト接続で視聴する為に URL に auth=... の形で付与される認証トークン文字列(ユーザー名とパスワー ドをハッシュ化したもの)を取得する。

(ポートごとにパスワードが違うはずだけど、JSON-RPC リクエストを受けとっ たポートの認証トークンになるのかな?)

array getBroadcastHistory()

チャンネル作成フォームに入れた内容の履歴。

[{"streamType"=>"RTMP Source",
  "streamUrl"=>"rtmp://localhost/live/livestream",
  "bitrate"=>0,
  "contentType"=>"Flash Video (FLV)",
  "yellowPage"=>"SP",
  "channelName"=>"予定地",
  "genre"=>"spプログラミング",
  "description"=>"ラムダ電卓",
  "comment"=>"短時間マイク無し",
  "contactUrl"=>
   "http://jbbs.shitaraba.net/bbs/read.cgi/game/48538/1391100125/",
  "trackTitle"=>"",
  "trackAlbum"=>"",
  "trackArtist"=>"",
  "trackGenre"=>"",
  "trackUrl"=>"",
  "favorite"=>false},
 ... ]

array getChannelConnections(string channelId)

チャンネルの接続情報。

[{"connectionId"=>1351461736,
  "type"=>"source",
  "status"=>"Connected",
  "sendRate"=>0.0,
  "recvRate"=>64698.2266,
  "protocolName"=>"RTMP Source",
  "localRelays"=>nil,
  "localDirects"=>nil,
  "contentPosition"=>345423,
  "agentName"=>"FMLE/3.0 (compatible; FMSc/1.0)",
  "remoteEndPoint"=>"127.0.0.1:64329",
  "remoteHostStatus"=>["local"],
  "remoteName"=>"rtmp://localhost/live/livestream"},
 {"connectionId"=>1724473770,
  "type"=>"direct",
  "status"=>"Connected",
  "sendRate"=>0.0,
  "recvRate"=>0.0,
  "protocolName"=>"HTTP Direct",
  "localRelays"=>nil,
  "localDirects"=>nil,
  "contentPosition"=>330616,
  "agentName"=>"VLC/2.1.5 LibVLC/2.1.5",
  "remoteEndPoint"=>"192.168.0.6:64320",
  "remoteHostStatus"=>["local"],
  "remoteName"=>"192.168.0.6:64320"},
 {"connectionId"=>919361550,
  "type"=>"relay",
  "status"=>"Connected",
  "sendRate"=>60694.1758,
  "recvRate"=>16.5836468,
  "protocolName"=>"PCP Relay",
  "localRelays"=>0,
  "localDirects"=>1,
  "contentPosition"=>135065042,
  "agentName"=>nil,
  "remoteEndPoint"=>"***.***.***.***:50475",
  "remoteHostStatus"=>["relayFull"],
  "remoteName"=>"***.***.***.***:50475"}]

object getChannelInfo(string channelId)

{"info"=>
 {"name"=>"テストch",
  "url"=>"",
  "genre"=>"",
  "desc"=>"",
  "comment"=>"",
  "bitrate"=>512,
  "contentType"=>"FLV",
  "mimeType"=>"video/x-flv"},
 "track"=>{"name"=>"", "genre"=>"", "album"=>"", "creator"=>"", "url"=>""},
 "yellowPages"=>[]}

array getChannelOutputs(string channelId)

動画プレーヤー接続の情報。

[{"outputId"=>1835339218,
  "name"=>"HTTP Direct 127.0.0.1:64191 (NSPlayer/12.0.7601.17514) 472kbps",      "type"=>1}]

array getChannelRelayTree(string channelId)

リレーツリー情報。ルートは自分自身。

[{"sessionId"=>"F46190087E454DE6977B957D2D74D599",
  "address"=>"110.4.130.220",
  "port"=>7144,
  "isFirewalled"=>false,
  "localRelays"=>1,
  "localDirects"=>0,
  "isTracker"=>false,
  "isRelayFull"=>true,
  "isDirectFull"=>true,
  "isReceiving"=>true,
  "isControlFull"=>false,
  "version"=>nil,
  "versionVP"=>nil,
  "children"=>
   [{"sessionId"=>"0078CC0C7CF28A909E3AF7C5A30FAED6",
     "address"=>"***.***.***.***",
     "port"=>7144,
     "isFirewalled"=>false,
     "localRelays"=>0,
     "localDirects"=>1,
     "isTracker"=>false,
     "isRelayFull"=>false,
     "isDirectFull"=>true,
     "isReceiving"=>true,
     "isControlFull"=>false,
     "version"=>1218,
     "versionVP"=>27,
     "versionEX"=>"IM45",
     "children"=>[]}]}]

object getChannelStatus(string channelId)

特定のチャンネルの情報。

{"status"=>"Searching",
 "source"=>"rtmp://localhost/live/livestream",
 "uptime"=>166,
 "localRelays"=>0,
 "localDirects"=>0,
 "totalRelays"=>0,
 "totalDirects"=>0,
 "isBroadcasting"=>true,
 "isRelayFull"=>false,
 "isDirectFull"=>false,
 "isReceiving"=>false}

array getChannels()

すべてのチャンネルの情報。

[{"channelId"=>"A0B184CC8F166FD0BCB9618B74A2CD80",
  "status"=>
   {"status"=>"Searching",
    "source"=>"rtmp://localhost/live/livestream",
    "uptime"=>3,
    "localRelays"=>0,
    "localDirects"=>0,
    "totalRelays"=>0,
    "totalDirects"=>0,
    "isBroadcasting"=>true,
    "isRelayFull"=>false,
    "isDirectFull"=>false,
    "isReceiving"=>false},
  "info"=>
   {"name"=>"テストch",
    "url"=>"",
    "genre"=>"",
    "desc"=>"",
    "comment"=>"",
    "bitrate"=>0,
    "contentType"=>nil,
    "mimeType"=>"application/octet-stream"},
  "track"=>{"name"=>"", "genre"=>"", "album"=>"", "creator"=>"", "url"=>""},
  "yellowPages"=>[]}]

array getContentReaders()

コンテント解析器の情報。

[{"name"=>"ASF(WMV or WMA)", "desc"=>"ASF(WMV or WMA)"},
 {"name"=>"RAW", "desc"=>"RAW"},
 {"name"=>"Flash Video (FLV)", "desc"=>"Flash Video (FLV)"},
 {"name"=>"Matroska (MKV or WebM)", "desc"=>"Matroska (MKV or WebM)"}]

ここで得られた名前を broadcastChannel の contentReader に指定する。

array getExternalIPAddresses()

ネットワークのルーターから UPnP 等で得られた外部IPアドレスを取得する。 返り値は文字列の配列。

array getListeners()

PeerCast の接続を受け付けるIPアドレスとポートの情報。

[{"listenerId"=>546346459,
  "address"=>"0.0.0.0",
  "port"=>7144,
  "localAccepts"=>2147483647,
  "globalAccepts"=>7,
  "localAuthorizationRequired"=>false,
  "globalAuthorizationRequired"=>false,
  "authenticationId"=>"-!FO;Zsk(atStMKU",
  "authenticationPassword"=>"ZVdf_xQqQ,vhDIKk",
  "isOpened"=>nil}]

object getLog(number? from, number? maxLines)

ログバッファーの内容の取得。from は取得を開始する行番号で、null の場合は 0 と同様にログバッファーの先頭から。maxLines は最大何行取得するかで、null の場合制限はなく、ログバッファーの最後まで取得される。

ログバッファーは、最終行としてまだコミットされていない作りかけの行がある。(空行にしかならない?) log キーのテキストは、最終行以外は "\n" で終端される。したがって、ログバッファーが空の場合(コミットされた行が無い場合)は以下のような応答になる。

{"from"=>0, "lines"=>1, "log"=>""}

一方、ログバッファーにコミットされた行が1行ある場合は lines キーは 2 になる。

{"from"=>0,
 "lines"=>2,
 "log"=>
 "OutputListener: 2015-01-18T10:19:31 [OutputListenerThread:0.0.0.0:7144] INFO  - Client connected 192.168.0.7:56442\n"}

object getLogSettings()

ログレベルの取得。0「ログの記録なし」、2「エラー」、3「警告」、4「付加的な情報」、5「デバッグ用の情報」。1「致命的なエラー」は欠番。

{"level"=>2}

array getNewVersions()

新バージョン情報の取得。返り値はオブジェクトの配列。

[
 {
  "title": "Version 2.3.8 (2017年06月02日開発版)",
  "publishDate": "2017-06-02T00:00:00+09:00",
  "link": "http://www.pecastation.org/files/PeerCastStation-2.3.8.zip",
  "description": "<h1>Version 2.3.8 (2017年06月02日開発版)</h1><p>バグ修正とマイナーな機能追加をしました。</p><ul><li>GUIの設定で通知を出さないよう設定できるようにしました。</li><li>GUIでの起動中 のアップデートチェック間隔を2時間から24時間にしました。</li><li>アップデートチェック時の転送量を減らしました。</li><li>チャンネル情報を取得できないチャンネルを視聴しようとした時に接続が切れずに残って いたのを修正しました。</li><li>起動時のポート開放確認で、ポート開放確認自体に失敗した時に未開放扱い になってしまっていたのを開放状態不明のままになるようにしました。</li><li>配信開始時のビットレートに 負数や空文字を設定するとビットレートが正しく設定されないのを修正しました。</li><li>YPからのチャンネ ル情報取得を設定している場合に http://localhost:7144/ypchannels/index.txt でindex.txtの再配信がされ るようにしました。</li><li>RTMPの送信パケットサイズを1536に変更しました。RTMP視聴時に通信のオーバー ヘッドが削減されます。</li><li>zip版でunblock.batで一部DLLのブロックが解除されなかったのを修正しました。</li><li>zip版にデバッグ用のpdbを追加しました。</li></ul>",
  "enclosures": [
    {
      "title": "",
      "url": "http://www.pecastation.org/files/PeerCastStation-2.3.8.zip",
      "length": 2160689,
      "installerType": "archive",
      "type": "application/octet-stream"
    },
    {
      "title": "",
      "url": "http://www.pecastation.org/files/PeerCastStation-2.3.8.exe",
      "length": 2323939,
      "installerType": "installer",
      "type": "application/octet-stream"
    },
    {
      "title": "",
      "url": "http://www.pecastation.org/files/PecaStationd-2.3.8.msi",
      "length": 2032488,
      "installerType": "serviceinstaller",
      "type": "application/octet-stream"
    }
  ]
}, ...
]

array getNotificationMessages()

ポップアップ用通知メッセージの取得。

[{"type"=>"error", "title"=>"テストch", "message"=>"チャンネルに接続できませんでした"},
 {"type"=>"info", "title"=>"テストch", "message"=>"チャンネルが終了しました"},
 ...]

array getPlugins()

プラグイン情報の取得。

[{"name"=>"ASF Content Reader",
  "isUsable"=>true,
  "assembly"=>
   {"name"=>"PeerCastStation.ASF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a441b7b23e9d2fd0",
    "path"=>"PeerCastStation.ASF.dll",
    "version"=>"1.7.9.1",
    "copyright"=>" "}},
  ... ]

object getSettings()

リレーに関する設定の取得。

{"maxRelays"=>2,
 "maxRelaysPerChannel"=>1,
 "maxDirects"=>2,
 "maxDirectsPerChannel"=>0,
 "maxUpstreamRate"=>600,
 "maxUpstreamRatePerChannel"=>0,
 "channelCleaner"=>{"mode"=>3, "inactiveLimit"=>60000}}

array getSourceStreams()

対応しているソースストリームプロトコルの情報を取得。

[{"name"=>"RTMP Source",
  "desc"=>"RTMP Source",
  "scheme"=>"rtmp",
  "type"=>1,
  "defaultUri"=>"rtmp://localhost/live/livestream"},
 {"name"=>"http",
  "desc"=>"http",
  "scheme"=>"http",
  "type"=>1,
  "defaultUri"=>"http://localhost:8080/"},
 {"name"=>"pcp",
  "desc"=>"pcp",
  "scheme"=>"pcp",
  "type"=>2,
  "defaultUri"=>""}]

type は用途を表す。1は「配信用入力ストリーム」、 2は「リレー用入力ストリーム」。

object getStatus()

{"uptime"=>58541,
 "isFirewalled"=>false,
 "globalRelayEndPoint"=>["110.*.*.*", 7144],
 "globalDirectEndPoint"=>["110.*.*.*", 7144],
 "localRelayEndPoint"=>["192.168.0.6", 7144],
 "localDirectEndPoint"=>["192.168.0.6", 7144]}

稼働時間、ポート開放状態、IPアドレスなどの情報の取得。

object getUserConfig(string user, string key)

組込み YP ブラウザなどのユーザー設定などを取得する。今のところ user は "default" 固定?

object getVersionInfo()

{"agentName"=>"PeerCastStation/1.7.9.1",
 "apiVersion"=>"1.0.0",
 "jsonrpc"=>"2.0"}

バージョン情報の取得。

array getYPChannels()

外部サイトの index.txt から取得されたチャンネル一覧。YP ブラウザでの表 示用。オブジェクトの配列。

[
 ...,
  {
  "yellowPage": "SP",
  "name": "SP ※お知らせ 3/30",
  "channelId": "00000000000000000000000000000000",
  "tracker": "",
  "contactUrl": "http://bayonet.ddo.jp/sp/xgame.html",
  "genre": "",
  "description": "【重要】配信コンテンツの自粛願いについて。昨今、配信ガイドラインが掲示されるケースが増えてきました。その都度お知らせするにしてもSPとしては限界がありますので、各配信者の方々は配信前にガイドラインの有無のご確認をよろしくお願いいたします。",
  "comment": "",
  "bitrate": 0,
  "contentType": "RAW",
  "trackTitle": "",
  "album": "",
  "creator": "",
  "trackUrl": "",
  "listeners": -9,
  "relays": -9,
  "uptime": 0
}]

array getYellowPageProtocols()

[{"name"=>"PCP", "protocol"=>"pcp"}]

array getYellowPages()

[{"yellowPageId"=>1901542310,
  "name"=>"SP",
  "uri"=>"pcp://bayonet.ddo.jp:7146/",
  "protocol"=>"pcp",
  "channels"=>[]},          # [{channelId, status}...]
  ... ]

登録されているイエローページの取得。status は配信中のチャンネルとルー トサーバーとの接続状態で、"Idle", "Connecting", "Connected", "Error" のいずれか。

void removeListener(number listenerId)

ポートリスナーを削除。

void removeYellowPage(number yellowPageId)

イエローページを削除。

object resetListenerAuthenticationKey(number listenerId)

ポートリスナーのユーザー名/パスワードを変える。

void restartAnnounce(number yellowPageId, string channelId=null)

YP への接続をはりなおす。

bool restartChannelConnection(string channelId, number connectionId)

void setChannelInfo(string channelId, object info, object track)

チャンネル詳細を変更。

void setListenerAccepts(number listenerId, number localAccepts, number globalAccepts)

ポートリスナーのアクセス許可設定を変更。以下の値の論理和である整数。

None: 0
Play: 1
Relay: 2
Metadata: 4
Interface: 8
All: 0x7FFFFFFF

void setListenerAuthorizationRequired(number listenerId, bool localAuthorizationRequired, bool globalAuthorizationRequired)

パスワードによる認証が必要であるかどうかの設定を変更する。

void setLogSettings(object settings)

settings は { "level" : 0 } のようなオブジェクト。数値の意味については getLogSettings の項を参照。ログレベル 1 は 2 と同じものとして扱われる。

void setSettings(object settings)

リレーに関する設定を変更。settings の形式については getSettings の項を 参照。

void stopAnnounce(number yellowPageId, string channelId=null)

イエローページへの掲載を停止する。

void stopChannel(string channelId)

チャンネルを停止する。

bool stopChannelConnection(string channelId, number connectionId)

チャンネルに関して特定の接続を停止する。成功すれば true、失敗すれば false を返す。

void stopChannelOutput(string channelId, number outputId)

array updateYPChannels()

YP から index.txt を取得する。

Clone this wiki locally