2012年3月31日土曜日

websocketについて再度やってみる。

websocket・・・html5の目玉の1つですね。

前々から興味もっててhttps://github.com/taktod/webSocketForRed5こんなのつくったりしていたわけですが、最近jqmobiを使うようになってまた、興味がわいてきました。

で、ここ数日websocketの動作について調査しつついろいろやっていたわけです。
上記のred5用のプラグインをきちんと整備して、とりあえずrtmpとwebsocketで情報を共有するチャットをとりあえずの目標にするわけですが、今日はhandshakeについてのメモ書き書いておきます。

websocketの動作は次のようなものになっています。
1:クライアントからhandshakeの要求が送られる
2:サーバーから応答のデータを送り返す。
ここでhandshake完了つながったままになる。
3:メッセージを送りたいときにおくる。データは0x00 (データ(UTF8)) 0xFFという形で送る。(この部分はRFC6455で大きくかわってしまったようです。)

だったとおもいます。
 websocketにはいくつかバージョンがあり、ブラウザの対応もまちまちです。
そしてサーバーの対応もまちまちです。
でも、主なものは2つです。
hybi-00とRFC6455の2つ

hybi-00は昔つくったプログラムでサポートした古いバージョン。セキュリティーがどうのこうのという理由でFirefoxが見切りをつけたバージョンです。
対応ブラウザで確認したものは手持ちのiphone4SのモバイルサファリとiMacにはいっているsafariはこちらの動作をしていました。

RFC6455は現行のFirefox 11、google chromeがサポートしているあたらしいバージョン。

とりあえずこの2つサポートしておけば、たいていのブラウザで動作可能になると思われます。
今のところ理解したのは、handshakeの仕方が違う。その他は多分同じということなので、そこを書きなぐっておきます。

hybi-00のhandshake(ネタ元はこちら)
クライアントからのデータ送信

