Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

try to call browse function

work in progress

work in progress

work in progress

+343 -21
+14
apps/tree.c
··· 621 621 /* gets the directory's name and put it into tc.currdir */ 622 622 filename = strrchr(path+1,'/'); 623 623 size_t endpos = filename - path; 624 + printf("%s | %s | %d\n", filename, path, endpos); 624 625 if (filename && endpos < MAX_PATH - 1) 625 626 { 626 627 strmemccpy(tc.currdir, path, endpos + 1); ··· 955 956 #endif 956 957 957 958 default: 959 + // return GO_TO_ROOT; 958 960 if (default_event_handler(button) == SYS_USB_CONNECTED) 959 961 { 960 962 if(*tc.dirfilter > NUM_FILTER_MODES) ··· 1123 1125 tc = backups[backup_count]; 1124 1126 1125 1127 return ret_val; 1128 + } 1129 + 1130 + int rockbox_browse_at(const char* path) 1131 + { 1132 + struct browse_context browse = { 1133 + .dirfilter = SHOW_SUPPORTED, 1134 + .icon = Icon_NOICON, 1135 + .root = path, 1136 + }; 1137 + strcpy(tc.currdir, path); 1138 + 1139 + return rockbox_browse(&browse); 1126 1140 } 1127 1141 1128 1142 static int move_callback(int handle, void* current, void* new)
+1
apps/tree.h
··· 114 114 void set_dirfilter(int l_dirfilter); 115 115 void set_current_file(const char *path); 116 116 int rockbox_browse(struct browse_context *browse); 117 + int rockbox_browse_root(); 117 118 int create_playlist(void); 118 119 void resume_directory(const char *dir); 119 120
+9
crates/server/src/lib.rs
··· 202 202 stream.write_all(response.as_bytes()).unwrap(); 203 203 return; 204 204 } 205 + "/tree_context" => { 206 + let context = rb::browse::tree_get_context(); 207 + let response = format!( 208 + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{}", 209 + serde_json::to_string(&context).unwrap() 210 + ); 211 + stream.write_all(response.as_bytes()).unwrap(); 212 + return; 213 + } 205 214 _ => { 206 215 if path.starts_with("/play?") { 207 216 let params: Vec<_> = path.split('?').collect();
+19 -8
crates/sys/src/browse.rs
··· 1 1 use std::ffi::CString; 2 2 3 - use crate::{AddToPlCallback, BrowseContext, Entry, Mp3Entry, PlaylistInsertCb, Tm, TreeContext}; 3 + use crate::{ 4 + types::tree::{Entry, TreeContext}, 5 + AddToPlCallback, Mp3Entry, PlaylistInsertCb, Tm, 6 + }; 4 7 5 - pub fn rockbox_browse(ctx: *mut BrowseContext) -> i32 { 6 - unsafe { crate::rockbox_browse(ctx) } 8 + pub fn rockbox_browse_at(path: &str) -> i32 { 9 + let path = CString::new(path).unwrap(); 10 + unsafe { crate::rockbox_browse_at(path.as_ptr()) } 11 + } 12 + 13 + pub fn rockbox_browse() -> i32 { 14 + unsafe { crate::rb_rockbox_browse() } 7 15 } 8 16 9 17 pub fn tree_get_context() -> TreeContext { 10 - unsafe { crate::tree_get_context() } 18 + let tc = unsafe { crate::rb_tree_get_context() }; 19 + tc.into() 11 20 } 12 21 13 - pub fn tree_get_entries(ctx: *mut TreeContext) -> Entry { 14 - unsafe { crate::tree_get_entries(ctx) } 22 + pub fn tree_get_entries() -> Entry { 23 + let entry = unsafe { crate::rb_tree_get_entries() }; 24 + entry.into() 15 25 } 16 26 17 - pub fn tree_get_entry_at(ctx: *mut TreeContext, index: i32) -> Entry { 18 - unsafe { crate::tree_get_entry_at(ctx, index) } 27 + pub fn tree_get_entry_at(index: i32) -> Entry { 28 + let entry = unsafe { crate::rb_tree_get_entry_at(index) }; 29 + entry.into() 19 30 } 20 31 21 32 pub fn set_current_file(path: &str) {
+32 -7
crates/sys/src/lib.rs
··· 51 51 }; 52 52 } 53 53 54 + #[macro_export] 55 + macro_rules! convert_ptr_to_vec { 56 + ($ptr:expr, $len:expr) => {{ 57 + if $ptr.is_null() { 58 + Vec::new() 59 + } else { 60 + // Safety: Ensure that the pointer is valid for $len elements, 61 + // and that the memory was allocated in a way that is compatible with Rust's Vec. 62 + unsafe { Vec::from_raw_parts($ptr, $len, $len) } 63 + } 64 + }}; 65 + } 66 + 67 + #[macro_export] 68 + macro_rules! ptr_to_option { 69 + ($ptr:expr) => { 70 + if $ptr.is_null() { 71 + None 72 + } else { 73 + unsafe { Some(*$ptr) } 74 + } 75 + }; 76 + } 77 + 54 78 #[repr(C)] 55 79 #[derive(Debug, Copy, Clone)] 56 80 pub struct Mp3Entry { ··· 224 248 } 225 249 226 250 #[repr(C)] 227 - #[derive(Debug)] 251 + #[derive(Debug, Copy, Clone)] 228 252 pub struct BrowseContext { 229 253 pub dirfilter: c_int, // int dirfilter 230 254 pub flags: c_uint, // unsigned flags ··· 1042 1066 // Playlist control 1043 1067 fn playlist_get_current() -> PlaylistInfo; 1044 1068 fn playlist_get_resume_info(resume_index: *mut c_int) -> c_int; 1045 - fn _get_track_info_from_current_playlist(index: i32) -> PlaylistTrackInfo; 1069 + fn rb_get_track_info_from_current_playlist(index: i32) -> PlaylistTrackInfo; 1046 1070 fn playlist_get_first_index(playlist: *mut PlaylistInfo) -> c_int; 1047 1071 fn playlist_get_display_index() -> c_int; 1048 1072 fn playlist_amount() -> c_int; ··· 1132 1156 fn keyclick_click(rawbutton: c_uchar, action: c_int); 1133 1157 1134 1158 // Browsing 1135 - fn rockbox_browse(browse: *mut BrowseContext) -> c_int; 1136 - fn tree_get_context() -> TreeContext; 1137 - fn tree_get_entries(t: *mut TreeContext) -> Entry; 1138 - fn tree_get_entry_at(t: *mut TreeContext, index: c_int) -> Entry; 1159 + fn rockbox_browse_at(path: *const c_char) -> c_int; 1160 + fn rb_rockbox_browse() -> c_int; 1161 + fn rb_tree_get_context() -> TreeContext; 1162 + fn rb_tree_get_entries() -> Entry; 1163 + fn rb_tree_get_entry_at(index: c_int) -> Entry; 1139 1164 fn set_current_file(path: *const c_char); 1140 1165 fn set_dirfilter(l_dirfilter: c_int); 1141 1166 fn onplay_show_playlist_menu( ··· 1187 1212 fn filetype_get_plugin(); 1188 1213 1189 1214 // Metadata 1190 - fn _get_metadata(fd: i32, trackname: *const c_char) -> Mp3Entry; 1215 + fn rb_get_metadata(fd: i32, trackname: *const c_char) -> Mp3Entry; 1191 1216 fn get_codec_string(codectype: c_int) -> *const c_char; 1192 1217 fn count_mp3_frames( 1193 1218 fd: c_int,
+1 -1
crates/sys/src/metadata.rs
··· 4 4 5 5 pub fn get_metadata(fd: i32, trackname: &str) -> Mp3Entry { 6 6 let trackname = CString::new(trackname).unwrap(); 7 - let id3 = unsafe { crate::_get_metadata(fd, trackname.as_ptr()) }; 7 + let id3 = unsafe { crate::rb_get_metadata(fd, trackname.as_ptr()) }; 8 8 id3.into() 9 9 } 10 10
+1 -1
crates/sys/src/playlist.rs
··· 11 11 } 12 12 13 13 pub fn get_track_info(index: i32) -> PlaylistTrackInfo { 14 - let track_info = unsafe { crate::_get_track_info_from_current_playlist(index) }; 14 + let track_info = unsafe { crate::rb_get_track_info_from_current_playlist(index) }; 15 15 track_info.into() 16 16 } 17 17
+1
crates/sys/src/types/mod.rs
··· 8 8 pub mod playlist_track_info; 9 9 pub mod system_status; 10 10 pub mod user_settings; 11 + pub mod tree; 11 12 12 13 #[derive(Serialize, Deserialize)] 13 14 pub struct RockboxVersion {
+113
crates/sys/src/types/tree.rs
··· 1 + use serde::{Deserialize, Serialize}; 2 + 3 + use crate::{cast_ptr, convert_ptr_to_vec, get_string_from_ptr, ptr_to_option}; 4 + 5 + #[derive(Debug, Serialize, Deserialize)] 6 + pub struct TreeCache { 7 + pub entries_handle: i32, // int entries_handle 8 + pub name_buffer_handle: i32, // int name_buffer_handle 9 + pub max_entries: i32, // int max_entries 10 + pub name_buffer_size: i32, // int name_buffer_size (in bytes) 11 + } 12 + 13 + impl From<crate::TreeCache> for TreeCache { 14 + fn from(cache: crate::TreeCache) -> Self { 15 + Self { 16 + entries_handle: cache.entries_handle, 17 + name_buffer_handle: cache.name_buffer_handle, 18 + max_entries: cache.max_entries, 19 + name_buffer_size: cache.name_buffer_size, 20 + } 21 + } 22 + } 23 + 24 + #[derive(Debug, Serialize, Deserialize)] 25 + pub struct TreeContext { 26 + pub currdir: String, // char currdir[MAX_PATH] 27 + pub dirlevel: i32, // int dirlevel 28 + pub selected_item: i32, // int selected_item 29 + pub selected_item_history: Vec<i32>, // int selected_item_history[MAX_DIR_LEVELS] 30 + pub filesindir: i32, // int filesindir 31 + pub dirsindir: i32, // int dirsindir 32 + pub dirlength: i32, // int dirlength 33 + pub currtable: i32, // int currtable (db use) 34 + pub currextra: i32, // int currextra (db use) 35 + pub sort_dir: i32, // int sort_dir 36 + pub out_of_tree: i32, // int out_of_tree 37 + pub cache: TreeCache, // struct tree_cache cache 38 + pub dirfull: bool, // bool dirfull 39 + pub is_browsing: bool, // bool is_browsing 40 + pub browse: Option<BrowseContext>, // struct browse_context* browse 41 + } 42 + 43 + impl From<crate::TreeContext> for TreeContext { 44 + fn from(context: crate::TreeContext) -> Self { 45 + Self { 46 + currdir: unsafe { 47 + std::ffi::CStr::from_ptr(cast_ptr!(context.currdir.as_ptr())) 48 + .to_string_lossy() 49 + .into_owned() 50 + }, 51 + dirlevel: context.dirlevel, 52 + selected_item: context.selected_item, 53 + selected_item_history: context.selected_item_history.to_vec(), 54 + filesindir: context.filesindir, 55 + dirsindir: context.dirsindir, 56 + dirlength: context.dirlength, 57 + currtable: context.currtable, 58 + currextra: context.currextra, 59 + sort_dir: context.sort_dir, 60 + out_of_tree: context.out_of_tree, 61 + cache: context.cache.into(), 62 + dirfull: context.dirfull, 63 + is_browsing: context.is_browsing, 64 + browse: None, 65 + // browse: ptr_to_option!(context.browse).map(|browse| browse.into()), 66 + } 67 + } 68 + } 69 + 70 + #[derive(Debug, Serialize, Deserialize)] 71 + pub struct BrowseContext { 72 + pub dirfilter: i32, // int dirfilter 73 + pub flags: u32, // unsigned flags 74 + pub title: String, // char* title 75 + // pub icon: ThemableIcons, // enum themable_icons icon 76 + pub root: String, // const char* root 77 + pub selected: String, // const char* selected 78 + pub buf: Vec<i8>, // char* buf 79 + pub bufsize: usize, // size_t bufsize 80 + } 81 + 82 + impl From<crate::BrowseContext> for BrowseContext { 83 + fn from(context: crate::BrowseContext) -> Self { 84 + Self { 85 + dirfilter: context.dirfilter, 86 + flags: context.flags, 87 + title: get_string_from_ptr!(context.title), 88 + root: get_string_from_ptr!(context.root), 89 + selected: get_string_from_ptr!(context.selected), 90 + buf: convert_ptr_to_vec!(context.buf, context.bufsize), 91 + bufsize: context.bufsize, 92 + } 93 + } 94 + } 95 + 96 + #[derive(Debug, Serialize, Deserialize)] 97 + pub struct Entry { 98 + pub name: String, // char* name 99 + pub attr: i32, // int attr (FAT attributes + file type flags) 100 + pub time_write: u32, // unsigned time_write (Last write time) 101 + pub customaction: i32, // int customaction (db use) 102 + } 103 + 104 + impl From<crate::Entry> for Entry { 105 + fn from(entry: crate::Entry) -> Self { 106 + Self { 107 + name: get_string_from_ptr!(entry.name), 108 + attr: entry.attr, 109 + time_write: entry.time_write, 110 + customaction: entry.customaction, 111 + } 112 + } 113 + }
+22 -2
src/main.zig
··· 1 1 const std = @import("std"); 2 2 const playlist = @import("rockbox/playlist.zig"); 3 3 const metadata = @import("rockbox/metadata.zig"); 4 + const tree = @import("rockbox/tree.zig"); 4 5 5 6 extern fn main_c() c_int; 6 7 extern fn parse_args(argc: usize, argv: [*]const [*]const u8) c_int; ··· 27 28 _ = main_c(); 28 29 } 29 30 30 - export fn _get_track_info_from_current_playlist(index: c_int) playlist.PlaylistTrackInfo { 31 + // playlist functions 32 + export fn rb_get_track_info_from_current_playlist(index: c_int) playlist.PlaylistTrackInfo { 31 33 return playlist._get_track_info_from_current_playlist(index); 32 34 } 33 35 34 - export fn _get_metadata(fd: c_int, trackname: [*]const u8) metadata.mp3entry { 36 + // metadata functions 37 + export fn rb_get_metadata(fd: c_int, trackname: [*]const u8) metadata.mp3entry { 35 38 return metadata._get_metadata(fd, trackname); 36 39 } 40 + 41 + // browsing functions 42 + export fn rb_rockbox_browse() c_int { 43 + return tree._rockbox_browse(); 44 + } 45 + 46 + export fn rb_tree_get_context() tree.tree_context { 47 + return tree._tree_get_context(); 48 + } 49 + 50 + export fn rb_tree_get_entries() *tree.entry { 51 + return tree._tree_get_entries(); 52 + } 53 + 54 + export fn rb_tree_get_entry_at(index: c_int) *tree.entry { 55 + return tree._tree_get_entry_at(index); 56 + }
-2
src/rockbox/playlist.zig
··· 1 - const std = @import("std"); 2 - 3 1 const MAX_PATH = 260; 4 2 const PLAYLIST_CONTROL_FILE_SIZE = 256; 5 3
+130
src/rockbox/tree.zig
··· 1 + const std = @import("std"); 2 + 3 + pub const MAX_PATH = 260; 4 + pub const MAX_DIR_LEVELS = 10; 5 + 6 + const themable_icons = enum(c_int) { 7 + NOICON = -2, 8 + Icon_NOICON = -1, 9 + Icon_Audio, 10 + Icon_Folder, 11 + Icon_Playlist, 12 + Icon_Cursor, 13 + Icon_Wps, 14 + Icon_Firmware, 15 + Icon_Font, 16 + Icon_Language, 17 + Icon_Config, 18 + Icon_Plugin, 19 + Icon_Bookmark, 20 + Icon_Preset, 21 + Icon_Queued, 22 + Icon_Moving, 23 + Icon_Keyboard, 24 + Icon_Reverse_Cursor, 25 + Icon_Questionmark, 26 + Icon_Menu_setting, 27 + Icon_Menu_functioncall, 28 + Icon_Submenu, 29 + Icon_Submenu_Entered, 30 + Icon_Recording, 31 + Icon_Voice, 32 + Icon_General_settings_menu, 33 + Icon_System_menu, 34 + Icon_Playback_menu, 35 + Icon_Display_menu, 36 + Icon_Remote_Display_menu, 37 + Icon_Radio_screen, 38 + Icon_file_view_menu, 39 + Icon_EQ, 40 + Icon_Rockbox, 41 + Icon_Last_Themeable, 42 + }; 43 + 44 + pub const browse_context = extern struct { 45 + dirfilter: c_int, 46 + flags: c_uint, // 'unsigned' is translated to 'c_uint' 47 + title: [*c]const u8, // Nullable C string for the title 48 + icon: themable_icons, // Enum 'themable_icons', assumed to be defined elsewhere 49 + root: [*c]const u8, // Const C string for root directory path 50 + selected: [*c]const u8, // Const C string for selected file name 51 + buf: [*c]u8, // Buffer for the selected file 52 + bufsize: usize, // Size of the buffer (translated to 'usize' for portability) 53 + }; 54 + 55 + const tree_cache = extern struct { 56 + entries_handle: c_int, // Handle to the entry cache 57 + name_buffer_handle: c_int, // Handle to the name cache 58 + max_entries: c_int, // Maximum number of entries in the cache 59 + name_buffer_size: c_int, // Size of the name buffer (in bytes) 60 + }; 61 + 62 + pub const tree_context = extern struct { 63 + currdir: [MAX_PATH]u8, // Fixed-size array for the current directory 64 + dirlevel: i32, // int in C is c_int in Zig 65 + selected_item: i32, // Selected file/id3dbitem index 66 + selected_item_history: [MAX_DIR_LEVELS]c_int, // History of selected items, fixed-size array 67 + 68 + dirfilter: ?*c_int, // Nullable pointer to an int for file use 69 + filesindir: i32, // Number of files in the directory cache 70 + dirsindir: i32, // Directory use 71 + dirlength: i32, // Total number of entries in directory 72 + 73 + currtable: i32, 74 + currextra: i32, 75 + 76 + sort_dir: i32, // Directory sort order 77 + out_of_tree: i32, // Shortcut from elsewhere 78 + cache: tree_cache, // Struct tree_cache, defined elsewhere 79 + 80 + dirfull: bool, 81 + is_browsing: bool, 82 + 83 + browse: ?*browse_context, // Pointer to browse_context, nullable 84 + }; 85 + pub const entry = extern struct { 86 + name: ?*c_char, // Pointer to the name (nullable) 87 + attr: c_int, // FAT attributes + file type flags 88 + time_write: c_uint, // Last write time (unsigned) 89 + customaction: c_int, // Custom action (for database use) 90 + }; 91 + 92 + extern fn tree_init() void; 93 + extern fn rockbox_browse(browse: ?*browse_context) c_int; 94 + extern fn rockbox_browse_at(path: [*]const u8) c_int; 95 + extern fn tree_get_context() *tree_context; 96 + extern fn tree_get_entries(t: *tree_context) *entry; 97 + extern fn tree_get_entry_at(t: *tree_context, index: c_int) *entry; 98 + 99 + pub fn _rockbox_browse() c_int { 100 + var browse: browse_context = .{ 101 + .dirfilter = 0, 102 + .flags = 0, 103 + .title = "demo", 104 + .icon = themable_icons.Icon_NOICON, 105 + .root = "/", 106 + .selected = null, 107 + .buf = null, 108 + .bufsize = 0, 109 + }; 110 + return rockbox_browse(&browse); 111 + } 112 + 113 + pub fn _tree_get_context() tree_context { 114 + const ret = rockbox_browse_at("/home"); 115 + std.debug.print("rockbox_browse_root: {}\n", .{ret}); 116 + const tc = tree_get_context(); 117 + const e = tree_get_entries(tc); 118 + std.debug.print("tree_get_context: {}\n{}\n", .{ tc, e }); 119 + return tc.*; 120 + } 121 + 122 + pub fn _tree_get_entries() *entry { 123 + const tc = tree_get_context(); 124 + return tree_get_entries(tc); 125 + } 126 + 127 + pub fn _tree_get_entry_at(index: c_int) *entry { 128 + const tc = tree_get_context(); 129 + return tree_get_entry_at(tc, index); 130 + }