/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2010 Jonathan Gordon * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "config.h" #include #include #include #include "system.h" #include "settings.h" #include "radio.h" #include "buffering.h" #include "playback.h" /* bufopen_user_data */ #include "file.h" #include "kernel.h" #include "string-extra.h" #include "pathfuncs.h" #include "core_alloc.h" #define MAX_RADIOART_IMAGES 10 struct radioart { int handle; long last_tick; struct dim dim; char name[MAX_FMPRESET_LEN+1]; }; static char* buf; static struct radioart radioart[MAX_RADIOART_IMAGES]; static int find_oldest_image_index(void) { unsigned i; long oldest_tick = current_tick; int oldest_idx = -1; for(i = 0; i < ARRAYLEN(radioart); i++) { struct radioart *ra = &radioart[i]; /* last_tick is only valid if it's actually loaded, i.e. valid handle */ if (ra->handle >= 0 && TIME_BEFORE(ra->last_tick, oldest_tick)) { oldest_tick = ra->last_tick; oldest_idx = i; } } return oldest_idx; } static int load_radioart_image(struct radioart *ra, const char* preset_name, struct dim *dim) { char path[MAX_PATH]; struct bufopen_bitmap_data user_data; #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(false); #endif snprintf(path, sizeof(path), FMPRESET_PATH "/%s.bmp",preset_name); if (!file_exists(path)) snprintf(path, sizeof(path), FMPRESET_PATH "/%s.jpg",preset_name); if (!file_exists(path)) { #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(true); #endif return -1; } strlcpy(ra->name, preset_name, MAX_FMPRESET_LEN+1); ra->dim.height = dim->height; ra->dim.width = dim->width; ra->last_tick = current_tick; user_data.embedded_albumart = NULL; user_data.dim = &ra->dim; ra->handle = bufopen(path, 0, TYPE_BITMAP, &user_data); if (ra->handle == ERR_BUFFER_FULL || ra->handle == ERR_BITMAP_TOO_LARGE) { int i = find_oldest_image_index(); if (i != -1) { bufclose(radioart[i].handle); ra->handle = bufopen(path, 0, TYPE_BITMAP, &user_data); } } #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(true); #endif return ra->handle; } int radio_get_art_hid(struct dim *requested_dim) { int preset = radio_current_preset(); int free_idx = -1; const char* preset_name; if (!buf || radio_scan_mode() || preset < 0) return -1; preset_name = radio_get_preset_name(preset); for (int i=0; iwidth && radioart[i].dim.height == requested_dim->height) { radioart[i].last_tick = current_tick; return radioart[i].handle; } } if (free_idx >= 0) { return load_radioart_image(&radioart[free_idx], preset_name, requested_dim); } else { int i = find_oldest_image_index(); if (i != -1) { bufclose(radioart[i].handle); return load_radioart_image(&radioart[i], preset_name, requested_dim); } } return -1; } static void buffer_reset_handler(unsigned short id, void *data, void *user_data) { buf = NULL; for(int i=0;i= 0) bufclose(radioart[i].handle); radioart[i].handle = -1; radioart[i].name[0] = '\0'; } (void)id; (void)data; (void)user_data; } static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) { (void)start; (void)old_size; ssize_t old_size_s = old_size; size_t size_hint = (hints & BUFLIB_SHRINK_SIZE_MASK); ssize_t wanted_size = old_size_s - size_hint; if (wanted_size <= 0) { core_free(handle); buffering_reset(NULL, 0); } else { if (hints & BUFLIB_SHRINK_POS_FRONT) start += size_hint; buffering_reset(start, wanted_size); core_shrink(handle, start, wanted_size); buf = start; /* one-shot */ add_event_ex(BUFFER_EVENT_BUFFER_RESET, true, buffer_reset_handler, NULL); } return BUFLIB_CB_OK; } static struct buflib_callbacks radioart_ops = { .shrink_callback = shrink_callback, }; void radioart_init(bool entering_screen) { if (entering_screen) { /* grab control over buffering */ size_t bufsize; int handle = core_alloc_maximum("radioart", &bufsize, &radioart_ops); buffering_reset(core_get_data(handle), bufsize); buf = core_get_data(handle); /* one-shot */ add_event_ex(BUFFER_EVENT_BUFFER_RESET, true, buffer_reset_handler, NULL); } else /* init at startup */ { for(int i=0;i