If your local network supports broadcasting, you can create peer-to-peer direct routing. All the clients need to be on the same subnet, but you do not need to manage them. Verify that your devices have WiFi enabled and are using the same network.
The code to create a peer-to-peer application with RTMFP is quite simple but introduces new concepts. Let’s go over all the steps one at a time.
The connection is established using the flash.net.NetConnection class. Set a listener to receive a NetStatusEvent event. Create the connection by calling the connect function and passing rtmfp as an argument:
[code]
import flash.net.NetConnection;
import flash.events.NetStatusEvent;
var connection:NetConnection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
connection.connect(“rtmfp:”);
[/code]
Wait for the connection to be established. Then several objects need to be created:
[code]
function onStatus(event:NetStatusEvent):void {
switch(event.info.code) {
case “NetConnection.Connect.Success” :
trace(“I am connected”);
// object creation can now happen
break;
}
}
[/code]
NetGroup is the group of peers. Its capabilities are defined in the GroupSpecifier. The IPMulticastAddress property stores the IPv4 multicast address. It needs to be in the range 224.0.0.0 through 239.255.255.25. The UDP port should be higher than 1024. A group name is passed in its constructor. Try to make it unique. The IPMulticast MemberUpdatesEnabled property must be set to true for clients to receive updates from other clients on a LAN. The postingEnabled property allows clients to send messages to the group:
[code]
import flash.net.GroupSpecifier;
var groupName:String = “com.veronique.simple/”;
var IPMulticastAddress:String = “230.0.0.1:3000″;
var groupSpec:GroupSpecifier = new GroupSpecifier(groupName);
groupSpec.addIPMulticastAddress(IPMulticastAddress);
groupSpec.ipMulticastMemberUpdatesEnabled = true;
groupSpec.postingEnabled = true;
[/code]
Now create the NetGroup. Pass the connection and the GroupSpecifier in its construction. The latter is passed with an authorization property to define the communication allowed: groupspecWithAuthorizations to post and multicast, or groupspecWithout Authorizations to only receive messages. Note that this setting is only relevant if a posting password is set (as defined by your application):
[code]
import flash.net.NetGroup;
var netGroup = new NetGroup
(connection, groupSpec.groupspecWithAuthorizations());
netGroup.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
[/code]
The group is composed of neighbors, you as well as others. Using the same Net StatusEvent event, check for its info.code. Wait to receive the NetGroup.Connect.Suc cess event before using the functionality of NetGroup to avoid getting an error.
When a user joins or leaves the group, the code is as follows:
[code]
function onStatus(event:NetStatusEvent):void {
switch(event.info.code) {
case ” NetGroup.Connect.Success” :
trace(“I joined the group”);
break;
case “NetGroup.Connect.Rejected” :
case “NetGroup.Connect.Failed” :
trace(“I am not a member”);
break;
}
}
[/code]
Others in the group receive the following events. Note that if the group is large, only a subset of members is informed that a new peer has joined or left the group:
[code]
function onStatus(event:NetStatusEvent):void {
switch(event.info.code) {
case “NetGroup.Neighbor.Connect” :
trace(“neighbor has arrived”, neighborCount);
break;
case “NetGroup.Neighbor.Disconnect” :
trace(“neighbor has left”);
break;
}
}
[/code]
To send a message, use the NetGroup.post method. It takes an Object as an argument. Messages are serialized in AMF (binary format for serialized ActionScript objects), so a variation of data types can be used, such as Object, Number, Integer, and String types:
[code]
var message:Object = new Object();
message.type = “testing”;
message.body = {name:”Véronique”, greeting:”Bonjour”};
group.post(message);
[/code]
To receive messages, check for an info.code equal to a NetGroup.Posting.Notify event. The message is received as event.info.message. The message is not distributed to the sender:
[code]
function onStatus(event:NetStatusEvent):void {
switch(event.info.code) {
case “NetGroup.Posting.Notify” :
trace(event.info.message); // [Object]
trace(event.info.message.body.greeting); // Bonjour
break;
}
}
[/code]
Identical messages are not re-sent. To make each message unique, store the current time as a property of the object:
[code]
var now:Date = new Date();
message.time = now.getHours() + “_” + now.getMinutes() +
“_” + now.getSeconds();
group.post(message);
[/code]
If the message only goes in one direction and there will be no overlap between clients, you could use a counter that gets incremented with every new message:
[code]message.count = count++;[/code]
When disconnecting, it is important to remove all objects and their listeners:
[code]
function onStatus(event:NetStatusEvent):void {
switch(event.info.code) {
case “NetConnection.Connect.Rejected” :
case “Connect.AppShutdown” :
trace(“I am not connected”);
onDisconnect();
break;
}
}
function onDisconnect():void {
group = null;
netGroup.removeEventListener(NetStatusEvent.NET_STATUS, onStatus);
netGroup = null;
connection.removeEventListener(NetStatusEvent.NET_STATUS, onStatus);
connection = null;
}
[/code]
Color Exchange
Let’s create a simple example. The hueMe application starts with a shape of a random color. Each client can send a color value to the other client’s application. On the receiving end, the shape changes to the new color (see Figure 15-1).
Draw the initial colored sprite:
[code]
var sprite:Sprite = new Sprite();
var g:Graphics = sprite.graphics;
g.beginFill(Math.round(Math.random()*0xFFFFFF));
g.drawRect(20, 20, 200, 150);
g.endFill();
[/code]
Create the connection for the P2P communication:
[code]
var connection:NetConnection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
connection.connect(“rtmfp:”);
[/code]
Once the connection is established, create the group and check that the user has successfully connected to it:
[code]
function onStatus(event:NetStatusEvent):void {
if (event.info.code == “NetConnection.Connect.Success”) {
var groupSpec:GroupSpecifier = new GroupSpecifier(“colorGroup”);
groupSpec.addIPMulticastAddress(“225.0.0.1:4000”);
groupSepc.postingEnabled = true;
groupSepc.ipMulticastMemberUpdatesEnabled = true;
group = new NetGroup(connection,
groupSpec.groupspecWithAuthorizations());
group.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
} else if (event.info.code == “NetGroup.Connect.Success”) {
trace(“I am part of the group “);
}
}
[/code]
Send a random color value to the group when clicking the sprite:
[code]
g.addEventListener(MouseEvent.CLICK, hueYou);
function hueYou(event:MouseEvent):void {
var randomHue:int = Math.round(Math.random()*0xFFFFFF);
var object:Object = {type:”color”, hue:randomHue};
group.post(object);
}
[/code]
Finally, add the functionality to receive the value from other members of the group and color the sprite:
[code]
import flash.geom.ColorTransform;
function onStatus(event:NetStatusEvent):void {
…
if (event.info.code == “NetGroup.Posting.Notify”) {
if (event.info.message.type == “color”) {
applyColor(Number(event.info.message.hue));
}
}
}
function applyColor(hue:int):void {
var colorTransform:ColorTransform = new ColorTransform();
colorTransform.color = hue;
sprite.transform.colorTransform = colorTransform;
}
[/code]
Companion AIR Application
To make your application unidirectional, as in a remote control-style application, have one client sending messages and the other receiving messages. Only the networked clients registered for the NetGroup.Posting.Notify event receive data.
Mihai Corlan developed an Android remote control for a desktop MP3 player; read about it at http://corlan.org/2010/07/02/creating-multi-screen-apps-for-android-and -desktop-using-air/.
Tom Krcha created a remote controller to send accelerometer, speed, and brake information to a car racing game (see http://www.flashrealtime.com/game-remote-device-con troller/).