Currently viewing: Streamspin » Main
Click here to view an introduction about Streamspin and how to create your own services.
Click here to download the StreamSpin VS2005 code templates.
Click here to download the CrypToLib .dll used for creating timestamp and signatures.
Click here to view the StreamSpin Web-services API.
Click here to download the StreamSpin .Net API
Click here to view the documentation for the StreamSpin .Net API
Click here to download the StreamSpin PHP API (see the README file for usage)
Click here to download the StreamSpin Java API (see the readme.html file for usage)
Click here to download the StreamSpin .Net Mobile Emulator User Control.
Click here to view a programmers guide to Streamspin.
Click here to view a short introduction to using the Windows Mobile emulator for testing your services. (This is an edited version of a section from the book: Mobile Phone Programming and its Application to Wireless Networking - ISBN: 978-1-4020-5968-1)

Installing VS2005 code templates

The code template is installed by placing the 3 template-files :

    StreamSpinRecieveLocationWebservice.zip
    StreamSpinServiceServer.zip
    StreamSpinSimpleServiceServer.zip

in the visual Studio 2005 template folder usually placed at :

    C:\Documents and Settings\admin\My Documents
    \Visual Studio 2005\Templates\ProjectTemplates

Restart Visual Studio and the templates are visible when creating new projects.

    [FILE][NEW][PROJECT] under [MY TEMPLATES]

The webservice template is accessible using.

    [FILE][NEW][WEB SITE] under [MY TEMPLATES]
The StreamSpinSimpleServiceServer VS2005 code template

The important part of the simple server is in Program.cs.

All action in this code occurs whenever the timer performs a tick. The action uses the StreamSpin web-service at services.streamspin.com.

Line 34 creates a StreamSpin content message.

Line 35 sets the message title, and line 36 sets the description or URL of the message.

If a message url is provided, the URL will be loaded when the user clicks the message description.

An extended description will be shown in the same manner. The URL and corresponding page must be used in order to load images.

The extended description only allows for both plain text and HTML.

Lines 38 - 54 signs the content object using the private secret key available from www.streamspin.com/Myinfo.aspx.

The signature is created using the CryptoLib dll dll file freely available from http://www.streamspin.com/.

The parameters in the signature text must be in alphabetical order.

//create a content object.
streamspinContentPublisher.Content content = new
StreamSpinSimpleServiceServer.streamspinContentPublisher.Content();

content.Description = "[MESSAGE DESCRIPTION]";
content.Url = "[MESSAGE URL OR EXTENDED DESCRIPTION]";

//the id of the service to which you are publishing.
int serviceId = -1;

//create a timestamp to be used with the signature
string timestamp = CryptoLib.Signatures.CreateTimeStamp(DateTime.Now);

//create the text message to be signed from the alphabetized parameters and timestamp.
string text = content.Description + content.Url + serviceId.ToString() + timestamp;

//find your secret on www.streamspin.com/MyInfo.aspx and sign the text.
string signature = CryptoLib.Signatures.Sign(text,
"[YOUR SECRET KEY]");

//create a publisher object
streamspinContentPublisher.ContentPublishing contentPublisher = new
StreamSpinSimpleServiceServer.streamspinContentPublisher.
ContentPublishing();

//publish your content. The server return codes is available
on http://www.streamspin.com/Unprotected/WebserviceAPI.aspx
#streamspinerrorcodes.
int returnVal = contentPublisher.PublishPrivateContent(content, serviceId, signature, timestamp);

The StreamSpinServiceServer VS2005 code template

The StreamSpinServiceServer template allows you to create a more complex streamspin service server. This server will use the locations of subscribed users when delivering service messages.

Start out by adding a new StreamSpinRecieveLocationWS web-service.

Now go to the StreamSpinServiceServer Server.cs class.

Change the following to point to the webadress of the web-service just created.

private string recieveLocationWebService = "http://[address]/.[name].asmx";

Insert your user key.

private string secretKey = "[insert your secret key]";

Change the service id in line 34.

private int serviceId = [insert the id of the service];

Go to the Server constructor and load your users from a database or XML.

Now go to the User.cs class file lines 51 and 56 and set the content message and description.

Use the guidelines in lines 26 - 42 to add location aware functionality.
The StreamSpinRecieveLocationWS VS2005 code template

The only change needed in the location recieve web-service is in line 35.

private string server = "[SERVER ADDRESS]";

