WinRT : Transfering a file between 2 peers using Wifi-Direct and Proximity API
On Windows 8.1 and WinRT, Wifi-direct enables wireless direct communication scenarios between devices executing the same application. That means you can exchange data between peers in areas without any internet network connectivity. All you need is a device that supports Wifi-Direct technology (Surface RT does, as well as most Windows 8 devices). This is complementary to the Share charm functionnality which helps sharing data between 2 apps on the same machine. Here you will share stuff on different machines that are executing the same app.
Wifi-direct can be a good alternative to NFC for some scenarios : you don’t need any NFC hardware but still can communicate between several close peers without network connectivity. If ever you want to test NFC but you don’t have the appropriate hardware, I wrote an article explaining how to install an NFC simulator driver on Windows 8.1 : Windows 8.1 : How to use Near-Field Proximity API without NFC hardware.
Wifi-direct communication is made possible thanks to the Proximity API (just like NFC does, but with different scenarios).
Here is a small lib providing the Wifi-direct file transfer fonctionnality and its sample demo application so that you can test it.
Please be aware that this was not tested for production : if you use it as is, it is at your own risks.
In this article, you will find:
- how to use the lib and the sample app
- behind the scene : how the Proximity API handles Wifi-direct
- more possibilities for Wifi-direct scenarios
How does the lib work ?
The WifiDirectTransfer library is based on the Proximity API. It is VERY easy to use : you just need 3 lines of code.
The lib contains a WifiDirectFileTransfer class.
The same class is used by both the sender and receiver.
public WifiDirectFileTransfer(Action<string> verboseCb = null)
public void Start()
public async Task<IEnumerable<PeerInformation>> FindPeersAsync()
public async Task ConnectAndSendFileAsync(PeerInformation selectedPeer, StorageFile selectedFile)
public async Task<string> ReceiveFileAsync(PeerInformation requestingPeer,
StorageFolder folder, string outputFilename = null)
The ctor parameter is an optional verbose callback, so that you can follow the communication process easily.
Once instanciated, you can:
Updating the manifest
For an application referencing the lib, you will have to check the proximity capability:
Testing with the sample application
The sample demo application must be started on 2 Windows 8.1 devices supporting Wifi-direct.
Sender | Receiver |
The application has 2 buttons. The sender should click the enabled button first:
Sender | Receiver |
The sender application just discovered another device running the same application, the device name is SurfaceRT.
Now, double-click the device you want to connect to and browse the file you want to send.
Sender
Click open : the receiver will then get the ConnectionRequested event.
Receiver
The SurfaceRT device has just received the connection request from the sender who’s machine name is MININT-A34GQT7.
Click the second button that was just enabled by the sender connection. The connection phase will take some time (on my device, it can be more than 10 secs): please be patient .
Now the file will be transfered from the sender to the receiver.
Sender | Receiver |
You will then see the download progress shown on the status bar.
Then, the image will be saved on disk and shown on the receiver screen.
Receiver
Note: Restart the app to initiate a new transfer.
Behind the scene : how the Proximity API handles Wifi-direct
The Proximity API provides an easy way to get a Stream socket with Wifi-direct.
Each peer should start by calling
PeerFinder.Start();
Then you can browse for other peers using the same application with
PeerFinder.FindAllPeersAsync();
You may have assigned roles (host, client, peers) to peers to be able to find only the appropriate ones.
You can then connect to a specific peer to get the stream socket:
var socket = await PeerFinder.ConnectAsync(selectedPeer);
The peer gets then a specific event:
PeerFinder.ConnectionRequested += PeerFinder_ConnectionRequested;
and can then connect in response :
StreamSocket socket = await PeerFinder.ConnectAsync(requestingPeer);
Then you can start exchanging data on the socket.
And what if I want to transfer other kind of data ?
I chose a file, but of course, any kind of data could be transfered : the communication is made on a classic Stream socket. Just make sure your receiver will be able to understand what you send him.
In my example, I made a little protocol to be able to transfer a file. I do it in 4 steps:
- send the filename length
- send the filename
- send the file length
- send the file itself
Here is an extract of the code:
private async Task SendFileToPeerAsync(PeerInformation selectedPeer,
StreamSocket socket, StorageFile selectedFile)
{
byte[] buff = new byte[BLOCK_SIZE];
var prop = await selectedFile.GetBasicPropertiesAsync();
using (var dw = new DataWriter(socket.OutputStream))
{
// 1. Send the filename length
dw.WriteInt32(selectedFile.Name.Length);
// 2. Send the filename
dw.WriteString(selectedFile.Name);
// 3. Send the file length
dw.WriteUInt64(prop.Size);
// 4. Send the file
var fileStream = await selectedFile.OpenStreamForReadAsync();
while (fileStream.Position < (long)prop.Size)
{
var rlen = await fileStream.ReadAsync(buff, 0, buff.Length);
dw.WriteBytes(buff);
}
await dw.FlushAsync();
await dw.StoreAsync();
await socket.OutputStream.FlushAsync();
}
}
The receiver will read each information step by step too:
private async Task<string> ReceiveFileFomPeer(StreamSocket socket,
StorageFolder folder, string outputFilename = null)
{
StorageFile file;
using (var rw = new DataReader(socket.InputStream))
{
// 1. Read the filename length
await rw.LoadAsync(sizeof(Int32));
var filenameLength = (uint)rw.ReadInt32();
// 2. Read the filename
await rw.LoadAsync(filenameLength);
var originalFilename = rw.ReadString(filenameLength);
if (outputFilename == null)
{
outputFilename = originalFilename;
}
//3. Read the file length
await rw.LoadAsync(sizeof(UInt64));
var fileLength = rw.ReadUInt64();
// 4. Reading file
using (var memStream = await DownloadFile(rw, fileLength))
{
file = await folder.CreateFileAsync(outputFilename,
CreationCollisionOption.ReplaceExisting);
using (var fileStream1 = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(
memStream.GetInputStreamAt(0), fileStream1.GetOutputStreamAt(0));
}
Verbose("Et voila :)");
rw.DetachStream();
}
}
return file.Path;
}
More possibilities with the Proximity API
Other scenarios are available, like listening to any proximity event occuring (with PeerFinder.CreateWatcher) or providing an early access to peer’s data during the accept phase. It can be useful to help decide how to handle the peer that is trying to connect or if it should accept the connection or not.
Comments
Anonymous
January 05, 2014
Great article! I would like to see something similar on Windows Phone.Anonymous
March 10, 2014
The ".zip" file that contains the code has some references to TFS and it cannot be opened properly.Anonymous
March 13, 2014
Hello Dillinger, you are right, the TFS references are still there, but it should not avoid you to use the project, you can just ignore themAnonymous
March 31, 2014
Thanks.Anonymous
April 29, 2014
my mobail karbonn a6 super beam wifi direct not conectAnonymous
May 07, 2014
unable to open the project, some issue with team foundation source control. please helpAnonymous
August 08, 2014
hello sir , i tried your code but due to some reasons i didn't got successful file transfer sir it's my humble request to you can you please provide sample project that you wrote my e-mail id is jayminsuthar93@outlook.com thankyou in advance :)Anonymous
August 22, 2014
Hello jaymin, the source code and app is available for download at the top of the article. For all : please just ignore the source control warning when you open the project : it's just a warning, not an error, you can still use the project as is.Anonymous
September 17, 2014
Great article! However, do you have an example/guidance on how to use WiFi-Direct between two Win 8.1 device running different Modern Apps?Anonymous
November 13, 2014
I didn't find the sample source code. My Email Id: sohagdas2007@gmail.com Could you send the sample source code. Thanks.Anonymous
February 23, 2015
Hello, I need to transfer a file from an android device... I don't have access to visual studio anymore, can you put an access to the binary?Anonymous
August 28, 2015
well done. a complex stuff easy explained.