Anpassungen für Player mit dem DFROBOT LISP3 Chip

Fortsetzung der Diskussion von MP3Player GD3200B im AZDelivery TonUINO Set:

So, auch ich konnte nicht anders und musste, nur um es zu wissen, bei tinytronics eine Bestellung aufgeben.
Als DFR0299 wurden mir, wie auf der Homepage dargestellt, Player mit dem DFROBOT LISP3 Chip geschickt.
Hier kann ich die Beobachtungen von @Thomas-Lehnert zum Einschaltgeräusch bestätigen. Der Player durchlief den DFPlayerAnalizer den ich auf github gefunden habe ohne Probleme. Auch die DEV schien zuerst ohne Probleme zu laufen. Allerdings ist mir dann doch aufgefallen, dass der Player nach der Advert-Funktion ein TrackFinished Event sendet, das beim Tonuino dann ein nextTrack auslöst.

Der als AC20BP angebotene Player ist mir mit einem JL Chip statt des abgebildeten YX5200 geliefert worden.
Dieser Player tut was er soll und läuft bisher ohne Probleme.
Edit: der gelieferte JL läuft doch nicht ganz reibungslos.
Der TrackFinish Event entspricht nicht dem alt bekannten, sondern dem vom hier im Forum auch schon besprochenen MH2024K-16SS

Das mit dem TrackFinish Event ist mir gar nicht aufgefallen. Werde ich mal explizit in der Dev. Testen.

Ich habe das mal gecheckt. Es ist tatsächlich so, dass der Player auch nach dem Abspielen eines Advert ein OnPlayFinished(DfMp3_PlaySources source, uint16_t track) ausgibt, das dann die Queue jeweils einen Wert weiter schaltet. Das bewirkt, dass wenn der aktuelle Track beendet ist, der nächste Track praktisch übersprungen wird. Werden beim Abspielen eines Tracks mehrere adverts abgespielt, werden soviele Tracks in Folge übersprungen wie Adverts abgespielt wurden. Man muss also einen Weg finden das nextTrack beim Abspielen eines Adverts zu unterdrücken und zwar explizit für den dfRobot Player.

Es gibt mehrere Player die das haben. Und ein Fix ist doch meine ich in der DEV sogar drin dafür. Ich habs in meiner Firmware auch behandelt.

Das Problem mit dem Finish-Event bei Advertisement gab’s schonmal in der Diskussion über den GB3200B. @Bastelmatz hat für seine Software dafür eine Lösung gefunden:

Hier dachte ich bisher, dass der o.a. Fix für das doppelte Finish-Event nach einer Datei aus den Ordner 1 bis 99 gedacht ist :thinking:

Das Phäomen hatte ich eben auch in der DEV, so dass der o.a. Fix hier nicht zu greifen scheint.

Ich habe eine Lösung dafür gefunden, die unabhängig davon ob ein Player das EndOfTrack Event nach Advert ausgibt oder nicht, funktioniert. Es ist also keine Unterscheidung mehr notwendig ob der Player das bei Advert ausgibt oder nicht.
Dazu habe ich eine boolVariable AdvPlaying eingefügt, die beim Abspielen von Advert auf true gesetzt wird.

// ******************** DF-Player **************************************************
// DFPlayer Mini
SoftwareSerial mySoftwareSerial(2, 3); // RX, TX   // Digitalpins zur Steuerung des DF-Players
uint8_t numFolders;                                // Anzahl der Ordner im Speichermedium
uint8_t numTracksInFolder;                         // Anzahl der Tracks im Ordner 
uint8_t firstTrack;                                // erster Track
uint8_t currentQueueIndex;                         // index in queue[] aktuelle Tracknr in der queue
uint8_t queueSize;                                 // Länge der queue
uint8_t queue[255];                                // max 255 tracks/folder. entries 0..254 and values 1..255 are used.
uint8_t volume;                                    // Lautstärke
bool AdvPlaying = false;                           // Advert wird abgespielt, Voreinstellung Nein

