From 50b12e45480455cc7da66af8d3351376130619ff Mon Sep 17 00:00:00 2001 From: anschrammh Date: Wed, 27 Sep 2023 23:07:20 +0200 Subject: [PATCH] Reworked the way the music player is keeping track of the play time of the current playing song so it doesn't desync when closing the player app or when the screen goes off --- src/W800_SDK_v1.00.10/app/gfx/gfx_task.c | 2 +- .../app/gfx/music_player_screen.c | 145 ++++++++++++------ .../app/gfx/music_player_screen.h | 16 +- 3 files changed, 105 insertions(+), 58 deletions(-) diff --git a/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c b/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c index d7be08d..dd90fac 100644 --- a/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c +++ b/src/W800_SDK_v1.00.10/app/gfx/gfx_task.c @@ -559,7 +559,7 @@ void gfx_task(void *param) music_player_screen_init(&musicPlayerScreen); music_player_screen_register_music_playback_control_cb(&musicPlayerScreen, &(sendMusicPlaybackBLECommandCb)); - music_player_screen_register_os_time_ms_ref_cb(&musicPlayerScreen, &(elapsed_ms)); + music_player_screen_register_music_player_time_ref_ms_cb(&musicPlayerScreen, &(elapsed_ms)); settings_screen_init(&settingsScreen); settings_screen_register_API_interface(&settingsScreen, &settingsScreenAPIInterface); diff --git a/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.c b/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.c index 9a287bf..165996c 100644 --- a/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.c +++ b/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.c @@ -4,7 +4,10 @@ #include "menu_screen.h" #include "translation.h" -void _set_UI_no_ble_connection(MusicPlayerScreen_t * const musicPlayerScreen, bool connected); +static void _set_UI_no_ble_connection(MusicPlayerScreen_t * const musicPlayerScreen, bool connected); +static void _update_playing_track_visuals(MusicPlayerScreen_t * const musicPlayerScreen); +static void _update_playing_track_ref_time(MusicPlayerScreen_t * const musicPlayerScreen); +static uint16_t _time_difference_in_ms(uint32_t referenceTimeMs, uint32_t currentTimeMs); static void gesture_event_cb(lv_event_t *e) { @@ -57,11 +60,37 @@ static void music_player_button_click_event_cb(lv_event_t *e) } else if(action == MUSIC_CONTROL_NEXT) { - musicPlayerScreen->musicPlaybackCtrlCb(e->code == LV_EVENT_SHORT_CLICKED ? MUSIC_CONTROL_NEXT : MUSIC_CONTROL_FORWARD); + if(e->code == LV_EVENT_SHORT_CLICKED) + { + musicPlayerScreen->musicPlaybackCtrlCb(MUSIC_CONTROL_NEXT); + } + else + { + musicPlayerScreen->musicPlaybackCtrlCb(MUSIC_CONTROL_FORWARD); + //Don't forget to add 10 seconds to the current song position + //10 seconds is the step used by the android AIMP player, this may vary + musicPlayerScreen->currentMusicPosition = musicPlayerScreen->currentMusicPosition/1000 + FAST_FORWARD_BACKWARD_STEP > musicPlayerScreen->currentMusicDuration ? + musicPlayerScreen->currentMusicDuration * 1000 : musicPlayerScreen->currentMusicPosition + FAST_FORWARD_BACKWARD_STEP * 1000; + _update_playing_track_visuals(musicPlayerScreen); + if(musicPlayerScreen->musicPlayerTimeRefmsCb)musicPlayerScreen->playerStartTimeRef = musicPlayerScreen->musicPlayerTimeRefmsCb(); + } } else if(action == MUSIC_CONTROL_PREVIOUS) { - musicPlayerScreen->musicPlaybackCtrlCb(e->code == LV_EVENT_SHORT_CLICKED ? MUSIC_CONTROL_PREVIOUS : MUSIC_CONTROL_REWIND); + if(e->code == LV_EVENT_SHORT_CLICKED) + { + musicPlayerScreen->musicPlaybackCtrlCb(MUSIC_CONTROL_PREVIOUS); + } + else + { + musicPlayerScreen->musicPlaybackCtrlCb(MUSIC_CONTROL_REWIND); + //Don't forget to remove 10 seconds to the current song position + //10 seconds is the step used by the android AIMP player, this may vary + musicPlayerScreen->currentMusicPosition = musicPlayerScreen->currentMusicPosition >= FAST_FORWARD_BACKWARD_STEP * 1000 ? + musicPlayerScreen->currentMusicPosition - FAST_FORWARD_BACKWARD_STEP * 1000 : 0; + _update_playing_track_visuals(musicPlayerScreen); + if(musicPlayerScreen->musicPlayerTimeRefmsCb)musicPlayerScreen->playerStartTimeRef = musicPlayerScreen->musicPlayerTimeRefmsCb(); + } } else { @@ -74,7 +103,11 @@ static void track_position_update_cb(lv_timer_t *timer) { MusicPlayerScreen_t *musicPlayerScreen = timer->user_data; - music_player_screen_set_music_position(musicPlayerScreen, ++musicPlayerScreen->currentMusicPosition); + if(musicPlayerScreen->currentMusicPosition == musicPlayerScreen->currentMusicDuration * 1000) return; + + //If the callback get's called, this means we are in the music play state + _update_playing_track_ref_time(musicPlayerScreen); + _update_playing_track_visuals(musicPlayerScreen); } void music_player_screen_init(MusicPlayerScreen_t * const musicPlayerScreen) @@ -100,7 +133,7 @@ void music_player_screen_register_music_playback_control_cb(MusicPlayerScreen_t musicPlayerScreen->musicPlaybackCtrlCb = musicPlaybackCtrlCb; } -void music_player_screen_register_os_time_ms_ref_cb(MusicPlayerScreen_t * const musicPlayerScreen, MusicPlayerTimeRefCb_t musicPlayerTimeRefCb) +void music_player_screen_register_music_player_time_ref_ms_cb(MusicPlayerScreen_t * const musicPlayerScreen, MusicPlayerTimeRefmsCb_t musicPlayerTimeRefmsCb) { if(!musicPlayerScreen) { @@ -108,7 +141,7 @@ void music_player_screen_register_os_time_ms_ref_cb(MusicPlayerScreen_t * const return; } - musicPlayerScreen->musicPlayerTimeRefCb = musicPlayerTimeRefCb; + musicPlayerScreen->musicPlayerTimeRefmsCb = musicPlayerTimeRefmsCb; } void music_player_screen_notify_BLE_connection_state(MusicPlayerScreen_t * const musicPlayerScreen, bool connected) @@ -137,9 +170,7 @@ void music_player_screen_set_playing_music_title_and_artist(MusicPlayerScreen_t if(title) { - strncpy(musicPlayerScreen->titleText, title, sizeof musicPlayerScreen->titleText); - musicPlayerScreen->titleText[sizeof(musicPlayerScreen->titleText) - 1] = '\0'; - + strncpy(musicPlayerScreen->titleText, title, sizeof(musicPlayerScreen->titleText)-1); if(musicPlayerScreen->titleLabel) { lv_label_set_text_static(musicPlayerScreen->titleLabel, musicPlayerScreen->titleText); @@ -148,9 +179,7 @@ void music_player_screen_set_playing_music_title_and_artist(MusicPlayerScreen_t if(artist) { - strncpy(musicPlayerScreen->artistText, artist, sizeof musicPlayerScreen->artistText); - musicPlayerScreen->artistText[sizeof(musicPlayerScreen->artistText) - 1] = '\0'; - + strncpy(musicPlayerScreen->artistText, artist, sizeof(musicPlayerScreen->artistText)-1); if(musicPlayerScreen->artistLabel) { lv_label_set_text_static(musicPlayerScreen->artistLabel, musicPlayerScreen->artistText); @@ -188,22 +217,13 @@ void music_player_screen_set_music_position(MusicPlayerScreen_t * const musicPla } positionInSeconds = positionInSeconds > musicPlayerScreen->currentMusicDuration ? musicPlayerScreen->currentMusicDuration : positionInSeconds; - musicPlayerScreen->currentMusicPosition = positionInSeconds; + musicPlayerScreen->currentMusicPosition = positionInSeconds * 1000; - //Let's update the time ref - if(musicPlayerScreen->musicPlayerTimeRefCb) - musicPlayerScreen->osTimeRef = musicPlayerScreen->musicPlayerTimeRefCb(); - - //If the widget is currently displayed, we update it as well ! - if(!musicPlayerScreen->playbackArc) return; - - lv_arc_set_value(musicPlayerScreen->playbackArc, musicPlayerScreen->currentMusicPosition); - - if(positionInSeconds < 3600)sprintf(musicPlayerScreen->positionTimeLabel.text, "%s%u:%s%u", positionInSeconds / 60 < 10 ? "0":"", positionInSeconds / 60, positionInSeconds % 60 < 10 ? "0":"", positionInSeconds % 60); - else sprintf(musicPlayerScreen->positionTimeLabel.text, "%s%u:%s%u:%s%u", positionInSeconds / 3600 < 10 ? "0":"", positionInSeconds / 3600, - (positionInSeconds % 3600) / 60 < 10 ? "0":"", (positionInSeconds % 3600) / 60, - (positionInSeconds % 3600) % 60 < 10 ? "0":"", (positionInSeconds % 3600) % 60); - lv_label_set_text_static(musicPlayerScreen->positionTimeLabel.label, musicPlayerScreen->positionTimeLabel.text); + //Let's update the current music position visually + if(music_player_screen_is_in_use(musicPlayerScreen)) + { + _update_playing_track_visuals(musicPlayerScreen); + } } void music_player_screen_set_music_playing_state(MusicPlayerScreen_t * const musicPlayerScreen, MusicPlaybackCtrlAction_e playingState) @@ -218,12 +238,15 @@ void music_player_screen_set_music_playing_state(MusicPlayerScreen_t * const mus musicPlayerScreen->currentPlayState = playingState; - if(musicPlayerScreen->currentPlayState == MUSIC_CONTROL_PLAY) - lv_timer_resume(musicPlayerScreen->timePositionTimer); - else - lv_timer_pause(musicPlayerScreen->timePositionTimer); + if(musicPlayerScreen->musicPlayerTimeRefmsCb) + musicPlayerScreen->playerStartTimeRef = musicPlayerScreen->musicPlayerTimeRefmsCb(); - if(!musicPlayerScreen->playPauseBtn.label) return; + if(!music_player_screen_is_in_use(musicPlayerScreen)) return; + + if(musicPlayerScreen->currentPlayState == MUSIC_CONTROL_PLAY) + lv_timer_resume(musicPlayerScreen->trackPlayCursorUpdateTimer); + else + lv_timer_pause(musicPlayerScreen->trackPlayCursorUpdateTimer); strcpy(musicPlayerScreen->playPauseBtn.icon, musicPlayerScreen->currentPlayState == MUSIC_CONTROL_PLAY ? LV_SYMBOL_PAUSE : LV_SYMBOL_PLAY); lv_label_set_text_static(musicPlayerScreen->playPauseBtn.label, musicPlayerScreen->playPauseBtn.icon); @@ -419,23 +442,17 @@ void music_player_screen_create(MusicPlayerScreen_t * const musicPlayerScreen) _set_UI_no_ble_connection(musicPlayerScreen, musicPlayerScreen->ble_connection_state); - if(musicPlayerScreen->timePositionTimer) + if(musicPlayerScreen->trackPlayCursorUpdateTimer) { - LV_LOG_ERROR("timePositionTimer should be NULL here !"); - lv_timer_del(musicPlayerScreen->timePositionTimer); - musicPlayerScreen->timePositionTimer = NULL; + LV_LOG_ERROR("trackPlayCursorUpdateTimer should be NULL here !"); + lv_timer_del(musicPlayerScreen->trackPlayCursorUpdateTimer); + musicPlayerScreen->trackPlayCursorUpdateTimer = NULL; } - musicPlayerScreen->timePositionTimer = lv_timer_create(&(track_position_update_cb), 1000, musicPlayerScreen); - //If the music was not currently playing, no need to start the music position update timer - if(musicPlayerScreen->currentPlayState != MUSIC_CONTROL_PLAY) - { - lv_timer_pause(musicPlayerScreen->timePositionTimer); - } - else if(musicPlayerScreen->musicPlayerTimeRefCb) //When we left the app, the music was running so we need to recompute the current position - { - musicPlayerScreen->currentMusicPosition += (musicPlayerScreen->musicPlayerTimeRefCb() - musicPlayerScreen->osTimeRef) / 1000; //We want seconds - } - music_player_screen_set_music_position(musicPlayerScreen, musicPlayerScreen->currentMusicPosition); + musicPlayerScreen->trackPlayCursorUpdateTimer = lv_timer_create(&(track_position_update_cb), 333, musicPlayerScreen); + if(musicPlayerScreen->currentPlayState != MUSIC_CONTROL_PLAY) lv_timer_pause(musicPlayerScreen->trackPlayCursorUpdateTimer); + if(musicPlayerScreen->currentPlayState == MUSIC_CONTROL_PLAY) _update_playing_track_ref_time(musicPlayerScreen); + + _update_playing_track_visuals(musicPlayerScreen); //We register the event callback to handle gestures lv_obj_add_event_cb(musicPlayerScreen->display, &(gesture_event_cb), LV_EVENT_GESTURE, musicPlayerScreen); @@ -450,12 +467,11 @@ void music_player_screen_destroy(MusicPlayerScreen_t * const musicPlayerScreen) LV_LOG_ERROR("NULL pointer given !"); return; } - - lv_timer_del(musicPlayerScreen->timePositionTimer); + lv_timer_del(musicPlayerScreen->trackPlayCursorUpdateTimer); memset(musicPlayerScreen, 0, offsetof(MusicPlayerScreen_t, musicPlaybackCtrlCb)); } -void _set_UI_no_ble_connection(MusicPlayerScreen_t * const musicPlayerScreen, bool connected) +static void _set_UI_no_ble_connection(MusicPlayerScreen_t * const musicPlayerScreen, bool connected) { if(connected) { @@ -479,3 +495,32 @@ void _set_UI_no_ble_connection(MusicPlayerScreen_t * const musicPlayerScreen, bo lv_obj_add_flag(musicPlayerScreen->artistLabel, LV_OBJ_FLAG_HIDDEN); } } + +static void _update_playing_track_visuals(MusicPlayerScreen_t * const musicPlayerScreen) +{ + //Do not forget to put the current music position back in seconds + uint16_t positionInSeconds = musicPlayerScreen->currentMusicPosition/1000; + lv_arc_set_value(musicPlayerScreen->playbackArc, positionInSeconds); + + if(positionInSeconds < 3600)sprintf(musicPlayerScreen->positionTimeLabel.text, "%s%u:%s%u", positionInSeconds / 60 < 10 ? "0":"", positionInSeconds / 60, positionInSeconds % 60 < 10 ? "0":"", positionInSeconds % 60); + else sprintf(musicPlayerScreen->positionTimeLabel.text, "%s%u:%s%u:%s%u", positionInSeconds / 3600 < 10 ? "0":"", positionInSeconds / 3600, + (positionInSeconds % 3600) / 60 < 10 ? "0":"", (positionInSeconds % 3600) / 60, + (positionInSeconds % 3600) % 60 < 10 ? "0":"", (positionInSeconds % 3600) % 60); + lv_label_set_text_static(musicPlayerScreen->positionTimeLabel.label, musicPlayerScreen->positionTimeLabel.text); +} + +static void _update_playing_track_ref_time(MusicPlayerScreen_t * const musicPlayerScreen) +{ + //Let's compute the time that has passed and update the current song position + uint32_t currentTimeMs = musicPlayerScreen->musicPlayerTimeRefmsCb ? musicPlayerScreen->musicPlayerTimeRefmsCb() : 0; + uint16_t timeDifferenceMs = _time_difference_in_ms(musicPlayerScreen->playerStartTimeRef, currentTimeMs); + musicPlayerScreen->playerStartTimeRef = currentTimeMs; + + musicPlayerScreen->currentMusicPosition = musicPlayerScreen->currentMusicPosition + timeDifferenceMs > musicPlayerScreen->currentMusicDuration * 1000 ? + musicPlayerScreen->currentMusicDuration * 1000 : musicPlayerScreen->currentMusicPosition + timeDifferenceMs; +} + +static uint16_t _time_difference_in_ms(uint32_t referenceTimeMs, uint32_t currentTimeMs) +{ + return currentTimeMs - referenceTimeMs; +} diff --git a/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.h b/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.h index 1045d07..01dae9d 100644 --- a/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.h +++ b/src/W800_SDK_v1.00.10/app/gfx/music_player_screen.h @@ -3,6 +3,8 @@ #include "lvgl.h" +#define FAST_FORWARD_BACKWARD_STEP (10) + typedef enum MusicPlaybackCtrlAction { MUSIC_CONTROL_PLAY = 0, @@ -17,7 +19,7 @@ typedef enum MusicPlaybackCtrlAction } MusicPlaybackCtrlAction_e; typedef void (*MusicPlaybackCtrlCb_t)(MusicPlaybackCtrlAction_e musicPlaybackCtrlAction); -typedef uint32_t (*MusicPlayerTimeRefCb_t)(void); +typedef uint32_t (*MusicPlayerTimeRefmsCb_t)(void); typedef struct PlayerButton { @@ -45,16 +47,16 @@ typedef struct MusicPlayerScreen lv_obj_t *titleLabel; lv_obj_t *artistLabel; TimeLabel_t positionTimeLabel, durationTimeLabel; - lv_timer_t *timePositionTimer; + lv_timer_t *trackPlayCursorUpdateTimer; //Should not be erased attributes MusicPlaybackCtrlCb_t musicPlaybackCtrlCb; - MusicPlayerTimeRefCb_t musicPlayerTimeRefCb; + MusicPlayerTimeRefmsCb_t musicPlayerTimeRefmsCb; MusicPlaybackCtrlAction_e currentPlayState; - uint16_t currentMusicDuration; //The currently playing music's total duration in seconds. - uint16_t currentMusicPosition; //The currently playing music's cursor position in seconds. - uint32_t osTimeRef; //Time reference used to compute the time elaspsed when the player is not running, but the song is playing. char titleText[60]; char artistText[30]; + uint16_t currentMusicDuration; //The currently playing music's total duration in seconds. + uint32_t currentMusicPosition; //The currently playing music's cursor position in milliseconds. + uint32_t playerStartTimeRef; bool ble_connection_state; } MusicPlayerScreen_t; @@ -68,7 +70,7 @@ void music_player_screen_init(MusicPlayerScreen_t * const musicPlayerScreen); void music_player_screen_register_music_playback_control_cb(MusicPlayerScreen_t * const musicPlayerScreen, MusicPlaybackCtrlCb_t musicPlaybackCtrlCb); -void music_player_screen_register_os_time_ms_ref_cb(MusicPlayerScreen_t * const musicPlayerScreen, MusicPlayerTimeRefCb_t musicPlayerTimeRefCb); +void music_player_screen_register_music_player_time_ref_ms_cb(MusicPlayerScreen_t * const musicPlayerScreen, MusicPlayerTimeRefmsCb_t musicPlayerTimeRefmsCb); void music_player_screen_notify_BLE_connection_state(MusicPlayerScreen_t * const musicPlayerScreen, bool connected);