The server address should be the ip or web-adress of a service server capable of recieving streamspin user locations over TCP-IP.

The location aware server can be created from the StreamSpinServiceServer VS2005 code template.
Walk-through: The TourBuilder private service server

The TourBuilder service allows users to build location aware mobile tours. The tours are constructed using a website where the user creates a tour containing one or more toursights. Each toursight has a location which is chosen using google maps. Whenever a user following one of the tours gets within a thresshold of one of the toursights, the toursight will be shown on the users mobile device.

The TourBuilder private service uses a website to set up the tours. The website will not be presented in this walk-through. Instead we will be looking at the Tourbuilder server.

You can download the source for the server here.

The TourServer console application is the actual server.

The DataLogic class-library is used for database access.

The TourLocationRecieveWS is a web-service used for receiving user location-changes from the StreamSpin server.

We use to servers in the console application server, one registering users wanting to join tours, and one listening for user location-changes.

This is why we use the following properties: two sets of ports, TCPListeneres, and threads.

TourServer.Program.cs

//server listening for user location changes
private const int port = 20000;
private Thread serverThread;
private TcpListener serverListener = null;

//server listening for users wanting to start tours.
private const int tourstarterport = 20001;
private Thread tourserverthread;
private TcpListener tourserverListener = null;

//a dictionary holding a userid and the tour he requested
IDictionary<int, Tour> runningTours = new Dictionary<int, Tour>();

//the streamspin user location webservice
UserLocationWS.UserLocation userLocationRequestWS = null;


We now move on to creating the two servers.

The server listening for users requesting tours is:

TourServer.Program.cs

...
private void StartTourStarterServer()
{
  bool running = true;
  serverListener = null;

  while (running)
  {
    try
    {
      IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
      IPAddress localAddr = host.AddressList[0];

      tourserverListener = new TcpListener(localAddr, tourstarterport);

      tourserverListener.Start();

      while (running)
      {
        try
        {
          TcpClient client = tourserverListener.AcceptTcpClient();
          Stream s = client.GetStream();

          BinaryReader binReader = new BinaryReader(s);

          //the id of the user to which the request is related
          int userID = binReader.ReadInt32();

          //The service id to which the user is subscribed
          int serviceID = binReader.ReadInt32();

          //Request location changes from the StreamSpin server
          if (RegisterUserLocationRequest(userID, serviceID))
          {
            //Start monitoring the location of the user
            runningTours.Add(userID, new Tour(serviceID));
          }

          client.Close();
        }

        catch (Exception ex)
        {
          running = false;
        }
      }
    }
    catch (Exception ex)
    {
       running = false;
    }
  }
}
...

The server listens for incomming connections. When connected it tries to retrieve ther userid and serviceid

The server now tries to register a user location request with the StreamSpin online server via a web-service.

TourServer.Program.cs

...
public bool RegisterUserLocationRequest(int userId, int serviceId)
{
  try
  {
    string url = "http://tourlocation.streamspin.com/Service.asmx/RecieveUserLocation";

    double movementThresshold = 5;

    string timestamp = CryptoLib.Signatures.CreateTimeStamp(DateTime.Now);

    string toSign = movementThresshold.ToString() + serviceId.ToString() + timestamp + userId.ToString() + url;

    string signature = CryptoLib.Signatures.Sign(toSign, "[SECRET KEY]");

    bool isRegistrered = userLocationRequestWS.RegisterUserLocationRequest( movementThresshold, serviceId, timestamp, userId, url, signature);
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message.ToString());
    return false;
  }
  return true;
}
...

What the RegisterUserLocationRequest method does is to ask the StreamSpin server if the user is online

The serviceId and password of the requesting services is also provided to autenticate the request.

If the user is online the boolean value true is returned, and the new location is sent to the web-service whenever the user moves more than 5 meters.

If the user location request succeeds an entry is added to the list of running tours, with the userid as key.

runningTours.Add(userID, new Tour(serviceID));

The new tour is created with a list of sights and a LocationChanged method which will be used when we recieve location changes from the StreamSpin server.

Now we need a server listening for location changes in already registered users.

The actual reporting to the server from the StreamSpin servers are done either through a web-service or a web-page as described in the web-service API in the The RegisterUserLocationRequest method

TourServer.Program.cs

