Red5でチャットや動画ライブストリミング配信とかやってみたよ

Red5のサンプルがいくつか更新されていたのでちょこっと勉強がてら遊んでみました。

作ったもの
簡単なチャットシステム

簡単なドラッグ共有

簡単なライブ配信システム

#録画はソース部分の"live"=>"record"でOK
参考にさせていただいたページ

こちらの本にRed5やらAMFやら旬な話題が載ってます。

The Essential Guide to Open Source Flash Development

The Essential Guide to Open Source Flash Development

ソースコードはこちら
#公式のサンプルがFlex1.5なのかそのままではうまくFlex3では動かなかったので、がんばって自分用に書きました。
チャットプログラム myChat.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    creationComplete="init()" backgroundAlpha="1" backgroundColor="0xffffff">
<mx:Script>
<![CDATA[
private var nc:NetConnection;
private var ns:NetStream;
private var dragging:Boolean = false;
private var so:SharedObject;
private function init():void{
    nc = new NetConnection();
    nc.client = new CustomClient();
    nc.objectEncoding = ObjectEncoding.AMF0;
    nc.connect("rtmp://localhost/oflaDemo");
    nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatus);
    nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
}
private function onNetStatus(evt:NetStatusEvent):void {
    //trace( "onNetstatus" );
    switch(evt.info.code) {
        case "NetConnection.Connect.Success":
            so = SharedObject.getRemote("ball", nc.uri, true );
            if( so ){
                so.addEventListener( SyncEvent.SYNC , function( evt:SyncEvent ):void{
                    if(dragging ) return;
                    serverTxt.text = "x=> " + so.data.mousePosition.x + " , y=> " + so.data.mousePosition.y;
                    logo.x = so.data.mousePosition.x;
                    logo.y = so.data.mousePosition.y;
                });
                so.connect(nc);
            }
            break;
        case "NetConnection.Connect.Closed":
            break;
        case "NetConnection.Connect.Failed":
            break;
        case "NetConnection.Connect.Rejected":
            break;
            default:
    }
}
private function onSecurityError(evt:SecurityErrorEvent):void {
}
private function startMove():void{
    dragging = true;
    logo.startDrag();
}
private function stopMove():void{
    dragging = false;
    logo.stopDrag();
}
private function onMouseMove():void{
    if( dragging == true ){
        localTxt.text = "x=> " + logo.x + " , y=> " + logo.y;
        so.setProperty("mousePosition", {x: logo.x, y: logo.y} );
    }
}
]]>
</mx:Script>
<mx:Image id="logo" x="51" y="111" width="192" height="176" source="logo.png"
    mouseDown="startMove()" mouseUp="stopMove()" mouseMove="onMouseMove()"/>
    <mx:Canvas x="10" y="10" width="255" height="72"
        backgroundAlpha="0.5" backgroundColor="0xffffff"
        dropShadowColor="0x000000" dropShadowEnabled="true"
        cornerRadius="10" borderColor="0xffccff" borderStyle="solid" borderThickness="3">
        <mx:Label x="10" y="10" text="Local:"/>
        <mx:Label x="10" y="36" text="Server:"/>
        <mx:Label x="68" y="10" id="localTxt" />
        <mx:Label x="68" y="36" id="serverTxt" />
    </mx:Canvas>
</mx:Application>

ドラッグ共有プログラム myBall.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute" creationComplete="init()"
    backgroundAlpha="1" backgroundColor="0xffffff">
<mx:Script>
<![CDATA[
private var nc:NetConnection = new NetConnection();
private var so:SharedObject;
private function init():void{
    nc = new NetConnection();
    nc.client = new CustomClient();
    nc.objectEncoding = ObjectEncoding.AMF0;
    nc.connect("rtmp://localhost/oflaDemo");
    nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatus);
    nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
}
private function onNetStatus(evt:NetStatusEvent):void {
    //trace( "onNetstatus" );
    switch(evt.info.code) {
        case "NetConnection.Connect.Success":
            trace("Success");
            initSO();
            break;
        case "NetConnection.Connect.Closed":
            trace("Closed");
            break;
        case "NetConnection.Connect.Failed":
            trace("Failed");
            break;
        case "NetConnection.Connect.Rejected":
            trace("Rejected");
            break;
            default:
        trace(evt.info.code);
    }
}
private function onSecurityError(evt:SecurityErrorEvent):void {
    trace("Security Error");
}
private function initSO():void{
    //trace( "initSO" );
    so = SharedObject.getRemote( "chat" , nc.uri , true );
    if( so ){
        so.addEventListener( SyncEvent.SYNC , function( evt:SyncEvent ):void{
            //trace( so.data.chatMessage );
            if( so.data.chatMessage != undefined ){
                history.text += so.data.chatMessage + "\n";
                message.text = "";
            }
        });
        so.connect(nc);
    }
}
private function sendMessage():void{
    //trace( "sendMessage" );
    if( message.text != "" ){
        //trace( "sendMessage2" );
        so.setProperty( "chatMessage" , message.text );
    }
}
]]>
</mx:Script>
<mx:TextInput id="message" x="10" y="220" width="402" enter="sendMessage()"
    backgroundAlpha="0.5" backgroundColor="0xffffff"
    dropShadowColor="0x000000" dropShadowEnabled="true"
    cornerRadius="10" borderColor="0xffccff" borderStyle="solid" borderThickness="3"
    />
