diff -Nurp vdr-plugin-radio-1.1.0.orig/Makefile vdr-plugin-radio-1.1.0.aac_rds_v7/Makefile
--- vdr-plugin-radio-1.1.0.orig/Makefile	2018-02-23 16:33:59.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/Makefile	2022-01-22 18:36:12.770294390 +0100
@@ -60,7 +60,7 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN
 
 ### The object files (add further files here):
 
-OBJS = $(PLUGIN).o radioaudio.o radioskin.o radiotools.o radioepg.o inforx.o
+OBJS = $(PLUGIN).o radioaudio.o radioskin.o radiotools.o radioepg.o inforx.o rdspatpmt.o
 
 ### The main target:
 
diff -Nurp vdr-plugin-radio-1.1.0.orig/radio.c vdr-plugin-radio-1.1.0.aac_rds_v7/radio.c
--- vdr-plugin-radio-1.1.0.orig/radio.c	2018-02-23 16:33:59.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/radio.c	2022-01-23 00:21:47.096762105 +0100
@@ -56,7 +56,7 @@ int S_RtMsgItems = 0;
 int S_RassText = 1;
 int S_ExtInfo = 0;
 uint32_t rt_color[9];
-int S_Verbose = 1;
+int S_Verbose = 0;
 int S_Encrypted = 0;
 // Radiotext
 char RT_Text[5][RT_MEL];
@@ -253,6 +253,7 @@ private:
     //int newS_RtpMemNo;
     int newS_RassText;
     int newS_ExtInfo;
+    const char *T_StillPic[3];
     const char *T_RtFunc[3];
     const char *T_RtOsdTags[3];
     const char *T_RtOsdPos[2];
@@ -270,6 +271,9 @@ public:
 
 cMenuSetupRadio::cMenuSetupRadio(void)
 {
+    T_StillPic[0] = tr("Use PlayPes-Function");
+    T_StillPic[1] = tr("Use StillPicture-Function");
+    T_StillPic[2] = tr("Off");
     T_RtFunc[0] = tr("Off");
     T_RtFunc[1] = tr("only Text");
     T_RtFunc[2] = tr("Text+TagInfo");
@@ -321,7 +325,7 @@ cMenuSetupRadio::cMenuSetupRadio(void)
     newS_ExtInfo = S_ExtInfo;
 
     Add(new cMenuEditBoolItem( tr("Activate"),                      &newS_Activate));
-    Add(new cMenuEditBoolItem( tr("Use StillPicture-Function"),     &newS_StillPic));
+    Add(new cMenuEditStraItem( tr("StillPicture"),                  &newS_StillPic, 3, T_StillPic));
     Add(new cMenuEditBoolItem( tr("Hide MainMenuEntry"),            &newS_HMEntry));
     Add(new cMenuEditStraItem( tr("RDSText Function"),              &newS_RtFunc, 3, T_RtFunc));
     Add(new cMenuEditStraItem( tr("RDSText OSD-Position"),          &newS_RtOsdPos, 2, T_RtOsdPos));
@@ -452,7 +456,7 @@ const char *cPluginRadio::CommandLineHel
            "  -l file,  --live=file      use file as default mpegfile in livemode (default: <dir>/radio.mpg)\n"
            "  -r file,  --replay=file    use file as default mpegfile in replaymode (default: <dir>/replay.mpg)\n"
            "  -e 1,     --encrypted=1    use transfermode/backgroundimage @ encrypted radiochannels     \n"
-           "  -v level, --verbose=level  set verbose level (default = 1, 0 = Off, 1 = RDS-Text+Tags,    \n"
+           "  -v level, --verbose=level  set verbose level (default = 0, 0 = Off, 1 = RDS-Text+Tags,    \n"
            "                                                2 = +RDS-Telegram/Debug, 3 = +RawData 0xfd, \n"
            "                                                += 16 = Rass-Info, +=32 = TMC-Info)         \n";
 }
diff -Nurp vdr-plugin-radio-1.1.0.orig/radioaudio.c vdr-plugin-radio-1.1.0.aac_rds_v7/radioaudio.c
--- vdr-plugin-radio-1.1.0.orig/radioaudio.c	2018-02-23 16:33:59.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/radioaudio.c	2022-01-22 23:01:04.344187087 +0100
@@ -154,6 +154,10 @@ void cRadioImage::Show(const char *file)
     int fd;
     struct stat st;
     struct video_still_picture sp;