...
private void StartRequestLocationTestServer()
{
   bool running = true;
   serverListener = null;

   while (running)
   {
     try
     {
       IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
       IPAddress localAddr = host.AddressList[0];

       // TcpListener server = new TcpListener(port);
       serverListener = new TcpListener(localAddr, port);

       // Start listening for client requests.
       serverListener.Start();

       while (running)
       {
         try
         {
           TcpClient client = serverListener.AcceptTcpClient();
           Stream s = client.GetStream();

           BinaryReader binReader = new BinaryReader(s);

           //the id of the user on which location is reported
           int userID = binReader.ReadInt32();

           //the new latitude of the user
           double lat = binReader.ReadDouble();

           //the new longitude of the user
           double lng = binReader.ReadDouble();

           if (lat != -999)
             //Check if the user is within a threshold of a tour sight.
             runningTours[userID].LocationChange(new Location(lat, lng));

           client.Close();
         }

         catch (Exception ex)
         {
           running = false;
         }
       }
     }
     catch (Exception ex)
     {
       running = false;
     }
  }
}
...

The user location changes is recieved through the TourBuilder TourLocationRecieve web-service.

Since the callback is a simple http request you must remember to add the following to your web service web.config file.

TourLocationRecieveWS.Web.config

...
<configuration>
     <appSettings/>
     <connectionStrings/>
     <system.web>
          <webServices>
               <protocols>
                    <add name="HttpGet" />
                    <add name="HttpPost" />
               </protocols>
          </webServices>
...

The web-service uses a socket to report user location changes to the server above.

Three values are reported by the StreamSpin location server. The userid and the latitude and longitude of the user.

If the user is ofline the Streamspin location server returns the latitude and longitude as -999.

If the user is online, then the server above uses the list of running tours.

runningTours[userID].LocationChange(new Location(lat, lng));

The LocationChange method of the tour checks whether the user is within a desired threshold of a tour sight.

TourServer.Tour.cs

...
IDictionary<int, Location> seights = new Dictionary<int, Location>();
IDictionary<int, string> seightNames = new Dictionary<int, string>();

contentpublisher.ContentPublishing cp = null;

public void LocationChange(Location userLocation)
{
   //check if tour seigth is within a thresshold of the location.
   foreach (KeyValuePair<int, Location> seightPair in seights)
   {
     Location seightLocation = seightPair.Value;
     double dist = seightLocation.Distance(userLocation);

     if (!seightLocation.IsViewed && dist < tourThressHold)
     {
       //set the sight as viewed
       seightLocation.IsViewed = true;

       //create a content object
       contentpublisher.Content content = new TourServer.contentpublisher.Content();

       //content description: tour - seight name
       content.Description = string.Format("Tour : {0}", seightNames[seightPair.Key]);

       //content url: http + seight id as parameter.
       content.Url = string.Format(
       "http://tourbuilder.streamspin.com/ShowSeight.aspx?seightid={0}",
      seightPair.Key);

       //publish using the content publishing web-service.
       string timestamp = CryptoLib.Signatures.CreateTimeStamp(DateTime.Now);

       string text = content.Description + content.Url + serviceId.ToString() + timestamp;

       string signature = CryptoLib.Signatures.Sign(text, "[SECRET KEY]");

       int returnVal = cp.PublishPrivateContent(content, serviceId, signature, timestamp);

       if (returnVal < -900)
         Console.WriteLine(returnVal.ToString());
     }
   }
}
...

Each tour has two dictionaries. One mapping sight ids to sight names, and one mapping sight ids to locations.

IDictionary<int, Location> seights = new Dictionary<int, Location>();
IDictionary<int, string> seightNames = new Dictionary<int, string>();

The LocationChange method checks if the new user location is within one of the not viewed sights.

A distance between the user location and the sight is calculated, and a check is performed to see whether the distance is less than the desired threshold. If so, then we send the sight to the user.

Location seightLocation = seightPair.Value;
double dist = seightLocation.Distance(userLocation);

