If you want to speed up my development process,
donate.
2.1 Overview
Milenia doesn't need installation, since it's one single ( 64 Kbtye length ) java jar file, you simply execute it with the java virtual machine. First you have to be sure that your system has Java Runtime Environment 1.5 or higher. If not, download it from sun. If you have it, simply type java -jar milgra.jar in the command line, and it should show up the version info and the parameter hints.The basic server package looks like this:applications <DIR>streams <DIR>sources <DIR>milgra.jarlicense.txt"applications" is the default custom application directory for the server. You have to copy your custom application jars here. "streams" is the default directory for streams, Milenia saves recorded stream here. "sources" contains the sources and the compiled admin application also. "milgra.jar" is the server itself, "license.txt" is the GPL v2 license.
2.2 Parameters
start
starts the server on the default port ( 1935 )
stop
stops the server on the default port ( 1935 )
port [number]
sets the listener port to given number
iostep [number]
sets the io process stepping delay in milisecs. Default is 15
iothreads [number]
sets the thread counts of process groups. If your server isn't under a heavy load, or you want other services to run on your machine, one thread is enough. But if you have a multi-processored multi-cored monster, you can start experimenting with this setting and the stress tester. It won't speed up data throughput since only one process can reach the system bus and the sockets at a time, but it fastens stream pushing between threads, and data processing also.
streams [directory]
sets the stream directory where milenia stores/reads up streams. The directory will be created under the directory where milgra.jar is
applications [directory]
sets the custom application directory where milenia looks for custm applications. The directory will be created under the directory where milgra.jar is.
examples:
The following command starts the server listeneing on port 80, with 20 milliseconds of io stepping and with the default stream directory "mystreams"
java -jar milgra.jar start port 80 iostep 20 streams mystreams
The following command stops the server listening on port 80
java -jar milgra.jar stop port 80
For performance tuning you may have to use additional java virtual machine switches, for example,
- server
or if jvm runs out of memory
-Xmn -Xms -Xmx to set memory size.
The following command starts Milenia with default settings with 500 megabytes of maximum memory usage.
java -Xmx500M -jar milgra.jar start
2.3 Admin Console
To use the admin console, ensure that the server-side application ( admin.jar ) is under the Milenia's custom application directory, and the server is running.Open admin.swf ( under sources directory by default ) in a web browser having Flash Player 9. For the first run type "admin" for both username and password.
Admin application creates a fourth directory called "admin" in Milenia's root for its config file and logs. I recommend to immediately set a new username/password in admin/config.xml, and you may define allowed ip addresses also.
In the console, you will see two main tabs, the Graphs and the Applications.
Graphs tab
After a succesful login, you will find yourself at the graphs tab. These graphs shows the i/o states of the server. "Bandwidth" shows the overall, incoming, and outgoing bandwidth in Megabits/second. "Connected Clients" shows the overall, passive and active client count on the server. Active clients are the clients created by a custom application to connect to other servers. "Processing Threads" shows socket, client and stream pool processing thread count," Execution Times" show the average process execution times of the different thread pools.
Applications tab
You can check the available applications here. They consists of the custom applications under Milenia Grafter Server / applications directory, and the running applications ( if custom application jar has been removed from the directory, but the application hasn't been unloaded ). You can check the status, connected clients and bandwidth info of an application. You can refresh application list any time, this case Milenia will reread the applicaitons directory. You have to wait for the next refresh event to see the new list. You can unload/load applications by pressing load/unload buttons.
Under applications tab, it will show one connected client ( you ) and one running application ( the admin application ).l
I also encourage the use of jconsole if you want to receive really detailed information about your machine and jvm health status.
2.4 Stress Tester
You can test how much load the server can handle on your system with the Stress Test part of the console.
If the server halts with a "java heap space" out of memory error, you have to give more memory to the virtual machine with, for example -Xmn100M -Xms500M -Xmx500M switches.
2.5 Unit tester
If you modified and want to test the server's source, or just want to check what milenia knows, you can start the unit tester client, and go through all the tests, it covers all functions of Milenia.
3.1 Overview
You can create custom applications or application packages for Milenia Grafter Server in Java. You simply have to create a jar package from your packages / classes, and copy it under Milenias custom application folder, and they are ready to use. Custom applications are dynamically loaded at startup and on the fly triggered from the admin console. Custom applications must not be in the classpath, otherwise jvm cannot reload them.
Development tip : always create a startup script, which compiles/packs your custom application in your workspace, then copies it under milenia, and starts up the server.
To reach Milenia's API, you have to use the API classes packed in Milenia.
There are three main rules for a custom application:
1. The main class of your application must be called Application
2. The main class of your application must be in a package called application
3. The main class of your application must implement IApplication interface
You have to be careful on the server with threads, because various events can come from various threads, use synchronization when there can be concurrencies.
There is also an important thing for the client side : never forget to set AMF object encoding to AMF0 on the client side, because Milenia uses AMF0.
3.2 IApplication interface - com.milgra.server.api.IApplication
You have to implement IApplication interface in the main class of your custom application. IApplication contains three main controller methods:
onClose ( )
The server will call it when the admin unloads this application from admin console during runtime. You have to define a complete cleanup code here to avoid memory leaks.
onEnter ( Client clientX , WrapperList argumentsX )
Client entering point, clientX is the client instance, messageX is the wrapperlist containing the arguments passed by the client. clientX will be in idle state, until you call the clientX.accept( ) or clientX.reject( ) methods.
onLeave ( Client clientX );
Client leaving point, do client-related cleanup here.
3.3 Client class - com.milgra.server.api.Client
Client class contains client related properties and methods.
Constructor
public Client ( IApplication applicationX )
You can create a new client instance with the constrcutor, attached to the given application. After creation, you can connect the client to a remote server, and exchange data, pull/push streams
Methods
public String getId ( )
The unique identifier number of the client.
public String getIp( )
The ip address of the client.
public String getAgent( )
The player / server info of the client.
public String getReferrer( )
The referrer of the client.
public Double getPing( )
The ping rountrip time of the client.
public Double getBandIn( )
The actual incoming bandwidth of the client in bytes per second.
public Double getbandOut( )
The actual outgoing bandwidth of the client in bytes per second.
public long getBytesIn( )
The received byte count by the server from this client
public long getBytesOut( )
The sent byte count to this client
public void addStreamEventListener ( EventListener listenerX )
You may add a stream event listener object to the client with this method.
public void addInvokeEventListener ( EventListener listenerX )
You may add an invoke event listener object to the client with this method.
public void addStatusEventListener ( EventListener listenerX )
You may add a status event listener object to the client with this method.
public HashMap < Double , String > getPlayers ( )
Returns the list of streams played by the client
public HashMap < Double , String >getRouters ( )
Returns the list of streams published by the client
public void call ( String invokeID )
Invokes a method on client side without arguments
public void call ( String invokeID , Wrapper argumentX )
Invokes a method on client side with a wrapper as arguments
public void call ( String invokeID , WrapperList argumentX )
Invokes a method on client side with an wrapperlist as argument
public void callResult ( String invokeID , Wrapper argumentX )
If a responder for a specific function is defined on client side, you may pass back a result with this function
public void callResult ( String invokeID , WrapperList argumentsX )
If a responder for a specific function is defined on client side, you may pass back a result with this function with a wrapperlist as an arguments
Passive mode only methods
public void accept ( )
Accepts the client
public void accept ( Wrapper wrapperX )
Accepts the client with a wrapper as acception info, the client receives it as the NetStatus event's info.applicaiton parameter
public void reject ( Wrapper wrapperX )
Rejects the client, you can pass a wrapper as rejection info, the client receives it as the NetStatus event's info.application parameter
public void detach ( )
Detaches the client from the server
Active mode only methods
public void connect ( String uriX , Wrapper argumentsX )
Connects the client to a remote server with address uriX, passing argumentX as connection object
public void connect ( String uriX , WrapperList argumentsX )
Connects the client to a remote server with address uriX, passing argumentsX as connection object
3.4 Stream class - com.milgra.server.api.stream
Stream class contains stream related properties and methods. There are two types of stream on Milenia : incoming streams, which is published by clients or other servers, and outgoing streams, which are played by clients or pushed by the server. Incoming streams are represented by stream routers, outgoing streams by stream players. Both of them are represented by the stream class. However if stream instance is a stream player, you can only enable/disable/delete it, other methods aren't working on it.
Mileania's stream pool is shared, so every applicaiton can reach every stream published to the server.
You can publihs/record/play streams from clients without access control by default. If you want to control stream access, you have to define a stream event listener in your custom application, and add it to the client with client.addStreamEventListener.
After this you will be notified about every NetStream.play and NetStream.publish event, and you have to enable or disable these requests.
Properties
public static final String PLAYER;
player type identifier
public static finalString ROUTER;
router type identifier
public String type;
type of the stream, can be PLAYER or ROUTER
public Client client;
owner of the stream, if stream has no owner, then null
public String name;
name of the played/routed stream. router names are unique, but multiple players can have the same name, when they are playing the same stream.
public String mode;
if type is router, then recording mode. can be live, record, append
public boolean hasVideo;
the stream transfers video data
public boolean hasAudio;
the stream transfers audio data
Methods
public Stream ( StringnameX )
creates a stream on local server under the given name
public Stream ( String nameX , Client clientX )
creates a stream on remote server defined by clientX.
public void play ( String nameX )
starts playing the given stream. if given stream doesn't exist, it waits for its appereance. If stream name exists, starts playing immediately, and you can play it from clients/push it to other server. If stream name ends with ".flv", it tries to play a recorded stream with that name from the default stream directory.
public void stop ( )
stops playing the stream.
public void pause ( boolean stateX )
pauses/resumes stream playing
public void record ( boolean stateX )
starts/stops recording the specific streams
public void delete ( )
deletes the stream from the server, if its a live stream, its broadcasting is stopped
public void enable ( )
enables a stream route/play request. if you have defined a stream event listener for a client, you have to enable/disable streams related to incoming events
public void disable ( )
disables a stream route/play request, the client will receive a NetStream.Publish.Failed or NetStream.Play.Failed event. if you have defined a stream event listener for a client, you have to enabled/disable streams related to incoming events.
public void enableAudio ( boolean stateX )
enables/disables audio transfer in the specific stream
public void enableVideo ( boolean stateX )
enables/disables video transfer in the specific streams
Static mehods
public static ArrayList < Stream > getPlayers ( )
returns an arraylist of all players available on the server
public static ArrayList < Stream > getRouters ( )
returns an arraylist of all routers available on the server
3.5 Wrapper classes
Wrapper classes are a simple value wrappers, but most of your time programming Milenia Grafter Server you will use wrappers.
As you know, java is a strictly typed language and actionscript is weakly typed. During data exchange flash can send objects and arrays containing mixed data types, and on the java side after deserialization we have to keep this state somehow in the strictly typed environment. That's why Wrapper class was born. AMF deserializer wraps data in Wrapper objects, and serializer uses Wrappers for input also.
public class Wrapper
wraps a java data type
Properties
public String type
contains the type of the wrapped value
public double doubleValue
the value of a wrapped double
public String stringValue
the value of a wrapped string
public boolean booleanValue
the value of a wrapped boolean
public WrapperMap mapValue
the value of a wrapped WrapperMap
public WrapperList listValue
the value of a wrapped WrapperList
Static properties
public static final String MAP
HashMap type identifier constant
public static final String NULL
Null type identifier constant
public static final String LIST
ArrayList type identifier constant
public static final String DOUBLE
Double type identifier constant
public static final String STRING
String type identifier constant
public static final String BOOLEAN
Boolean type identifier constant
Methods
public Wrapper ( valueX )
the constructor of Wrapper, accepts double, boolean, string, hashmap, arraylist
as parameters, if it receives no parameter, then wrapped type will be null.
public class WrapperList
wraps an ArrayList of wrapper objects
Methods
public WrapperList ( )
public WrapperList ( Wrapper itemX )
public WrapperList ( List < Wrapper > sourceX )
public void add ( )
public void add ( String stringX )
public void add ( double doubleX )
public void add ( boolean booleanX )
public void add ( WrapperMap mapX )
public void add ( WrapperList listX )
public String getType ( int indexX )
public String getString ( int indexX )
public double getDouble ( int indexX )
public boolean getBoolean ( int indexX )
public WrapperMap getMap ( int indexX )
public WrapperList getList ( int indexX )
public class WrapperMap
wraps a HashMap of wrapper objects
Methods
public WrapperMap ( )
public WrapperMap ( Map < String , Wrapper > sourceX )
public WrapperMap ( String [ ] keysX , Object [ ] valuesX )
public void put ( String keyX )
public void put ( String keyX , String stringX )
public void put ( String keyX , double doubleX )
public void put ( String keyX , boolean booleanX )
public void put ( String keyX , WrapperMap mapX )
public void put ( String keyX , WrapperList listX )
public String getType ( String keyX )
public String getString ( String keyX )
public double getDouble ( String keyX )
public boolean getBoolean ( String keyX )
public WrapperMap getMap ( String keyX )
public WrapperList getList ( String keyX )
3.6 InvokeEvent
InvokeEvent is an event information holder for invoke calls. It is dispatched by client instances. To watch for invoke events, first you have to create an instance of the EventListener class, and redefine its onEvent function where you define what to do with the event, then you have to add this eventlistener instance to a client by calling Client.addInvokeEventListener.
Properties
public String id
identifier of the call, this is what you pass on the client side with NetConnection.call( identifier ... )
public Client client
the client instance where this event is coming from
public WrapperList arguments
the arguments related to this call
3.7 Stream Events
StreamEvent is an event information holder for stream events. It is dispatched by client instances To watch for stream events, first you have to create an instance of the EventListener class, and redefine its onEvent function where you define what to do with the event, then you have to add this eventlistener instance to a client by calling Client.addStreamEventListener.
Properties
public Client client
the client instance where this event is coming from
public Stream stream
the stream instance related to this stream. you may check the type of the instance first with Stream.type, then the name with Stream.name, then you have to enable or disable this request with Stream.enable( ) or Stream.disable( ). you can event store the stream instance, and enable/disable it later, the stream will be in idle state till that, and wont transfer any data.
3.8 Status Events
StatusEvent is an event information holder for client's status or stream events. It is dispatched by client instances To watch for status events, first you have to create an instance of the EventListener class, and redefine its onEvent function where you define what to do with the event, then you have to add this eventlistener instance to a client by calling Client.addStatusEventListener.
Properties
public String code
the code word for the actual event
public Client client
the client instance where this event is coming from
public WrapperMap info
the information map related to the event
Static Properties
public static final String FAILURE
connection failure event code word container.
public static final String CLOSURE
connection closure event code word container
public static final String SUCCESS
connection success event code word container. the info property of the event may
contain additional information about the success in the "application" key
public static final String REJECTION
connection rejection event code word container. the info property of the event may contain additional information about the rejection in the "application" key
public static final String PLAYSTART
If client is pushing a stream to a remote server, this is the event code word for a succesful play start
public static final String PLAYRESET
public static final String PLAYFAILED
public static final String PUBLISHSTART
public static final String RECORDNOACCESS
public static final String UNPUBLISHSUCCESS
3.9 Utilities
Timer - com.milgra.server.api.Timer
Simple timer. You have to define an EventListener first, then instantiate the timer with an arbitray interval in milliseconds, and the eventlistener. For example:
LogWriter - com.milgra.server.util.LogWriter
Log writer. Instantiate it with the log file name, then call addLog( String log ) to add new entry. Close it with close( ). Example: