From 6f7d70797e3521ef72b509e72c2914e1fc5ee0c3 Mon Sep 17 00:00:00 2001 From: Petr Mikhalicin Date: Sun, 28 Dec 2025 00:17:06 +0500 Subject: [PATCH] plugin api: Add audio_pre_ff_rewind to plugin's API According to wps code audio_pre_ff_rewind function should be called before any rewinding. It stops playback and automatically resumes it after audio_ff_rewind call So, let's add audio_pre_ff_rewind to plugin's API Lua scipts were tested: ```lua -- has issue with rewinding rb.audio("ff_rewind", 0) ``` ```lua -- no issue with rewinding rb.audio("pre_ff_rewind") rb.audio("ff_rewind", 0) ``` Change-Id: I2ad6b9c396760b2086bc0a28633a1c80c3512739 --- apps/plugin.c | 51 ++++++++++----------- apps/plugin.h | 62 +++++++++++++------------- apps/plugins/lua/include_lua/audio.lua | 1 + apps/plugins/lua/rocklib.c | 12 +++-- apps/plugins/lua/rocklib_aux.pl | 2 +- docs/PLUGIN_API | 4 ++ firmware/export/audio.h | 1 + 7 files changed, 73 insertions(+), 60 deletions(-) diff --git a/apps/plugin.c b/apps/plugin.c index cb319ab073..98292c26e6 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -356,6 +356,8 @@ static const struct plugin_api rockbox_api = { simplelist_info_init, simplelist_show_list, yesno_pop, + yesno_pop_confirm, + sb_set_title_text, /* action handling */ get_custom_action, @@ -363,6 +365,18 @@ static const struct plugin_api rockbox_api = { #ifdef HAVE_TOUCHSCREEN action_get_touchscreen_press, action_get_touchscreen_press_in_vp, + action_get_touch_event, + action_gesture_reset, + action_gesture_get_event_in_vp, + action_gesture_get_event, + action_gesture_is_valid, + action_gesture_is_pressed, + gesture_reset, + gesture_process, + gesture_get_event_in_vp, + gesture_vel_reset, + gesture_vel_process, + gesture_vel_get, #endif action_userabort, core_set_keyremap, @@ -428,6 +442,9 @@ static const struct plugin_api rockbox_api = { crc_32r, filetype_get_attr, filetype_get_plugin, +#ifdef HAVE_DIRCACHE + dircache_wait, +#endif /* dir */ FS_PREFIX(opendir), @@ -565,6 +582,7 @@ static const struct plugin_api rockbox_api = { strncmp, strcasecmp, strncasecmp, + strstr, memset, memcpy, memmove, @@ -729,6 +747,7 @@ static const struct plugin_api rockbox_api = { audio_resume, audio_next, audio_prev, + audio_pre_ff_rewind, audio_ff_rewind, audio_next_track, audio_status, @@ -738,6 +757,7 @@ static const struct plugin_api rockbox_api = { #ifdef PLUGIN_USE_IRAM audio_hard_stop, #endif + add_playbacklog, /* menu */ root_menu_get_options, @@ -761,6 +781,7 @@ static const struct plugin_api rockbox_api = { #endif /* power */ + &device_battery_tables, battery_level, battery_level_safe, battery_time, @@ -772,12 +793,17 @@ static const struct plugin_api rockbox_api = { charging_state, # endif #endif + /* usb */ usb_inserted, usb_acknowledge, #ifdef USB_ENABLE_HID usb_hid_send, #endif +#ifdef USB_ENABLE_AUDIO + usb_audio_get_playing, +#endif + /* misc */ #if (CONFIG_PLATFORM & PLATFORM_NATIVE) __errno, @@ -849,31 +875,6 @@ static const struct plugin_api rockbox_api = { /* new stuff at the end, sort into place next time the API gets incompatible */ - add_playbacklog, - &device_battery_tables, - yesno_pop_confirm, -#ifdef USB_ENABLE_AUDIO - usb_audio_get_playing, -#endif -#ifdef HAVE_TOUCHSCREEN - action_get_touch_event, - action_gesture_reset, - action_gesture_get_event_in_vp, - action_gesture_get_event, - action_gesture_is_valid, - action_gesture_is_pressed, - gesture_reset, - gesture_process, - gesture_get_event_in_vp, - gesture_vel_reset, - gesture_vel_process, - gesture_vel_get, -#endif - strstr, - sb_set_title_text, -#ifdef HAVE_DIRCACHE - dircache_wait, -#endif }; static int plugin_buffer_handle; diff --git a/apps/plugin.h b/apps/plugin.h index 51466cc70a..523e0cddd2 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -178,7 +178,7 @@ int plugin_open(const char *plugin, const char *parameter); * when this happens please take the opportunity to sort in * any new functions "waiting" at the end of the list. */ -#define PLUGIN_API_VERSION 274 +#define PLUGIN_API_VERSION 275 /* 239 Marks the removal of ARCHOS HWCODEC and CHARCELL */ @@ -418,6 +418,8 @@ struct plugin_api { int count, void* data); bool (*simplelist_show_list)(struct simplelist_info *info); bool (*yesno_pop)(const char* text); + bool (*yesno_pop_confirm)(const char* text); + bool (*sb_set_title_text)(const char* title, enum themable_icons icon, enum screen_type screen); /* action handling */ int (*get_custom_action)(int context,int timeout, @@ -426,6 +428,22 @@ struct plugin_api { #ifdef HAVE_TOUCHSCREEN int (*action_get_touchscreen_press)(short *x, short *y); int (*action_get_touchscreen_press_in_vp)(short *x1, short *y1, struct viewport *vp); + int (*action_get_touch_event)(struct touchevent *ev); + void (*action_gesture_reset)(void); + bool (*action_gesture_get_event_in_vp)(struct gesture_event *gevt, + const struct viewport *vp); + bool (*action_gesture_get_event)(struct gesture_event *gevt); + bool (*action_gesture_is_valid)(void); + bool (*action_gesture_is_pressed)(void); + void (*gesture_reset)(struct gesture *g); + void (*gesture_process)(struct gesture *g, const struct touchevent *ev); + bool (*gesture_get_event_in_vp)(struct gesture *g, + struct gesture_event *gevt, + const struct viewport *vp); + void (*gesture_vel_reset)(struct gesture_vel *gv); + void (*gesture_vel_process)(struct gesture_vel *gv, + const struct touchevent *ev); + bool (*gesture_vel_get)(struct gesture_vel *gv, int *xvel, int *yvel); #endif bool (*action_userabort)(int timeout); int (*core_set_keyremap)(struct button_mapping* core_keymap, int count); @@ -493,6 +511,9 @@ struct plugin_api { int (*filetype_get_attr)(const char* file); char* (*filetype_get_plugin)(int attr, char *buffer, size_t buffer_len); +#ifdef HAVE_DIRCACHE + void (*dircache_wait)(void); +#endif /* dir */ DIR * (*opendir)(const char *dirname); @@ -652,6 +673,7 @@ struct plugin_api { int (*strncmp)(const char *, const char *, size_t); int (*strcasecmp)(const char *, const char *); int (*strncasecmp)(const char *s1, const char *s2, size_t n); + char* (*strstr)(const char *s1, const char *s2); void* (*memset)(void *dst, int c, size_t length); void* (*memcpy)(void *out, const void *in, size_t n); void* (*memmove)(void *out, const void *in, size_t n); @@ -853,6 +875,7 @@ struct plugin_api { void (*audio_resume)(void); void (*audio_next)(void); void (*audio_prev)(void); + void (*audio_pre_ff_rewind)(void); void (*audio_ff_rewind)(long newtime); struct mp3entry* (*audio_next_track)(void); int (*audio_status)(void); @@ -862,6 +885,7 @@ struct plugin_api { #ifdef PLUGIN_USE_IRAM void (*audio_hard_stop)(void); #endif + void (*add_playbacklog)(struct mp3entry *id3); /* menu */ struct menu_table *(*root_menu_get_options)(int *nb_options); @@ -902,6 +926,7 @@ struct plugin_api { #endif /* power */ + struct battery_tables_t *device_battery_tables; int (*battery_level)(void); bool (*battery_level_safe)(void); int (*battery_time)(void); @@ -913,12 +938,17 @@ struct plugin_api { bool (*charging_state)(void); # endif #endif + /* usb */ bool (*usb_inserted)(void); void (*usb_acknowledge)(long id); #ifdef USB_ENABLE_HID void (*usb_hid_send)(usage_page_t usage_page, int id); #endif +#ifdef USB_ENABLE_AUDIO + bool (*usb_audio_get_playing)(void); +#endif + /* misc */ #if (CONFIG_PLATFORM & PLATFORM_NATIVE) int * (*__errno)(void); @@ -994,37 +1024,9 @@ struct plugin_api { #ifdef HAVE_MULTIVOLUME int (*path_strip_volume)(const char *name, const char **nameptr, bool greedy); #endif + /* new stuff at the end, sort into place next time the API gets incompatible */ - void (*add_playbacklog)(struct mp3entry *id3); - struct battery_tables_t *device_battery_tables; - bool (*yesno_pop_confirm)(const char* text); -#ifdef USB_ENABLE_AUDIO - bool (*usb_audio_get_playing)(void); -#endif -#ifdef HAVE_TOUCHSCREEN - int (*action_get_touch_event)(struct touchevent *ev); - void (*action_gesture_reset)(void); - bool (*action_gesture_get_event_in_vp)(struct gesture_event *gevt, - const struct viewport *vp); - bool (*action_gesture_get_event)(struct gesture_event *gevt); - bool (*action_gesture_is_valid)(void); - bool (*action_gesture_is_pressed)(void); - void (*gesture_reset)(struct gesture *g); - void (*gesture_process)(struct gesture *g, const struct touchevent *ev); - bool (*gesture_get_event_in_vp)(struct gesture *g, - struct gesture_event *gevt, - const struct viewport *vp); - void (*gesture_vel_reset)(struct gesture_vel *gv); - void (*gesture_vel_process)(struct gesture_vel *gv, - const struct touchevent *ev); - bool (*gesture_vel_get)(struct gesture_vel *gv, int *xvel, int *yvel); -#endif - char* (*strstr)(const char *s1, const char *s2); - bool (*sb_set_title_text)(const char* title, enum themable_icons icon, enum screen_type screen); -#ifdef HAVE_DIRCACHE - void (*dircache_wait)(void); -#endif }; /* plugin header */ diff --git a/apps/plugins/lua/include_lua/audio.lua b/apps/plugins/lua/include_lua/audio.lua index 8f343c8486..87fca61fc2 100644 --- a/apps/plugins/lua/include_lua/audio.lua +++ b/apps/plugins/lua/include_lua/audio.lua @@ -31,6 +31,7 @@ rb.audio_pause = function() rb.audio("pause") end rb.audio_resume = function() rb.audio("resume") end rb.audio_next = function() rb.audio("next") end rb.audio_prev = function() rb.audio("prev") end +rb.audio_pre_ff_rewind = function () rb.audio("pre_ff_rewind") end rb.audio_ff_rewind = function (newtime) rb.audio("ff_rewind", newtime) end rb.audio_flush_and_reload_tracks = function() rb.audio("flush_and_reload_tracks") end rb.audio_get_file_pos = function() return rb.audio("get_file_pos") end diff --git a/apps/plugins/lua/rocklib.c b/apps/plugins/lua/rocklib.c index 3a318fcd96..bd9d60959d 100644 --- a/apps/plugins/lua/rocklib.c +++ b/apps/plugins/lua/rocklib.c @@ -410,12 +410,12 @@ RB_WRAP(playlist) RB_WRAP(audio) { enum e_audio {AUDIO_STATUS = 0, AUDIO_PLAY, AUDIO_STOP, AUDIO_PAUSE, - AUDIO_RESUME, AUDIO_NEXT, AUDIO_PREV, AUDIO_FFREWIND, - AUDIO_FLUSHANDRELOADTRACKS, AUDIO_GETPOS, AUDIO_LENGTH, - AUDIO_ELAPSED, AUDIO_ECOUNT}; + AUDIO_RESUME, AUDIO_NEXT, AUDIO_PREV, AUDIO_PREFFREWIND, + AUDIO_FFREWIND, AUDIO_FLUSHANDRELOADTRACKS, AUDIO_GETPOS, + AUDIO_LENGTH, AUDIO_ELAPSED, AUDIO_ECOUNT}; const char *audio_option[] = {"status", "play", "stop", "pause", "resume", "next", - "prev", "ff_rewind", + "prev", "pre_ff_rewind", "ff_rewind", "flush_and_reload_tracks", "get_file_pos", "length", "elapsed", NULL}; @@ -434,6 +434,7 @@ RB_WRAP(audio) if (status == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE)) { /* not perfect but provides a decent compromise */ + rb->audio_pre_ff_rewind(); rb->audio_ff_rewind(elapsed + offset); rb->audio_resume(); } @@ -456,6 +457,9 @@ RB_WRAP(audio) case AUDIO_PREV: rb->audio_prev(); break; + case AUDIO_PREFFREWIND: + rb->audio_pre_ff_rewind(); + break; case AUDIO_FFREWIND: newtime = (long) luaL_checkint(L, 2); rb->audio_ff_rewind(newtime); diff --git a/apps/plugins/lua/rocklib_aux.pl b/apps/plugins/lua/rocklib_aux.pl index 85beb82237..823a699e4d 100755 --- a/apps/plugins/lua/rocklib_aux.pl +++ b/apps/plugins/lua/rocklib_aux.pl @@ -97,7 +97,7 @@ my @forbidden_functions = ('^atoi$', '^__.+$', '^.+_(un)?cached$', '^audio_(status|get_file_pos|flush_and_reload_tracks)$', - '^audio_(ff_rewind|next|prev|play|pause|resume|stop)$', + '^audio_(pre_ff_rewind|ff_rewind|next|prev|play|pause|resume|stop)$', '^playlist_(amount|add|create|start|resume|shuffle)$', '^playlist_(sync|resume_track|remove_all_tracks)$', '^playlist_(insert_track|insert_directory)$', diff --git a/docs/PLUGIN_API b/docs/PLUGIN_API index 330d165982..96c936fda1 100644 --- a/docs/PLUGIN_API +++ b/docs/PLUGIN_API @@ -89,6 +89,10 @@ struct mp3entry* audio_current_track(void) \description \see [S[firmware/export/id3.h]] +void audio_pre_ff_rewind(void) + \group playback control + \description prepare playback for rewinding. Playback will be paused + void audio_ff_rewind(long newtime) \group playback control \param newtime diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 4fa7841b65..30acfd1e3c 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h @@ -61,6 +61,7 @@ size_t audio_buffer_size(void); /* size of the buffer available for allocating memory from the audio buffer using core_*() * returns core_available() if audio buffer is not allocated yet */ size_t audio_buffer_available(void); +void audio_pre_ff_rewind(void); void audio_ff_rewind(long newpos); void audio_flush_and_reload_tracks(void); struct mp3entry* audio_current_track(void);