After quite a long break, I resume the series of articles on my XNA Streaming project by describing the actual Stream Service component. This component is responsible for transmitting the broadcast information to all connected users.
The information is encoded in (<property name>, <value>) pairs. All serializable data types are supported for values. Users register with the Stream Service either as Broadcaster or as Observer. After this step, the Broadcaster uses the service to send updates for information (property-value pairs). Observers get notified by the service of the updated information via a IXNAStreamCallback callback contract, a feature of WCF services.
Updates for a certain variable can occur at a very high frequency (camera angle in a 3D application). If a separate call to the service would be generated every few milliseconds, then the service would easily become overwhelmed by the calls. The solution chosen is to “buffer” several information changes and send them all at time, at set time intervals. We name this “buffer” a TimeSlice. A time slice has a Duration and several time slice entries. A TimeSliceEntry has a PropertyName, a Value and a SliceOffset, used to express the time since the beginning of the TimeSlice when the value change has occurred. This way we gain control over the number of calls made to the service.
The Stream Service provides the following operations:
RegisterCallback: used to register with an application (given by name) for a role (given as a member of a GameMode enumeration). Only one Broadcaster can exist. This operation involves storing a user’s callback interface instance in a dictionary that has the application’s name as key and a list of callback interfaces (IXNAStreamCallback) instances.
UnregisterCallback: used to safely end a registration with an application (if a client does not unregister, sending updates or requesting the overall state would fail).
UpdateStateVariables: used to send a TimeSlice to all subscribers of an application. This is the actual method that performs the broadcast. It uses a method defined in the callback contract to broadcast the TimeSlice to all registered clients except the broadcaster.
GetCurrentState: to be used by an Observer in order to resynchronize with the broadcaster. This method should be called right after registering with an application. The GameState returned is a collection of game state entries. Each GameStateEntry contains a Key (the name of the variable) and a Value. The Stream Service request the current GameState from the Broadcaster via the callback contract.
The IXNAStreamCallback contract contains the following operations:
StateVariablesChanged: service calls this method for Observers whenever it receives a TimeSlice from the Broadcaster. It is up to the client to reconstruct the information changes in the TimeSlice with proper timing.
GetCurrentState: service calls this method for the Broadcaster whenever it receives a corresponding request from an Observer. The method returns the current GameState.
The Stream Service does not provide complex functionality, in order to make the actual information broadcast as fast as possible. The more complex functionality is implemented in the Communication Broker, that will be described in the next part of the series.