Wird jetzt ein Advert abgespielt und der Player gibt ein EndOfTrack Event aus, wird bei AdvPlaying = true ,die Anweisung nextTrack(track); nicht ausgeführt. Im Code sieht das so aus:

    // Meldung vom Df Player - Track beendet ,                                  Meldung erfolgt
    static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track)    //  am Ende von normalen mp3 Files 
    {                                                                       //  am Ende von Files aus dem mp3-Ordner
    delay(100);
                                                                            // Zusatzabfrage für DF-Player, die auch am Ende
                                                                            // von Adverts ein Track beendet ausgeben. z.B.DFROBOT DF 290
    if(!AdvPlaying)                                                         // Wenn kein Advert abgespielt wurde
      {
// #ifdef Konsole
      PrintlnSourceAction(source, "OPFin -> nxtTr");                        //  wird am Ende von advert-Tracks nicht gesendet
// #endif
      nextTrack(track);                                                     // Wenn der Track regulär beendet wird , nextTrack.
      }
     AdvPlaying = false;                                                    // Marker zurücksetzen dass Advert gespielt wurde
    }                                                                       // außer bei advert-Tracks

Zu jeder PlayAdvert Anweisung wurde das setzen der Variable AdvPlaying auf true hinzugefügt.
z.B.

 mp3.playAdvertisement(302);                 //advert-302- Schlummerfunktion aktiviert.
        AdvPlaying = true;

Vielleicht geht das auch eleganter. Ich habe es erst mal so gelöst.

1 „Gefällt mir“

@Thomas-Lehnert würdest du das vielleicht auch einmal so teilen, dass man das mit der DEV nutzen kann. Denn das define für die Konsole gibts da ja nicht

Ja, ist doch ganz einfach. die #ifdef und #endif weglassen und es geht in der DEV. Auch ohne die def geht das, dann wird nur die Ausgabe in der Konsole nicht ausgeführt. Aber ja, ich werde das so ändern, dass es überall funktioniert.

1 „Gefällt mir“

Diese ganzen Klone sind echt der „Hammer“!
Diese Lösung klappt gut, für die meißten Versionen, die ich ausprobiert habe! Leider führt sie bei meinen „neuen JL“ von tinytronics dazu, dass, nachdem einmal ein Advertisement abgespielt wurde, das nextTrack nicht mehr verarbeitet wird :joy:.
Also doch wieder Codeanpassung je nach Modell :person_facepalming:

Hast du konsequent nach jedem Advertaufruf diese Zeile eingefügt?

Das NextTrack wird nach abspielen eines Advert nur unterdrückt, wenn der Player nach dem Abspielen eines Advert das EndOfTrack Event ausgibt. Gibt der Player das Event nicht aus, wird dieser Part gar nicht ausgeführt. Wichtig ist das Zurücksetzen der Variablen AdvPlaying auf false, nach jedem Event EOT, sonst wird jeder weitere NextTrack auch unterdrückt.

Zusätzlich sollte bei den Fehlermeldungen des DF-Players bei Auftreten eines advertiseErrors das advPlaying auch auf false zurückgesetzt werden. Je nach Fork kann das unterschiedlich aussehen. Bei mir sieht das so aus.

      case DfMp3_Error_Advertise: {
            Serial.print(F("7- adv"));               // Fehler beim Abspielen Advert
            AdvPlaying = false;
            break;
          }

Jupp, habe die DEV dahingehend durchsucht und die Zeile bei jedem Advertaufruf eigefügt.

Das habe ich in die static void OnPlayFinished so wie von dir geschrieben rein gesetzt.
Habe dann nach dem Raufladen nur den Player getauscht, und wie geschrieben, bei den meißten Exemplaren macht es das was es soll. Nur der neue JL führt kein nextTrack mehr aus nachdem einmal ein advert gelaufen ist. Bis dahin gibt es keine Probleme.
Eine Fehlermeldung bekomme ich nie ausgegeben, aber

das werde ich nochmal austesten
Edit: wobei ich in der DEV keine eigene Fehlerausgabe nur für Advert gefunden habe, sondern nur eine static void OnError

Setze mal diesen Part zusätzlich vor die if(!AdvPlaying)