<mx:TextArea id="history" x="10" y="10" width="505" height="202"
    backgroundAlpha="0.5" backgroundColor="0xffffff"
    dropShadowColor="0x000000" dropShadowEnabled="true"
    cornerRadius="10" borderColor="0xffccff" borderStyle="solid" borderThickness="3"/>
<mx:Button id="btn" x="420" y="220" label="コメントする" width="95" click="sendMessage()" height="24"/>
</mx:Application>

動画ライブストリーミングプログラム myStreaming.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute"
    creationComplete="init()"
    backgroundAlpha="1" backgroundColor="0xffffff">
<mx:Script>
<![CDATA[
private var nc:NetConnection;
private var ns:NetStream;
private var cam:Camera;
private var mic:Microphone;
private function init():void{
    nc = new NetConnection();
    nc.client = new CustomClient();
    nc.connect("rtmp://localhost/oflaDemo");
    nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatus);
    nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
    setupCameraMic();
}
private function onNetStatus(evt:NetStatusEvent):void {
    //trace( "onNetstatus" );
    switch(evt.info.code) {
        case "NetConnection.Connect.Success":
            ns = new NetStream( nc );
            trace("Success");
            break;
        case "NetConnection.Connect.Closed":
            trace("Closed");
            break;
        case "NetConnection.Connect.Failed":
            trace("Failed");
            break;
        case "NetConnection.Connect.Rejected":
            trace("Rejected");
            break;
            default:
    }
}
private function onSecurityError(evt:SecurityErrorEvent):void {
    trace("Security Error");
}
private function broadcastClick():void{
    ns.attachCamera(cam);
    ns.attachAudio(mic);
    //ns.publish( "red5BroadcastDemo" , "record" );
    ns.publish( "red5BroadcastDemo" , "live" );
    playButton.enabled = false;
    stopButton.enabled = true;
}
private function stopClick():void{
    ns.close();
    playButton.enabled = true;
    stopButton.enabled = false;
}
private function setupCameraMic():void{
    cam = Camera.getCamera();
    cam.setMode(320, 240, 30);
    cam.setQuality(0,90);
    mic = Microphone.getMicrophone();
    mic.rate = 44;
    if(cam != null) {
        videoContainer.attachCamera(cam);
    }
}
]]>
</mx:Script>
    <mx:Canvas x="42" y="27" width="338" height="260"
        backgroundAlpha="0.5" backgroundColor="0xffffff"
        dropShadowColor="0x000000" dropShadowEnabled="true"
        cornerRadius="10" borderColor="0xffccff" borderStyle="solid" borderThickness="3"
        >
        <mx:VideoDisplay id="videoContainer" x="6" y="7" width="320" height="240"/>
    </mx:Canvas>
    <mx:Canvas x="216" y="304" width="164" height="44"
        backgroundAlpha="0.5" backgroundColor="0xffffff"
        dropShadowColor="0x000000" dropShadowEnabled="true"
        cornerRadius="10" borderColor="0xffccff" borderStyle="solid" borderThickness="3"
        >
        <mx:Button id="playButton" x="9" y="8" label="broadcast" click="broadcastClick()"/>
        <mx:Button id="stopButton" x="100" y="8" label="stop" click="stopClick()" enabled="false"/>
    </mx:Canvas>
</mx:Application>

動画ライブストリーミング再生 myStreamingPlayer.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    backgroundAlpha="1" backgroundColor="0xffffff"
    creationComplete="init()" xmlns:media="flash.media.*">
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
private var nc:NetConnection;
private var ns:NetStream;
private var cam:Camera;
private var mic:Microphone;
private function init():void{
    nc = new NetConnection();
    nc.client = new CustomClient();
    nc.connect("rtmp://localhost/oflaDemo");
    nc.addEventListener(NetStatusEvent.NET_STATUS,onNetStatus);
    nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
}
private function onNetStatus(evt:NetStatusEvent):void {
    //trace( "onNetstatus" );
    switch(evt.info.code) {
        case "NetConnection.Connect.Success":
            setupCameraMic();
            trace("Success");
            break;
        case "NetConnection.Connect.Closed":
            trace("Closed");
            break;
        case "NetConnection.Connect.Failed":
            trace("Failed");
            break;
        case "NetConnection.Connect.Rejected":
            trace("Rejected");
            break;
            default:
    }
}
private function onSecurityError(evt:SecurityErrorEvent):void {
    trace("Security Error");
}
private function setupCameraMic():void{
    ns = new NetStream( nc );
    ns.client = new CustomClient();
    var video:Video = new Video();
    video.attachNetStream(ns);
    ns.play("red5BroadcastDemo" , -1 );
    myVideoContainer.addChild(video);
}
private function onMetaData(data:Object):void{
}
]]>
</mx:Script>
<media:Video id="myVideo" width="320" height="240"/>
    <mx:Canvas x="33" y="40" width="342" height="269"
        backgroundAlpha="0.5" backgroundColor="0xffffff"
        dropShadowColor="0x000000" dropShadowEnabled="true"
        cornerRadius="10" borderColor="0xffccff" borderStyle="solid" borderThickness="3"
        >
        <mx:VideoDisplay id="myVideoContainer" width="320" height="240" x="8" y="10"/>
    </mx:Canvas>
</mx:Application>