Network
Archives
Flash間データ通信:Flash Media Server 2
2009.10.16 金曜日
前回の記事で紹介した「Flash Media Server」を試す機会があったので、簡単なライブ映像のストリーミングサンプルをアップします。
下記サンプルコードを試すには、「Flash Media Server」をインストールする必要があります。インストールは前回の記事でも紹介した「Flash Media Server 2 メモ」などを参考にしてください。あと、「C:Program FilesAdobeFlash Media Server 3.5applications」に「test」フォルダが必要。
下記プログラムを実行すると、起動時にWebカメラの映像をそのまま表示、キーボードの「1」を押すと配信開始、「2」を押すと受信して表示します。
注意点は、受信時にvideoをそのままステージに追加していますが、これをBitmapDataにdraw()する場合、セキュリティエラーでひっかかるのでクロスドメイン関係の処理が必要になります。また以下はローカルホストで作業していますが、ネットワーク越しに作業する場合はポート番号1935を開放して下さい。
package {
import flash.display.MovieClip;
import flash.events.KeyboardEvent;
import flash.events.NetStatusEvent;
import flash.media.Camera;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.ObjectEncoding;
public class Main extends MovieClip {
//Webカメラ
private var camera:Camera;
//通信
private var nc:NetConnection;
//初期設定
public function Main():void {
//Webカメラの設定、配置
camera = Camera.getCamera("0");
camera.setMode(320, 240, 30, false);
var video:Video = new Video(camera.width, camera.height);
video.attachCamera(camera);
this.addChild(video);
//FMSの設定
nc = new NetConnection();
nc.objectEncoding = ObjectEncoding.AMF0;
nc.addEventListener(NetStatusEvent.NET_STATUS, CheckFMS);
nc.connect("rtmp://127.0.0.1/test");
//キーボード
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
}
//FMSステータス確認
private function CheckFMS(e:NetStatusEvent):void {
//取得
var info:String = e.info.code;
var status:String;
//ステータス出力
if (info == "NetConnection.Connect.Success") trace("Connected");
else if (info == "NetConnection.Connect.Closed") trace("Closed");
else if (info == "NetConnection.Connect.Failed") trace("Failed");
else if (info == "NetConnection.Connect.Rejected") trace("Rejected");
}
//キーボードが押された場合
private function KeyDown(e:KeyboardEvent):void {
//ストリーミング変数
var stream:NetStream;
//「1」
if (e.keyCode == 49) {
//Webカメラの映像を配信
stream = new NetStream(nc);
stream.attachCamera(camera);
stream.publish("sample");
//ステータス出力
trace("Send")
}
//「2」
else if (e.keyCode == 50) {
//ストリーミングを受信
stream = new NetStream(nc);
var video:Video = new Video(camera.width, camera.height);
video.attachNetStream(stream);
this.addChild(video);
video.x = camera.width;
stream.play("sample");
//ステータス出力
trace("Receive")
}
}
}
}
Posted by tmdf|ActionScript Network|comments (0)
Flash間データ通信:Flash Media Server
2009.10.4 日曜日
複数のFlash間のデータ通信に特化したAdobe純正サーバーソフトが「Adobe – Flash Media Server」です。本気仕様のサーバーソフトなので、同時アクセスが10台以下なら無償のデベロッパー版を試せますが、残念ながらWindowsとLinuxでしか動作しません。以前のバージョンですが「Flash Media Server 2 メモ」で、詳しく使い方などが掲載されているので参考にして下さい。
上記Webサイトを参考に、自分のWebカメラの映像を、ストリーミング用のクラスではなく、サーバーに作ったShareObjectを使ったバイト配列のやりとりで行おうとしたら320x240x5fpsぐらいしかスピードが出ませんでした。リアルタイムな映像の共有はストリーム用のクラスでやるべきみたいです。試す機会があったら追記します。
Posted by tmdf|ActionScript Network|comments (0)
Flash間データ通信:FlashLCS
2009.10.3 土曜日
前々回に紹介したLocalConnectionを独自に拡張した「FlashLCS」なるものが、今年登場していたようです。公式ブログ?によると20Mbpsくらい速度が出るそうなので、このライブラリを使っても40KB制限を気にせずに済みそうです。
この記事を書いている現在、google codeで公開されているページにはサンプル、リファレンスがないのでよく分かりませんでしたが、FASH CS4にasタイプのライブラリを使ってコンパイルするとエラーが出ていました。swcの方は試していません。
日本語の情報もあまりありませんが、「alt 無制限に双方向通信が可能なLocalConnectionクラス「FlashLCS」」でテストされている方がいます。サンプルコードも配布されているようですが、このページで使われているライブラリは、現在配られているものより少し古いバージョンのようで、こちらのライブラリを流用するとうまくコンパイルできました。
実験で書いた下記サンプルコードで、Webカメラの映像をリアルタイムに送信してみたところ、自分の環境では少し(0.2秒くらい)遅れてました。LCS_B → LCS_A の順に起動してデータを送信します。
//LCS_A.as
package {
import com.blitzagency.rpc.LocalConnectionService;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.events.Event;
import flash.media.Camera;
import flash.media.Video;
import flash.utils.ByteArray;
public class LCS_A extends MovieClip {
//データ送受信用変数
private var lcs:LocalConnectionService;
//Webカメラ用変数
private var video:Video;
//初期設定
public function LCS_A():void {
//LCS設定
lcs = new LocalConnectionService();
lcs.client = this;
lcs.connect();
//Webカメラ設定
var camera:Camera = Camera.getCamera("2");
camera.setMode(320, 240, 30);
//ビデオ設定
video = new Video(camera.width, camera.height);
video.attachCamera(camera);
//リスナー登録
this.addEventListener(Event.ENTER_FRAME, Update);
}
//データ送信
private function Update(e:Event):void {
//Webカメラの映像をバイト配列に変換
var bmd:BitmapData = new BitmapData(320, 240, false);
bmd.draw(video);
var data:ByteArray = new ByteArray();
data = bmd.getPixels(bmd.rect);
data.position = 0;
//描画更新
lcs.Update(data);
}
}
}
//LCS_B.as
package {
import com.blitzagency.rpc.LocalConnectionService;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.utils.ByteArray;
public class LCS_B extends MovieClip {
//データ送受信用変数
private var lcs:LocalConnectionService;
//画面表示用変数
private var bmd:BitmapData;
private var bmp:Bitmap;
//初期設定
public function LCS_B():void {
//LCS設定
lcs = new LocalConnectionService();
lcs.client = this;
lcs.connect();
//ビットマップ設定
bmd = new BitmapData(320, 240, false);
bmp = new Bitmap(bmd);
this.addChild(bmp);
}
//描画更新
public function Update(_data:ByteArray):void {
//バイト配列を画像に変換
_data.position = 0;
bmd.setPixels(bmd.rect, _data);
}
}
}
Posted by tmdf|ActionScript Network|comments (0)
Flash間データ通信:Socket
2009.10.2 金曜日
異なるPCで起動しているFlash間で通信を行いたい場合、TCPのソケットサーバーを間に立て、Socket通信を行うのがベストだと思います。FLASHはTCPといった遅い通信プロトコルを採用しているため、処理の重いString型を扱うXML Socket通信より、ByteArray型を扱うSocket通信を使った方が、若干スピードのメリットがあります。
話は逸れますが、Flashの扱えるTCPは信頼性>速度の通信プロトコルのため、データを確実に送ることはできますが、大容量のデータを送り続けた場合には数十秒のタイムラグが発生します。現在のFlashでは扱えないUDPは、信頼性<速度の通信プロトコルなので、いつかサポートしてほしいところです。プロトコルの詳しい情報はWikipediaの「TCP」と「UDP」などをご覧ください。
AIR2.0からUDPのサポート、TCPサーバー(以前はクライアントだけ)にもなれます。
Flashの間に立てるソケットサーバーですが、フリーウェアでは「Socket Debugger (Free)」があります。このソフトウェアはバッファサイズが99,999Byteが限度のようなので、大きいデータのリアルタイムなやりとりには向きませんが、ちょっとしたテスト環境の構築には便利です。
また、単純なTCPサーバーならProcessingでも作れます。下記コードでは「Flash clientA」からポート3000を通して「Processing serverA」にデータを送り、受信したデータを「Processing serverB」からポート3001経由で「Flash clientB」に戻しています。動作検証用のサンプルなので、同じPC内(localhost)にサーバーとクライアントの全てを起動させていますし、接続確認や細かいエラー処理などは省いています。Processing → FLASHの順に起動し、FLASHの画面をクリックするとデータの送受信を行います。
//Server.pde
import processing.net.*;
//サーバー変数
Server serverA;
Server serverB;
//初期設定
void setup() {
//サーバーの作成
serverA = new Server(this, 3000);
serverB = new Server(this, 3001);
}
//常時実行
void draw() {
//serverAに接続しているクライアントを取得
Client client = serverA.available();
//クライアントがいた場合
if (client != null) {
//データを取得
String data = client.readString();
//データがある場合
if (data != null) {
//serverBに書き込み
serverB.write(data);
}
}
}
//Client.as
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.net.Socket;
public class Client extends MovieClip {
//クライアント変数
private var clientA:Socket;
private var clientB:Socket;
//初期設定
public function Client():void {
//リスナー登録
stage.addEventListener(MouseEvent.CLICK, Send);
//clientA serverAに接続
clientA = new Socket();
clientA.connect(&quot;localhost&quot;, 3000);
//clientB serverBに接続、リスナー登録
clientB = new Socket();
clientB.addEventListener(ProgressEvent.SOCKET_DATA, Recieve);
clientB.connect(&quot;localhost&quot;, 3001);
}
//データ送信
private function Send(e:MouseEvent):void {
//データを書き込み
clientA.writeUTFBytes(String(Math.random()));
//serverAに送信
clientA.flush();
}
//データ受信
private function Recieve(e:ProgressEvent):void {
//受信した文字データを出力
trace(clientB.readUTFBytes(clientB.bytesAvailable));
}
}
}
Posted by tmdf|ActionScript Network Processing|comments (0)
Flash間データ通信:LocalConnection
2009.10.1 木曜日
普通は使うシチュエーションがあまりないと思いますが、複数のFlash間でのデータ通信の方法を数回にわたって紹介します。
まず最初は、同じPCで起動している複数のFlash間の通信を行いたい場合。これはLocalConnection(以下LC)が簡単。LCのメリットは、別のFlashの関数を呼び出して引数を直接渡せるところ。デメリットは40KBまでしか一度にデータを送れない、片方向通信なので双方向にするために2つのLCを作らないといけない、FLASHが強制終了した場合などにLCの切断(再接続)がうまくできない時がある、など。
このデメリットの中でも40KB制限が個人的には一番のネック。これの解決方法として思いついたのが、データ本体のやりとりには40KB制限のないShareObjectを使い、データ更新のプッシュ通知のみにLCを使った通信環境です。通信速度を正確に測ったことはありませんが、Webカメラの映像(320x240x30fps)をByteArray型に変換してリアルタイムに送信できてそうでした。ShareObjectを使っているので、ArrayやXMLなどのデータもそのまま保持できるのもメリットです。こういったShareObjectの使い方は、今後紹介しようと思っている「Flash Media Server」と似ています。
下記のサンプルコードは「LC_A」の画面クリックでデータ送信(SharedObject書き込み)、LCでプッシュ通知を受けた「LC_B」が受信(SharedObject読み込み)となっています。ポイントはSharedObject.getLocal()の第2引数のパスを設定するところ。サンプルのように”/”でなくてもいいですが、ここを共通のパスにしておかないとうまく動きません。また、このサンプルを試すにはFlash Playerの設定で「ローカル記憶容量」とプライバシーの高度な設定で「グローバルセキュリティ設定」を調整する必要があります。
//LC_A.as
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.net.LocalConnection;
import flash.net.SharedObject;
public class LC_A extends MovieClip {
//初期設定
public function LC_A():void {
//リスナー登録
stage.addEventListener(MouseEvent.CLICK, Send);
}
//データ送信
private function Send(e:MouseEvent):void {
//ShareObject設定
var so:SharedObject = SharedObject.getLocal("tmdf", "/";);
//データを設定
so.data.mouseX = mouseX
so.data.mouseY = mouseY;
//データを書き込み
so.flush();
//LocalConnectionでプッシュ通知
var lc:LocalConnection = new LocalConnection();
lc.send("tmdf", "Push");
}
}
}
//LC_B.as
package {
import flash.display.MovieClip;
import flash.net.LocalConnection;
import flash.net.SharedObject;
public class LC_B extends MovieClip {
//データ送受信用変数
private var lc:LocalConnection;
//初期設定
public function LC_B():void {
//LocalConnection設定
lc = new LocalConnection();
lc.client = this;
lc.connect("tmdf");
}
//プッシュ通知
public function Push():void {
//ShareObject設定
var so:SharedObject = SharedObject.getLocal("tmdf", "/");
//出力
trace(so.data.mouseX, so.data.mouseY);
}
}
}
Posted by tmdf|ActionScript Network|comments (1)