2

I'm a newbie trying to use NSD in an application I'm building to find peers running the same service on the same wifi network and connect to the it.

[Refer to code] I have one device running HostActivity.java and one running GuestActivity.java. Clicking the floating button in Host registers a service on port 9000 ( preset for now ) and clicking it in Guest starts running a service discovery for the same. Both are connected to the same wifi network.

In my logcat, I observe that registration from HostActivity.java works fine - I get the requisite log messages from NsdHelper.java. However, running GuestActivity.java just logs 'Service Discovery started' and never ends up resolving to the service that exists on the network.

What am I doing wrong? Please help.

Relevant code -

HostActivity.java

NsdHelper mNsdHelper;

public static final String TAG = "ABC";
private final int ABC_PORT = 9000;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_shared_list);


    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);


    mNsdHelper = new NsdHelper(this);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Started Registration", Snackbar.LENGTH_LONG)
                    .setAction("CLOSE", null).show();
            mNsdHelper.initializeNsd();
            mNsdHelper.registerService(ABC_PORT);
            Snackbar.make(view, "Completed Registration", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();

        }
    });
}

@Override
protected void onPause() {
    super.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    if (mNsdHelper != null) {
        mNsdHelper.initializeNsd();
        mNsdHelper.registerService(ABC_PORT);
    }
}

@Override
protected void onDestroy() {
    mNsdHelper.tearDown();
    super.onDestroy();
}

GuestActivity.java

NsdHelper mNsdHelper;

public static final String TAG = "ABC";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_shared_list);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    mNsdHelper = new NsdHelper(this);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Searching for available services", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
            mNsdHelper.initializeNsd();
            mNsdHelper.discoverServices();
        }
    });
}

@Override
protected void onPause() {
    super.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    if(mNsdHelper != null) {
        mNsdHelper.initializeNsd();
        mNsdHelper.discoverServices();
    }
}

@Override
protected void onDestroy() {
    mNsdHelper.tearDown();
    super.onDestroy();
}

NsdHelper.java - This contains all the NSD implementation details

public class NsdHelper {
    Context mContext;

    NsdManager mNsdManager;
    NsdManager.ResolveListener mResolveListener;
    NsdManager.DiscoveryListener mDiscoveryListener;
    NsdManager.RegistrationListener mRegistrationListener;

    private static final String SERVICE_TYPE = "_http._tcp.";

    private static final String TAG = "NsdHelper";
    private String mServiceName = "ABC";

    // First step : register a NsdServiceInfo object to advertise your service
    NsdServiceInfo mService;

    public NsdHelper(Context context) {
    mContext = context;
    mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
}


public void initializeNsd() {
    initializeRegistrationListener();
    initializeDiscoveryListener();
    initializeResolveListener();

}


// Check success of service registration
public void initializeRegistrationListener() {
    mRegistrationListener = new NsdManager.RegistrationListener() {

        @Override
        public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
            mServiceName = nsdServiceInfo.getServiceName();
            Log.d(TAG, "Registered name : " + mServiceName);
        }

        @Override
        public void onRegistrationFailed(NsdServiceInfo nsdServiceInfo, int arg1) {
            Log.d(TAG, "Registration Failed");
        }

        @Override
        public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {
            Log.d(TAG, "Unregistered");
        }

        @Override
        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
        }

    };
}

public void registerService(int port) {
    NsdServiceInfo serviceInfo  = new NsdServiceInfo();
    serviceInfo.setPort(port);
    serviceInfo.setServiceName(mServiceName);
    serviceInfo.setServiceType(SERVICE_TYPE);

    mNsdManager.registerService(
            serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);

}