Dann kannst du in der Konsole sehen wann das EOT Event ausgegeben wird, unabhängig ob von Advert oder normalem mp3Track. Die ausführung des nextTrack ist trotzdem von der if abfrage abhängig, auch wenn es jedesmal angezeigt wird. Wenn es ausgeführt wird, wird es dann doppelt angezeigt.

Der Advertiseerror hat den Fehlercode 7. Den müsstest du dann abfragen.
Das müsste in der DEV dann in etwa so aussehen.

class Mp3Notify {
  public:
    static void OnError(uint16_t errorCode) {
      // see DfMp3_Error for code meaning
      Serial.println();
      Serial.print("Com Error ");
      Serial.println(errorCode);
if(errorCode==7) AdvPlaying = false;
    }

Was hast du für einen IL Player. Ich bin das grad am Checken mit einem ILAA19HF 8328-94.
So, bei diesem Player funktioniert das ganze einwandfrei.

Es ist wohl ein AC20BP.


Der sendet auch generell ein anderes Finish-Event, aber das habe habe in der dfplayer lib schon angepasst. Das Problem war schon vom MH2024K-16SS her bekannt.

Hier mal ein Konsolenauszug . Es wird im Albummodus abgespielt.
Die 3x Wait for TrackToFinisch kommen nachdem ich 3x über Longpress PlayTaste die Tracknummer als Advertise ansagen ließ.
Das darauffolgende nextTrack wurde manuell über die VorwTaste ausgelöst. OK.
Die folgenden 3 WaitForTrack… wurden wieder durch 3 maliges Ansagen der Tracknummer durch Longpress Play als advert ausgegeben.
Der folgende Nexttrack wurde durch normales weitergehen in der Queue ohne Tastendruck ausgeführt. OK.
Sichtbar durch SD-K OPFin -> nxtTr OK.

14:25:00.259 -> Alb.modus -> nxtTrk 
14:25:00.259 -> idx: 2 --> 3 von: 76
14:25:00.307 -> Play Q-idx: 3, Trk: 4
14:25:00.307 -> 
14:25:00.307 -> StdBy OFF
14:25:06.968 ->  Wait for Track To Finish
14:25:12.829 ->  Wait for Track To Finish
14:25:18.562 ->  Wait for Track To Finish
14:25:23.049 -> 
14:25:23.049 -> Alb.modus -> nxtTrk 
14:25:23.049 -> idx: 3 --> 4 von: 76
14:25:23.049 -> Play Q-idx: 4, Trk: 5
14:25:23.049 -> 
14:25:23.049 -> StdBy OFF
14:25:36.436 ->  Wait for Track To Finish
14:25:41.354 ->  Wait for Track To Finish
14:25:45.606 ->  Wait for Track To Finish
14:28:31.834 -> SD-K OPFin -> nxtTr
14:28:31.834 -> 
14:28:31.834 -> Alb.modus -> nxtTrk 
14:28:31.834 -> idx: 4 --> 5 von: 76
14:28:31.834 -> Play Q-idx: 5, Trk: 6
14:28:31.834 -> 
14:28:31.834 -> StdBy OFF

Sobald ich ein Advert ausgegeben hatte bekomme ich nur noch das vor dem if angezeigt. Habe das nxtTr zur Unterscheidung mit 1 und 2 ergänzt.
Das Zurücksetzen von AdvPlaying auf false scheint dann also bei dem Chip irgendwie nicht zu klappen. :person_shrugging:
Kann dann ja eigentlich nur mit dem anderen Finish-Event zusammen hängen, oder?! :thinking:

Poste doch bitte mal deinen Part des Codes dieses Phänomen betreffend.

Das Rücksetzen wird ja nicht von dem Chip gemacht, sondern jedesmal wenn das TrackFinish Event vom Player kommt, wird das advPlaying auf false gesetzt.
Wenn das erste nxtTrk nach deiner nummerierung kommt, dann tritt auch das Event auf und das Rücksetzen müsste durch den Code erfolgen. Hast du die geschweiften Klammern richtig gesetzt, so dass das Rücksetzen ausserhalb der if abfrage erfolgt? Wenn das in der Abfrage ist, kann das Rücksetzen nicht funktionieren, weil durch das Abspielen des Advert advPlaying ja true ist. dadurch wird die Abfragebedingung nicht erfüllt und das Rücksetzen geht nicht, und der automatische nextTrack auch nicht.

class Mp3Notify {
  public:
    static void OnError(uint16_t errorCode) {
  // see DfMp3_Error for code meaning
      Serial.println();
      Serial.print("Com Error ");
      Serial.println(errorCode);
      if(errorCode==7) AdvPlaying = false;
    }
    static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action) {
      if (source & DfMp3_PlaySources_Sd) Serial.print(F("SD"));
      if (source & DfMp3_PlaySources_Usb) Serial.print(F("USB"));
      if (source & DfMp3_PlaySources_Flash) Serial.print(F("Flash"));
      Serial.println(action);
    }
    static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track) {
//      Serial.print("Track beendet");
//      Serial.println(track);
      delay(100);

      PrintlnSourceAction(source, "OPin -> nxtTr1");

      if (!AdvPlaying) {
        PrintlnSourceAction(source, "OPin -> nxtTr2");
        nextTrack(track);
      }
      AdvPlaying = false;
    }

