--- a/src/ohplaylist.cxx
+++ b/src/ohplaylist.cxx
@@ -290,6 +290,18 @@
         m_dev->loopWakeup();
 }
 
+void OHPlaylist::setActive(bool onoff)
+{
+    m_active = onoff;
+    if (m_active) {
+        m_dev->m_mpdcli->clearQueue();
+        m_dev->m_mpdcli->restoreState(m_mpdsavedstate);
+        maybeWakeUp(true);
+    } else {
+        m_dev->m_mpdcli->saveState(m_mpdsavedstate, 0);
+    }
+}
+
 int OHPlaylist::play(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::play" << endl);
@@ -436,6 +448,15 @@
 int OHPlaylist::seekId(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::seekId" << endl);
+    if (!m_active) {
+        // If I'm not active, the ids in the playlist are those of
+        // another service (e.g. radio). If I activate myself and
+        // restore the playlist, the mpd ids are going to be different
+        // from what the caller may have in store. This just can't
+        // work as long as we use mpd ids directly.
+        LOGERR("OHPlaylist::seekId: not active" << endl);
+        return UPNP_E_INTERNAL_ERROR;
+    }
     int id;
     bool ok = sc.get("Value", &id);
     if (ok) {
@@ -449,6 +470,12 @@
 int OHPlaylist::seekIndex(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::seekIndex" << endl);
+
+    // Unlike seekid, this should work as the indices are restored by
+    // mpdcli restorestate
+    if (!m_active && m_dev->m_ohpr) {
+        m_dev->m_ohpr->iSetSourceIndexByName("Playlist");
+    }
     int pos;
     bool ok = sc.get("Value", &pos);
     if (ok) {
@@ -462,6 +489,9 @@
 int OHPlaylist::id(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::id" << endl);
+    if (!m_active && m_dev->m_ohpr) {
+        m_dev->m_ohpr->iSetSourceIndexByName("Playlist");
+    }
     const MpdStatus &mpds = m_dev->getMpdStatusNoUpdate();
     data.addarg("Value", mpds.songid == -1 ? "0" : SoapHelp::i2s(mpds.songid));
     return UPNP_E_SUCCESS;
@@ -481,6 +511,11 @@
 // Returns a 800 fault code if the given id is not in the playlist. 
 int OHPlaylist::ohread(const SoapIncoming& sc, SoapOutgoing& data)
 {
+    if (!m_active) {
+        // See comment in seekId()
+        LOGERR("OHPlaylist::read: not active" << endl);
+        return UPNP_E_INTERNAL_ERROR;
+    }
     int id;
     bool ok = sc.get("Id", &id);
     LOGDEB("OHPlaylist::ohread id " << id << endl);
@@ -518,6 +553,11 @@
 // Any ids not in the playlist are ignored. 
 int OHPlaylist::readList(const SoapIncoming& sc, SoapOutgoing& data)
 {
+    if (!m_active) {
+        // See comment in seekId()
+        LOGERR("OHPlaylist::readList: not active" << endl);
+        return UPNP_E_INTERNAL_ERROR;
+    }
     string sids;
     bool ok = sc.get("IdList", &sids);
     LOGDEB("OHPlaylist::readList: [" << sids << "]" << endl);
@@ -596,6 +636,20 @@
     if (ok)
         ok = ok && sc.get("Metadata", &metadata);
 
+    if (!m_active) {
+        // See comment in seekId()
+        // It's not clear if special-casing afterId == 0 is a good
+        // idea because it makes the device appear even more
+        // unpredictable. Otoh, it allows Bubble (basic, not DS) to
+        // switch to playlist by just adding tracks.
+        if (afterid == 0 && m_dev->m_ohpr) {
+            m_dev->m_ohpr->iSetSourceIndexByName("Playlist");
+        } else {
+            LOGERR("OHPlaylist::insert: not active" << endl);
+            return UPNP_E_INTERNAL_ERROR;
+        }
+    }
+
     LOGDEB("OHPlaylist::insert: afterid " << afterid << " Uri " <<
            uri << " Metadata " << metadata << endl);
     if (ok) {
@@ -614,6 +668,10 @@
                            const string& metadata, int *newid)
 {
     LOGDEB1("OHPlaylist::insertUri: " << uri << endl);
+    if (!m_active) {
+        LOGERR("OHPlaylist::insertUri: not active" << endl);
+        return UPNP_E_INTERNAL_ERROR;
+    }
     UpSong metaformpd;
     if (!uMetaToUpSong(metadata, &metaformpd)) {
         LOGERR("OHPlaylist::insert: failed to parse metadata " << " Uri [" 
@@ -636,6 +694,11 @@
 int OHPlaylist::deleteId(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::deleteId" << endl);
+    if (!m_active) {
+        // See comment in seekId()
+        LOGERR("OHPlaylist::deleteId: not active" << endl);
+        return UPNP_E_INTERNAL_ERROR;
+    }
     int id;
     bool ok = sc.get("Value", &id);
     if (ok) {
@@ -655,6 +718,9 @@
 int OHPlaylist::deleteAll(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::deleteAll" << endl);
+    if (!m_active && m_dev->m_ohpr) {
+        m_dev->m_ohpr->iSetSourceIndexByName("Playlist");
+    }
     bool ok = m_dev->m_mpdcli->clearQueue();
     m_mpdqvers = -1;
     maybeWakeUp(ok);
@@ -673,6 +739,9 @@
 int OHPlaylist::idArray(const SoapIncoming& sc, SoapOutgoing& data)
 {
     LOGDEB("OHPlaylist::idArray" << endl);
+    if (!m_active && m_dev->m_ohpr) {
+        m_dev->m_ohpr->iSetSourceIndexByName("Playlist");
+    }
     string idarray;
     int token;
     if (iidArray(idarray, &token)) {