+
+    if (S_StillPic > 1) // use with xineliboutput -> no stillpicture, but sound
+        return;
+
     if ((fd = open(file, O_RDONLY)) >= 0) {
         fstat(fd, &st);
         sp.iFrame = (char *) malloc(st.st_size);
@@ -229,6 +233,8 @@ cRDSReceiver::cRDSReceiver(int Pid) {
 
     pid = Pid;
     rt_start = rt_bstuff = false;
+    SetPids(NULL);
+    AddPid(pid);
 }
 
 cRDSReceiver::~cRDSReceiver() {
@@ -255,12 +261,8 @@ void cRDSReceiver::Receive(const uchar *
     int offset;
     if (Data[1] & 0x40) {                      // 1.TS-Frame, payload-unit-start
         offset = (Data[3] & 0x20) ? Data[4] + 11 : 10; // Header + ADFL + 6 byte: PES-Startcode, -StreamID, -PacketLength
-        if (Data[offset - 3] == 0xbd) { // StreamID = Private stream 1 (for rds)
-            offset += 3;                     // 3 byte: Extension + Headerlength
-            offset += Data[offset - 1];
-        } else {
-            return;
-        }
+        offset += 3;                     // 3 byte: Extension + Headerlength
+        offset += Data[offset - 1];
     } else {
         offset = (Data[3] & 0x20) ? Data[4] + 5 : 4;    // Header + ADFL
     }
@@ -269,18 +271,10 @@ void cRDSReceiver::Receive(const uchar *
         return;
     }
     // print TS-RawData with RDS
-    if ((S_Verbose & 0x02) == 0x02) {
-        printf("\n\nTS-Data(%d):\n", Length);
-        int cnt = 0;
-        for (int a = 0; a < Length; a++) {
-            printf("%02x ", Data[a]);
-            cnt++;
-            if (cnt > 15) {
-                cnt = 0;
-                printf("\n");
-            }
-        }
-        printf("(End)\n");
+    if ((S_Verbose & 0x0f) >= 3) {
+        dsyslog("TS-Data(%d):", Length);
+        hexdump(Data, Length);
+        dsyslog("(TS-End)");
     }
 
     for (int i = 0, val = 0; i < (TS_SIZE - offset); i++) {
@@ -363,6 +357,8 @@ void cRDSReceiver::Receive(const uchar *
                     printf("RDS-Error: too short -> garbage ?\n");
                 }
             } else {
+                if ((S_Verbose & 0x0f) >= 1)
+                    { dsyslog("-- RDS [%02X] --", mtext[5]); hexdump(mtext, index+1); }
                 // crc16-check
                 unsigned short crc16 = crc16_ccitt(mtext, index - 3, true);
                 if (crc16 != (mtext[index - 2] << 8) + mtext[index - 1]) {
@@ -433,13 +429,14 @@ void cRDSReceiver::Receive(const uchar *
 // --- cRadioAudio -------------------------------------------------------------
 
 cRadioAudio::cRadioAudio() :
-        cAudio(), enabled(false), first_packets(0), audiopid(0), bratefound(
-                false), rdsdevice(NULL), bitrate(NULL) {
+        cAudio(), enabled(false), first_packets(0), audiopid(0),
+        rdsdevice(NULL), bitrate(NULL), rdsSeen(false) {
     RadioAudio = this;
     dsyslog("radio: new cRadioAudio");
 }
 
 cRadioAudio::~cRadioAudio() {
+    free(bitrate);
     dsyslog("radio: delete cRadioAudio");
 }
 
@@ -448,6 +445,8 @@ void cRadioAudio::Play(const uchar *Data
     if (!enabled) {
         return;
     }
+    if (RDSReceiver)
+        return;
     if (Id < 0xc0 || Id > 0xdf) {
         return;
     }
@@ -468,6 +467,7 @@ void cRadioAudio::Play(const uchar *Data
     if (first_packets < 3) {
         first_packets++;
         if (first_packets == 3) {
+            free(bitrate);
             bitrate = audiobitrate(Data);
         }
         return;
@@ -483,6 +483,8 @@ void cRadioAudio::PlayTs(const uchar *Da
     if (!enabled) {
         return;
     }
+    if (RDSReceiver)
+        return;
 
     // Rass-Images Slideshow
     if (S_RassText > 0 && Rass_Archiv == -1 && Rass_Show == 1) {
@@ -693,105 +695,326 @@ void cRadioAudio::RadiotextCheckPES(cons
     }
 }
 
-void cRadioAudio::RadiotextCheckTS(const uchar *data, int len) {
-    static int pesfound = 0;
-    const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
-    static unsigned char mtext[mframel + 1], lastframe[TS_SIZE - 4];
-    static int rt_start = 0, rt_bstuff = 0;
-    static int index;
-    static int mec = 0;
-    int i, ii, val;
+int cRadioAudio::GetLatmRdsDSE(const uchar *plBuffer, int plBufferCnt, bool rt_start) {
 
-    /* TS-Frame && Payload, correct AudioPID ? */
-    if ((data[0] != 0x47) || !(data[3] & 0x10)) { // || audiopid != ((data[1] & 0x1f)<<8) + data[2])) {
-        pesfound = 0;
-        return;
-    }
+    // 'Data Stream Element' <DSE> reverse scanning:
+    //
+    // AAC-LATM frames contain one or more elements and are always terminated by element-id <TERM>.
+    // element/frame format: <other>+<DSE>?<FIL>?<[TERM>
+    // element IDs (3 bits): <DSE>=4 (100), <FIL>=6 (110), <TERM>=7 (111)
+    // To find a <DSE>
+    // - count the required bitwise shift to byte-align <TERM> ('111' -> 1110_0000 / 0xE0).
+    // - byte-align all data in front of <TERM> and search for <DSE> ('100' -> 1000_0000 / 0x80) with matching length-field
+    // - if no <DSE> but a potential <FIL> was detected (0x6x), adjust the shift, skip over <FIL> and search once again for <DSE>
+    //
+    // The <DSE> may held RDS-data - complete or splitted over multiple frames, in the order [0xfe,...,0xff]).
+    //
+    // Assumptions to keep the code simple:
+    // only one short <FIL> element, RDS data is originally not(!) byte-aligned after the <DSE> header, <DSE> Len < 255 bytes
 
-    if ((S_Verbose & 0x02) == 0x02) {
-        printf("\nTS-Data(%d):\n", len);
-        int cnt = 0;
-        for (int a = 0; a < len; a++) {
-            printf("%02x ", data[a]);
-            cnt++;
-            if (cnt > 15) {
-                printf("\n");
-                cnt = 0;
-            }
-        }
-        printf("(TS-End)\n");
-    }
-
-    int offset = TS_SIZE - 1;
-    int rdsl = 0, afdl = 0;
-    if ((data[1] & 0x40) == 0x40) {                                // 1.TS-Frame
-        offset = ((data[3] & 0x20) >> 4) ? data[4] + 5 : 4;       // Header+ADFL
-        if (data[offset] == 0x00 && data[offset + 1] == 0x00
-                && data[offset + 2] == 0x01 && // PES-Startcode
-                data[offset + 3] >= 0xc0 && data[offset + 3] <= 0xdf) { // PES-Audiostream MP1/2
-            pesfound = 1;
-            if (!bratefound) {
-                bitrate = audiobitrate(data + offset);
-                bratefound = true;
-            }
-            return;
-        }
-    }
-    // RDS DataSync = 0xfd @ audio-end
-    else if (pesfound && data[3] == 0x3f && data[offset] == 0xfd) { // last TS-Frame
-        rdsl = data[offset - 1];
-        pesfound = 0;
-    } else if (pesfound) {                                  // TS-Frames between
-        afdl = ((data[3] & 0x20) >> 4) ? data[4] + 1 : 0; // AdaptationField-Length
-        // search for PES-Change
-        for (i = afdl + 3; i < TS_SIZE - 4; i++) {
-            if (data[i] == 0xfd && data[i + 1] == 0xff
-                    && ((data[i + 2] & 0xf0) == 0xf0)
-                    && ((data[i + 3] & 0x04) == 0x04)) {
-                // && ((data[i+4] & 0x0f) != 0x0f))
-                offset = i;
-                rdsl = data[offset - 1];
+    const uchar *p = plBuffer + plBufferCnt - 1; // start at the end of the frame
+    while (!*p) { p--; }                // last byte with non-zero bits
+    uint16_t tmp = (p[-1] << 8) | p[0]; // read 16 bits
+
+    // find required bit-shifts to byte-align <TERM>
+    int rs = 0;
+    while   (tmp & 0x1F)  { tmp <<= 1; rs--; }
+    while (!(tmp & 0x20)) { tmp >>= 1; rs++; }
+
+    if ((tmp & 0xFF) == 0xE0) { // <TERM> -> search for <DSE>, 8-bit header
+        int eCnt = -1;
+
+        while (p > plBuffer) {
+            const uchar *eFIL = NULL;
+            int eLen = -2;
+            eCnt++;
+
+            if (rs < 0)
+                rs += 8; // data is at current byte-pos
+            else
+                p--;     // data is at byte-pos -1
+
+            int i;
+            for (i = 0; i < RDS_CHUNKSIZE && p > plBuffer; i++, p--) { // store reversed, as in MPEG-1 TS
+                tmp = (p[-1] << 8) | p[0];
+                uchar eCh = (tmp >> rs) & 0xFF;
+                rdsChunk[i] = eCh;
+
+                if (eCnt == 0 && i < 0xF && !eFIL && (eCh & 0xF) == i && (eCh & 0x70) == 0x60) { // potential short <FIL>, 7-bit header
+                    eFIL = p;
+                    //dsyslog("%s: <FIL> (ID-byte %02X)", __func__, eCh & 0x7F); hexdump(rdsChunk, i + 1);
+                    }
+                if (eCh == 0x80 && eLen == (i - 1)) { // <DSE> with matching len-field
+                    if (eLen == 3 && rdsChunk[i-2] == 0xBC && rdsChunk[i-3] == 0xC0 && rdsChunk[i-4] == 0x0) {
+                        eFIL = NULL;
+                        if ((S_Verbose & 0x0f) >= 1) dsyslog("%s: skip MPEG-4 ancillary data (sync %02X, len %d.)", __func__, rdsChunk[i-2], eLen);
+                        break;// skip this known <DSE> and search next
+                        }
+                    if (rt_start || (eLen > 0 && rdsChunk[i-2] == 0xFE && (eLen < 2 || rdsChunk[i-3] == 0x00))) { // check 4 bytes "0x80, eLen, 0xfe, 0x00"
+                        //dsyslog("%s: <DSE>[%d]", __func__, eCnt); hexdump(rdsChunk, eLen + 2);
+                        return eLen; // <DSE> found
+                        }
+                    }
+                // simple plausibilty checks - invalid 'rt_stop','rt_start' or 'stuffing'
+                if ((i > 0 && (eCh == 0xFF && rdsChunk[i-1] != 0xFE) || (eCh == 0xFD && rdsChunk[i-1] > 2)) || (i > 1 && rdsChunk[i-2] == 0xFE && rdsChunk[i-1] != 0xFF)) {
+                    //dsyslog("%s: <--->[%d/%d] invalid start/stop/stuffing %02X,%02X", __func__, eCnt, i, eCh, rdsChunk[i-1]);
+                    i = RDS_CHUNKSIZE; // retry with <FIL> or return
+                    }
+                eLen = eCh;
+                }
+
+            if (eFIL) { // skip <FIL> and search for <DSE> again
+                p = eFIL;
+                rs--; // adjust shift
+                }
+            else if (i >= RDS_CHUNKSIZE)
                 break;
             }
         }
-    } else {
-        /* no PES-Audio MPEG-1/2 found */
+    else {
+        if ((S_Verbose & 0x0f) >= 1) dsyslog("%s: <TERM> not found (0x%02X)", __func__, tmp & 0xFF);
+        }
+    return -1;
+}
+
+enum eStreamType
+{
+    st_NONE = 1,
+    st_MPEG,
+    st_LATM
+};
+
+void cRadioAudio::RadiotextCheckTS(const uchar *data, int len) {
+    static bool pesfound = false;
+    static int streamType = 0;
+    static int pPesLen = 0;
+    static int pFrameSize = 0;
+    static int frameSize = 0; // static for mpaFrameInfo
+    static uint32_t mpaFrameInfo = 0;
+
+    #define PAYLOAD_BUFSIZE (((RDS_CHUNKSIZE/TS_SIZE)+2)*TS_SIZE)
+    static uchar plBuffer[PAYLOAD_BUFSIZE];
+    static int plBufferCnt = 0;
+    #define HEADER_SIZE 4
+    static uchar buFrameHeader[HEADER_SIZE];
+    static int buFrameHeaderCnt = -1;
+    static int lastApid = -1;
+    static bool rt_start = false;
+    static uchar ccn = 0;
+    #define RDS_SCAN_TIMEOUT 60 // seconds before considering audiostream has no RDS data
+    static time_t rdsScan = 0;
+
+    // verify TS
+    if (data[0] != 0x47) {
+        pesfound = false;
+        return;
+        }
+    if (!TsHasPayload(data))
         return;
-    }
 
-    if (rdsl <= 0) {    // save payload of last frame with no PES-Change
-        for (i = TS_SIZE - 1, ii = 0; i > 3; i--) {
-            lastframe[ii++] = data[i];
+    // audio track
+    if (TsPid(data) != lastApid) {
+        dsyslog("%s: new audio track - Pid %d", __func__, TsPid(data));
+        pesfound = false;
+        streamType = 0;
+        mpaFrameInfo = 0;
+        lastApid = TsPid(data);
+        rt_start = RadiotextParseTS(NULL, 0); // reset RDS parser
+        ccn = TsContinuityCounter(data);
+        rdsScan = time(NULL);
+        rdsSeen = false;
         }
+
+    if (!rdsScan)
         return;
-    }
 
-    // RDS data
-    for (i = offset - 2, ii = 0; i > offset - 2 - rdsl; i--) { // <-- data reverse, from end to start
-        if (i > afdl + 3) {
-            val = data[i];
-        } else if (ii < TS_SIZE - 5) {
-            val = lastframe[ii++];
-        } else {
-            return;
+    if ((S_Verbose & 0x0f) >= 3) {
+        dsyslog("TS-Data(%d):", len);
+        hexdump(data, len);
+        dsyslog("(TS-End)");
         }
 
-        if (val == 0xfe) {      // Start
-            index = -1;
-            rt_start = 1;
-            rt_bstuff = 0;
-            mec = 0;
-            if ((S_Verbose & 0x0f) >= 2) {
-                printf("\nRDS-Start: ");
+    uchar ccc = TsContinuityCounter(data);
+    if (ccc != ccn) {
+        dsyslog("CC-ERROR: want %d, got %d", ccn, ccc);
+        // reset RDS parser and frame detection
+        rt_start = RadiotextParseTS(NULL, 0);
+        pesfound = false;
+        }
+    ccn = (ccc + 1) & 0xF;
+
+    int pOffset = TsPayloadOffset(data); // TS-Header+ADFL
+    int payloadLen = TS_SIZE - pOffset;
+
+    if (TsPayloadStart(data)) {
+        pesfound = false;
+        if (data[pOffset] == 0x00 && data[pOffset + 1] == 0x00
+                && data[pOffset + 2] == 0x01 && // PES-Startcode
+                data[pOffset + 3] >= 0xc0 && data[pOffset + 3] <= 0xdf) {
+            // PES-Audiostream
+            int pesLen = (data[pOffset + 4] << 8) + data[pOffset + 5];
+            pPesLen = pesLen + 6; // from payload start
+            pesfound = true;
+
+            int headerLen = 8 + data[pOffset + 8] + 1; // PES headerlen
+            pOffset += headerLen; // from frame start
+            pPesLen -= headerLen;
+            payloadLen -= headerLen;
+
+            pFrameSize = 0;
+            buFrameHeaderCnt = 0; // start of frame
             }
         }
 
+    if (!pesfound)
+        return; /* no PES-Audio found */
+
+    //dsyslog("+++ offset %2d fs %3d ps %3d pll %3d - PUSI %d", pOffset, pFrameSize, pPesLen, payloadLen, TsPayloadStart(data));
+
+    while (payloadLen > 0 && payloadLen <= pPesLen) {
+        if (buFrameHeaderCnt >= 0) { // start of frame
+            // read (remaining) frameheader
+            for (int p = pOffset; p < TS_SIZE && buFrameHeaderCnt < HEADER_SIZE; p++) {
+                buFrameHeader[buFrameHeaderCnt++] = data[p];
+                }
+            if (buFrameHeaderCnt < HEADER_SIZE) {
+                break; // need more data
+                }
+            buFrameHeaderCnt = -1;
+            plBufferCnt = 0; // reset payload buffer
+
+            int hdStreamType = st_NONE;
+            if (buFrameHeader[0] == 0x56 && (buFrameHeader[1] & 0xE0) == 0xE0) {
+                hdStreamType = st_LATM;
+                frameSize = ((buFrameHeader[1] & 0x1F) << 8) + buFrameHeader[2];
+                pFrameSize += frameSize + 3; // from frame start
+                }
+            else if (buFrameHeader[0] == 0xFF && (buFrameHeader[1] & 0xE0) == 0xE0) {
+                ParseMpaFrameHeader(buFrameHeader, &mpaFrameInfo, &frameSize, &bitrate);
+                hdStreamType = st_MPEG;
+                pFrameSize += frameSize; // from frame start
+                }
+
+            if (frameSize <= 0 || pFrameSize > pPesLen)
+                hdStreamType = st_NONE;
+
+            if (streamType != hdStreamType) {
+                streamType = hdStreamType;
+                if ((S_Verbose & 0x0f) >= 1) {
+                    if (streamType != st_NONE)
+                        dsyslog("%s: audioformat: %s", __func__, streamType == st_LATM ? "AAC-LC" : "MPEG-1");
+                    else
+                        dsyslog("%s: ERROR - unhandled audioformat or invalid header: <%02X %02X %02X>", __func__, buFrameHeader[0], buFrameHeader[1], buFrameHeader[2]);
+                    }
+                }
+
+            if (streamType == st_NONE) {
+                pesfound = false;
+                return;
+                }
+#if 0
+            if (pFrameSize <= payloadLen && (S_Verbose & 0x0f) >= 1) // frame start and end within one TS
+                { dsyslog("%s: short frame - len %d/0x%02X, payload %d, peslen %d", __func__, pFrameSize, pFrameSize, payloadLen, pPesLen); hexdump(data, len); }
+#endif
+            }
+        if (pFrameSize <= payloadLen) { // end of frame
+            // copy into payload buffer
+            memcpy(plBuffer + plBufferCnt, data + pOffset, pFrameSize);
+            plBufferCnt += pFrameSize;
+
+            //--- RDS
+            const uchar *rdsData = NULL;
+            int rdsLen = 0;
+
+            if (streamType == st_LATM) {
+                rdsLen = GetLatmRdsDSE(plBuffer, plBufferCnt, rt_start);
+                rdsData = rdsChunk;
+                }
+            else if (streamType == st_MPEG) {
+                if (plBuffer[plBufferCnt - 1] == 0xFD) {
+                    rdsLen = plBuffer[plBufferCnt - 2];
+                    rdsData = plBuffer + plBufferCnt - (rdsLen + 2);
+                    }
+                }
+            if (rdsLen > 0)
+                rt_start = RadiotextParseTS(rdsData, rdsLen);
+            //---
+
+            if (pPesLen > pFrameSize) { // more frames in PES - goto next frame header
+                pOffset += pFrameSize;
+                buFrameHeaderCnt = 0;
+                }
+            payloadLen -= pFrameSize;
+            pPesLen -= pFrameSize;
+            pFrameSize = 0;
+            }
+        else { // save payload for a minimum data size of RDS_CHUNKSIZE
+            if ((pFrameSize - payloadLen) < RDS_CHUNKSIZE) {
+                memcpy(plBuffer, data + pOffset, payloadLen); // may include PES and Audio Headers!
+                plBufferCnt = payloadLen;
+                }
+            break;
+            }
+        }
+    pFrameSize -= payloadLen;
+    pPesLen -= payloadLen;
+    pesfound = (pPesLen > 0);
+
+    if (pPesLen < 0 || (pPesLen == 0 && pFrameSize != 0))
+        if ((S_Verbose & 0x0f) >= 1) dsyslog("%s: ERROR - invalid PesLen or FrameSize missmatch: PayloadLen:%d PesLen:%d FrameSize:%d", __func__, payloadLen, pPesLen, pFrameSize);
+
+    if (!rdsSeen) {
+        if ((time(NULL) - rdsScan) > RDS_SCAN_TIMEOUT) {
+            dsyslog("%s: no RDS data after %d seconds - disable RDS scan", __func__, RDS_SCAN_TIMEOUT);
+            rdsScan = 0;
+            rdsSeen = true; // no more checks
+            }
+        }
+}
+
+bool cRadioAudio::RadiotextParseTS(const uchar *RdsData, int RdsLen) {
+    #define MSG_SIZE 263 // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
+    static unsigned char mtext[MSG_SIZE + 1];
+    static int rt_start = 0, rt_bstuff = 0, rt_lastVal = 0xff;
+    static int index;
+    static int mec = 0;
+
+    if (!RdsData) { // reset
+        rt_start = 0;
+        return rt_start;
+        }
+
+    if (!rt_start)
+        rt_lastVal = 0xff;
+
+    // RDS data
+    int stop_index = (rt_start && index >= 4) ? mtext[4] + 7 : MSG_SIZE - 1;
+    for (const uchar *p = RdsData + RdsLen - 1; p >= RdsData; p--) { // <-- data reverse, from end to start
+        int val = *p;
+        if (val == 0xfe ) { // Start
+            if (rt_lastVal == 0xff) { // valid start
+                index = -1;
+                rt_start = 1;
+                rt_bstuff = 0;
+                mec = 0;
+                if ((S_Verbose & 0x0f) >= 2) {
+                    printf("\nRDS-Start: ");
+                }
+            }
+            else if (rt_start) {
+                if ((S_Verbose & 0x0f) >= 1) dsyslog("Invalid RDS-start[%d/%d]: %02x %02x", index, RdsLen, rt_lastVal, val);
+                rt_start = 0;
+                break;
+            }
+        }
+        rt_lastVal = val;
+
         if (rt_start == 1) {
             if ((S_Verbose & 0x0f) >= 2) {
                 printf("%02x ", val);
             }
-
             // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff
+            int stv = val;
             if (rt_bstuff == 1) {
                 switch (val) {
                 case 0x00:
@@ -804,44 +1027,51 @@ void cRadioAudio::RadiotextCheckTS(const
                     mtext[index] = 0xff;
                     break;
                 default:
-                    mtext[++index] = val;      // should never be
+                    if ((S_Verbose & 0x0f) >= 1)
+                        dsyslog("RDS-Error(TS): invalid Bytestuffing at [%d]: 0x%02x, garbage ?", index, val);
+                    rt_start = 0;
+                    break;
                 }
                 rt_bstuff = 0;
                 if ((S_Verbose & 0x0f) >= 2) {
                     printf("(Bytestuffing -> %02x) ", mtext[index]);
                 }
+                stv = mtext[index]; // stuffed value
             } else {
                 mtext[++index] = val;
+                if (val == 0xfd) { // stuffing found
+                    rt_bstuff = 1;
+                    continue;
+                }
             }
-            if (val == 0xfd && index > 0) {      // stuffing found
-                rt_bstuff = 1;
-            }
-
             // early check for used mec
             if (index == 5) {
-                switch (val) {
+                switch (stv) {
                 case 0x0a:                  // RT
                 case 0x46:                  // ODA-Data
                 case 0xda:                  // Rass
                 case 0x07:                  // PTY
                 case 0x3e:                  // PTYN
                 case 0x30:                  // TMC
-                case 0x02:
-                    mec = val;      // PS
+                case 0x02:                  // PS
+                    mec = stv;
                     RdsLogo = true;
                     break;
                 default:
-                    rt_start = 0;
+                    mec = 0;
                     if ((S_Verbose & 0x0f) >= 2) {
-                        printf("[RDS-MEC '%02x' not used -> End]\n", val);
+                        dsyslog("[RDS-MEC '%02x' not used -> End]", stv);
                     }
                 }
             }
-            if (index >= mframel) {     // max. rdslength, garbage ?
-                if ((S_Verbose & 0x0f) >= 1) {
-                    printf("RDS-Error(TS): too long, garbage ?\n");
-                }
+            else if (index == 4) // MFL
+                stop_index = stv + 7;
+
+            if (val == 0xff ? index != stop_index : index == stop_index ) { // wrong rdslength or rt_stop, garbage ?
+                if ((S_Verbose & 0x0f) >= 1)
+                    dsyslog("RDS-Error(TS): invalid RDS length: index %d, stop %d, val %02x, garbage ?", index, stop_index, val);
                 rt_start = 0;
+                break;
             }
         }
 
@@ -850,17 +1080,20 @@ void cRadioAudio::RadiotextCheckTS(const
                 printf("(RDS-End)\n");
             }
             rt_start = 0;
+            rdsSeen = true;
+            if ((S_Verbose & 0x0f) >= 1)
+                { dsyslog("-- RDS [%02X] --", mtext[5]); hexdump(mtext, index+1); }
+
             if (index < 9) {		//  min. rdslength, garbage ?
                 if ((S_Verbose & 0x0f) >= 1) {
-                    printf("RDS-Error(TS): too short -> garbage ?\n");
+                    dsyslog("RDS-Error(TS): too short: %d -> garbage ?", index);
                 }
-            } else {
+            } else if (mec > 0) {
                 // crc16-check
                 unsigned short crc16 = crc16_ccitt(mtext, index - 3, 1);
                 if (crc16 != (mtext[index - 2] << 8) + mtext[index - 1]) {
                     if ((S_Verbose & 0x0f) >= 1) {
-                        printf(
-                                "RDS-Error(TS): wrong CRC # calc = %04x <> transmit = %02x%02x\n",
+                        dsyslog("RDS-Error(TS): wrong CRC # calc = %04x <> transmit = %02x%02x\n",
                                 crc16, mtext[index - 2], mtext[index - 1]);
                     }
                 } else {
@@ -894,8 +1127,7 @@ void cRadioAudio::RadiotextCheckTS(const
                     case 0x07:
                         RT_PTY = mtext[8];								// PTY
                         if ((S_Verbose & 0x0f) >= 1) {
-                            printf("RDS-PTY set to '%s'\n",
-                                    ptynr2string(RT_PTY));
+                            dsyslog("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY));
                         }
                         break;
                     case 0x3e:
@@ -921,6 +1153,7 @@ void cRadioAudio::RadiotextCheckTS(const
             }
         }
     }
+    return rt_start;
 }
 
 void cRadioAudio::RadiotextDecode(unsigned char *mtext, int len) {
@@ -1595,7 +1828,7 @@ void cRadioAudio::EnableRadioTextProcess
 
     first_packets = 0;
     enabled = true;
-    bratefound = false;
+    free(bitrate);
     asprintf(&bitrate, "...");
 
     // Radiotext init
@@ -1678,44 +1911,66 @@ void cRadioAudio::EnableRadioTextProcess
         return;
     }
 
-    // RDS-Receiver for seperate Data-PIDs, only Livemode, hardcoded Astra_19E + Hotbird 13E
-    int pid = 0;
+    // RDS-Receiver for seperate Data-PIDs, only Livemode
     if (!replay) {
-        switch (chan->Tid()) {
-        case 1113:
-            switch (pid = chan->Apid(0)) {  // Astra_19.2E - 12633 GHz
-            /*  case 0x161: pid = 0x229;    //  radio top40
-             break; */
-            case 0x400:                 //  Hitradio FFH
-            case 0x406:                 //  planet radio
-            case 0x40c:
-                pid += 1;       //  harmony.ffm
-                break;
-            default:
-                return;
-            }
-            break;
-        case 5300:
-            switch (pid = chan->Apid(0)) { // Hotbird_13E - 11747 GHz, no Radiotext @ moment, only TMC + MECs 25/26
-            case 0xdc3:             //  Radio 1
-            case 0xdd3:             //  Radio 3
-            case 0xddb:             //  Radio 5
-            case 0xde3:             //  Radio Exterior
-            case 0xdeb:
-                pid += 1;   //  Radio 4
-                break;
-            default:
-                return;
-            }
-            break;
-        default:
-            return;
-        }
-        RDSReceiver = new cRDSReceiver(pid);
         rdsdevice = cDevice::ActualDevice();
+        EnableRdsPidFilter(chan->Sid());
+    }
+}
+
+void cRadioAudio::EnableRdsPidFilter(int Sid) {
+    if (rdsdevice) {
+        rdsdevice->AttachFilter(&rdsPidFilter);
+        rdsPidFilter.Trigger(Sid);
+    }
+}
+
+void cRadioAudio::DisableRdsPidFilter(void) {
+    if (rdsdevice) {
+        rdsPidFilter.Trigger();
+        rdsdevice->Detach(&rdsPidFilter);
+    }
+}
+
+void cRadioAudio::EnableRdsReceiver(int Pid) {
+    if (rdsdevice) {
+        if (RDSReceiver)
+            DisableRdsReceiver();
+        RDSReceiver = new cRDSReceiver(Pid);
         rdsdevice->AttachReceiver(RDSReceiver);
     }
+}
+
+void cRadioAudio::DisableRdsReceiver(void) {
+    if (rdsdevice) {
+        if (RDSReceiver) {
+            rdsdevice->Detach(RDSReceiver);
+            delete RDSReceiver;
+            RDSReceiver = NULL;
+        }
+    }
+}
 
+void cRadioAudio::HandleRdsPids(const int *RdsPids, int NumRdsPids) {
+    if (chan) {
+        const int *a = chan->Apids();
+        const int *d = chan->Dpids();
+
+        for (int i = 0; i < NumRdsPids; i++) {
+            int pid = RdsPids[i];
+            bool found = false;
+            for (int j = 0; !found && a[i]; i++)
+                found = (a[i] == pid);
+            for (int j = 0; !found && d[i]; i++)
+                found = (d[i] == pid);
+            if ((S_Verbose & 0x0f) >= 1)
+                dsyslog("%s: RDS Pid %d - in %s-stream", __func__, pid, found ? "Audio" : "separate Data");
+            if (!found) { // seperate RDS-stream
+                EnableRdsReceiver(pid);
+                break;
+            }
+        }
+    }
 }
 
 void cRadioAudio::DisableRadioTextProcessing() {
@@ -1731,10 +1986,9 @@ void cRadioAudio::DisableRadioTextProces
         RadioTextOsd->Hide();
     }
 
-    if (RDSReceiver != NULL) {
-        rdsdevice->Detach(RDSReceiver);
-        delete RDSReceiver;
-        RDSReceiver = NULL;
+    if (rdsdevice) { // live
+        DisableRdsReceiver();
+        DisableRdsPidFilter();
         rdsdevice = NULL;
     }
 }
diff -Nurp vdr-plugin-radio-1.1.0.orig/radioaudio.h vdr-plugin-radio-1.1.0.aac_rds_v7/radioaudio.h
--- vdr-plugin-radio-1.1.0.orig/radioaudio.h	2018-02-23 16:33:59.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/radioaudio.h	2022-01-22 22:38:04.297472145 +0100
@@ -16,6 +16,7 @@
 #include <vdr/osd.h>
 #include <vdr/menu.h>
 #include <vdr/receiver.h>
+#include "rdspatpmt.h"
 
 extern char *ConfigDir;
 extern char *DataDir;
@@ -96,11 +97,16 @@ private:
     bool enabled;
     int first_packets;
     int audiopid;
-    bool bratefound;
+    #define RDS_CHUNKSIZE 128 // assumed max. size of splitted RDS chunks in MPEG and AAC-LATM frames
+    uchar rdsChunk[RDS_CHUNKSIZE];
     //Radiotext
     cDevice *rdsdevice;
+    cRdsPidFilter rdsPidFilter;
     void RadiotextCheckPES(const uchar *Data, int Length);
+    bool ParseMpaFrameInfo(const uchar *Data, uint32_t *mpaFrameInfo, int *frameSize);
+    int GetLatmRdsDSE(const uchar *plBuffer, int plBufferCnt, bool rt_start);
     void RadiotextCheckTS(const uchar *Data, int Length);
+    bool RadiotextParseTS(const uchar *RdsData, int RdsLen);
     void AudioRecorderService(void);
     void RassDecode(uchar *Data, int Length);
 protected:
@@ -111,7 +117,13 @@ protected:
 public:
     cRadioAudio(void);
     virtual ~cRadioAudio(void);
+    void EnableRdsPidFilter(int Sid);
+    void DisableRdsPidFilter(void);
+    void EnableRdsReceiver(int Pid);
+    void DisableRdsReceiver(void);
+    void HandleRdsPids(const int *RdsPids, int NumRdsPids);
     char *bitrate;
+    bool rdsSeen;
     void EnableRadioTextProcessing(const char *Titel, int apid, bool replay = false);
     void DisableRadioTextProcessing();
     void RadiotextDecode(uchar *Data, int Length);
diff -Nurp vdr-plugin-radio-1.1.0.orig/radiotools.c vdr-plugin-radio-1.1.0.aac_rds_v7/radiotools.c
--- vdr-plugin-radio-1.1.0.orig/radiotools.c	2018-02-23 16:33:59.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/radiotools.c	2022-01-13 21:03:44.356793877 +0100
@@ -5,6 +5,7 @@
  *
  */
  
+#include <ctype.h>
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
@@ -88,6 +89,43 @@ unsigned short crc16_ccitt(unsigned char
 
 /* ----------------------------------------------------------------------------------------------------------- */
 
+#define HEXDUMP_COLS 16
+void hexdump(const void *Data, int Len)
+{
+  if (!Data || Len <= 0)
+     return;
+
+  char hex[(3 * HEXDUMP_COLS) + 1];
+  char ascii[HEXDUMP_COLS + 1];
+
+  uint8_t *p = (uint8_t *)Data;
+  int ofs = 0;
+  while (Len) {
+        char *h = hex;
+        int i = Len > HEXDUMP_COLS ? HEXDUMP_COLS : Len;
+
+        *h = 0;
+        int j = 0;
+
+        while(j < i) {
+            uint8_t c = *p++;
+            h += sprintf(h, "%02x ", c);
+            ascii[j++] = isprint(c) ? c : '.';
+            }
+        ascii[j] = '\0';
+
+        for (; j < HEXDUMP_COLS; j++)
+            h += sprintf(h, "   ");
+
+        dsyslog("0x%06x: %s  %s", ofs, hex, ascii);
+
+        Len -= i;
+        ofs += i;
+        }
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
 #define EntityChars 56
 const char *entitystr[EntityChars]  = { "&apos;",   "&amp;",    "&quot;",  "&gt",      "&lt",      "&copy;",   "&times;", "&nbsp;",
                                         "&Auml;",   "&auml;",   "&Ouml;",  "&ouml;",   "&Uuml;",   "&uuml;",   "&szlig;", "&deg;",
@@ -203,6 +241,56 @@ char *rtrim(char *text)
 
 /* ----------------------------------------------------------------------------------------------------------- */
 
+bool ParseMpaFrameHeader(const uchar *data, uint32_t *mpaFrameInfo, int *frameSize, char **bitRate) {
+    uint32_t info = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+
+    if ((info & ~0x1FF) == (*mpaFrameInfo & ~0x1FF))
+        return false; // unchanged
+
+    int A = (info >> 21) & 0x7FF;
+    int B = (info >> 19) & 0x3;
+    int C = (info >> 17) & 0x3;
+    int D = (info >> 16) & 0x1;
+    int E = (info >> 12) & 0xF;
+    int F = (info >> 10) & 0x3;
+    int G = (info >>  9) & 0x1;
+
+    int mpa_sr[4] = { 44100, 48000, 32000, 0 }; // v1, v2/2, v2.5/4
+
+    int mpa_br11[16] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 };
+    int mpa_br12[16] = { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0 };
+    int mpa_br13[16] = { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0 };
+
+    int mpa_br21[16] = { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, 0 };
+    int mpa_br22[16] = { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, 0 };
+
+    //dsyslog("%08X : A=%X B=%d C=%d D=%d E=%d F=%d G=%d", info, A, B, C, D, E, F, G);
+
+    int MPver = 4 - B; // 1,2,x,2.5
+    int MPlay = 4 - C; // 1,2,3,x
+    int BR = (MPver == 1) ?
+                (MPlay == 1) ? mpa_br11[E] : (MPlay == 2) ? mpa_br12[E] : (MPlay == 3) ? mpa_br13[E] : 0 :
+             (MPver == 2 || MPver == 4) ?
+                (MPlay == 1) ? mpa_br21[E] : (MPlay == 2 || MPlay == 3) ? mpa_br22[E] : 0 : 0;
+
+    int SR = mpa_sr[F];
+    if      (B == 2) { SR /= 2; }
+    else if (B == 0) { SR /= 4; }
+
+    int FrameSize = (BR && SR) ? (MPlay == 1) ? (12 * BR * 1000 / SR + G) * 4 : (144 * BR * 1000 / SR + G) : 0;
+
+    if ((info & ~0x3FF) != (*mpaFrameInfo & ~0x3FF)) // changed, not only padding bit
+        dsyslog("MPEG-%d L%d BR %d SR %d FSize %d", MPver, MPlay, BR, SR, FrameSize);
+
+    free(*bitRate);
+    asprintf(bitRate, "%dk", BR);
+
+    *mpaFrameInfo = info;
+    *frameSize = FrameSize;
+
+    return true; // changed
+}
+
 const char *bitrates[5][16] = {
     // MPEG 1, Layer 1-3
     { "free", "32k", "64k", "96k", "128k", "160k", "192k", "224k", "256k", "288k", "320k", "352k", "384k", "416k", "448k", "bad" },
diff -Nurp vdr-plugin-radio-1.1.0.orig/radiotools.h vdr-plugin-radio-1.1.0.aac_rds_v7/radiotools.h
--- vdr-plugin-radio-1.1.0.orig/radiotools.h	2018-02-23 16:33:59.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/radiotools.h	2022-01-13 21:03:44.356793877 +0100
@@ -11,9 +11,11 @@
 bool file_exists(const char *filename);
 bool enforce_directory(const char *path);
 unsigned short crc16_ccitt(unsigned char *daten, int len, bool skipfirst);
+void hexdump(const void *Data, int Len);
 char *rds_entitychar(char *text);
 char *xhtml2text(char *text);
 char *rtrim(char *text);
+bool ParseMpaFrameHeader(const uchar *data, uint32_t *mpaFrameInfo, int *frameSize, char **bitRate);
 char *audiobitrate(const unsigned char *data);
 void tmc_parser(unsigned char *data, int len);		// Alert-c
 const char* ptynr2string(int nr);
diff -Nurp vdr-plugin-radio-1.1.0.orig/rdspatpmt.c vdr-plugin-radio-1.1.0.aac_rds_v7/rdspatpmt.c
--- vdr-plugin-radio-1.1.0.orig/rdspatpmt.c	1970-01-01 01:00:00.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/rdspatpmt.c	2022-01-22 22:45:05.550820255 +0100
@@ -0,0 +1,141 @@
+/*
+ * rdspatpmt.c: PAT section filter
+ */
+
+#include <vdr/libsi/descriptor.h>
+#include "rdspatpmt.h"
+#include "radioaudio.h"
+
+#define PMT_SCAN_TIMEOUT  2000 // ms
+
+extern cRadioAudio *RadioAudio;
+
+// --- cRdsPidFilter ------------------------------------------------------------
+
+//#define DEBUG_RDS_PATPMT
+#ifdef DEBUG_RDS_PATPMT
+#define DBGLOG(a...) { cString s = cString::sprintf(a); fprintf(stderr, "%s\n", *s); dsyslog("%s", *s); }
+#else
+#define DBGLOG(a...) void()
+#endif
+
+cRdsPidFilter::cRdsPidFilter(void)
+{
+  ResetPat();
+  ResetPmt();
+  Set(0x00, 0x00);  // PAT
+}
+
+void cRdsPidFilter::ResetPat(void)
+{
+  patVersion = -1;
+  sectionSyncer.Reset();
+}
+
+void cRdsPidFilter::ResetPmt(void)
+{
+  sid = -1;
+  pid = 0;
+  numRdsPids = 0;
+}
+
+void cRdsPidFilter::SetStatus(bool On)
+{
+  cMutexLock MutexLock(&mutex);
+  if (On) { // restart PAT or PMT Pid
+     if (pid)
+        timer.Set(PMT_SCAN_TIMEOUT);
+     }
+  DBGLOG("RdsPAT filter set status %d, patVersion %d, sid %d, pmtpid %d", On, patVersion, sid, pid);
+  cFilter::SetStatus(On);
+}
+
+void cRdsPidFilter::Trigger(int Sid, int Pid)
+{
+  cMutexLock MutexLock(&mutex);
+  DBGLOG("RdsPAT filter trigger SID %d (%d) PID %d (%d)", Sid, sid, Pid, pid);
+
+  SetStatus(false);
+  if (pid > 0)
+     Del(pid, SI::TableIdPMT);
+
+  if (Sid < 0) {
+     ResetPat();
+     ResetPmt();
+     }
+  else {
+     ResetPmt();
+     if (Pid > 0)
+        Add(Pid, SI::TableIdPMT);
+     sid = Sid;
+     pid = Pid;
+     SetStatus(true);
+     }
+}
+
+void cRdsPidFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
+{
+  cMutexLock MutexLock(&mutex);
+
+  DBGLOG("RdsPAT: Process(Sid %d) Pid %d Tid %d Len %d", sid, Pid, Tid, Length);
+
+  if (Pid == 0x00 && Tid == SI::TableIdPAT) {
+     SI::PAT pat(Data, false);
+     if (!pat.CheckCRCAndParse())
+        return;
+#if VDRVERSNUM >= 20502
+     if (sectionSyncer.Check(pat.getVersionNumber(), pat.getSectionNumber()))
+#else
+     if (sectionSyncer.Sync(pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber()))
+#endif
+        {
+        DBGLOG("RdsPAT: %d %d -> %d %d/%d", Transponder(), patVersion, pat.getVersionNumber(), pat.getSectionNumber(), pat.getLastSectionNumber());
+        if (pat.getVersionNumber() != patVersion) {
+           if (patVersion >= 0 && pid > 0)
+              Trigger(sid); // restart PMT filter
+           patVersion = pat.getVersionNumber();
+           }
+
+        SI::PAT::Association assoc;
+        for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
+            if (!assoc.isNITPid()) {
+               if (assoc.getServiceId() == sid) {
+                  int Pmt = assoc.getPid();
+                  DBGLOG("RdsPAT: PmtPid %d sid %d", Pmt, sid);
+                  Trigger(sid, Pmt); // start PMT Filter
+                  break;
+                  }
+               }
+            }
+        }
+     }
+  else if (pid == Pid && Tid == SI::TableIdPMT) {
+     SI::PMT pmt(Data, false);
+     if (!pmt.CheckCRCAndParse())
+        return;
+
+     if (pmt.getServiceId() == sid) {
+        // Scan the stream-specific loop:
+        SI::PMT::Stream stream;
+        for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) {
+            int esPid = stream.getPid();
+            ///// RDS /////
+            SI::AncillaryDataDescriptor *ad;
+            for (SI::Loop::Iterator it; (ad = (SI::AncillaryDataDescriptor *)stream.streamDescriptors.getNext(it, SI::AncillaryDataDescriptorTag)); ) {
+                if (ad->getAncillaryDataIdentifier() & 0x40) { // RDS via UECP
+                   DBGLOG(">>>> %s : RDS via UECP (type: 0x%X pid: %d/0x%X)", Channel()->Name(), stream.getStreamType(), esPid, esPid);
+                   if (numRdsPids < MAXRDSPIDS)
+                      rdsPids[numRdsPids++] = esPid;
+                   }
+                delete ad;
+                }
+            }
+        RadioAudio->HandleRdsPids(rdsPids, numRdsPids);
+        Trigger(); // stop PAt+PMT Filter
+        }
+     }
+  if (timer.TimedOut()) {
+     DBGLOG("RdsPMT timeout Pid %d", pid);
+     Trigger(); // stop PAt+PMT Filter
+     }
+}
diff -Nurp vdr-plugin-radio-1.1.0.orig/rdspatpmt.h vdr-plugin-radio-1.1.0.aac_rds_v7/rdspatpmt.h
--- vdr-plugin-radio-1.1.0.orig/rdspatpmt.h	1970-01-01 01:00:00.000000000 +0100
+++ vdr-plugin-radio-1.1.0.aac_rds_v7/rdspatpmt.h	2022-01-22 22:17:24.877428459 +0100
@@ -0,0 +1,34 @@
+/*
+ * rdspatpmt.h: PAT section filter
+ */
+
+#ifndef __RDSPATPMT_H
+#define __RDSPATPMT_H
+
+#include <vdr/filter.h>
+#include <vdr/thread.h>
+
+#define MAXRDSPIDS 16
+
+class cRdsPidFilter : public cFilter {
+private:
+  cMutex mutex;
+  cTimeMs timer;
+  int patVersion;
+  int sid;
+  int pid;
+  int numRdsPids;
+  int rdsPids[MAXRDSPIDS];
+  cSectionSyncer sectionSyncer;
+  void ResetPat(void);
+  void ResetPmt(void);
+protected:
+  virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
+
+public:
+  cRdsPidFilter(void);
+  virtual void SetStatus(bool On);
+  void Trigger(int Sid = -1, int Pid = 0); // triggers reading the PMT PID
+  };
+
+#endif //__RDSPATPMT_H
