Reputation: 5459
I'm trying to build a server-client architecture using two Android devices with a peer-to-peer WiFi connection. I've got a clear distinction between client and server, so I'm trying to prune out unnecessary code. Using directions from http://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct.html I've got...
public class PeerToPeerService {
private static final Logger LOG = LoggerFactory.getLogger(PeerToPeerService.class);
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private final Context mContext;
private final WifiP2pDnsSdServiceInfo mService;
public PeerToPeerService(Context context, String name) {
mContext = context;
Map<String, String> record = new HashMap<String, String>();
record.put(Constants.SERVICE_PROPERTY_NAME, name);
record.put(Constants.SERVICE_PROPERTY_PORT, "12345");
mService = WifiP2pDnsSdServiceInfo.newInstance(
"_test", "_presence._tcp", record);
}
public void start() {
mManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(mContext, mContext.getMainLooper(), null);
mManager.addLocalService(mChannel, mService, new ActionListener() {
@Override
public void onSuccess() {
LOG.info("Started Service");
}
@Override
public void onFailure(int error) {
LOG.warn("Failed to Start Service: {}", error);
}
});
}
public void stop() {
mManager.removeLocalService(mChannel, mService, null);
mManager = null;
LOG.info("Stopped Service");
}
}
public class PeerToPeerClient {
private static final Logger LOG = LoggerFactory.getLogger(PeerToPeerClient.class);
private WifiP2pManager mManager;
private WifiP2pManager.Channel mChannel;
private final Context mContext;
public PeerToPeerClient(Context context) {
mContext = context;
}
public void findServices() {
mManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(mContext, mContext.getMainLooper(), null);
mManager.setDnsSdResponseListeners(mChannel,
new DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice device) {
LOG.info("A");
LOG.info("Service Found: {}:{}", instanceName, registrationType);
}
},
new DnsSdTxtRecordListener() {
@Override
public void onDnsSdTxtRecordAvailable(String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
LOG.info("B");
LOG.info("{}:{} is {}", device.deviceName,
record.get(Constants.SERVICE_PROPERTY_PORT), record.get(Constants.SERVICE_PROPERTY_NAME));
}
});
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(mChannel, serviceRequest,
new ActionListener() {
@Override
public void onSuccess() {
LOG.info("Added service discovery request");
}
@Override
public void onFailure(int error) {
LOG.info("Failed adding service discovery request: {}", error);
}
});
mManager.discoverServices(mChannel, new ActionListener() {
@Override
public void onSuccess() {
LOG.info("Service discovery initiated");
}
@Override
public void onFailure(int arg0) {
LOG.info("Service discovery failed");
}
});
}
}
Every single ActionListener has onSuccess called, no failures anywhere. But I never get any of the setDnsSdResponseListeners callbacks. Any ideas where I might have gone wrong?
Upvotes: 8
Views: 3411
Reputation: 2630
After tons of trying, I got the robust workable flow like this:
...
wifiP2pManager.clearLocalServices(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
HashMap<String, String> record = new HashMap<>();
record.put("name", "Amos");
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(AppConfig.DNS_SD_SERVICE_NAME, AppConfig.DNS_SD_SERVICE_TYPE, record);
wifiP2pManager.addLocalService(wifiP2pChannel, serviceInfo, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.setDnsSdResponseListeners(wifiP2pChannel, WifiDirectFragment.this, WifiDirectFragment.this);
wifiP2pManager.clearServiceRequests(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.addServiceRequest(wifiP2pChannel, WifiP2pDnsSdServiceRequest.newInstance(), new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.discoverPeers(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
wifiP2pManager.discoverServices(wifiP2pChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// this is my recursive discovery approach
handler.postDelayed(discoveryRunnable, AppConfig.DNS_SD_SERVICE_DISCOVERABLE_DURATION_S * 1000);
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
}
@Override
public void onFailure(int code) {
}
});
Upvotes: 0
Reputation: 323
For both client & server, you must call addLocalService
and discoverServices
for WifiP2p to work.
Map record = new HashMap();
record.put("name","your_app_anme");
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence.tcp", record);
wifiP2pManager.addLocalService(wifiP2pChannel, serviceInfo, null);
wifiP2pManager.setDnsSdResponseListeners(wifiP2pChannel, new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String s, String s1, WifiP2pDevice wifiP2pDevice) {
Log.wtf("WTF", "device "+wifiP2pDevice.deviceName + "/"+wifiP2pDevice.deviceAddress);
}
}, new WifiP2pManager.DnsSdTxtRecordListener() {
@Override
public void onDnsSdTxtRecordAvailable(String s, Map<String, String> map, WifiP2pDevice wifiP2pDevice) {
Log.wtf("WTF", "got txt "+map.get("name") );
}
});
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
wifiP2pManager.addServiceRequest(wifiP2pChannel, serviceRequest, null);
wifiP2pManager.discoverServices(wifiP2pChannel, null);
Upvotes: 0
Reputation: 8478
I think you have missed some points :
PeerToPeerService : server code
1. implement discovery of clients
PeerToPeerClient : client code
1. implement addint client local service
which will be discovered by servers
PeerToPeerService :
// after adding local service
manager.setDnsSdResponseListeners(channel,
new DnsSdServiceResponseListener() {
...
}
PeerToPeerClient :
mChannel = mManager.initialize(mContext, mContext.getMainLooper(), null);
// add client local service
mManager.addLocalService(mChannel, mService, new ActionListener() {
@Override
public void onSuccess() {
LOG.info("Started Service");
}
@Override
public void onFailure(int error) {
LOG.warn("Failed to Start Service: {}", error);
}
});
After this code, you will be able to get callback onDnsSdResponseListener
and you can connect
After connect, you can check if you are server side or client side by WifiP2pInfo.isGroupOwner -- true for server and false for client
Upvotes: 0
Reputation: 183
I have some experience with working with Wi-Fi Direct on Android devices, I am writing an app to connect devices ad-hoc and enabling chatting across this link.
To be discoverable on Wi-Fi Direct, both devices needs to be scanning, ie. mWifiP2pManager.discoverPeers()
.
Strangely, this also affects the discovery of DnsTxtRecordServices
. Thus, I have found it works if you start your scanning( discoverPeers())
on both devices and then start discoverPeers()
.
Hope this helps! :)
Upvotes: 6