cspot fixes - release

This commit is contained in:
philippe44
2023-10-06 23:38:07 -07:00
parent e3650413f5
commit 61f58f9a52
11 changed files with 106 additions and 76 deletions

View File

@@ -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)

View File

@@ -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++;
}

View File

@@ -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 );

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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, ...) \

View File

@@ -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();
};

View File

@@ -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;

View File

@@ -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();
bool SpircHandler::skipSong(TrackQueue::SkipDirection dir) {
bool skipped = trackQueue->skipTrack(dir);
// Reset track state
trackPlayer->resetState();
// Reset track state
trackPlayer->resetState(!skipped);
sendEvent(EventType::PLAY_PAUSE, false);
} else {
playbackState->setPlaybackState(PlaybackState::State::Paused);
playbackState->updatePositionMs(0);
notify();
sendEvent(EventType::PLAY_PAUSE, true);
}
notify();
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() {

View File

@@ -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 =

View File

@@ -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;
if (currentTracksIndex > 0 && position < 3000) {
queueNextTrack(-1);
if (preloadedTracks.size() > MAX_TRACKS_PRELOAD) {
preloadedTracks.pop_back();
}
currentTracksIndex--;
} else {
queueNextTrack(0);
}
currentTracksIndex++;
} else {
queueNextTrack(-1);
if (currentTracks.size() > currentTracksIndex + 1) {
preloadedTracks.pop_front();
if (preloadedTracks.size() > MAX_TRACKS_PRELOAD) {
preloadedTracks.pop_back();
}
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() {