RTMFP(Yasume)のSpeed Test

RTMFPで相互通信をする場合、NetGroupを使うと非常に手軽に実装できるのだが、先日の計測でとても時間がかかることがわかった。
本来、一方向用のNetStreamを二つ用意したほうが早いとのことなので、使いやすくライブラリ化したYasumeでのSpeed Testをしてみた。

Get Adobe Flash player


同じLANに繋がっているPCで、同時に立ち上げてSpeed Testすると、往復の時間がわかるはず。
先日のNetGroupを使ったものでは往復に1000msec以上かかっていたが、ほぼ同じ環境で10~50msec程度になった。

2012/5/24追記
FPSに依存する可能性がある。
試しに5 fpsにしたところ、往復で数百secになった。
このページに貼り付けたswfは60 fps。

使える場面も増えるかも。

◆使い方。

1:同じLANに繋がった、二台のPCでこのページを開く。
2:ピアアシスト設定のダイアログが出るので、二台とも許可をクリック。
3:自動的に、お互いを見つけに行く。
4:どちらかのPCの接続ボタンを押す。
5:接続完了。ちゃんと繋がっている場合、Speed Testボタンがアクティブになる。
6:どちらかのPCのSpeed Testボタンを押すと数字がでる。
この数字が、往復のミリ秒。

ActionScript Game Utility Library ‘ヤスメ’

http://www.libspark.org/wiki/asahiufo/Yasume

http://www.ahiufomasao.org/blog/archives/46

[sourcecode language=”as3″]
package
{

import com.bit101.components.InputText;
import com.bit101.components.Label;
import com.bit101.components.NumericStepper;
import com.bit101.components.PushButton;
import com.bit101.components.Style;
import com.bit101.components.TextArea;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.NetStream;
import org.ahiufomasao.yasume.events.NetStreamGroupEvent;
import org.ahiufomasao.yasume.events.NetStreamGroupEventKind;
import org.ahiufomasao.yasume.net.NetStreamGroup;
/**
* …
* @author umhr
*/
[SWF(width = 500, height = 350, backgroundColor = 0xEEEEEE, frameRate = 60)]
public class YasumeChat extends Sprite
{
private var _connectUI:ConnectUI = new ConnectUI();
private var _time:Number;
private var _isTryConnect:Boolean;
//UI
private var _initializeBt:PushButton;
private var _searchHostBt:PushButton;
private var _speedTestBt:PushButton;
private var _speedTxt:InputText;
private var _farIDTI:InputText;
private var _connectBt:PushButton;
private var _sendMessageTI:InputText;
private var _sendBt:PushButton;
private var _receiveMessageTA:TextArea;
private var _disconnectBt:PushButton;
private var _terminateBt:PushButton;
private var _netStatusMessageTA:TextArea;
private var _numericStepper:NumericStepper;

public function YasumeChat()
{
init();
}
private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}

private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// entry point

graphics.beginFill(0xEEEEEE);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill();

setUI();

_onClickForInitializeBt(null);

_searchHostBt.enabled = false;
_farIDTI.enabled = false;
_connectBt.enabled = false;
_sendMessageTI.enabled = false;
_sendBt.enabled = false;
_disconnectBt.enabled = false;
_terminateBt.enabled = false;
_speedTestBt.enabled = false;
}

private function setUI():void
{

Style.embedFonts = false;
Style.fontName = "_typewriter";
Style.fontSize = 12;

_initializeBt = new PushButton(this, 50, 0, "初期処理", _onClickForInitializeBt);
_searchHostBt = new PushButton(this, 50, 25, "ホスト検索", _onClickForSearchHostBt);
//searchHostBt.enabled = false;

new Label(this, 456, 6, "FarID");
_farIDTI = new InputText();
_farIDTI.x = 154;
_farIDTI.y = 25;
_farIDTI.width = 342;
_farIDTI.textField.selectable = false;
//farIDTI.enabled = false;
addChild(_farIDTI);

_connectBt = new PushButton(this, 50, 50, "接続", _onClickForConnectBt);
//connectBt.enabled = false;

new Label(this, 0, 75, "入力");
_sendMessageTI = new InputText();
_sendMessageTI.x = 50;
_sendMessageTI.y = 75;
_sendMessageTI.width = 342;
//sendMessageTI.enabled = false;
addChild(_sendMessageTI);
_sendBt = new PushButton(this, 396, 75, "送信", _onClickForSendBt);
//sendBt.enabled = false;

new Label(this, 0, 100, "受信");
_receiveMessageTA = new TextArea();
_receiveMessageTA.x = 50;
_receiveMessageTA.y = 100;
_receiveMessageTA.width = 446;
_receiveMessageTA.height = 96;
addChild(_receiveMessageTA);
////////////////////////////////////

new Label(this, 0, 200, "処理結果");
_netStatusMessageTA = new TextArea();
_netStatusMessageTA.x = 50;
_netStatusMessageTA.y = 200;
_netStatusMessageTA.width = 446;
_netStatusMessageTA.height = 96;
addChild(_netStatusMessageTA);

// Speed Test
_speedTestBt = new PushButton(this, 50, 300, "Speed Test", _onClickForSpeedTestBt);
_speedTxt = new InputText(this, 154, 300);
_speedTxt.width = 100;
_speedTxt.height = 20;
_speedTxt.textField.selectable = false;
new Label(this, 258, 300, "msec");

_disconnectBt = new PushButton(this, 292, 325, "切断", _onClickForDisconnectBt);
//disconnectBt.enabled = false;
_terminateBt = new PushButton(this, 396, 325, "終了処理", _onClickForTerminateBt);
//terminateBt.enabled = false;

setFPSStepper();
}

