2011年5月21日土曜日

RtmpClientの使い方その3 Red5側のプログラムを修正してみる場合

Red5に搭載されているRTMPClient(とそれに付随する継承クラス)では2つの問題をはらんでいます。
1つ目は、サーバー側からのクライアント上の関数実行命令に対する返答のしかたがおかしいこと。
2つ目は、HandShakeの仕方が不正であること。

1つ目の問題では、Red5サーバーに接続しにいった状態で、放送を受信しつつサーバーからクライアント関数の実行を実施されると、パケットが混乱し、サーバーから切断されるという不具合があります。
(相手がRed5ならNG、Wowzaなら発生せず、FMSの場合は不明)

2つ目の問題では、Red5サーバーに接続しにいったときにサーバー側で不正なクライアントによる接続と判定されます。また、FMSには接続したあとにすぐ切断させられます。
(相手がRed5なら警告でてそのままつながる、Wowzaつながる、FMS接続後即切断)

今回はRed5側のプログラムを修正して再コンパイルして直す方法です。
まず、Red5のプログラムをSubversionで取得、ant(1.7以降)を準備しておきます。
まずは問題その1、クライアント関数の実行応答が不正な件
src/org/red5/server/net/rtmp/BaseRTMPClientHandler.javaのonInvoke関数の一番最後の部分に手を加えます。

} else if (!onStatus) {
    Invoke reply = new Invoke();
    reply.setCall(call);
    reply.setInvokeId(invoke.getInvokeId());
    log.debug("Sending empty call reply: {}", reply);
    channel.write(reply);
}

となっている部分を

} else if (!onStatus) {
    Invoke reply = new Invoke();
    call.setStatus(Call.STATUS_METHOD_NOT_FOUND);
    reply.setHeader(source);
    reply.setCall(call);
    reply.setInvokeId(invoke.getInvokeId());
    log.debug("Sending empty call reply: {}", reply);
    channel.write(reply);
}

強制的に実行しようとした関数はありませんでした。と応答させてみました。
実行結果を返したい場合はRed5_phpのリポジトリのRtmpClientExのonInvokeの中に記述書いてあるので興味ある人はのぞいてみてください。

つぎに問題その2、Handshakeがこける問題。(FMSにはつながりにいくようになりますが、放送の受信ができなくなる。どうやらこの方法だとRTMPEの動作と認識されるっぽい。[つまり本物のFlashのHandshakeのやり方とは違うということ。])
src/org/red5/server/net/rtmp/RTMPMinaIoHandler.javaのsessionCreated関数をいじります。中盤あたり

if(rtmp.getMode() == RTMP.MODE_CLIENT) {
    // create an outbound handshake
    OutboundHandshake outgoingHandshake = new OutboundHandshake();
    // if handler is rtmpe client set encryption on the protocol state
    // if (handler instanceof RTMPEClient) {
        // rtmp.setEncrypted(true);
        // set the handshake type to encrypted as well
        // outgoingHandshake.setHandshakeType(RTMPConnection.RTMPENCRYPTED);
    //}
    // add the handshake
    session.setAttribute(RTMPConnection.RTMP_HANDSHAKE, outgoingHandshake);
}
となっている部分を・・・
if(rtmp.getMode() == RTMP.MODE_CLIENT) {
    // create an outbound handshake
    OutboundHandshake outgoingHandshake = new OutboundHandshake();
    // if handler is rtmpe client set encryption on the protocol state
    // if (handler instanceof RTMPEClient) {
        rtmp.setEncrypted(true);
        // set the handshake type to encrypted as well
        outgoingHandshake.setHandshakeType(RTMPConnection.RTMPENCRYPTED);
    //}
    // add the handshake
    session.setAttribute(RTMPConnection.RTMP_HANDSHAKE, outgoingHandshake);
}
この2カ所のコメントをはずせば暗号化されたプレーヤーのバージョン情報が記録されるようになり、ただしくプレーヤーからの接続のHandshakeが完了するようになります。
--追記--
すみません、この記述うそです。
Rtmpeとして接続しにいこうとして、Handshakeは成立しますが動画データのやりとりでこけます。Red5やWowzaとデータのやりとりをする場合は元のRTMPMinaIoHandlerつかって処理してもらって、内部判定はInvalidClientとして操作させるかScheme1でValidationを通るように修正するかするといいかと思います。
別の記事であきらめていますが、Scheme1でValidと判定されるようにしてもFlashMediaServerへの接続は失敗します。
--追記ここまで--

あとは、大本のディレクトリにもどって、antを実行すればコンパイルがおわり修正されたRed5.jarが生成されました。

一応これで動作するようにはなるのですが、Red5そのものの修正するのはバージョンがかわるたびにパッチを当てないといけなくなって面倒なので、ちょっと拡張クラス側で対応できないか模索したいと思っています。
僕のつくったRtmpClientExで対応完了するなら、その方が使いやすいですからw

0 件のコメント:

コメントを投稿