The steps are:
Lots of steps but it’s easier to build as you might think. We’ll start with the service as that’s the glue to hold everything together.
Since we need some form of real-time communication I’ve decided to use SignalR. A snippet from the SignalR page that describes its functionality (http://signalr.net/):
ASP.NET SignalR is a new library for ASP.NET developers that makes it incredibly simple to add real-time web functionality to your applications. What is "real-time web" functionality? It's the ability to have your server-side code push content to the connected clients as it happens, in real-time.
You may have heard of WebSockets, a new HTML5 API that enables bi-directional communication between the browser and server. SignalR will use WebSockets under the covers when it's available, and gracefully fallback to other techniques and technologies when it isn't, while your application code stays the same.
All we need to get started is an empty web project and a nuget package use the package manager or the GUI
SignalR, at the time of writing, is in Release Candidate, so we need to include prerelease versions in Nuget or you won’t find signalR at all. (although it’s prerelease, SignalR is working really well so no worries)
Before we start building the service we need to add some method calls in Global.asax.cs in the Application_Start method.
The MapHubs() makes sure that the service calls are rerouted to the correct functions. The EnableAutoRejoiningGroups() is something that we need to do in this RC2 version but it will go away in RTM, see my StackOverflow question for more information.
SignalR uses the concept of Hubs, a hub is a class that contains all the service calls. Add a class called ImgHub to a folder called Hubs in the empty web project.
That’s really not a lot of code for a service. First, every hub in a SignalR project needs to inherit from Microsoft.AspNet.SignalR.Hub. Next to that, every public method we declare in this class will be callable from the clients. First method is Create(), this takes in the unique ID that will be generated by the webclient in a minute. That ID is used to create a group. SignalR tries to add the connectionId from the client to a group with the guid as groupname. If that group doesn’t exist yet it will create it. The second method is ShareImage. This will take in the deserialized image (as a byte array) and that same guid again. Now we need to send that byte array to other clients so we call Clients.OthersInGroup, other options are Clients.All, Clients.Groups, Clients.Others, Clients.Caller, Clients.AllExcept. Plenty of choices but OthersInGroup suits our needs the best. The OthersInGroup returns a dynamic object, we can attach anything we want here. We want to call ReceiveImage() on the client, that method isn’t declared anywhere but since the object is dynamic the compiler won’t give us any trouble. And finally there’s a Leave() method allowing us to leave a group should it be needed.
The SignalR project can be hosted on any webhost that supports .net, for this demo I’ve used Windows Azure Websites.
1/3th done, the second part is the webclient. This is a normal website using asp.net webforms. It’s responsible for generating the ID, passing it to SignalR to create the group, get a QR code and receive the image.
First some HTML code, the Default.aspx page is nothing fancy, it will only show the QR code.
Notice the imagehandler.ashx reference? That’s a generic handler that will take care of generating the QR code and passing it into this img tag. Generic handler is a file type that you can add through Visual Studio, here’s the code for imagehandler.ashx.
We’re getting our guid from the session object (how it got there, we’ll see in a minute) that’s why we need the IRequiresSessionState interface. The ProcessRequest method we get from IHttpHandler and will get executed when the handler is called. So we first get the guid from the session, then we’ll build a url to qpi.qrserver.com, an api that takes in a value and generates a QR code from that value. We use WebClient to get the data from that url, the byte array that we receive from it will be our generated QR code, we write it to the outputstream of the page’s context and set the type to be an image/JPEG. There should be some error handling here if you’re using this for production code (sometimes the qrserver API takes to long and times out).
Next, we’ll have a look at Default.aspx.cs.
Not much going on, we generate a new Guid and set it to the current session object.
Now, let’s have a look at connection the webclient to the signalR server and getting ready to receive the image.
In Default.aspx we add this script
We’ll need a second page in this webclient to actually show the image. Only one element on the page, an img element.
The img element uses a second generic handler that will take care of deserializing the byte array back into an image.
We’ll get the byte array from the session object. SignalR encodes arrays with Base64 encoding so we need to decode that first, once that’s done we can just write the byte array into the outputstream as a JPEG, just like we did with the QR code. Onto the ImagePage.aspx.cs to see how the byte array goes into the session object
We get our POST values from Request.Form, look for the hidden field called hiddenByteArray and place its value in the session.
We now have our service and one client complete, all that’s left is building a Windows Phone application that connects to that same group on that same service and send the picture over.
For this we’ll need a Windows Phone 8 project as SignalR has no official support for Windows Phone 7. Make sure that you have the latest version of Nuget installed or it won’t find the correct SignalR assembly for Windows Phone 8 (thanks David Fowler for pointing this out).
Add the SignalR.Client assembly to the project. Here’s the XAML for the MainPage.
I use one of the default textboxes in the page’s header for a connection status. In the content grid we place a rectangle filled with a VideoBrush, this will be used to scan the QR code, Let’s have a look at the code for the WP app.
First we declare some fields
I’ll explain these when we encounter them. Now for the page’s constructor
First we initialize a PhotoCamera instance. _previewVideo is the VideoBrush set in the rectangle, we set its source to the PhotoCamera instance. On line 8 we state that when the hardware camera button is half pressed we focus the camera, just a small helper for when the app has troubles reading the QR code. The next part is calling the PhotoChooserTask, this task gives us access to the albums and pictures on the device. We’ll need a timer as well, every timer tick we’ll check if the camera preview window contains a QR code. We’ve declared some event handlers in this constructor, let’s go over them one by one. We’ll start with the OnPhotoCameraInitialized.
We get the resolution’s width and height and turn the flash off. The PhotoCameraLuminanceSource on line 7 is a custom class that will provide us with a previewbuffer that we can fill. Here’s the class
The class inherits from LuminanceSource which comes from the Google zxing project. Zxing is a library to decode QR and barcode images, it has a .NET port on codeplex (http://zxingnet.codeplex.com/) that port is what I use in this project and that’s where the LuminanceSource comes from. That’s also where the QRCodeReader class lives.
Next event handler that we attached in the constructor is the photoChooserTask_Completed
If the task returns succesfully we’ll set the chosen photo, which arrives here as a stream, to the _imgStream field and we start the timer. Now on every timer tick (every 250 milliseconds in this example) we will scan the previewbuffer for QR codes.
First thing we do here is checking if we already have a guid, if we do we stop the timer and send the image to the SignalR service. If _guid is still null we’ll get the previewbuffer and try to decode it, if there’s no QR code in the previewbuffer it will throw an exception, hence the empty catch block. When we can decode we’ll go to the SendImage() method.
If there’s no active connection, we’ll call the SetupSignalRConnection() method. if there is and we are connected we copy the imagestream into a MemoryStream and we invoke the ShareImage() method on the SignalR server, passing in the memorystream, converted into a byte array, and the guid we got from the qr code.
Now for the connection to the server.
And that’s it, we can now start sending images to any device with a browser and an internet connection.
In this post I’ve tried to demystify the magic from Nokia’s Photobeamer app. It is a really cool app but when you take it apart, it’s not that magical. Like a lot of impressive looking tech it just combines a bunch of existing techs into something no one else thought of.
The code in this article is all my own, I have no clue how the Nokia app actually works and what technology they are using, I’m only mimicking their behavior.
Update: I've uploaded the project to Github https://github.com/NicoVermeir/photobeamerclone
This is an imported post. It was imported from my old blog using an automated tool and may contain formatting errors and/or broken images.