private function setFPSStepper():void
{
new Label(this, 320, 440, "FPS:");
_numericStepper = new NumericStepper(this, 410, 300, onNumericStepper);
_numericStepper.minimum = 1;
_numericStepper.maximum = 120;
_numericStepper.value = 60;
}

private function onNumericStepper(event:Event):void
{
stage.frameRate = _numericStepper.value;
}

private function _onClickForSpeedTestBt(event:Event):void
{
var data:Object = {};
data.ping = "echoRequest";
_time = new Date().time;
_netStreamGroup.send(data);
}

/** STRATUSサーバーのURL */
private static const _STRATUS_URL:String = "rtmfp://p2p.rtmfp.net/";
/** デベロッパーキー */
private static const _DEVELOPER_KEY:String = "dfb4523e3b903bf5b39b1058-2a475abd8e6f";
/** グループ名 */
private static const _GROUP_NAME:String = "org.ahiufomasao.rtmfp.group.netstreamchat";
/** ストリーム名 */
private static const _STREAM_NAME:String = "org.ahiufomasao.rtmfp.stream.netstreamchat";

private var _netStreamGroup:NetStreamGroup; // ネットストリームコネクター

/**
* 初期処理ボタンクリックイベントハンドラ
*
* @param event イベント
*/
private function _onClickForInitializeBt(event:Event):void
{
_netStreamGroup = new NetStreamGroup();
_netStreamGroup.addEventListener(NetStreamGroupEvent.INITIALIZE_COMPLETE, _onInitializeComplete);
_netStreamGroup.addEventListener(NetStreamGroupEvent.NET_STATUS, _onNetStatus);

_initializeBt.enabled = false;
_searchHostBt.enabled = false;
_farIDTI.enabled = false;
_connectBt.enabled = false;
_sendMessageTI.enabled = false;
_sendBt.enabled = false;
_disconnectBt.enabled = false;
_terminateBt.enabled = false;

_netStreamGroup.initialize(_STRATUS_URL + _DEVELOPER_KEY);
}

/**
* 初期処理完了イベントハンドラ
*
* @param event イベント
*/
private function _onInitializeComplete(event:NetStreamGroupEvent):void
{
_netStreamGroup.removeEventListener(NetStreamGroupEvent.INITIALIZE_COMPLETE, _onInitializeComplete);

_searchHostBt.enabled = true;
_farIDTI.enabled = true;
//connectBt.enabled = true;
_onClickForSearchHostBt(null);
}

/**
* ホスト検索ボタンクリックイベントハンドラ
*
* @param event イベント
*/
private function _onClickForSearchHostBt(event:Event):void
{
if (_netStreamGroup.requestingHostFarID)
{
_netStreamGroup.stopRequestHostFarID();
_netStreamGroup.removeEventListener(NetStreamGroupEvent.HOST_FAR_ID_RECEIVE, _onHostFarIDReceive);
}
_netStreamGroup.startRequestHostFarID(_GROUP_NAME);
_netStreamGroup.addEventListener(NetStreamGroupEvent.HOST_FAR_ID_RECEIVE, _onHostFarIDReceive);
}

/**
* ホスト FarID 受信イベントハンドラ
*
* @param event イベント
*/
private function _onHostFarIDReceive(event:NetStreamGroupEvent):void
{
trace(event.info.hostFarID);
_netStreamGroup.removeEventListener(NetStreamGroupEvent.HOST_FAR_ID_RECEIVE, _onHostFarIDReceive);
_netStreamGroup.stopRequestHostFarID();

_farIDTI.text = event.info.hostFarID;

_onClickForConnectBt(null);
}

/**
* 接続ボタンクリックイベントハンドラ
*
* @param event イベント
*/
private function _onClickForConnectBt(event:Event):void
{
_initializeBt.enabled = false;
_searchHostBt.enabled = false;
_farIDTI.enabled = false;
_connectBt.enabled = false;
_sendMessageTI.enabled = false;
_sendBt.enabled = false;
_disconnectBt.enabled = false;
_terminateBt.enabled = false;
_speedTestBt.enabled = true;

if (_netStreamGroup.requestingHostFarID)
{
_netStreamGroup.stopRequestHostFarID();
}

if (String(_farIDTI.text).length == 0)
{
_netStreamGroup.addEventListener(NetStreamGroupEvent.CONNECT_READY_COMPLETE, _onConnectReadyComplete);
_netStreamGroup.listen(_STREAM_NAME, _GROUP_NAME, _accessPermissionCondition);
}
else
{
_netStreamGroup.addEventListener(NetStreamGroupEvent.CONNECT_COMPLETE, _onConnectReadyComplete);
_netStreamGroup.connect(_STREAM_NAME, _farIDTI.text, _accessPermissionCondition);
}
}