GET /demo HTTP/1.1
        Host: example.com
        Connection: Upgrade
        Sec-WebSocket-Key2: 12998 5 Y3 1  .P00
        Sec-WebSocket-Protocol: sample
        Upgrade: WebSocket
        Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5
        Origin: http://example.com

        ^n:ds[4U

サーバーからの応答

HTTP/1.1 101 WebSocket Protocol Handshake
        Upgrade: WebSocket
        Connection: Upgrade
        Sec-WebSocket-Origin: http://example.com
        Sec-WebSocket-Location: ws://example.com/demo
        Sec-WebSocket-Protocol: sample

        8jKS'y:G*Co,Wxa-

赤文字にした部分を操作して青文字にしたデータを作成します。
やり方は次のとおり。
Key1とKey2を数値データに戻します。
例としてKey2をあげると
> 12998 5 Y3 1  .P00
数字の部分を取り出して空白の数を数えます。
> 1299853100 と 5
数字の部分/空白の数の値をだします。
> 259970620
hexに直す
> 0x0F7ED63C
同じことをkey1にもやります。
> 0x316E4113
16のHexを作成します。key1 key2 と最後の赤文字のやつとなります。
> 0x31 0x6E 0x41 0x13 0x0F 0x7E 0xD6 0x3C '^' 'n' ':' 'd' 's' '[' '4' 'U'
これをMD5にかけると・・・
> 8jKS'y:G*Co,Wxa-
になるというわけです。

つづいてRFC6455の方。(ネタもとはこちら)
クライアントからの要求はこんな感じ

GET /chat HTTP/1.1
        Host: server.example.com
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
        Origin: http://example.com
        Sec-WebSocket-Protocol: chat, superchat
        Sec-WebSocket-Version: 13

サーバーの応答はこんな感じ

HTTP/1.1 101 Switching Protocols
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
        Sec-WebSocket-Protocol: chat

なぜかクライアントによってはProtocolの部分が抜け落ちていたりしていました。まぁ気にしないけど。
では計算のやり方。
必要なのは赤字のKeyの部分と、定義されているGUID(258EAFA5-E914-47DA-95CA-C5AB0DC85B11)の2つです。
いきなりGUIDがでてきて、これなに?と思うとおもいますが、この値のGUIDでないとだめみたいです。
キー
> gDhllHNhbXBsZSBub25jZQ==
ここにGUIDを連結します。

> gDhllHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
これをSHA1で変換かけてやると
> s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
になります。
あとは、サーバー応答のフォーマットにあわせてデータを送り返してやればOKとなります。

Handshake以外の部分の動作についてはまたあとで調査しますので、また記事みてね。
ではでは

2012年3月7日水曜日

HttpTakStreamingのデモを公開しておきます。

httpTakStreamingの動作デモを公開しておきます。

何かしら不具合が発生した場合に、公開デモを停止することがあることをご了承ください。

1:red5のpublisher等rtmpの配信のできるデモを準備する。
2:rtmp://49.212.39.17/htsに向かってなにかしら配信を実行する。
3:http://49.212.39.17/hts/player/player.htmlにアクセスする。
4:プレーヤーのテキストボックスの部分にhttp://49.212.39.17/hts?path=/default/hts/配信名をいれる。
5:playボタンを押す。

これで試すことができます。

例としては、rtmp://49.212.39.17/htsにむかってlivestreamという名前で放送をした場合
プレーヤーに渡すhttpTakStreamingのパスはhttp://49.212.39.17/hts?path=/default/hts/livestreamになります。

Flashプレーヤーの動作は現在のところ調整中ですが、ChromeやFirefoxのNetworkデータを確認すると、ファイルがぞくぞくとDownloadされ、内容が放送されるのがわかるとおもいます。

例として、red5のpublisherデモを使うとします。
locationは49.212.39.17/htsにあわせる。

放送する名前は適当につける。

http://49.212.39.17/hts/player/player.htmlの設定のパスをtestStreamにあわせる。
この場合はhttp://49.212.39.17/hts?path=/default/hts/testStream

放送の映像がはじまったらGoogleChromeのNetwork等で確認するとファイルの断片がどんどん落ちてくる。

という形になります。
とりあえずサンプルはこんな感じ。試してやってください。

Flex(actionScript)でSetTimeoutは、つかわない方がいいらしい。

HttpTakStreamingでは、setTimeoutを大量につかうようにプログラミングをしてあるのですが、今日こんな記事をみつけた。

連続稼動でsetTimeout関数が途中で止まってしまう
http://www.fxug.net/modules/xhnewbb/viewtopic.php?topic_id=4204

FlexのAPIによるとsetTimeoutはあまりつかわないで、Timerをつかって処理した方がのぞましいとしてるみたいですね。

http://livedocs.adobe.com/flash/9.0_jp/ActionScriptLangRefV3/flash/utils/package.html#setTimeout%28%29
このメソッドを使用する代わりに、repeatCount パラメータを 1 (タイマーを 1 回のみ実行する設定) にして、指定した間隔で Timer オブジェクトを作成することを検討してください。

とのことです。
というわけで今日はHttpTakStreamingのsetTimeoutをTimerに変えるところから作業するか・・・

2012年3月4日日曜日

FlvデータをFlashPlayerに送り届ける話。

前回の記事でNetStream.appendBytesについてちょこっとだけ書きましたが、Flvデータをガンガンおくってやれば、映像を流すことができます。

んで流す方法の話。
まず僕が興味をもったのは、Rtmfpをつかう方法
rtmfpでもFlashのストリームを流すことができますが、Flashが吐き出すデータに限られます。これだとFlash以外のソース(FMEとか)での配信がながせず、映像は残念なものになります。
そこでデータの送信を独自に作成し、appendBytesをつかってデータを再生してやれば綺麗な映像を安定して流すことができます。
やってみた方法は
1:Red5サーバーにデータを流す。
2:そのデータをバイトデータとしてrtmpメッセージとして送り返す。
3:rtmpメッセージをrtmfpのネットワークで共有する。
4:うけとったクライアントはそれぞれ映像をappendBytesで再生する。
というやりかた。

rtmfpのnetGroupで共有すればいいかなと思ったんですが、netGroupの共有ではデータの送信が間に合いませんでしたので、netStreamのデータ通信でやりとりする形に変更してやってみました。実験段階では、問題なく動作し、なんかいかGlobal経由での実験も特に問題なく成功。
問題はnetStreamのNodeの管理が煩雑になりすぎて、飽きましたw。

つづいて興味をもったのはhttpを使う方法。
URLLoaderをつかってapacheサーバーからデータをガンガンもらって動作させるというやり方。
上記のp2pと動作は基本的に同じ
1:Red5サーバーにデータを流す。
2:そのデータをfthファイルとftmファイルに分解してhttpでダウンロードできるように変更。
3:プレーヤーは各自ダウンロードをし、appendBytesで再生する。
というやり方。

こちらも実験では問題なく動作し、Global経由での実験も特に問題なし、まぁ、つくったFlashプログラムのダウンロードタイミングにちと問題があって、再生が微妙につまったりしましたが、そこもなんとかしました。
これが今回のHttpTakStreamingでのやり方です。
ただ、Flash側からアクセスしなければいけなく、メッセージができ次第pushするわけではないのでどうしても遅延が大きくなる傾向があります。

netStream.appendBytesの話

さて、githubにhttpTakStreamingを公開したわけですが、ここでつかわれている、netStream.appendBytesについて、ちょっと紹介しておきたいと思います。

ActionScriptのnetStreamにはFlashPlayer10.1から(だったと思いますが)、appendBytesというメソッドが追加されています。
どういう動作かというと、netConnectionのサーバー指定しないものをベースにした、netStreamでは、追記されたFLVバイトデータを再生することができるというものです。

これをつかえばPC内にあるFLVデータを再生するプレーヤーとかつくることができます。
http://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html#appendBytes()
さて、アドベの説明によると[バイトパーサーは、ヘッダー付きの FLV ファイルを認識します。ヘッダーが解析された後、appendBytes() は、今後のすべての呼び出しが同じ実際のファイルまたは仮想ファイルの連続であると予期します。appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN) が呼び出さるまでは、別のヘッダーは予期されません。]とあります。

