WifiP2p
(in general):
Some time ago I was developing an application with a pretty complex network connectivity system based on WifiP2p
with Service Broadcasting/Discovery
. And based on that experience I already wrote few posts here on SO about how difficult, wearing and problematic that is. Here are two of them (they are quite full of the inside knowledge I acquired about WifiP2p
with Service Discovery
, and WifiP2p
itself):
Why is discovering peers for Android WifiDirect so unreliable
Wi-fi P2P. Inform all peers available of some event
I would advise you to read both of my answers (even though they are focused a bit more on the WifiP2p
itself). They should give you some perspective on the things you should be looking for when working with the WifiP2p Service Discovery
.
I can easily say that if you want to build an efficient, relatively reliable and robust WifiP2p
connection system (especially with Service Discovery
), you will have to work your ass off.
WifiP2p Service Discovery
:
To better answer your exact question, I will tell you what I did (different from you) to make my Service Discovery
work pretty reliably.
1. Broadcasting Service
:
First of all: before registering your Service
(with addLocalService
method) you should use the WifiP2pManager
's clearLocalServices
method. And it is important, that you should only call addLocalService
if the listener passed in the clearLocalServices
returned with the onSuccess
callback.
Although this sets up the broadcasting pretty nicely, I found that other nodes were not always able to detect the broadcasted service
(especially when those nodes weren't already actively detecting services at the moment of registering your local Service
- but they "joined" later). I couldn't find a way to fix this issue 100% reliably. And believe me I was trying probably everything WifiP2p
-related. And no, the clearLocalServices
-addLocalService
sequence wasn't really giving satisfying results. Or more so: doing something different was working much better. What I decided to do, was after I successfully added local service (onSuccess
callback from addLocalService
), I started a Thread
that would periodically call WifiP2pManager
's method discoverPeers
. That seemed to be forcing to rebroadcast all the service
information.
So... basically the base of your broadcasting code should look more-less like this (bare in mind that every single piece of code I will post here is stripped-off of all "checks" if the network connectivity system is in the right state, you should design them yourself to fit your solution the best):
public void startBroadcastingService(){
mWifiP2pManager.clearLocalServices(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mWifiP2pManager.addLocalService(mWifiP2pChannel, mWifiP2pServiceInfo,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// service broadcasting started
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable,
SERVICE_BROADCASTING_INTERVAL);
}
@Override
public void onFailure(int error) {
// react to failure of adding the local service
}
});
}
@Override
public void onFailure(int error) {
// react to failure of clearing the local services
}
});
}
where the mServiceBroadcastingRunnable
should be:
private Runnable mServiceBroadcastingRunnable = new Runnable() {
@Override
public void run() {
mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int error) {
}
});
mServiceBroadcastingHandler
.postDelayed(mServiceBroadcastingRunnable, SERVICE_BROADCASTING_INTERVAL);
}
};
2. Discovering Service
:
For the discovering of your service
I used similar approach. Both with the setting up the discovering, and with trying to force "rediscovery" of services
.
Setting up was performed with the sequence of the following three WifiP2pManager
's methods:
removeServiceRequest
, addServiceRequest
, discoverServices
They were called in this exact order and a particular method (second or the third one to be exact) has been called only after the previous one had "returned" with the onSuccess
callback.
The rediscovery of services
was being performed with the intuitive method (just by repeating the mentioned sequence: removeServiceRequest
-> addServiceRequest
-> discoverServices
).
The base of my code looked more-less like this (to start Service Discovery
I would first call prepareServiceDiscovery()
and then startServiceDiscovery()
):
public void prepareServiceDiscovery() {
mWifiP2pManager.setDnsSdResponseListeners(mWifiP2pChannel,
new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// do all the things you need to do with detected service
}
}, new WifiP2pManager.DnsSdTxtRecordListener() {
@Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
// do all the things you need to do with detailed information about detected service
}
});
mWifiP2pServiceRequest = WifiP2pDnsSdServiceRequest.newInstance();
}
private void startServiceDiscovery() {
mWifiP2pManager.removeServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mWifiP2pManager.addServiceRequest(mWifiP2pChannel, mWifiP2pServiceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
mWifiP2pManager.discoverServices(mWifiP2pChannel,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
//service discovery started
mServiceDiscoveringHandler.postDelayed(
mServiceDiscoveringRunnable,
SERVICE_DISCOVERING_INTERVAL);
}
@Override
public void onFailure(int error) {
// react to failure of starting service discovery
}
});
}
@Override
public void onFailure(int error) {
// react to failure of adding service request
}
});
}
@Override
public void onFailure(int reason) {
// react to failure of removing service request
}
});
}
the mServiceDiscoveringRunnable
was just:
private Runnable mServiceDiscoveringRunnable = new Runnable() {
@Override
public void run() {
startServiceDiscovery();
}
};
All this made my system work quite well. It wasn't perfect yet, but with the lack of documentation on this subject I think I couldn't do much more to improve it.
If you test this approach, be sure to tell me how it works for you (or if it works for you ;) ).