Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is discovering peers for Android Wi-Fi Direct so unreliable?

I am experimenting with Android's Wi-Fi Direct (or P2P if you prefer). I thought it was working very nicely between my two phones, but I realized I am encountering issues with the WifiP2pManager.discoverPeers() and/or WifiP2pManager.requestPeers(). I have observed these results:

  • No peers are discovered and no callbacks are fired for a good 1+ minute. I observe this through the Wi-Fi Direct portion of the Android Wi-Fi settings as well. This is odd because sometimes the discovery completes almost immediately.

  • I have a Roku device and phone B sitting next to phone A. While all are connected to my Wi-Fi, the Roku only appears ~10% of the time, while phones A and B appear to each other.

  • When I disconnected the two phones from all Wi-Fi and did another scan, the Roku showed up (!!!) but phone B did not until I had refreshed at least ten times.

My two phones are a Nexus 7 (running 4.4.4) and a Nexus 5 (running 5.0).

like image 770
Mark Herscher Avatar asked Dec 15 '14 02:12

Mark Herscher


2 Answers

I've been recently developing an application with a connection system based on WiFi Direct (with WiFi P2P Service Discovery) and the one thing I can most certainly say is that the whole thing is a huge pain in the ... . Mostly because of the lack of documentation but also because when developing a wifi-direct-based solution you need to pay attention to basically everything (especially to all callbacks from listeners) before making any method call.

Two most annoying things were I guess:

  • An undocumented UNKNOWN_ERROR (I think its int code was -3) that is being thrown in ActionListener onFailure method. It seems to be some sort of issue with the wifi daemon itself. The only thing that seems to work to prevent it from happening is resetting WiFi before you even start messing around with WiFi direct.

  • Something being in the wrong state for your method call - for example if WIFI_P2P_STATE_CHANGED_ACTION has not been received in your broadcast receiver with the WIFI_P2P_STATE_ENABLED or if 'your_device' has not received a proper status in the WIFI_P2P_THIS_DEVICE_CHANGED_ACTION. This usually results in onFailure call in one of your ActionListeners (with for example ERROR or BUSY failure reason).

like image 166
Bartek Lipinski Avatar answered Sep 20 '22 06:09

Bartek Lipinski


From my experience it's reliable. 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) {
            }
        });
like image 24
Amos Avatar answered Sep 19 '22 06:09

Amos