要するに追記されたデータはすべて同じファイルの続きであると解釈して動作しますよ。ということです。

いいかえると、後から追記するデータでも、同じファイルとして成立するならば、再生データとして受け入れるということです。
もちろんデータの供給がおいつかなくなるとNetStream.Buffer.Emptyとかがでてとまっちゃいますが、そうでなければ大丈夫です。

というわけで、HttpTakStreamingでは、FLVのファイルとして成立させるために、Fthファイル(FlvTakHeaderファイル)をまず読み込ませFLVデータの土台を送りつけたあとに、Ftmファイル(FlvTakMediaファイル)を動画の本体として連続でどんどん読み込ませるという方法で、ライブ放送を成立させています。

2012年3月3日土曜日

自前でhttpのstreamingをつくってみました。その3

HttpTakStreamingのプログラムをgithubに公開しました。

https://github.com/taktod/HttpTakStreaming

http経由のストリーミングなので、apacheやnginxでスケーリングすればOK
しかもダウンロード先を中途で変更しても、ダウンロードファイルに矛盾がでなければOK
さらに、遅延も一応最高で5秒を達成してあります。

というなかなかいけるんじゃない?というものができあがりました。

いまのところ、flexのダウンロードタイミングにちと難があるみたいですが、そこらへんをぼちぼち修正していきたいところ。

2012年3月2日金曜日

red5 ivyの依存関係でつまったら・・・

red5の最新の開発版が利用したかったので、subversionでダウンロードしました。

antでコンパイルしてみたところ

[ivy:resolve] ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:resolve] ::          UNRESOLVED DEPENDENCIES         ::
[ivy:resolve] ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:resolve] :: org.slf4j#com.springsource.slf4j.api;1.6.1: ・・・
というエラーがでて、コンパイルできませんでした。

原因はivyの設定がまちがっているとか、red5のリポジトリがこわれているとかではなく、
「以前のコンパイル時のivyのcacheがシステムにのこっているために、バージョンがあわない」
というもののようです。

そこでおまじない
$ ant ivyclear
これを実行するとivyのcacheがクリアされます。
$ ant
んで、antを実行。

これでコンパイルが無事おわりred5が生成されました。