if (!seightLocation.IsViewed && dist < tourThressHold)
{
...

We use the StreamSpin content publishing webservice to send the sigth to the user.

contentpublisher.Content content = new TourServer.contentpublisher.Content();

The content description is set to the name of the sight.

content.Description = string.Format("Tour : {0}", seightNames[seightPair.Key]);

The content url is set to link to a tourbuilder web-page which will show the details of the sight.

content.Url = string.Format(
"http://tourbuilder.streamspin.com/ShowSeight.aspx?seightid={0}", seightPair.Key);

Finally the content is published to the user, along with the serviceid and password of the tourbuilder service for authentication.

int returnVal = cp.PublishPrivateContent(content, serviceId, signature, timestamp);


This is the end of the walk-through.

The remaining files in the tour builder project is merely used for accessing the database (DataLogic.Tours.cs) and representing locations and sights aswell as distance calculations (TourServer.Location.cs).

The server is started in the TourServer.Program.cs constructor.

TourServer.Program.cs

...
public Program()
{
      //Start the tourserver in a thread
      tourserverthread = new Thread(new ThreadStart(StartTourStarterServer));
      tourserverthread.Start();

      //Start the request location change server in a thread
      serverThread = new Thread(new ThreadStart(StartRequestLocationTestServer));
      serverThread.Start();
}
...

Jump up to the start of the example

Hello World

Download the code for the tutorial [here].

Signup for a StreamSpin account.


Go to the MyServices page and create a new private service.



Create a new Visual Studio console application and add the following two constants.

private const int serviceID = THE ID OF YOUR SERVICE
private const string key = YOUR SYMMETRIC KEY

The serviceID is found in the MyServices page on StreamSpin.com.



The symmetric key is found in the MyInfo page on StreamSpin.com.



Create a web-reference to the StreamSpin server services

  http://serverservices.streamspin.com/contentpublishing.asmx

Add a reference to the CryptoLib dll dll.
Add the following import to your Program.cs file.

using CryptoLib.Signatures;

Add the following code to the main method.

static void Main(string[] args)
{
     //create a streamspin publish object
     ServerServices.ContentPublishing publisher = new ServerServices.ContentPublishing();

     //create a streamspin content object
     ServerServices.Content content = new ServerServices.Content();

     //set the description of the content object
     content.Description = "Streamspin demo";

     //set the body of the content object
     content.Url = "Hello World"

     //now we need to sign the content, first we create a timestamp
     string timestamp = Signatures.CreateTimeStamp(DateTime.Now);

     //then we create the textstring to sign
     string toSign = content.Description + content.Url + serviceID + timestamp;

     //finally we create the signature using the key from MyInfo
     string signature = Signatures.Sign(toSign, key);

     //we then publish the content using the publisher object
     publish.PublishPrivateContent(content, serviceID, signature, timestamp);

}

What we do here is to create a content publisher object, along with a content object. The content object is a wrapper for StreamSpin messages.

We then proceed by creating a timestamp. The timestamp is neccesary to avoid abuse by message playback.

We create a signature by signing the alphabetically sorted parameters, and finally we publish the content to the StreamSpin server, which will pass the message on to any subscribed users.

Now go to the StreamSpin Services page and find the HelloWorld service we just created.




Click the subscribe link button and go to the My subscriptions - Non approved page




Approve the service subscription. We are now ready to test our first mobile service.
Download the StreamSpin windows mobile client here.

Start the client and login.


You are now presented with the main mobile window.


Content descriptions are presented in the top window, and content url or extended descriptions are presented in the bottom window.

Now go to your computer and run the console application.

Go to the mobile client, you should now have one message saying "Streamspin demo".


Click the message and you should now see the extended description "Hello World".


Congratulations. You have created your first StreamSpin service.

Jump up to the start of the example

Hello World with locations

Download the code for the tutorial [here].

This tutorial will show you how to make a service that recieves the location of subscribed and online users.

Create a new Visual Studio solution and add a web application.

Add the following web-reference to your web application.

  http://serverservices.streamspin.com/contentpublishing.asmx

Add the following two constants.

private const int serviceID = THE ID OF YOUR SERVICE
private const string key = YOUR SYMMETRIC KEY

Add the following code to the Page_Load of the default web-page.

protected void Page_Load(object sender, EventArgs e)
{
     //The userId from the StreamSpin server.
     int userId = Convert.ToInt32(Request.QueryString["userId"]);

     //The latitude and longitude from the StreamSpin server.
     double lat = Convert.ToDouble(Request.QueryString["lat"]);
     double lng = Convert.ToDouble(Request.QueryString["lng"]);

     //Create the ContentPublishing and Content objects.
     ServerServices.ContentPublishing publisher = new ServerServices.ContentPublishing();
     ServerServices.Content content = new ServerServices.Content();

     content.Description = "Streamspin location demo";

     //The extended description will tell the location.
     content.Url = "<html><body>Your location<br>" +
          "Latitude: " + lat.ToString() + "<br>" +
          "Longitude: " + lng.ToString() + "<br>" +
          "<img src='http://www.rico-wind.dk/daisy.gif'>";

     //Create the signature and publish
     string timestamp = Signatures.CreateTimeStamp(DateTime.Now);
     string toSign = content.Description + content.Url + serviceID + timestamp;
     string signature = Signatures.Sign(toSign, key);
     publisher.PublishPrivateContent(content, serviceID, signature, timestamp);

     //We must tell the location server that the user is online.
     Response.Write("<returnvalue>true</returnvalue>");
     Response.End();
}

The web code above will send a content message to the user everytime the location changes.

However, to make the StreamSpin server send the location changes we need to register a location request.

Add a console application to your solution.

Add the following web-reference to your console application.

  http://serverservices.streamspin.com/userlocation.asmx

Add a reference to the CryptoLib dll.

Add the following two constants.

private const int serviceID = 224; //THE ID OF YOUR SERVICE
private const string key = "uAcf3RRr5hFn51ubFKD1WjvmajvOYi3X"; //YOUR KEY

Now add the following code to your Main method.

static void Main(string[] args)
{
     //Create a LocationServer object.
     LocationServices.UserLocation LocationServer = new LocationServices.UserLocation();

     //The url should point to the web-page you created earlier.
     string url = "http://demo.streamspin.com/Default.aspx";

     //Create a signature.
     string timestamp = Signatures.CreateTimeStamp(DateTime.Now);
     string toSign = "25" + serviceID.ToString() + timestamp + "9041" + url ;
     string signature = Signatures.Sign(toSign, key);

     //Register the user location request.
     LocationServer.RegisterUserLocationRequest(
               25, serviceID, timestamp, 9041, url, signature);
}

What happens here is that we tell the StreamSpin location server to send the location of the user each time the distance to the previous location is more than 25 meters (movement threshold). The changed location is send to the web-page created above (url).

Create two locations on the StreamSpin webpage.




Login to the StreamSpin mobile client.



Run the console application once.




Change the location on the mobile client.



You will now recieve the latitude and longitude of the new location.



You can also use the mobile client GPS if available. In that case you do not need to create locations and manually change the location.

Congratulations, you have created your first location aware streamspin service.

Jump up to the start of the example

The StreamSpin .Net Mobile Emulator User Control


Download the StreamSpinMobileEmulator.rar file here.

The StreamSpin mobile emulator user control can be added to the VS2005 toolbar by right-clicking the toolbar, pressing choose items, and then browsing to the extracted content of the downloaded StreamSpinMobileEmulator.rar.

The emulator user control will now be available as MobileClient in the toolbar.

The user control can be used in windows forms projects by simply dragging the control onto the form.


Multiple clients can be started at once.

The following code logs in 4 users.

mobileClient1.UserName = "Kenneth";
mobileClient1.Password = "1234567";

mobileClient2.UserName = "Kenneth1";
mobileClient2.Password = "1234568";

mobileClient3.UserName = "Kenneth2";
mobileClient3.Password = "1234569";

mobileClient4.UserName = "Kenneth3";
mobileClient4.Password = "1234560";

mobileClient1.Login();
mobileClient2.Login();
mobileClient3.Login();
mobileClient4.Login();

The user control can be used for testing purposes and acts just as the client would on a physical windows mobile client.
Client to provider interaction
The client to provider interaction makes it possible to create services that require the user(client) to provide location aware info to the provider.

Examples of such services are a geo-caching service where a cache is placed and an image, description and location of the cache is send to a provider.

Another example is a service that keeps the user updated on good restaurants within close proximity. That type of service could rely on the users providing the location and reviews on new restaurants.

The interaction is made possible by attaching a small XML-script to the private service. The script must be created according to the following xml-schema:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="serviceinput">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="parameter">
<xs:complexType>
<xs:attribute name="type" type="xs:string" use="required" />
<xs:attribute name="title" type="xs:string" use="optional" />
<xs:attribute name="name" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="serviceid" type="xs:unsignedShort" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>



An example script with a text field, image field and location looks as follows.

<serviceinput serviceid='265'>
      <parameter type='text' title='Nice Spot' name='spot'/>
      <parameter type='image' title='Image' name='image1'/>
      <parameter type='location'/>
</serviceinput>

When the client submits the result of a service script, the result is send using HTTP POST, and can be retrieved by the recieving provider as follows (C#).

Back to top