private function _accessPermissionCondition(subscriber:NetStream):Boolean
{
return true;
}

/**
* 接続準備完了イベントハンドラ
*
* @param event イベント
*/
private function _onConnectReadyComplete(event:NetStreamGroupEvent):void
{
if (_netStreamGroup.host)
{
_netStreamGroup.removeEventListener(NetStreamGroupEvent.CONNECT_READY_COMPLETE, _onConnectReadyComplete);
}
else
{
_netStreamGroup.removeEventListener(NetStreamGroupEvent.CONNECT_COMPLETE, _onConnectReadyComplete);
}

_netStatusMessageTA.text = "NearID: " + _netStreamGroup.nearID + "\n" + _netStatusMessageTA.text;

_sendMessageTI.enabled = true;
_sendBt.enabled = true;
_disconnectBt.enabled = true;
//_speedTestBt.enabled = true;

_netStreamGroup.addEventListener(NetStreamGroupEvent.RECEIVE_DATA, _onReceiveData);
}

/**
* 送信ボタンクリックイベントハンドラ
*
* @param event イベント
*/
private function _onClickForSendBt(event:Event, isResponse:Boolean = false):void
{
var data:Object = {};
data.message = _sendMessageTI.text;
_netStreamGroup.send(data);

_receiveMessageTA.text = data.message + "\n" + _receiveMessageTA.text;
_sendMessageTI.text = "";
}

/**
* データ受信イベントハンドラ
*
* @param event イベント
*/
private function _onReceiveData(event:NetStreamGroupEvent):void
{
var data:Object = event.info.receiveData;

if (data.ping) {
if (data.ping == "echoRequest") {
_netStreamGroup.send( { ping:"echoReply" } );
}else if (data.ping == "echoReply") {
_speedTxt.text = String(new Date().time-_time);
}
return;
}

_receiveMessageTA.text = data.message + "\n" + _receiveMessageTA.text;
}

/**
* 切断ボタンクリックイベントハンドラ
*
* @param event イベント
*/
private function _onClickForDisconnectBt(event:Event):void
{
_netStreamGroup.addEventListener(NetStreamGroupEvent.DISCONNECT_COMPLETE, _onDisconnectComplete);

_initializeBt.enabled = false;
_searchHostBt.enabled = false;
_farIDTI.enabled = false;
_connectBt.enabled = false;
_sendMessageTI.enabled = false;
_sendBt.enabled = false;
_disconnectBt.enabled = false;
_terminateBt.enabled = false;

_netStreamGroup.close();
}

/**
* 切断完了イベントハンドラ
*
* @param event イベント
*/
private function _onDisconnectComplete(event:NetStreamGroupEvent):void
{
_netStreamGroup.removeEventListener(NetStreamGroupEvent.DISCONNECT_COMPLETE, _onDisconnectComplete);

_farIDTI.enabled = true;
_connectBt.enabled = true;
_terminateBt.enabled = true;
}

/**
* 終了処理ボタンクリックイベントハンドラ
*
* @param event イベント
*/
private function _onClickForTerminateBt(event:Event):void
{
_netStreamGroup.addEventListener(NetStreamGroupEvent.TERMINATE_COMPLETE, _onTerminateComplete);

_initializeBt.enabled = false;
_searchHostBt.enabled = false;
_farIDTI.enabled = false;
_connectBt.enabled = false;
_sendMessageTI.enabled = false;
_sendBt.enabled = false;
_disconnectBt.enabled = false;
_terminateBt.enabled = false;
_netStreamGroup.terminate();
}

/**
* 終了処理完了イベントハンドラ
*
* @param event イベント
*/
private function _onTerminateComplete(event:NetStreamGroupEvent):void
{
_netStreamGroup.removeEventListener(NetStreamGroupEvent.TERMINATE_COMPLETE, _onTerminateComplete);

_initializeBt.enabled = true;
}

/**
* ネットステータスイベントハンドラ
*
* @param event イベント
*/
private function _onNetStatus(event:NetStreamGroupEvent):void
{
var kind:String;
switch (event.kind)
{
case NetStreamGroupEventKind.NET_CONNECTION:
kind = "NetConnection";
break;
case NetStreamGroupEventKind.SEND_NET_STREAM:
kind = "送信用 NetStream";
break;
case NetStreamGroupEventKind.RECEIVE_NET_STREAM:
kind = "受信用 NetStream";
break;
case NetStreamGroupEventKind.NET_GROUP:
kind = "NetGroup";
break;
default:
kind = "不明";
break;
}
try
{
_netStatusMessageTA.text = kind + " のイベント: " + event.info.code + "\n" + _netStatusMessageTA.text;
}
catch (e:Error)
{
}

if (!_isTryConnect && event.info.code == "NetGroup.Posting.Notify") {
_isTryConnect = true;
_searchHostBt.enabled = false;
_connectBt.enabled = true;
}
}

}
}
[/sourcecode]