diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 10d4c6d0..f4b9d5d4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4,8 +4,8 @@
android:versionName="1.0" >
+ android:minSdkVersion="10"
+ android:targetSdkVersion="10" />
diff --git a/libs/jmdns-3.4.1.jar b/libs/jmdns-3.4.1.jar
new file mode 100644
index 00000000..4fcd002b
Binary files /dev/null and b/libs/jmdns-3.4.1.jar differ
diff --git a/src/com/connectsdk/discovery/provider/ZeroconfDiscoveryProvider.java b/src/com/connectsdk/discovery/provider/ZeroconfDiscoveryProvider.java
index 4a1f6c53..aa4373cd 100644
--- a/src/com/connectsdk/discovery/provider/ZeroconfDiscoveryProvider.java
+++ b/src/com/connectsdk/discovery/provider/ZeroconfDiscoveryProvider.java
@@ -20,77 +20,163 @@
package com.connectsdk.discovery.provider;
-import java.io.UnsupportedEncodingException;
-import java.net.Inet4Address;
+import java.io.IOException;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import javax.jmdns.JmDNS;
+import javax.jmdns.ServiceEvent;
+import javax.jmdns.ServiceListener;
+
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdManager.DiscoveryListener;
-import android.net.nsd.NsdManager.ResolveListener;
-import android.net.nsd.NsdServiceInfo;
import android.util.Log;
+import com.connectsdk.core.Util;
import com.connectsdk.discovery.DiscoveryProvider;
import com.connectsdk.discovery.DiscoveryProviderListener;
import com.connectsdk.service.AirPlayService;
-import com.connectsdk.service.command.ServiceCommandError;
import com.connectsdk.service.config.ServiceDescription;
public class ZeroconfDiscoveryProvider implements DiscoveryProvider {
- public static String TAG = "Connect SDK";
+ JmDNS jmdns;
- private NsdManager mNsdManager;
-
+ private final static int RESCAN_INTERVAL = 10000;
+ private Timer dataTimer;
+
List serviceFilters;
- private DiscoveryListener mDnsListener;
- private ResolveListener mResolveFoundListener;
- private ResolveListener mResolveLostListener;
+ ServiceListener jmdnsListener = new ServiceListener() {
+
+ @Override
+ public void serviceResolved(ServiceEvent ev) {
+ @SuppressWarnings("deprecation")
+ String ipAddress = ev.getInfo().getHostAddress();
+ if (!Util.isIPv4Address(ipAddress)) {
+ // Currently, we only support ipv4 for airplay service
+ return;
+ }
+
+ String uuid = ipAddress;
+ String friendlyName = ev.getInfo().getName();
+ int port = ev.getInfo().getPort();
+
+ ServiceDescription oldService = services.get(uuid);
+
+ ServiceDescription newService;
+ if ( oldService == null ) {
+ newService = new ServiceDescription(ev.getInfo().getType(), uuid, ipAddress);
+ }
+ else {
+ newService = oldService;
+ newService.setIpAddress(ipAddress);
+ }
+
+ newService.setServiceID(AirPlayService.ID);
+ newService.setFriendlyName(friendlyName);
+ newService.setPort(port);
+
+ services.put(uuid, newService);
+
+ for ( DiscoveryProviderListener listener: serviceListeners) {
+ listener.onServiceAdded(ZeroconfDiscoveryProvider.this, newService);
+ }
+ }
+
+ @Override
+ public void serviceRemoved(ServiceEvent ev) {
+ @SuppressWarnings("deprecation")
+ String uuid = ev.getInfo().getHostAddress();
+ ServiceDescription service = services.get(uuid);
+
+ if ( service != null ) {
+ services.remove(uuid);
+
+ for ( DiscoveryProviderListener listener: serviceListeners) {
+ listener.onServiceRemoved(ZeroconfDiscoveryProvider.this, service);
+ }
+ }
+ }
+
+ @Override
+ public void serviceAdded(ServiceEvent event) {
+ // Required to force serviceResolved to be called again
+ // (after the first search)
+ jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
+ }
+ };
private ConcurrentHashMap services;
private CopyOnWriteArrayList serviceListeners;
public ZeroconfDiscoveryProvider(Context context) {
+ initJmDNS();
+
services = new ConcurrentHashMap(8, 0.75f, 2);
serviceListeners = new CopyOnWriteArrayList();
serviceFilters = new ArrayList();
-
- mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
- initListener();
+ }
+
+ private void initJmDNS() {
+ Util.runInBackground(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ jmdns = JmDNS.create();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ });
}
@Override
public void start() {
- Iterator iterator = serviceFilters.iterator();
-
- while (iterator.hasNext()) {
- JSONObject filter = iterator.next();
- String filterName = null;
-
- try {
- filterName = filter.getString("filter");
- } catch (JSONException ex) {
- // do nothing
+ dataTimer = new Timer();
+ MDNSSearchTask sendSearch = new MDNSSearchTask();
+ dataTimer.schedule(sendSearch, 100, RESCAN_INTERVAL);
+ }
+
+ private class MDNSSearchTask extends TimerTask {
+
+ @Override
+ public void run() {
+ if (jmdns != null) {
+ for (JSONObject searchTarget : serviceFilters) {
+ try {
+ String filter = searchTarget.getString("filter");
+ jmdns.addServiceListener(filter, jmdnsListener);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ };
}
-
- if (filterName == null)
- continue;
-
- mNsdManager.discoverServices(filterName, NsdManager.PROTOCOL_DNS_SD, mDnsListener);
}
}
@Override
public void stop() {
- mNsdManager.stopServiceDiscovery(mDnsListener);
+ if (dataTimer != null) {
+ dataTimer.cancel();
+ }
+
+ if (jmdns != null) {
+ for (JSONObject searchTarget : serviceFilters) {
+ try {
+ String filter = searchTarget.getString("filter");
+ jmdns.removeServiceListener(filter, jmdnsListener);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ };
+ }
}
@Override
@@ -149,117 +235,4 @@ public void removeDeviceFilter(JSONObject parameters) {
public boolean isEmpty() {
return serviceFilters.size() == 0;
}
-
- private void initListener() {
- mResolveFoundListener = new ResolveListener() {
-
- @Override
- public void onServiceResolved(NsdServiceInfo serviceInfo) {
- if (!(serviceInfo.getHost() instanceof Inet4Address)) {
- // Currently, we only support ipv4 for airplay service
- return;
- }
-
- String ipAddress = serviceInfo.getHost().toString();
-
- if (ipAddress.charAt(0) == '/')
- ipAddress = ipAddress.substring(1);
-
- String uuid = ipAddress;
- String friendlyName = serviceInfo.getServiceName();
-
- try {
- byte[] utf8 = friendlyName.getBytes("UTF-8");
- friendlyName = new String(utf8, "UTF-8");
- } catch (UnsupportedEncodingException e) { }
-
- int port = serviceInfo.getPort();
-
- Log.d(TAG, "Zeroconf found device " + friendlyName + " with service type " + serviceInfo.getServiceType());
-
- ServiceDescription oldService = services.get(uuid);
-
- ServiceDescription newService;
- if ( oldService == null ) {
- newService = new ServiceDescription(serviceInfo.getServiceType(), uuid, ipAddress);
- }
- else {
- newService = oldService;
- newService.setIpAddress(ipAddress);
- }
-
- newService.setServiceID(AirPlayService.ID);
- newService.setFriendlyName(friendlyName);
- newService.setPort(port);
-
- services.put(uuid, newService);
-
- for ( DiscoveryProviderListener listener: serviceListeners) {
- listener.onServiceAdded(ZeroconfDiscoveryProvider.this, newService);
- }
- }
-
- @Override
- public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { }
- };
-
- mResolveLostListener = new ResolveListener() {
-
- @Override
- public void onServiceResolved(NsdServiceInfo serviceInfo) {
- String ipAddress = serviceInfo.getHost().toString();
-
- if (ipAddress.charAt(0) == '/')
- ipAddress = ipAddress.substring(1);
-
- ServiceDescription service = services.get(ipAddress);
-
- if ( service != null ) {
- services.remove(ipAddress);
-
- Log.d(TAG, "Zeroconf lost device " + serviceInfo.getServiceName() + " with service type " + serviceInfo.getServiceType());
-
- for ( DiscoveryProviderListener listener: serviceListeners) {
- listener.onServiceRemoved(ZeroconfDiscoveryProvider.this, service);
- }
- }
- }
-
- @Override
- public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { }
- };
-
- mDnsListener = new DiscoveryListener() {
-
- @Override
- public void onStopDiscoveryFailed(String serviceType, int errorCode) {
- for ( DiscoveryProviderListener listener: serviceListeners) {
- listener.onServiceDiscoveryFailed(ZeroconfDiscoveryProvider.this, new ServiceCommandError(errorCode, "Discovery failed", serviceType));
- }
- }
-
- @Override
- public void onStartDiscoveryFailed(String serviceType, int errorCode) {
- for ( DiscoveryProviderListener listener: serviceListeners) {
- listener.onServiceDiscoveryFailed(ZeroconfDiscoveryProvider.this, new ServiceCommandError(errorCode, "Discovery failed", serviceType));
- }
- }
-
- @Override
- public void onServiceFound(NsdServiceInfo serviceInfo) {
- mNsdManager.resolveService(serviceInfo, mResolveFoundListener);
- }
-
- @Override
- public void onServiceLost(NsdServiceInfo serviceInfo) {
- mNsdManager.resolveService(serviceInfo, mResolveLostListener);
- }
-
- @Override
- public void onDiscoveryStopped(String serviceType) { }
-
- @Override
- public void onDiscoveryStarted(String serviceType) { }
- };
- }
}
diff --git a/src/com/connectsdk/service/AirPlayService.java b/src/com/connectsdk/service/AirPlayService.java
index b4d166fa..aee90491 100644
--- a/src/com/connectsdk/service/AirPlayService.java
+++ b/src/com/connectsdk/service/AirPlayService.java
@@ -93,7 +93,7 @@ public static JSONObject discoveryParameters() {
try {
params.put("serviceId", ID);
- params.put("filter", "_airplay._tcp.");
+ params.put("filter", "_airplay._tcp.local.");
} catch (JSONException e) {
e.printStackTrace();
}