So habe ich das Zurücksetzen im Code verewigt.
Und noch eine Konsolenausgabe.
Habe eine Karte mit Hörbuch-Modus aufgelegt, ein automatisches nextTrack abgewartet, dann eine Sleeptimer-Karte aufgelegt (als advertise wird der Modifier-Aktivierungssound abgespielt) (Phänomen ist aber jedem anderen advertise das gleiche), dann wieder bis zum nächsten automatischen nextTrack gewartet und da kommt dann halt nur die Ausgabe vor der if-Abfrage.

15:38:50.981 -> RFID UID:  15 55 9C 28
15:38:50.981 -> PICC type: MIFARE 1KB
15:38:50.981 -> Authenticating Classic using key A..
15:38:50.981 -> Reading block 4 ..
15:38:50.981 -> Data on RFID :
15:38:50.981 ->  13 37 B3 47 02 13 05 00 00 00 00 00 00 00 00 00
15:38:51.014 -> 
15:38:51.014 -> 19
15:38:51.014 -> 19
15:38:51.014 -> == playFolder()
15:38:51.014 -> == disablestandby()
15:38:52.669 -> 147 Dateien in Ordner 19
15:38:52.669 -> Hörbuch Modus
15:40:25.472 -> SDOPin -> nxtTr1
15:40:25.472 -> SDOPin -> nxtTr2
15:40:25.505 -> == nextTrack()
15:40:25.505 -> Hörbuch Modus -> nächster Track & Fortschritt sichern
15:40:25.505 -> 2
15:40:45.002 -> RFID UID:  50 A5 7D 30
15:40:45.002 -> PICC type: MIFARE 1KB
15:40:45.002 -> Authenticating Classic using key A..
15:40:45.002 -> Reading block 4 ..
15:40:45.002 -> Data on RFID :
15:40:45.002 ->  13 37 B3 47 02 00 01 05 00 00 50 00 00 00 00 00
15:40:45.002 -> 
15:40:45.002 -> == SleepTimer()
15:40:45.002 -> 5
15:43:03.810 -> SDOPin -> nxtTr1
15:45:45.325 -> == SleepTimer::loop() -> SLEEP
15:45:45.325 -> == setstandbyTimer()
15:45:45.325 -> 428910

Das advertisement rufe ich mit dem Modifier so auf:

      if (tempCard.nfcFolderSettings.mode != 0 && tempCard.nfcFolderSettings.mode != 255) {
        if (isPlaying()) {
          mp3.playAdvertisement(260);
          AdvPlaying = true;
        }
        else {
          mp3.start();
          delay(100);
          mp3.playAdvertisement(260);
          AdvPlaying = true;
          delay(100);
          mp3.pause();
        }
      }

Aber als advertisement z.B. die Track-Ansage zu nehmen ändert auch nichts.