// To discover services of the type you're looking for on the network
public void initializeDiscoveryListener() {
    mDiscoveryListener = new NsdManager.DiscoveryListener() {

        @Override
        public void onDiscoveryStarted(String regType) {
            Log.d(TAG, "Service discovery started");
        }

        @Override
        public void onServiceFound(NsdServiceInfo service) {
            Log.d(TAG, "Service discovery success : " + service);
            Log.d(TAG, "Host = "+ service.getServiceName());
            Log.d(TAG, "port = " + String.valueOf(service.getPort()));

            if (!service.getServiceType().equals(SERVICE_TYPE)) {
                Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
            } else if (service.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same machine: " + mServiceName);
            } else if (service.getServiceName().contains(mServiceName)){
                mNsdManager.resolveService(service, mResolveListener);
            }
        }

        @Override
        public void onServiceLost(NsdServiceInfo service) {
            Log.e(TAG, "service lost" + service);
            if (mService == service) {
                mService = null;
                Log.e(TAG, "service lost" + service);
            }
        }

        @Override
        public void onDiscoveryStopped(String serviceType) {
            Log.i(TAG, "Discovery stopped: " + serviceType);
        }

        @Override
        public void onStartDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }

        @Override
        public void onStopDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }
    };
}

public void discoverServices() {
    mNsdManager.discoverServices(
            SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}


// Connection handshake
public void initializeResolveListener() {
    mResolveListener = new NsdManager.ResolveListener() {

        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
            Log.e(TAG, "Resolve failed" + errorCode);
        }

        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            Log.e(TAG, "Resolve Succeeded. " + serviceInfo);

            if (serviceInfo.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same IP.");
                return;
            }
            mService = serviceInfo;
            int port = mService.getPort();
            InetAddress host = mService.getHost();
        }
    };
}

public void stopDiscovery() {
    if (mNsdManager != null) {
        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    }
}

public NsdServiceInfo getChosenServiceInfo() {
    return mService;
}

public void tearDown() {
    if (mNsdManager != null) {
        if (mRegistrationListener != null) {
            mNsdManager.unregisterService(mRegistrationListener);
        }
        if (mDiscoveryListener != null) {
            mNsdManager.stopServiceDiscovery(mDiscoveryListener);
        }
    }
}

}

fwx
  • 333
  • 1
  • 5
  • 14
  • I have never played with NSD, so I don't have any recommendations with respect to this code. In cases like this, I try to find some existing working code, then slowly modify that code until it does what I need it to do. Either I'll eventually figure out where I'm breaking things, or I get working code. :-) Google might have an NSD sample, and I seem to recall seeing that a recent Android conference (droidcon.it 2016?) had a presentation on NSD, which might include a working sample. – CommonsWare Apr 17 '16 at 11:12
  • Most (all?) of the core NSD code is basically taken verbatim from http://developer.android.com/training/connect-devices-wirelessly/nsd.html - so I can't really proceed with changes to it if the base from Google itself doesn't work. I've also looked at similar code that claims to work (albeit from 2 years ago) here - http://www.jayrambhia.com/blog/android-wireless-connection-1/ But that doesn't hold up either. I'll look for droidcon presentations about the same - let's hope I can find something. Thanks for the tip. – fwx Apr 17 '16 at 12:11
  • If public void onServiceFound(NsdServiceInfo service) was being called you would at least see your log statements. I am running a similar program on a couple of generic android tablets. Once the service can't be found I have to shut both devices off and then turn them on again. Using a quickboot restart does not work. This is a workaround, I am open to a better way to do this. – Michael Perry Jan 08 '17 at 19:15

1 Answers1

0

It seems you followed the code sample on Android developer site, and there're two mistakes which block us:

  1. In the public void onServiceFound(NsdServiceInfo service) method, the code to check service name is not correct. From my understanding, the other device in the same network could also use the same service naming, so remove the if (service.getServiceName().equals(mServiceName)) code block.
  2. The same thing happens in the public void onServiceResolved(NsdServiceInfo serviceInfo) code block. please remove the if (serviceInfo.getServiceName().equals(mServiceName)) code block.
mxi1
  • 166
  • 7
  • I agree with your comments, but here the problem is "onServiceFound(NsdServiceInfo service)" method is not getting called even there are multiple devices connected to network. I am using SERVICE_TYPE is "_http._tcp." – sandeepmaaram May 17 '17 at 05:06