Go Down

Topic: DFPlayer detect when song is done playing (Read 9824 times) previous topic - next topic

jksemple

I've now tested the DFPlayer mini with my Saleae Logic analyser and I can confirm that usually the DFPlayer sends the 'Finished' message twice (but sometimes only once).

My sketch cycles through a sequence of several sounds waiting for each one to finish before playing the next.

In the screenshots the upper line is the TX into the DFPlayer and the lower line is the RX from the DFPlayer.

The first (ascii1.jpg) starts with a single 'Finished' message (7E FF 06 3D 00 00 15 FE A9 EF) from the previous sound which initiates the request to playback the next sound (7E FF 06 12 01 00 15 FE D3 EF).  The DFPlayer then acknowledges the playback command (7E FF 06 41 00 00 00 FE BA EF) and starts playing.

The second (ascii2.jpg) starts with a Finished message (7E FF 06 3D 00 00 10 FE AE EF) which triggers the request to play the next sound but as that request is being sent out you can see a second copy of the Finished message arriving from the DFPlayer. Interestingly, as SoftwareSerial has to handle the RX message you can see it causes a little delay in sending out some of the characters of the TX message.  Then shortly after the DFPlayer acknowledges the play request.

So, ideally, the library needs to be altered to ignore repeated RX messages.  The workaround in the meantime is to ensure that all incoming messages are handled as soon as they are received and not left lurking to be read later when they may be misinterpreted.

jksemple

#31
May 28, 2018, 12:44 pm Last Edit: May 28, 2018, 01:02 pm by jksemple
My test sketch (omitting the setup) is as follows:
Code: [Select]

bool _finished = true;
bool _ready = true;
int _playList[] = { 21, 22, 23, 24, 25, 26 };
int idx = 0;
void loop()
{
  if (_finished && _ready){
    myDFPlayer.playMp3Folder(_playList[idx++]);  //Play next mp3
    _finished = false;
  }
  if (idx == 6) idx = 0;
  while (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }
}

 
void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      _finished = true;
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      _ready = true;
      _finished = true;
      break;
    case DFPlayerPlayFinished:
      //Serial.print(F("Number:"));
      //Serial.print(value);
      //Serial.println(F(" Play Finished!"));
      _finished = true;
     
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
    Serial.println(F("??")); 
      break;
  }
 //delay(100);
}

ChuckM

#32
Jul 07, 2018, 08:05 am Last Edit: Jul 07, 2018, 08:10 am by ChuckM
This will eliminate the DFPlayer module's power on/off speaker 'pop' (when using the DFRobotDFPlayerMini-master library).

As has been noted in this thread, a call to reset() in the library causes the audio amp to pop the speaker; resetting the player while the audio amp is active causes the pop. You do not need to modify the library.

To prevent reset() from being called add the appropriate parameter to the begin() function call, as shown in the code below.

The 'false' parameter does the trick (prevents call to reset()). The 'true' parameter enables ACK in the module, which is what you want if your code reads data from the player:

Code: [Select]

 if (!DFPlayer.begin(serialVoice, true, false)) {
   Serial.println(F("Unable to begin:"));
   Serial.println(F("1.Recheck the connection."));
   Serial.println(F("2.Insert the SD card."));
   while(true)
   {
     delay(0);  // the ESP8266 watchdog likes this.
   }
 }



Viola! No more 'pop'.


This is my function to play the designated file in a folder at a specified volume. The function returns after file playback is complete:

Code: [Select]

int playVoice(int folder, int file, int volume) {
  DFPlayer.volume(volume);
  DFPlayer.playFolder(folder, file);
  delay(100);
  int playerState = 0;
  while(playerState != 512) {
    delay(500);          // prevents clicks and static during playback - increase if necessary.
    playerState = DFPlayer.readState();
  }
  DFPlayer.volume(0);
  return playerState;
}


Add an exit conditional to the while loop in case of module/playback failure. If playerState does not change from 0 at any time then a problem occurred... use that and a time elapsed to exit.

Lukijan

#33
Feb 14, 2019, 01:26 am Last Edit: Feb 14, 2019, 01:27 am by Lukijan
For playing mp3 till the end i use this code, and it works on mine NodeMCU and DFPlayer Mini.

Code: [Select]
     
     myDFPlayer.playFolder(01, 4);  //play
     delay(300);  //Wait for
     int stt = myDFPlayer.readState();
     while ( stt == 529 || stt == 513 || stt == 512){
        stt = myDFPlayer.readState();
        //Serial.println( stt );
        //Serial.println( myDFPlayer.readType() );
        delay(300);
     }

Go Up