Parcourir la source

cspot fixes - release

philippe44 il y a 1 an
Parent
commit
61f58f9a52

+ 5 - 0
CHANGELOG

@@ -1,3 +1,8 @@
+2023-10-06
+ - fix cspot PREV on first track, NEXT on last track and normal ending
+ - use DMA_AUTO for SPI
+ - cspot share same time log
+ 
 2023-10-06
  - Fix bootswatch bug that caused difficult to read UI ( issue #319)
 

+ 2 - 2
components/platform_console/cmd_i2ctools.c

@@ -477,7 +477,7 @@ static int do_spiconfig_cmd(int argc, char **argv){
 
 	if(!nerrors){
 		fprintf(f,"Configuring SPI data=%d clock=%d host=%u dc: %d\n", spi_config.mosi_io_num, spi_config.sclk_io_num, host, dc);
-		err=spi_bus_initialize( host, &spi_config, 1 );
+		err=spi_bus_initialize( host, &spi_config, SPI_DMA_CH_AUTO );
 		if(err!=ESP_OK){
 			if(err==ESP_ERR_INVALID_STATE){
 				// if user is changing the host number, we need to try freeing both hosts
@@ -485,7 +485,7 @@ static int do_spiconfig_cmd(int argc, char **argv){
 					fprintf(f,"SPI bus init failed. Please clear SPI configuration, restart the device and try again. %s\n", esp_err_to_name(err));
 					nerrors++;
 				}
-				else if((err=spi_bus_initialize( host, &spi_config, 1 ))!=ESP_OK){
+				else if((err=spi_bus_initialize( host, &spi_config, SPI_DMA_CH_AUTO ))!=ESP_OK){
 					fprintf(f,"Failed to initialize SPI Bus. %s\n", esp_err_to_name(err));
 					nerrors++;
 				}

+ 1 - 1
components/services/services.c

@@ -380,7 +380,7 @@ void services_init(void) {
 	ESP_LOGI(TAG,"Configuring SPI mosi:%d miso:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->miso_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
 
 	if (spi_config->mosi_io_num != -1 && spi_config->sclk_io_num != -1) {
-		spi_bus_initialize( spi_system_host, spi_config, 1 );
+		spi_bus_initialize( spi_system_host, spi_config, SPI_DMA_CH_AUTO );
 		if (spi_system_dc_gpio != -1) {
 			gpio_reset_pin(spi_system_dc_gpio);
 			gpio_set_direction( spi_system_dc_gpio, GPIO_MODE_OUTPUT );

+ 2 - 2
components/spotify/Shim.cpp

@@ -229,7 +229,6 @@ void cspotPlayer::eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event
     case cspot::SpircHandler::EventType::NEXT:
     case cspot::SpircHandler::EventType::PREV:
     case cspot::SpircHandler::EventType::FLUSH: {
-        // FLUSH is sent when there is no next, just clean everything
         cmdHandler(CSPOT_FLUSH);
         break;
     }
@@ -424,7 +423,7 @@ void cspotPlayer::runTask() {
                         CSPOT_LOG(info, "last track finished");
                         trackStatus = TRACK_INIT;
                         cmdHandler(CSPOT_STOP);
-                        spirc->setPause(true);
+                        spirc->notifyAudioEnded();
                     }
                 }
                 
@@ -461,6 +460,7 @@ void cspotPlayer::runTask() {
  */
 struct cspot_s* cspot_create(const char *name, httpd_handle_t server, int port, cspot_cmd_cb_t cmd_cb, cspot_data_cb_t data_cb) {
 	bell::setDefaultLogger();
+    bell::enableTimestampLogging(true);
     player = new cspotPlayer(name, server, port, cmd_cb, data_cb);
     player->startTask();
 	return (cspot_s*) player;

+ 2 - 1
components/spotify/cspot/bell/main/utilities/BellLogger.cpp

@@ -10,6 +10,7 @@ void bell::enableSubmoduleLogging() {
   bell::bellGlobalLogger->enableSubmodule = true;
 }
 
-void bell::enableTimestampLogging() {
+void bell::enableTimestampLogging(bool local) {
   bell::bellGlobalLogger->enableTimestamp = true;
+  bell::bellGlobalLogger->shortTime = local;
 }

+ 13 - 4
components/spotify/cspot/bell/main/utilities/include/BellLogger.h

@@ -14,6 +14,7 @@ class AbstractLogger {
  public:
   bool enableSubmodule = false;
   bool enableTimestamp = false;
+  bool shortTime = false;
 
   virtual void debug(std::string filename, int line, std::string submodule,
                      const char* format, ...) = 0;
@@ -94,10 +95,18 @@ class BellLogger : public bell::AbstractLogger {
                              now.time_since_epoch()) %
                          1000;
 
-      auto gmt_time = gmtime(&now_time);
       printf(colorReset);
-      std::cout << std::put_time(gmt_time, "[%Y-%m-%d %H:%M:%S") << '.'
-                << std::setfill('0') << std::setw(3) << nowMs.count() << "] ";
+      struct tm* gmt_time;
+      if (shortTime) {
+        gmt_time = localtime(&now_time);
+        std::cout << std::put_time(gmt_time, "[%H:%M:%S") << '.'
+                  << std::setfill('0') << std::setw(3) << nowMs.count() << "] ";
+      }
+      else {
+          gmt_time = gmtime(&now_time);
+          std::cout << std::put_time(gmt_time, "[%Y-%m-%d %H:%M:%S") << '.'
+              << std::setfill('0') << std::setw(3) << nowMs.count() << "] ";
+      }
     }
   }
 
@@ -129,7 +138,7 @@ class BellLogger : public bell::AbstractLogger {
 
 void setDefaultLogger();
 void enableSubmoduleLogging();
-void enableTimestampLogging();
+void enableTimestampLogging(bool local = false);
 }  // namespace bell
 
 #define BELL_LOG(type, ...)                                        \

+ 4 - 3
components/spotify/cspot/include/SpircHandler.h

@@ -48,11 +48,12 @@ class SpircHandler {
 
   void setPause(bool pause);
 
-  void previousSong();
+  bool previousSong();
 
-  void nextSong();
+  bool nextSong();
 
   void notifyAudioReachedPlayback();
+  void notifyAudioEnded();
   void updatePositionMs(uint32_t position);
   void setRemoteVolume(int volume);
   void loadTrackFromURI(const std::string& uri);
@@ -74,7 +75,7 @@ class SpircHandler {
   void sendEvent(EventType type);
   void sendEvent(EventType type, EventData data);
 
-  void skipSong(TrackQueue::SkipDirection dir);
+  bool skipSong(TrackQueue::SkipDirection dir);
   void handleFrame(std::vector<uint8_t>& data);
   void notify();
 };

+ 3 - 2
components/spotify/cspot/include/TrackPlayer.h

@@ -32,7 +32,7 @@ struct TrackReference;
 class TrackPlayer : bell::Task {
  public:
   // Callback types
-  typedef std::function<void(std::shared_ptr<QueuedTrack>)> TrackLoadedCallback;
+  typedef std::function<void(std::shared_ptr<QueuedTrack>, bool)> TrackLoadedCallback;
   typedef std::function<size_t(uint8_t*, size_t, std::string_view)>
       DataCallback;
   typedef std::function<void()> EOFCallback;
@@ -49,7 +49,7 @@ class TrackPlayer : bell::Task {
 
   // CDNTrackStream::TrackInfo getCurrentTrackInfo();
   void seekMs(size_t ms);
-  void resetState();
+  void resetState(bool paused = false);
 
   // Vorbis codec callbacks
   size_t _vorbisRead(void* ptr, size_t size, size_t nmemb);
@@ -89,6 +89,7 @@ class TrackPlayer : bell::Task {
   std::atomic<bool> pendingReset = false;
   std::atomic<bool> inFuture = false;
   std::atomic<size_t> pendingSeekPositionMs = 0;
+  std::atomic<bool> startPaused = false;
 
   std::mutex runningMutex;
 

+ 27 - 32
components/spotify/cspot/src/SpircHandler.cpp

@@ -31,15 +31,15 @@ SpircHandler::SpircHandler(std::shared_ptr<cspot::Context> ctx) {
     }
   };
 
-  auto trackLoadedCallback = [this](std::shared_ptr<QueuedTrack> track) {
-    playbackState->setPlaybackState(PlaybackState::State::Playing);
+  auto trackLoadedCallback = [this](std::shared_ptr<QueuedTrack> track, bool paused = false) {
+    playbackState->setPlaybackState(paused ? PlaybackState::State::Paused : PlaybackState::State::Playing);
     playbackState->updatePositionMs(track->requestedPosition);
 
     this->notify();
 
-    // Send playback start event, unpause
+    // Send playback start event, pause/unpause per request
     sendEvent(EventType::PLAYBACK_START, (int)track->requestedPosition);
-    sendEvent(EventType::PLAY_PAUSE, false);
+    sendEvent(EventType::PLAY_PAUSE, paused);
   };
 
   this->ctx = ctx;
@@ -77,6 +77,12 @@ void SpircHandler::subscribeToMercury() {
 
 void SpircHandler::loadTrackFromURI(const std::string& uri) {}
 
+void SpircHandler::notifyAudioEnded() {
+    playbackState->updatePositionMs(0);
+    notify();
+    trackPlayer->resetState(true);
+}
+
 void SpircHandler::notifyAudioReachedPlayback() {
   int offset = 0;
 
@@ -142,7 +148,6 @@ void SpircHandler::handleFrame(std::vector<uint8_t>& data) {
       notify();
 
       sendEvent(EventType::SEEK, (int)playbackState->remoteFrame.position);
-      //sendEvent(EventType::FLUSH);
       break;
     }
     case MessageType_kMessageTypeVolume:
@@ -157,12 +162,14 @@ void SpircHandler::handleFrame(std::vector<uint8_t>& data) {
       setPause(false);
       break;
     case MessageType_kMessageTypeNext:
-      nextSong();
-      sendEvent(EventType::NEXT);
+      if (nextSong()) {
+        sendEvent(EventType::NEXT);
+      }
       break;
     case MessageType_kMessageTypePrev:
-      previousSong();
-      sendEvent(EventType::PREV);
+      if (previousSong()) {
+        sendEvent(EventType::PREV);
+      }
       break;
     case MessageType_kMessageTypeLoad: {
       this->trackPlayer->start();
@@ -199,8 +206,8 @@ void SpircHandler::handleFrame(std::vector<uint8_t>& data) {
                                false);
       this->notify();
 
-      trackPlayer->resetState();
       sendEvent(EventType::FLUSH);
+      trackPlayer->resetState();
       break;
     }
     case MessageType_kMessageTypeShuffle: {
@@ -227,34 +234,22 @@ void SpircHandler::notify() {
   this->sendCmd(MessageType_kMessageTypeNotify);
 }
 
-void SpircHandler::skipSong(TrackQueue::SkipDirection dir) {
-  if (trackQueue->skipTrack(dir)) {
-    playbackState->setPlaybackState(PlaybackState::State::Playing);
-    notify();
-
-    // Reset track state
-    trackPlayer->resetState();
-
-    sendEvent(EventType::PLAY_PAUSE, false);
-  } else {
-    playbackState->setPlaybackState(PlaybackState::State::Paused);
-    playbackState->updatePositionMs(0);
-    notify();
-
-    sendEvent(EventType::PLAY_PAUSE, true);
-  }
+bool SpircHandler::skipSong(TrackQueue::SkipDirection dir) {  
+  bool skipped = trackQueue->skipTrack(dir);
 
-  notify();
+  // Reset track state
+  trackPlayer->resetState(!skipped);
 
-  sendEvent(EventType::FLUSH);
+  // send NEXT or PREV event only when successful
+  return skipped;
 }
 
-void SpircHandler::nextSong() {
-  skipSong(TrackQueue::SkipDirection::NEXT);
+bool SpircHandler::nextSong() {
+  return skipSong(TrackQueue::SkipDirection::NEXT);
 }
 
-void SpircHandler::previousSong() {
-  skipSong(TrackQueue::SkipDirection::PREV);
+bool SpircHandler::previousSong() {
+  return skipSong(TrackQueue::SkipDirection::PREV);
 }
 
 std::shared_ptr<TrackPlayer> SpircHandler::getTrackPlayer() {

+ 5 - 3
components/spotify/cspot/src/TrackPlayer.cpp

@@ -87,10 +87,11 @@ void TrackPlayer::stop() {
   std::scoped_lock lock(runningMutex);
 }
 
-void TrackPlayer::resetState() {
+void TrackPlayer::resetState(bool paused) {
   // Mark for reset
   this->pendingReset = true;
   this->currentSongPlaying = false;
+  this->startPaused = paused;
 
   std::scoped_lock lock(dataOutMutex);
 
@@ -119,7 +120,7 @@ void TrackPlayer::runTask() {
   while (isRunning) {
     // Ensure we even have any tracks to play
     if (!this->trackQueue->hasTracks() ||
-        (endOfQueueReached && trackQueue->isFinished())) {
+        (!pendingReset && endOfQueueReached && trackQueue->isFinished())) {
       this->trackQueue->playableSemaphore->twait(300);
       continue;
     }
@@ -184,7 +185,8 @@ void TrackPlayer::runTask() {
       }
 
       if (trackOffset == 0 && pendingSeekPositionMs == 0) {
-        this->trackLoaded(track);
+        this->trackLoaded(track, startPaused);
+        startPaused = false;
       }
 
       int32_t r =

+ 42 - 26
components/spotify/cspot/src/TrackQueue.cpp

@@ -504,11 +504,18 @@ void TrackQueue::processTrack(std::shared_ptr<QueuedTrack> track) {
 
 bool TrackQueue::queueNextTrack(int offset, uint32_t positionMs) {
   const int requestedRefIndex = offset + currentTracksIndex;
+
   if (requestedRefIndex < 0 || requestedRefIndex >= currentTracks.size()) {
     return false;
   }
 
-  if (offset < 0) {
+  // in case we re-queue current track, make sure position is updated (0)
+  if (offset == 0 && preloadedTracks.size() && 
+      preloadedTracks[0]->ref == currentTracks[currentTracksIndex]) {
+      preloadedTracks.pop_front();
+  }
+
+  if (offset <= 0) {
     preloadedTracks.push_front(std::make_shared<QueuedTrack>(
         currentTracks[requestedRefIndex], ctx, positionMs));
   } else {
@@ -520,42 +527,51 @@ bool TrackQueue::queueNextTrack(int offset, uint32_t positionMs) {
 }
 
 bool TrackQueue::skipTrack(SkipDirection dir, bool expectNotify) {
-  bool canSkipNext = currentTracks.size() > currentTracksIndex + 1;
-  bool canSkipPrev = currentTracksIndex > 0;
-
-  if ((dir == SkipDirection::NEXT && canSkipNext) ||
-      (dir == SkipDirection::PREV && canSkipPrev)) {
+    bool skipped = true;
     std::scoped_lock lock(tracksMutex);
-    if (dir == SkipDirection::NEXT) {
-      preloadedTracks.pop_front();
 
-      if (!queueNextTrack(preloadedTracks.size() + 1)) {
-        CSPOT_LOG(info, "Failed to queue next track");
-      }
+    if (dir == SkipDirection::PREV) {
+      uint64_t position = !playbackState->innerFrame.state.has_position_ms ? 0 :
+          playbackState->innerFrame.state.position_ms +
+          ctx->timeProvider->getSyncedTimestamp() -
+          playbackState->innerFrame.state.position_measured_at;
 
-      currentTracksIndex++;
-    } else {
-      queueNextTrack(-1);
+      if (currentTracksIndex > 0 && position < 3000) {
+        queueNextTrack(-1);
 
-      if (preloadedTracks.size() > MAX_TRACKS_PRELOAD) {
-        preloadedTracks.pop_back();
+        if (preloadedTracks.size() > MAX_TRACKS_PRELOAD) {
+            preloadedTracks.pop_back();
+        }
+
+        currentTracksIndex--;
+      } else {
+        queueNextTrack(0);
       }
+    } else {
+      if (currentTracks.size() > currentTracksIndex + 1) {
+        preloadedTracks.pop_front();
+
+        if (!queueNextTrack(preloadedTracks.size() + 1)) {
+          CSPOT_LOG(info, "Failed to queue next track");
+        }
 
-      currentTracksIndex--;
+        currentTracksIndex++;
+       } else {
+         skipped = false;
+       }
     }
 
-    // Update frame data
-    playbackState->innerFrame.state.playing_track_index = currentTracksIndex;
+    if (skipped) {
+        // Update frame data
+        playbackState->innerFrame.state.playing_track_index = currentTracksIndex;
 
-    if (expectNotify) {
-      // Reset position to zero
-      notifyPending = true;
+        if (expectNotify) {
+            // Reset position to zero
+            notifyPending = true;
+        }
     }
 
-    return true;
-  }
-
-  return false;
+    return skipped;
 }
 
 bool TrackQueue::hasTracks() {