--- a/upexplo/upexplo.cxx
+++ b/upexplo/upexplo.cxx
@@ -23,16 +23,109 @@
 #include <string>
 #include <iostream>
 #include <vector>
+#include <algorithm>
 using namespace std;
 
 #include "libupnpp/log.hxx"
 #include "libupnpp/upnpplib.hxx"
+#include "libupnpp/upnpputils.hxx"
+#include "libupnpp/upnpputils.hxx"
+#include "libupnpp/ptmutex.hxx"
 #include "libupnpp/control/service.hxx"
 #include "libupnpp/control/cdirectory.hxx"
 #include "libupnpp/control/mediarenderer.hxx"
 #include "libupnpp/control/renderingcontrol.hxx"
+#include "libupnpp/control/discovery.hxx"
 
 using namespace UPnPClient;
+
+UPnPDeviceDirectory *superdir;
+
+PTMutexInit reporterLock;
+static pthread_cond_t evloopcond = PTHREAD_COND_INITIALIZER;
+
+vector<string> deviceFNs;
+vector<string> deviceUDNs;
+vector<string> deviceTypes;
+static void clearDevices() {
+    deviceFNs.clear();
+    deviceUDNs.clear();
+    deviceTypes.clear();
+}
+
+static bool 
+reporter(const UPnPDeviceDesc& device, const UPnPServiceDesc&)
+{
+    PTMutexLocker lock(reporterLock);
+    //cerr << "reporter: " << device.friendlyName << " s " << 
+    // device.deviceType << endl;
+    if (find(deviceUDNs.begin(), deviceUDNs.end(), device.UDN)
+        == deviceUDNs.end()) {
+        deviceFNs.push_back(device.friendlyName);
+        deviceUDNs.push_back(device.UDN);
+        deviceTypes.push_back(device.deviceType);
+        pthread_cond_broadcast(&evloopcond);
+    }
+    return true;
+}
+
+static bool traverser(const UPnPDeviceDesc& device, const UPnPServiceDesc& srv)
+{
+    if (find(deviceUDNs.begin(), deviceUDNs.end(), device.UDN)
+        == deviceUDNs.end()) {
+        cout << device.friendlyName <<" ("<< device.deviceType << ")" << endl;
+        deviceUDNs.push_back(device.UDN);
+    }        
+    return true;
+}
+
+void listDevices()
+{
+    cout << "UPnP devices:" << endl;
+    static int cbindex = -1;
+    if (cbindex == -1) {
+        cbindex = UPnPDeviceDirectory::addCallback(reporter);
+    }
+
+    struct timespec wkuptime;
+    
+    long long nanos = 0;
+    unsigned int ndevices = 0;
+    do {
+        PTMutexLocker lock(reporterLock);
+        if (superdir == 0) {
+            // First time. Use the event reporting to list the devices
+            // as soon as they are discovered
+            superdir = UPnPDeviceDirectory::getTheDir();
+            nanos = superdir->getRemainingDelay() * 1000*1000*1000;
+        }
+        if (nanos > 0) {
+            clock_gettime(CLOCK_REALTIME, &wkuptime);
+            UPnPP::timespec_addnanos(&wkuptime, nanos);
+            pthread_cond_timedwait(&evloopcond, lock.getMutex(), &wkuptime);
+            if (deviceFNs.size() > ndevices) {
+                for (unsigned int i = ndevices; i < deviceFNs.size(); i++) {
+                    cout << deviceFNs[i] <<" ("<< deviceTypes[i] << ")" << endl;
+                }
+                ndevices = deviceFNs.size();
+            }
+        }
+    } while (superdir->getRemainingDelay() > 0);
+
+    if (nanos == 0) {
+        if (cbindex >= 0) {
+            UPnPDeviceDirectory::delCallback(cbindex);
+            cbindex = -2;
+        }
+        // Not the first time: just list the device pool.
+        if (superdir == 0) {
+            cerr << "nanos and superdir both zero" << endl;
+            exit(1);
+        }
+        clearDevices();
+        superdir->traverse(traverser);
+    }
+}
 
 void listServers()
 {
@@ -87,23 +180,16 @@
 
 MRDH getRenderer(const string& friendlyName)
 {
-    MRDH rdr;
-    vector<UPnPDeviceDesc> vdds;
-    if (!MediaRenderer::getDeviceDescs(vdds, friendlyName)) {
-        cerr << "MediaRenderer::getDeviceDescs" << endl;
-        return rdr;
-    }
-
-    if (vdds.size() == 0) {
-        cerr << "Player not found" << endl;
-        return rdr;
-    } else if (vdds.size() > 1) {
-        cerr << "Multiple players found" << endl;
-        return rdr;
-    }
-
-    UPnPDeviceDesc& dev = vdds[0];
-    return MRDH(new MediaRenderer(dev));
+    if (superdir == 0) {
+        superdir = UPnPDeviceDirectory::getTheDir();
+    }
+
+    UPnPDeviceDesc ddesc;
+    if (superdir->getDevByFName(friendlyName, ddesc)) {
+        return MRDH(new MediaRenderer(ddesc));
+    }
+    cerr << "getDevByFname failed" << endl;
+    return MRDH();
 }
 
 void getsetVolume(const string& friendlyName, int volume = -1)
@@ -371,8 +457,7 @@
 
     if ((op_flags & OPT_l)) {
         while (true) {
-            listServers();
-            listPlayers();
+            listDevices();
             sleep(5);
         }
     } else if ((op_flags & OPT_m)) {