A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 531 lines 15 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005 Peter D'Hoye 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include "plugin.h" 22#include "lib/helper.h" 23#include "lib/grey.h" 24#include "lib/pluginlib_touchscreen.h" 25#include "lib/pluginlib_exit.h" 26#include "lib/pluginlib_actions.h" 27 28/* this set the context to use with PLA */ 29static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; 30 31 32#define FPS_QUIT PLA_EXIT 33#define FPS_QUIT2 PLA_CANCEL 34 35#define DURATION (2*HZ) /* longer duration gives more precise results */ 36 37/* Screen logging */ 38#define MIN_LINE_LEN 32 39static int line; 40static char *lines = NULL; 41 42static int max_line; 43static int max_line_len; 44 45#ifdef HAVE_REMOTE_LCD 46static char *remote_lines = NULL; /* Not implemented */ 47static int remote_line; 48static int remote_max_line; 49static int remote_max_line_len; 50#endif 51 52size_t plugin_buf_len; 53void* plugin_buf; 54 55#define PREP_LOG_BUF(BUF, BUF_SZ) { \ 56 if ((int)plugin_buf_len > BUF_SZ){ \ 57 BUF = plugin_buf; \ 58 rb->memset(BUF, 0, BUF_SZ); \ 59 plugin_buf += BUF_SZ; \ 60 plugin_buf_len -= BUF_SZ; \ 61 } \ 62} \ 63 64static void log_init(void) 65{ 66 int h; 67 68 int w = rb->lcd_getstringsize("A", NULL, &h); 69 70 max_line_len = MAX(MIN_LINE_LEN, (LCD_WIDTH / w) * 2); 71 max_line = LCD_HEIGHT / h; 72 73 int linebuf_sz = ((max_line_len + 1) * max_line + 1) + 1; 74 75 PREP_LOG_BUF(lines, linebuf_sz); 76 77 line = 0; 78 rb->lcd_clear_display(); 79 rb->lcd_update(); 80 81#ifdef HAVE_REMOTE_LCD 82 w = rb->lcd_remote_getstringsize("A", NULL, &h); 83 remote_max_line_len = MAX(MIN_LINE_LEN, (LCD_REMOTE_WIDTH / w) * 2); 84 remote_max_line = LCD_REMOTE_HEIGHT / h; 85 86 linebuf_sz = ((remote_max_line_len + 1) * remote_max_line + 1) + 1; 87 /* PREP_LOG_BUF(remote_lines, linebuf_sz); needs testing on real hardware */ 88 89 remote_line = 0; 90 rb->lcd_remote_clear_display(); 91 rb->lcd_remote_update(); 92#endif 93} 94 95static void show_log(void) 96{ 97 if (lines) 98 { 99 for (int ln = 0; ln <= line; ln++) 100 { 101 char *this_line = lines + (ln * max_line_len); 102 rb->lcd_puts(0, ln, this_line); 103 } 104 rb->lcd_update(); 105 } 106#ifdef HAVE_REMOTE_LCD 107 if (remote_lines) 108 { 109 for (int ln = 0; ln <= remote_line; ln++) 110 { 111 char *this_line = remote_lines + (ln * remote_max_line_len); 112 rb->lcd_remote_puts(0, ln, this_line); 113 } 114 rb->lcd_remote_update(); 115 } 116#endif 117} 118 119static void log_text(char *text) 120{ 121 if (lines) 122 { 123 char *this_line = lines + (line * max_line_len); 124 rb->strlcpy(this_line, text, max_line_len); 125 this_line[max_line_len] = '\0'; 126 } 127 else 128 { 129 rb->lcd_puts(0, line, text); 130 rb->lcd_update(); 131 } 132 133#ifdef HAVE_REMOTE_LCD 134 135 if (remote_lines) 136 { 137 char *this_line = remote_lines + (remote_line * remote_max_line_len); 138 rb->strlcpy(this_line, text, remote_max_line_len); 139 this_line[remote_max_line_len] = '\0'; 140 } 141 else 142 { 143 rb->lcd_remote_puts(0, remote_line, text); 144 rb->lcd_remote_update(); 145 } 146 147#endif 148 149 show_log(); 150 151 if (++line >= max_line) 152 { 153 line = 0; 154 } 155 156#ifdef HAVE_REMOTE_LCD 157 if (++remote_line >= remote_max_line) 158 { 159 remote_line = 0; 160 } 161#endif 162 163} 164 165static int calc_tenth_fps(int framecount, long ticks) 166{ 167 return (10*HZ) * framecount / ticks; 168} 169 170static void time_main_update(void) 171{ 172 char str[32]; /* text buffer */ 173 long time_start; /* start tickcount */ 174 long time_end; /* end tickcount */ 175 int frame_count; 176 int fps; 177 178 const int part14_x = LCD_WIDTH/4; /* x-offset for 1/4 update test */ 179 const int part14_w = LCD_WIDTH/2; /* x-size for 1/4 update test */ 180 const int part14_y = LCD_HEIGHT/4; /* y-offset for 1/4 update test */ 181 const int part14_h = LCD_HEIGHT/2; /* y-size for 1/4 update test */ 182 183 log_text("Main LCD Update"); 184 rb->sleep(HZ / 2); 185 186 /* Test 1: full LCD update */ 187 frame_count = 0; 188 rb->sleep(0); /* sync to tick */ 189 time_start = *rb->current_tick; 190 while((time_end = *rb->current_tick) - time_start < DURATION) 191 { 192 rb->lcd_update(); 193 frame_count++; 194 } 195 fps = calc_tenth_fps(frame_count, time_end - time_start); 196 rb->snprintf(str, sizeof(str), "1/1: %d.%d fps", fps / 10, fps % 10); 197 log_text(str); 198 199 /* Test 2: quarter LCD update */ 200 frame_count = 0; 201 rb->sleep(0); /* sync to tick */ 202 time_start = *rb->current_tick; 203 while((time_end = *rb->current_tick) - time_start < DURATION) 204 { 205 rb->lcd_update_rect(part14_x, part14_y, part14_w, part14_h); 206 frame_count++; 207 } 208 fps = calc_tenth_fps(frame_count, time_end - time_start); 209 rb->snprintf(str, sizeof(str), "1/4: %d.%d fps", fps / 10, fps % 10); 210 log_text(str); 211} 212 213#if defined(HAVE_LCD_COLOR) && (MEMORYSIZE > 2) 214 215#if LCD_WIDTH >= LCD_HEIGHT 216#define YUV_WIDTH LCD_WIDTH 217#define YUV_HEIGHT LCD_HEIGHT 218#else /* Assume the screen is rotated on portrait LCDs */ 219#define YUV_WIDTH LCD_HEIGHT 220#define YUV_HEIGHT LCD_WIDTH 221#endif 222 223static unsigned char ydata[YUV_HEIGHT][YUV_WIDTH]; 224static unsigned char udata[YUV_HEIGHT/2][YUV_WIDTH/2]; 225static unsigned char vdata[YUV_HEIGHT/2][YUV_WIDTH/2]; 226 227static unsigned char * const yuvbuf[3] = { 228 (void*)ydata, 229 (void*)udata, 230 (void*)vdata 231}; 232 233static void make_gradient_rect(int width, int height) 234{ 235 unsigned char vline[YUV_WIDTH/2]; 236 int x, y; 237 238 width /= 2; 239 height /= 2; 240 241 for (x = 0; x < width; x++) 242 vline[x] = (x << 8) / width; 243 for (y = 0; y < height; y++) 244 { 245 rb->memset(udata[y], (y << 8) / height, width); 246 rb->memcpy(vdata[y], vline, width); 247 } 248} 249 250static void time_main_yuv(void) 251{ 252 char str[32]; /* text buffer */ 253 long time_start; /* start tickcount */ 254 long time_end; /* end tickcount */ 255 int frame_count; 256 int fps; 257 258 const int part14_x = YUV_WIDTH/4; /* x-offset for 1/4 update test */ 259 const int part14_w = YUV_WIDTH/2; /* x-size for 1/4 update test */ 260 const int part14_y = YUV_HEIGHT/4; /* y-offset for 1/4 update test */ 261 const int part14_h = YUV_HEIGHT/2; /* y-size for 1/4 update test */ 262 263 log_text("Main LCD YUV"); 264 rb->sleep(HZ / 2); 265 266 rb->memset(ydata, 128, sizeof(ydata)); /* medium grey */ 267 268 /* Test 1: full LCD update */ 269 make_gradient_rect(YUV_WIDTH, YUV_HEIGHT); 270 271 frame_count = 0; 272 rb->sleep(0); /* sync to tick */ 273 time_start = *rb->current_tick; 274 while((time_end = *rb->current_tick) - time_start < DURATION) 275 { 276 rb->lcd_blit_yuv(yuvbuf, 0, 0, YUV_WIDTH, 277 0, 0, YUV_WIDTH, YUV_HEIGHT); 278 frame_count++; 279 } 280 fps = calc_tenth_fps(frame_count, time_end - time_start); 281 rb->snprintf(str, sizeof(str), "1/1: %d.%d fps", fps / 10, fps % 10); 282 log_text(str); 283 284 /* Test 2: quarter LCD update */ 285 make_gradient_rect(YUV_WIDTH/2, YUV_HEIGHT/2); 286 287 frame_count = 0; 288 rb->sleep(0); /* sync to tick */ 289 time_start = *rb->current_tick; 290 while((time_end = *rb->current_tick) - time_start < DURATION) 291 { 292 rb->lcd_blit_yuv(yuvbuf, 0, 0, YUV_WIDTH, 293 part14_x, part14_y, part14_w, part14_h); 294 frame_count++; 295 } 296 fps = calc_tenth_fps(frame_count, time_end - time_start); 297 rb->snprintf(str, sizeof(str), "1/4: %d.%d fps", fps / 10, fps % 10); 298 log_text(str); 299} 300#endif 301 302#ifdef HAVE_REMOTE_LCD 303static void time_remote_update(void) 304{ 305 char str[32]; /* text buffer */ 306 long time_start; /* start tickcount */ 307 long time_end; /* end tickcount */ 308 int frame_count; 309 int fps; 310 311 const int part14_x = LCD_REMOTE_WIDTH/4; /* x-offset for 1/4 update test */ 312 const int part14_w = LCD_REMOTE_WIDTH/2; /* x-size for 1/4 update test */ 313 const int part14_y = LCD_REMOTE_HEIGHT/4; /* y-offset for 1/4 update test */ 314 const int part14_h = LCD_REMOTE_HEIGHT/2; /* y-size for 1/4 update test */ 315 316 log_text("Remote LCD Update"); 317 rb->sleep(HZ / 2); 318 319 /* Test 1: full LCD update */ 320 frame_count = 0; 321 rb->sleep(0); /* sync to tick */ 322 time_start = *rb->current_tick; 323 while((time_end = *rb->current_tick) - time_start < DURATION) 324 { 325 rb->lcd_remote_update(); 326 frame_count++; 327 } 328 fps = calc_tenth_fps(frame_count, time_end - time_start); 329 rb->snprintf(str, sizeof(str), "1/1: %d.%d fps", fps / 10, fps % 10); 330 log_text(str); 331 332 /* Test 2: quarter LCD update */ 333 frame_count = 0; 334 rb->sleep(0); /* sync to tick */ 335 time_start = *rb->current_tick; 336 while((time_end = *rb->current_tick) - time_start < DURATION) 337 { 338 rb->lcd_remote_update_rect(part14_x, part14_y, part14_w, part14_h); 339 frame_count++; 340 } 341 fps = calc_tenth_fps(frame_count, time_end - time_start); 342 rb->snprintf(str, sizeof(str), "1/4: %d.%d fps", fps / 10, fps % 10); 343 log_text(str); 344} 345#endif 346 347#if LCD_DEPTH < 4 348 349GREY_INFO_STRUCT_IRAM 350static unsigned char greydata[LCD_HEIGHT][LCD_WIDTH]; 351 352static void make_grey_rect(int width, int height) 353{ 354 unsigned char vline[LCD_WIDTH]; 355 int x, y; 356 357 for (x = 0; x < width; x++) 358 vline[x] = (x << 8) / width; 359 for (y = 0; y < height; y++) 360 rb->memcpy(greydata[y], vline, width); 361} 362 363static void time_greyscale(void) 364{ 365 char str[32]; /* text buffer */ 366 long time_start; /* start tickcount */ 367 long time_end; /* end tickcount */ 368 long time_1, time_2; 369 int frames_1, frames_2; 370 int fps, load; 371 size_t gbuf_size = plugin_buf_len; 372 unsigned char *gbuf = (unsigned char *) plugin_buf; 373 374#if NUM_CORES > 1 375 int i; 376 for (i = 0; i < NUM_CORES; i++) 377 { 378 rb->snprintf(str, sizeof(str), "Greyscale (%s)", 379 (i > 0) ? "COP" : "CPU"); 380 log_text(str); 381#else 382 const int i = 0; 383 log_text("Greyscale library"); 384 rb->sleep(HZ / 2); 385 386 { 387#endif 388 389 if (!grey_init(gbuf, gbuf_size, (i > 0) ? GREY_ON_COP : 0, 390 LCD_WIDTH, LCD_HEIGHT, NULL)) 391 { 392 log_text("greylib: out of memory."); 393 return; 394 } 395 make_grey_rect(LCD_WIDTH, LCD_HEIGHT); 396 397 /* Test 1 - greyscale overlay not yet enabled */ 398 frames_1 = 0; 399 rb->sleep(0); /* sync to tick */ 400 time_start = *rb->current_tick; 401 while((time_end = *rb->current_tick) - time_start < DURATION) 402 { 403 grey_ub_gray_bitmap(greydata[0], 0, 0, LCD_WIDTH, LCD_HEIGHT); 404 frames_1++; 405 } 406 time_1 = time_end - time_start; 407 408 /* Test 2 - greyscale overlay enabled */ 409 grey_show(true); 410 frames_2 = 0; 411 rb->sleep(0); /* sync to tick */ 412 time_start = *rb->current_tick; 413 while((time_end = *rb->current_tick) - time_start < DURATION) 414 { 415 grey_ub_gray_bitmap(greydata[0], 0, 0, LCD_WIDTH, LCD_HEIGHT); 416 frames_2++; 417 } 418 time_2 = time_end - time_start; 419 420 grey_release(); 421 fps = calc_tenth_fps(frames_2, time_2); 422 load = 100 - (100 * frames_2 * time_1) / (frames_1 * time_2); 423 rb->snprintf(str, sizeof(str), "1/1: %d.%d fps", fps / 10, fps % 10); 424 log_text(str); 425 426 if (load > 0 && load < 100) 427 { 428 rb->snprintf(str, sizeof(str), "CPU load: %d%%", load); 429 log_text(str); 430 } 431 else 432 log_text("CPU load err (boost?)"); 433 } 434} 435#endif 436 437void plugin_quit(void) 438{ 439#ifdef HAVE_TOUCHSCREEN 440 static struct touchbutton button[] = {{ 441 .action = ACTION_STD_OK, 442 .title = "OK", 443 /* .vp runtime initialized, rest false/NULL */ 444 }}; 445 struct viewport *vp = &button[0].vp; 446 struct screen *lcd = rb->screens[SCREEN_MAIN]; 447 rb->viewport_set_defaults(vp, SCREEN_MAIN); 448 const int border = 10; 449 const int height = 50; 450 451 lcd->set_viewport(vp); 452 /* button matches the bottom center in the grid */ 453 vp->x = lcd->lcdwidth/3; 454 vp->width = lcd->lcdwidth/3; 455 vp->height = height; 456 vp->y = lcd->lcdheight - height - border; 457 458 touchbutton_draw(button, ARRAYLEN(button)); 459 lcd->update_viewport(); 460 if (rb->touchscreen_get_mode() == TOUCHSCREEN_POINT) 461 { 462 while(touchbutton_get(button, ARRAYLEN(button)) != ACTION_STD_OK); 463 } 464 else 465#endif 466 while (1) 467 { 468 int btn = pluginlib_getaction(TIMEOUT_BLOCK, plugin_contexts, 469 ARRAYLEN(plugin_contexts)); 470 exit_on_usb(btn); 471 if ((btn == FPS_QUIT) || (btn == FPS_QUIT2)) 472 break; 473 } 474} 475 476/* plugin entry point */ 477enum plugin_status plugin_start(const void* parameter) 478{ 479#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 480 char str[32]; 481 int cpu_freq; 482#endif 483 484 /* standard stuff */ 485 (void)parameter; 486 487#ifdef HAVE_TOUCHSCREEN 488 rb->touchscreen_set_mode(rb->global_settings->touch_mode); 489#endif 490 491 /* Get the plugin buffer for the log and greylib */ 492 plugin_buf = (unsigned char *)rb->plugin_get_buffer(&plugin_buf_len); 493 494 log_init(); 495#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 496 cpu_freq = *rb->cpu_frequency; /* remember CPU frequency */ 497#endif 498 499 backlight_ignore_timeout(); 500 501 time_main_update(); 502 rb->sleep(HZ* 5); 503 504#if defined(HAVE_LCD_COLOR) && (MEMORYSIZE > 2) 505 time_main_yuv(); 506#endif 507#if LCD_DEPTH < 4 508 time_greyscale(); 509#endif 510#ifdef HAVE_REMOTE_LCD 511 time_remote_update(); 512#endif 513 514#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 515 if (*rb->cpu_frequency != cpu_freq) 516 rb->snprintf(str, sizeof(str), "CPU clock changed!"); 517 else 518 rb->snprintf(str, sizeof(str), "CPU: %d MHz", 519 (cpu_freq + 500000) / 1000000); 520 log_text(str); 521#endif 522 523 show_log(); 524 525 backlight_use_settings(); 526 527 /* wait until user closes plugin */ 528 plugin_quit(); 529 530 return PLUGIN_OK; 531}