A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1#include "plugin.h"
2#include "lib/helper.h"
3#include "lib/configfile.h"
4
5#include "mpegplayer.h"
6#include "mpeg_settings.h"
7
8struct mpeg_settings settings;
9
10#define THUMB_DELAY (75*HZ/100)
11
12/* button definitions */
13#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
14 (CONFIG_KEYPAD == IRIVER_H300_PAD)
15#define MPEG_START_TIME_SELECT BUTTON_ON
16#define MPEG_START_TIME_LEFT BUTTON_LEFT
17#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
18#define MPEG_START_TIME_UP BUTTON_UP
19#define MPEG_START_TIME_DOWN BUTTON_DOWN
20#define MPEG_START_TIME_EXIT BUTTON_OFF
21
22#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
23#define MPEG_START_TIME_SELECT BUTTON_PLAY
24#define MPEG_START_TIME_LEFT BUTTON_LEFT
25#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
26#define MPEG_START_TIME_UP BUTTON_UP
27#define MPEG_START_TIME_DOWN BUTTON_DOWN
28#define MPEG_START_TIME_EXIT BUTTON_POWER
29
30#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
31 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
32 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
33#define MPEG_START_TIME_SELECT BUTTON_SELECT
34#define MPEG_START_TIME_LEFT BUTTON_LEFT
35#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
36#define MPEG_START_TIME_UP BUTTON_SCROLL_FWD
37#define MPEG_START_TIME_DOWN BUTTON_SCROLL_BACK
38#define MPEG_START_TIME_EXIT BUTTON_MENU
39
40#elif CONFIG_KEYPAD == GIGABEAT_PAD
41#define MPEG_START_TIME_SELECT BUTTON_SELECT
42#define MPEG_START_TIME_LEFT BUTTON_LEFT
43#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
44#define MPEG_START_TIME_UP BUTTON_UP
45#define MPEG_START_TIME_DOWN BUTTON_DOWN
46#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
47#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
48#define MPEG_START_TIME_EXIT BUTTON_POWER
49
50#define MPEG_START_TIME_RC_SELECT (BUTTON_RC_PLAY | BUTTON_REL)
51#define MPEG_START_TIME_RC_LEFT BUTTON_RC_REW
52#define MPEG_START_TIME_RC_RIGHT BUTTON_RC_FF
53#define MPEG_START_TIME_RC_UP BUTTON_RC_VOL_UP
54#define MPEG_START_TIME_RC_DOWN BUTTON_RC_VOL_DOWN
55#define MPEG_START_TIME_RC_EXIT (BUTTON_RC_PLAY | BUTTON_REPEAT)
56
57#elif CONFIG_KEYPAD == GIGABEAT_S_PAD
58#define MPEG_START_TIME_SELECT BUTTON_SELECT
59#define MPEG_START_TIME_LEFT BUTTON_LEFT
60#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
61#define MPEG_START_TIME_UP BUTTON_UP
62#define MPEG_START_TIME_DOWN BUTTON_DOWN
63#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
64#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
65#define MPEG_START_TIME_EXIT BUTTON_POWER
66
67#define MPEG_START_TIME_RC_SELECT (BUTTON_RC_PLAY | BUTTON_REL)
68#define MPEG_START_TIME_RC_LEFT BUTTON_RC_REW
69#define MPEG_START_TIME_RC_RIGHT BUTTON_RC_FF
70#define MPEG_START_TIME_RC_UP BUTTON_RC_VOL_UP
71#define MPEG_START_TIME_RC_DOWN BUTTON_RC_VOL_DOWN
72#define MPEG_START_TIME_RC_EXIT (BUTTON_RC_PLAY | BUTTON_REPEAT)
73
74#elif CONFIG_KEYPAD == IRIVER_H10_PAD
75#define MPEG_START_TIME_SELECT BUTTON_PLAY
76#define MPEG_START_TIME_LEFT BUTTON_LEFT
77#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
78#define MPEG_START_TIME_UP BUTTON_SCROLL_UP
79#define MPEG_START_TIME_DOWN BUTTON_SCROLL_DOWN
80#define MPEG_START_TIME_EXIT BUTTON_POWER
81
82#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
83#define MPEG_START_TIME_SELECT BUTTON_SELECT
84#define MPEG_START_TIME_LEFT BUTTON_LEFT
85#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
86#define MPEG_START_TIME_UP BUTTON_UP
87#define MPEG_START_TIME_DOWN BUTTON_DOWN
88#define MPEG_START_TIME_LEFT2 BUTTON_SCROLL_BACK
89#define MPEG_START_TIME_RIGHT2 BUTTON_SCROLL_FWD
90#define MPEG_START_TIME_EXIT BUTTON_POWER
91
92#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
93#define MPEG_START_TIME_SELECT BUTTON_SELECT
94#define MPEG_START_TIME_LEFT BUTTON_LEFT
95#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
96#define MPEG_START_TIME_UP BUTTON_UP
97#define MPEG_START_TIME_DOWN BUTTON_DOWN
98#define MPEG_START_TIME_LEFT2 BUTTON_SCROLL_BACK
99#define MPEG_START_TIME_RIGHT2 BUTTON_SCROLL_FWD
100#define MPEG_START_TIME_EXIT (BUTTON_HOME|BUTTON_REPEAT)
101
102#elif (CONFIG_KEYPAD == SANSA_C200_PAD) || \
103(CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
104(CONFIG_KEYPAD == SANSA_M200_PAD)
105#define MPEG_START_TIME_SELECT BUTTON_SELECT
106#define MPEG_START_TIME_LEFT BUTTON_LEFT
107#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
108#define MPEG_START_TIME_UP BUTTON_UP
109#define MPEG_START_TIME_DOWN BUTTON_DOWN
110#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
111#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
112#define MPEG_START_TIME_EXIT BUTTON_POWER
113
114#elif CONFIG_KEYPAD == MROBE500_PAD
115#define MPEG_START_TIME_SELECT BUTTON_RC_HEART
116#define MPEG_START_TIME_LEFT BUTTON_LEFT
117#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
118#define MPEG_START_TIME_UP BUTTON_RC_PLAY
119#define MPEG_START_TIME_DOWN BUTTON_RC_DOWN
120#define MPEG_START_TIME_LEFT2 BUTTON_RC_VOL_UP
121#define MPEG_START_TIME_RIGHT2 BUTTON_RC_VOL_DOWN
122#define MPEG_START_TIME_EXIT BUTTON_POWER
123
124#elif CONFIG_KEYPAD == MROBE100_PAD
125#define MPEG_START_TIME_SELECT BUTTON_SELECT
126#define MPEG_START_TIME_LEFT BUTTON_LEFT
127#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
128#define MPEG_START_TIME_UP BUTTON_UP
129#define MPEG_START_TIME_DOWN BUTTON_DOWN
130#define MPEG_START_TIME_LEFT2 BUTTON_PLAY
131#define MPEG_START_TIME_RIGHT2 BUTTON_MENU
132#define MPEG_START_TIME_EXIT BUTTON_POWER
133
134#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
135#define MPEG_START_TIME_SELECT BUTTON_RC_PLAY
136#define MPEG_START_TIME_LEFT BUTTON_RC_REW
137#define MPEG_START_TIME_RIGHT BUTTON_RC_FF
138#define MPEG_START_TIME_UP BUTTON_RC_VOL_UP
139#define MPEG_START_TIME_DOWN BUTTON_RC_VOL_DOWN
140#define MPEG_START_TIME_EXIT BUTTON_RC_REC
141
142#elif CONFIG_KEYPAD == COWON_D2_PAD
143#define MPEG_START_TIME_EXIT BUTTON_POWER
144
145#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
146#define MPEG_START_TIME_SELECT BUTTON_SELECT
147#define MPEG_START_TIME_LEFT BUTTON_LEFT
148#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
149#define MPEG_START_TIME_UP BUTTON_UP
150#define MPEG_START_TIME_DOWN BUTTON_DOWN
151#define MPEG_START_TIME_LEFT2 BUTTON_PLAY
152#define MPEG_START_TIME_RIGHT2 BUTTON_MENU
153#define MPEG_START_TIME_EXIT BUTTON_BACK
154
155#elif (CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD)
156#define MPEG_START_TIME_SELECT (BUTTON_PLAY|BUTTON_REL)
157#define MPEG_START_TIME_LEFT BUTTON_BACK
158#define MPEG_START_TIME_RIGHT BUTTON_MENU
159#define MPEG_START_TIME_UP BUTTON_UP
160#define MPEG_START_TIME_DOWN BUTTON_DOWN
161#define MPEG_START_TIME_EXIT (BUTTON_PLAY|BUTTON_REPEAT)
162
163#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
164#define MPEG_START_TIME_SELECT BUTTON_SELECT
165#define MPEG_START_TIME_LEFT BUTTON_LEFT
166#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
167#define MPEG_START_TIME_UP BUTTON_UP
168#define MPEG_START_TIME_DOWN BUTTON_DOWN
169#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
170#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
171#define MPEG_START_TIME_EXIT BUTTON_POWER
172
173#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
174#define MPEG_START_TIME_SELECT BUTTON_PLAY
175#define MPEG_START_TIME_LEFT BUTTON_LEFT
176#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
177#define MPEG_START_TIME_UP BUTTON_UP
178#define MPEG_START_TIME_DOWN BUTTON_DOWN
179#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
180#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
181#define MPEG_START_TIME_EXIT BUTTON_POWER
182
183#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
184#define MPEG_START_TIME_SELECT BUTTON_PLAY
185#define MPEG_START_TIME_LEFT BUTTON_PREV
186#define MPEG_START_TIME_RIGHT BUTTON_NEXT
187#define MPEG_START_TIME_UP BUTTON_UP
188#define MPEG_START_TIME_DOWN BUTTON_DOWN
189#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
190#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
191#define MPEG_START_TIME_EXIT BUTTON_POWER
192
193#elif CONFIG_KEYPAD == ONDAVX747_PAD
194#define MPEG_START_TIME_EXIT BUTTON_POWER
195
196#elif CONFIG_KEYPAD == ONDAVX777_PAD
197#define MPEG_START_TIME_EXIT BUTTON_POWER
198
199#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \
200 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
201#define MPEG_START_TIME_SELECT BUTTON_PLAY
202#define MPEG_START_TIME_LEFT BUTTON_LEFT
203#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
204#define MPEG_START_TIME_UP BUTTON_UP
205#define MPEG_START_TIME_DOWN BUTTON_DOWN
206#define MPEG_START_TIME_EXIT BUTTON_REW
207
208#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
209#define MPEG_START_TIME_SELECT BUTTON_PLAY
210#define MPEG_START_TIME_LEFT BUTTON_PREV
211#define MPEG_START_TIME_RIGHT BUTTON_NEXT
212#define MPEG_START_TIME_UP BUTTON_UP
213#define MPEG_START_TIME_DOWN BUTTON_DOWN
214#define MPEG_START_TIME_LEFT2 BUTTON_OK
215#define MPEG_START_TIME_RIGHT2 BUTTON_CANCEL
216#define MPEG_START_TIME_EXIT BUTTON_REC
217
218#elif CONFIG_KEYPAD == MPIO_HD200_PAD
219#define MPEG_START_TIME_SELECT BUTTON_FUNC
220#define MPEG_START_TIME_LEFT BUTTON_REW
221#define MPEG_START_TIME_RIGHT BUTTON_FF
222#define MPEG_START_TIME_UP BUTTON_VOL_UP
223#define MPEG_START_TIME_DOWN BUTTON_VOL_DOWN
224#define MPEG_START_TIME_EXIT BUTTON_REC
225
226#elif CONFIG_KEYPAD == MPIO_HD300_PAD
227#define MPEG_START_TIME_SELECT BUTTON_ENTER
228#define MPEG_START_TIME_LEFT BUTTON_REW
229#define MPEG_START_TIME_RIGHT BUTTON_FF
230#define MPEG_START_TIME_UP BUTTON_UP
231#define MPEG_START_TIME_DOWN BUTTON_DOWN
232#define MPEG_START_TIME_EXIT BUTTON_REC
233
234#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
235#define MPEG_START_TIME_SELECT BUTTON_SELECT
236#define MPEG_START_TIME_LEFT BUTTON_LEFT
237#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
238#define MPEG_START_TIME_UP BUTTON_UP
239#define MPEG_START_TIME_DOWN BUTTON_DOWN
240#define MPEG_START_TIME_EXIT BUTTON_POWER
241
242#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
243#define MPEG_START_TIME_SELECT BUTTON_SELECT
244#define MPEG_START_TIME_LEFT BUTTON_LEFT
245#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
246#define MPEG_START_TIME_UP BUTTON_UP
247#define MPEG_START_TIME_DOWN BUTTON_DOWN
248#define MPEG_START_TIME_EXIT BUTTON_POWER
249
250#elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
251#define MPEG_START_TIME_SELECT BUTTON_SELECT
252#define MPEG_START_TIME_LEFT BUTTON_LEFT
253#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
254#define MPEG_START_TIME_UP BUTTON_UP
255#define MPEG_START_TIME_DOWN BUTTON_DOWN
256#define MPEG_START_TIME_EXIT BUTTON_BACK
257
258#elif (CONFIG_KEYPAD == HM60X_PAD) || (CONFIG_KEYPAD == HM801_PAD)
259#define MPEG_START_TIME_SELECT BUTTON_SELECT
260#define MPEG_START_TIME_LEFT BUTTON_LEFT
261#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
262#define MPEG_START_TIME_UP BUTTON_UP
263#define MPEG_START_TIME_DOWN BUTTON_DOWN
264#define MPEG_START_TIME_EXIT BUTTON_POWER
265
266#elif CONFIG_KEYPAD == SONY_NWZ_PAD
267#define MPEG_START_TIME_SELECT BUTTON_PLAY
268#define MPEG_START_TIME_LEFT BUTTON_LEFT
269#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
270#define MPEG_START_TIME_UP BUTTON_UP
271#define MPEG_START_TIME_DOWN BUTTON_DOWN
272#define MPEG_START_TIME_EXIT BUTTON_BACK
273
274#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
275#define MPEG_START_TIME_SELECT BUTTON_SELECT
276#define MPEG_START_TIME_LEFT BUTTON_LEFT
277#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
278#define MPEG_START_TIME_UP BUTTON_UP
279#define MPEG_START_TIME_DOWN BUTTON_DOWN
280#define MPEG_START_TIME_EXIT BUTTON_BACK
281
282#elif CONFIG_KEYPAD == DX50_PAD
283#define MPEG_START_TIME_EXIT BUTTON_POWER
284#define MPEG_START_TIME_SELECT BUTTON_PLAY
285#define MPEG_START_TIME_LEFT BUTTON_LEFT
286#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
287#define MPEG_START_TIME_UP BUTTON_VOL_UP
288#define MPEG_START_TIME_DOWN BUTTON_VOL_DOWN
289
290#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
291#define MPEG_START_TIME_EXIT BUTTON_POWER
292
293#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
294#define MPEG_START_TIME_SELECT BUTTON_SELECT
295#define MPEG_START_TIME_LEFT BUTTON_LEFT
296#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
297#define MPEG_START_TIME_UP BUTTON_UP
298#define MPEG_START_TIME_DOWN BUTTON_DOWN
299#define MPEG_START_TIME_EXIT BUTTON_POWER
300
301#elif CONFIG_KEYPAD == XDUOO_X3_PAD
302#define MPEG_START_TIME_SELECT BUTTON_PLAY
303#define MPEG_START_TIME_LEFT BUTTON_PREV
304#define MPEG_START_TIME_RIGHT BUTTON_NEXT
305#define MPEG_START_TIME_UP BUTTON_HOME
306#define MPEG_START_TIME_DOWN BUTTON_OPTION
307#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
308#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
309#define MPEG_START_TIME_EXIT BUTTON_POWER
310
311#elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD
312#define MPEG_START_TIME_SELECT BUTTON_PLAY
313#define MPEG_START_TIME_LEFT BUTTON_PREV
314#define MPEG_START_TIME_RIGHT BUTTON_NEXT
315#define MPEG_START_TIME_UP BUTTON_HOME
316#define MPEG_START_TIME_DOWN BUTTON_OPTION
317#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
318#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
319#define MPEG_START_TIME_EXIT BUTTON_POWER
320
321#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
322#define MPEG_START_TIME_SELECT BUTTON_PLAY
323#define MPEG_START_TIME_LEFT BUTTON_PREV
324#define MPEG_START_TIME_RIGHT BUTTON_NEXT
325#define MPEG_START_TIME_UP BUTTON_HOME
326#define MPEG_START_TIME_DOWN BUTTON_OPTION
327#define MPEG_START_TIME_LEFT2 BUTTON_VOL_UP
328#define MPEG_START_TIME_RIGHT2 BUTTON_VOL_DOWN
329#define MPEG_START_TIME_EXIT BUTTON_POWER
330
331#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD
332#define MPEG_START_TIME_SELECT BUTTON_PLAY
333#define MPEG_START_TIME_LEFT BUTTON_HOME
334#define MPEG_START_TIME_RIGHT BUTTON_VOL_DOWN
335#define MPEG_START_TIME_UP BUTTON_PREV
336#define MPEG_START_TIME_DOWN BUTTON_NEXT
337#define MPEG_START_TIME_LEFT2 (BUTTON_POWER + BUTTON_HOME)
338#define MPEG_START_TIME_RIGHT2 (BUTTON_POWER + BUTTON_VOL_DOWN)
339#define MPEG_START_TIME_EXIT BUTTON_POWER
340
341#elif CONFIG_KEYPAD == EROSQ_PAD
342#define MPEG_START_TIME_SELECT BUTTON_PLAY
343#define MPEG_START_TIME_LEFT BUTTON_SCROLL_BACK
344#define MPEG_START_TIME_RIGHT BUTTON_SCROLL_FWD
345#define MPEG_START_TIME_UP BUTTON_PREV
346#define MPEG_START_TIME_DOWN BUTTON_NEXT
347#define MPEG_START_TIME_EXIT BUTTON_POWER
348
349#elif CONFIG_KEYPAD == FIIO_M3K_PAD
350#define MPEG_START_TIME_SELECT BUTTON_SELECT
351#define MPEG_START_TIME_LEFT BUTTON_LEFT
352#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
353#define MPEG_START_TIME_UP BUTTON_UP
354#define MPEG_START_TIME_DOWN BUTTON_DOWN
355#define MPEG_START_TIME_EXIT BUTTON_POWER
356
357#elif CONFIG_KEYPAD == MA_PAD
358#define MPEG_START_TIME_SELECT BUTTON_PLAY
359#define MPEG_START_TIME_LEFT BUTTON_LEFT
360#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
361#define MPEG_START_TIME_UP BUTTON_UP
362#define MPEG_START_TIME_DOWN BUTTON_DOWN
363#define MPEG_START_TIME_EXIT BUTTON_BACK
364
365#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
366#define MPEG_START_TIME_EXIT BUTTON_POWER
367
368#elif CONFIG_KEYPAD == RG_NANO_PAD
369#define MPEG_START_TIME_SELECT BUTTON_A
370#define MPEG_START_TIME_LEFT BUTTON_LEFT
371#define MPEG_START_TIME_RIGHT BUTTON_RIGHT
372#define MPEG_START_TIME_LEFT2 BUTTON_L
373#define MPEG_START_TIME_RIGHT2 BUTTON_R
374#define MPEG_START_TIME_UP BUTTON_UP
375#define MPEG_START_TIME_DOWN BUTTON_DOWN
376#define MPEG_START_TIME_EXIT BUTTON_START
377
378#else
379#error No keymap defined!
380#endif
381
382#ifdef HAVE_TOUCHSCREEN
383#ifndef MPEG_START_TIME_SELECT
384#define MPEG_START_TIME_SELECT BUTTON_CENTER
385#endif
386#ifndef MPEG_START_TIME_LEFT
387#define MPEG_START_TIME_LEFT BUTTON_MIDLEFT
388#endif
389#ifndef MPEG_START_TIME_RIGHT
390#define MPEG_START_TIME_RIGHT BUTTON_MIDRIGHT
391#endif
392#ifndef MPEG_START_TIME_UP
393#define MPEG_START_TIME_UP BUTTON_TOPMIDDLE
394#endif
395#ifndef MPEG_START_TIME_DOWN
396#define MPEG_START_TIME_DOWN BUTTON_BOTTOMMIDDLE
397#endif
398#ifndef MPEG_START_TIME_LEFT2
399#define MPEG_START_TIME_LEFT2 BUTTON_TOPRIGHT
400#endif
401#ifndef MPEG_START_TIME_RIGHT2
402#define MPEG_START_TIME_RIGHT2 BUTTON_TOPLEFT
403#endif
404#ifndef MPEG_START_TIME_EXIT
405#define MPEG_START_TIME_EXIT BUTTON_TOPLEFT
406#endif
407#endif
408
409static struct configdata config[] =
410{
411 {TYPE_INT, 0, 2, { .int_p = &settings.showfps }, "Show FPS", NULL},
412 {TYPE_INT, 0, 2, { .int_p = &settings.limitfps }, "Limit FPS", NULL},
413 {TYPE_INT, 0, 2, { .int_p = &settings.skipframes }, "Skip frames", NULL},
414 {TYPE_INT, 0, INT_MAX, { .int_p = &settings.resume_count }, "Resume count",
415 NULL},
416 {TYPE_INT, 0, MPEG_RESUME_NUM_OPTIONS,
417 { .int_p = &settings.resume_options }, "Resume options", NULL},
418#if MPEG_OPTION_DITHERING_ENABLED
419 {TYPE_INT, 0, INT_MAX, { .int_p = &settings.displayoptions },
420 "Display options", NULL},
421#endif
422 {TYPE_INT, 0, 2, { .int_p = &settings.tone_controls }, "Tone controls",
423 NULL},
424 {TYPE_INT, 0, 2, { .int_p = &settings.channel_modes }, "Channel modes",
425 NULL},
426 {TYPE_INT, 0, 2, { .int_p = &settings.crossfeed }, "Crossfeed", NULL},
427 {TYPE_INT, 0, 2, { .int_p = &settings.equalizer }, "Equalizer", NULL},
428 {TYPE_INT, 0, 2, { .int_p = &settings.dithering }, "Dithering", NULL},
429 {TYPE_INT, 0, 2, { .int_p = &settings.play_mode }, "Play mode", NULL},
430#ifdef HAVE_BACKLIGHT_BRIGHTNESS
431 {TYPE_INT, -1, INT_MAX, { .int_p = &settings.backlight_brightness },
432 "Backlight brightness", NULL},
433#endif
434};
435
436static const struct opt_items noyes[2] = {
437 { STR(LANG_SET_BOOL_NO) },
438 { STR(LANG_SET_BOOL_YES) },
439};
440
441static const struct opt_items singleall[2] = {
442 { STR(LANG_SINGLE) },
443 { STR(LANG_ALL) },
444};
445
446static const struct opt_items globaloff[2] = {
447 { STR(LANG_OFF) },
448 { STR(LANG_USE_SOUND_SETTING) },
449};
450
451static void mpeg_settings(void);
452static bool mpeg_set_option(const char* string,
453 void* variable,
454 enum optiontype type,
455 const struct opt_items* options,
456 int numoptions,
457 void (*function)(int))
458{
459 mpeg_sysevent_clear();
460
461 /* This eats SYS_POWEROFF - :\ */
462 bool usb = rb->set_option(string, variable, type, options, numoptions,
463 function);
464
465 if (usb)
466 mpeg_sysevent_set();
467
468 return usb;
469}
470
471#ifdef HAVE_BACKLIGHT_BRIGHTNESS /* Only used for this atm */
472static bool mpeg_set_int(const char *string, const char *unit,
473 int voice_unit, const int *variable,
474 void (*function)(int), int step,
475 int min,
476 int max,
477 const char* (*formatter)(char*, size_t, int, const char*),
478 int32_t (*get_talk_id)(int, int))
479{
480 mpeg_sysevent_clear();
481
482 bool usb = rb->set_int_ex(string, unit, voice_unit, variable, function,
483 step, min, max, formatter, get_talk_id);
484
485 if (usb)
486 mpeg_sysevent_set();
487
488 return usb;
489}
490
491static int32_t backlight_brightness_getlang(int value, int unit)
492{
493 if (value < 0)
494 return LANG_USE_COMMON_SETTING;
495
496 return TALK_ID(value + MIN_BRIGHTNESS_SETTING, unit);
497}
498
499void mpeg_backlight_update_brightness(int value)
500{
501 if (value >= 0)
502 {
503 value += MIN_BRIGHTNESS_SETTING;
504 backlight_brightness_set(value);
505 }
506 else
507 {
508 backlight_brightness_use_setting();
509 }
510}
511
512static void backlight_brightness_function(int value)
513{
514 mpeg_backlight_update_brightness(value);
515}
516
517static const char* backlight_brightness_formatter(char *buf, size_t length,
518 int value, const char *input)
519{
520 (void)input;
521
522 if (value < 0)
523 return rb->str(LANG_USE_COMMON_SETTING);
524 else
525 rb->snprintf(buf, length, "%d", value + MIN_BRIGHTNESS_SETTING);
526 return buf;
527}
528#endif /* HAVE_BACKLIGHT_BRIGHTNESS */
529
530/* Sync a particular audio setting to global or mpegplayer forced off */
531static void sync_audio_setting(int setting, bool global)
532{
533 switch (setting)
534 {
535 case MPEG_AUDIO_TONE_CONTROLS:
536 #ifdef AUDIOHW_HAVE_BASS
537 rb->sound_set(SOUND_BASS, (global || settings.tone_controls)
538 ? rb->global_settings->bass
539 : rb->sound_default(SOUND_BASS));
540 #endif
541 #ifdef AUDIOHW_HAVE_TREBLE
542 rb->sound_set(SOUND_TREBLE, (global || settings.tone_controls)
543 ? rb->global_settings->treble
544 : rb->sound_default(SOUND_TREBLE));
545 #endif
546
547 #ifdef AUDIOHW_HAVE_EQ
548 for (int band = 0;; band++)
549 {
550 int setting = rb->sound_enum_hw_eq_band_setting(band, AUDIOHW_EQ_GAIN);
551
552 if (setting == -1)
553 break;
554
555 rb->sound_set(setting, (global || settings.tone_controls)
556 ? rb->global_settings->hw_eq_bands[band].gain
557 : rb->sound_default(setting));
558 }
559 #endif /* AUDIOHW_HAVE_EQ */
560 break;
561
562 case MPEG_AUDIO_CHANNEL_MODES:
563 rb->sound_set(SOUND_CHANNELS, (global || settings.channel_modes)
564 ? rb->global_settings->channel_config
565 : SOUND_CHAN_STEREO);
566 break;
567
568 case MPEG_AUDIO_CROSSFEED:
569 rb->dsp_set_crossfeed_type((global || settings.crossfeed) ?
570 rb->global_settings->crossfeed :
571 CROSSFEED_TYPE_NONE);
572 break;
573
574 case MPEG_AUDIO_EQUALIZER:
575 rb->dsp_eq_enable((global || settings.equalizer) ?
576 rb->global_settings->eq_enabled : false);
577 break;
578
579 case MPEG_AUDIO_DITHERING:
580 rb->dsp_dither_enable((global || settings.dithering) ?
581 rb->global_settings->dithering_enabled : false);
582 break;
583 }
584}
585
586/* Sync all audio settings to global or mpegplayer forced off */
587static void sync_audio_settings(bool global)
588{
589 static const int setting_index[] =
590 {
591 MPEG_AUDIO_TONE_CONTROLS,
592 MPEG_AUDIO_CHANNEL_MODES,
593 MPEG_AUDIO_CROSSFEED,
594 MPEG_AUDIO_EQUALIZER,
595 MPEG_AUDIO_DITHERING,
596 };
597 unsigned i;
598
599 for (i = 0; i < ARRAYLEN(setting_index); i++)
600 {
601 sync_audio_setting(setting_index[i], global);
602 }
603}
604
605#ifndef HAVE_LCD_COLOR
606/* Cheapo splash implementation for the grey surface */
607static void grey_splash(int ticks, const unsigned char *fmt, ...)
608{
609 unsigned char buffer[256];
610 int x, y, w, h;
611 int oldfg, oldmode;
612
613 va_list ap;
614 va_start(ap, fmt);
615
616 rb->vsnprintf(buffer, sizeof (buffer), fmt, ap);
617
618 va_end(ap);
619
620 grey_getstringsize(buffer, &w, &h);
621
622 oldfg = grey_get_foreground();
623 oldmode = grey_get_drawmode();
624
625 grey_set_drawmode(DRMODE_FG);
626 grey_set_foreground(GREY_LIGHTGRAY);
627
628 x = (LCD_WIDTH - w) / 2;
629 y = (LCD_HEIGHT - h) / 2;
630
631 grey_fillrect(x - 1, y - 1, w + 2, h + 2);
632
633 grey_set_foreground(GREY_BLACK);
634
635 grey_putsxy(x, y, buffer);
636 grey_drawrect(x - 2, y - 2, w + 4, h + 4);
637
638 grey_set_foreground(oldfg);
639 grey_set_drawmode(oldmode);
640
641 grey_update();
642
643 if (ticks > 0)
644 rb->sleep(ticks);
645}
646#endif /* !HAVE_LCD_COLOR */
647
648static void show_loading(struct vo_rect *rc)
649{
650 int oldmode = mylcd_get_drawmode();
651 mylcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
652 mylcd_fillrect(rc->l-1, rc->t-1, rc->r - rc->l + 2, rc->b - rc->t + 2);
653 mylcd_set_drawmode(oldmode);
654 mylcd_splash(0, "Loading...");
655}
656
657static void draw_slider(uint32_t range, uint32_t pos, struct vo_rect *rc)
658{
659 #define SLIDER_WIDTH (LCD_WIDTH-SLIDER_LMARGIN-SLIDER_RMARGIN)
660 #define SLIDER_X SLIDER_LMARGIN
661 #define SLIDER_Y (LCD_HEIGHT-SLIDER_HEIGHT-SLIDER_BMARGIN)
662 #define SLIDER_HEIGHT 8
663 #define SLIDER_TEXTMARGIN 1
664 #define SLIDER_LMARGIN 1
665 #define SLIDER_RMARGIN 1
666 #define SLIDER_TMARGIN 1
667 #define SLIDER_BMARGIN 1
668 #define SCREEN_MARGIN 1
669
670 struct hms hms;
671 char str[32];
672 int text_w, text_h, text_y;
673
674 /* Put positition on left */
675 ts_to_hms(pos, &hms);
676 hms_format(str, sizeof(str), &hms);
677 mylcd_getstringsize(str, NULL, &text_h);
678 text_y = SLIDER_Y - SLIDER_TEXTMARGIN - text_h;
679
680 if (rc == NULL)
681 {
682 int oldmode = mylcd_get_drawmode();
683 mylcd_set_drawmode(DRMODE_BG | DRMODE_INVERSEVID);
684 mylcd_fillrect(SLIDER_X, text_y, SLIDER_WIDTH,
685 LCD_HEIGHT - SLIDER_BMARGIN - text_y
686 - SLIDER_TMARGIN);
687 mylcd_set_drawmode(oldmode);
688
689 mylcd_putsxy(SLIDER_X, text_y, str);
690
691 /* Put duration on right */
692 ts_to_hms(range, &hms);
693 hms_format(str, sizeof(str), &hms);
694 mylcd_getstringsize(str, &text_w, NULL);
695
696 mylcd_putsxy(SLIDER_X + SLIDER_WIDTH - text_w, text_y, str);
697
698 /* Draw slider */
699 mylcd_drawrect(SLIDER_X, SLIDER_Y, SLIDER_WIDTH, SLIDER_HEIGHT);
700 mylcd_fillrect(SLIDER_X, SLIDER_Y,
701 muldiv_uint32(pos, SLIDER_WIDTH, range),
702 SLIDER_HEIGHT);
703
704 /* Update screen */
705 mylcd_update_rect(SLIDER_X, text_y - SLIDER_TMARGIN, SLIDER_WIDTH,
706 LCD_HEIGHT - SLIDER_BMARGIN - text_y + SLIDER_TEXTMARGIN);
707 }
708 else
709 {
710 /* Just return slider rectangle */
711 rc->l = SLIDER_X;
712 rc->t = text_y - SLIDER_TMARGIN;
713 rc->r = rc->l + SLIDER_WIDTH;
714 rc->b = rc->t + LCD_HEIGHT - SLIDER_BMARGIN - text_y;
715 }
716}
717
718static bool display_thumb_image(const struct vo_rect *rc)
719{
720 bool retval = true;
721 unsigned ltgray = MYLCD_LIGHTGRAY;
722 unsigned dkgray = MYLCD_DARKGRAY;
723
724 int oldcolor = mylcd_get_foreground();
725
726 if (!stream_display_thumb(rc))
727 {
728 /* Display "No Frame" and erase any border */
729 const char * const str = "No Frame";
730 int x, y, w, h;
731
732 mylcd_getstringsize(str, &w, &h);
733 x = (rc->r + rc->l - w) / 2;
734 y = (rc->b + rc->t - h) / 2;
735 mylcd_putsxy(x, y, str);
736
737 mylcd_update_rect(x, y, w, h);
738
739 ltgray = dkgray = mylcd_get_background();
740 retval = false;
741 }
742
743 /* Draw a raised border around the frame (or erase if no frame) */
744
745 mylcd_set_foreground(ltgray);
746
747 mylcd_hline(rc->l-1, rc->r-1, rc->t-1);
748 mylcd_vline(rc->l-1, rc->t, rc->b-1);
749
750 mylcd_set_foreground(dkgray);
751
752 mylcd_hline(rc->l-1, rc->r, rc->b);
753 mylcd_vline(rc->r, rc->t-1, rc->b);
754
755 mylcd_set_foreground(oldcolor);
756
757 mylcd_update_rect(rc->l-1, rc->t-1, rc->r - rc->l + 2, 1);
758 mylcd_update_rect(rc->l-1, rc->t, 1, rc->b - rc->t);
759 mylcd_update_rect(rc->l-1, rc->b, rc->r - rc->l + 2, 1);
760 mylcd_update_rect(rc->r, rc->t, 1, rc->b - rc->t);
761
762 return retval;
763}
764
765/* Add an amount to the specified time - with saturation */
766static uint32_t increment_time(uint32_t val, int32_t amount, uint32_t range)
767{
768 if (amount < 0)
769 {
770 uint32_t off = -amount;
771 if (range > off && val >= off)
772 val -= off;
773 else
774 val = 0;
775 }
776 else if (amount > 0)
777 {
778 uint32_t off = amount;
779 if (range > off && val <= range - off)
780 val += off;
781 else
782 val = range;
783 }
784
785 return val;
786}
787
788#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
789static void get_start_time_lcd_enable_hook(unsigned short id, void *param)
790{
791 (void)id;
792 (void)param;
793 rb->button_queue_post(LCD_ENABLE_EVENT_0, 0);
794}
795#endif /* HAVE_LCD_ENABLE */
796
797static int get_start_time(uint32_t duration)
798{
799 int button = 0;
800 int tmo = TIMEOUT_NOBLOCK;
801 uint32_t resume_time = settings.resume_time;
802 struct vo_rect rc_vid, rc_bound;
803 uint32_t aspect_vid, aspect_bound;
804 bool sliding = false;
805
806 enum state_enum slider_state = STATE0;
807
808 mylcd_clear_display();
809 mylcd_update();
810
811#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
812 rb->add_event(LCD_EVENT_ACTIVATION, get_start_time_lcd_enable_hook);
813#endif
814
815 draw_slider(0, 100, &rc_bound);
816 rc_bound.b = rc_bound.t - SLIDER_TMARGIN;
817 rc_bound.t = SCREEN_MARGIN;
818
819 DEBUGF("rc_bound: %d, %d, %d, %d\n", rc_bound.l, rc_bound.t,
820 rc_bound.r, rc_bound.b);
821
822 rc_vid.l = rc_vid.t = 0;
823 if (!stream_vo_get_size((struct vo_ext *)&rc_vid.r))
824 {
825 /* Can't get size - fill whole thing */
826 rc_vid.r = rc_bound.r - rc_bound.l;
827 rc_vid.b = rc_bound.b - rc_bound.t;
828 }
829
830 /* Get aspect ratio of bounding rectangle and video in u16.16 */
831 aspect_bound = ((rc_bound.r - rc_bound.l) << 16) /
832 (rc_bound.b - rc_bound.t);
833
834 DEBUGF("aspect_bound: %u.%02u\n", (unsigned)(aspect_bound >> 16),
835 (unsigned)(100*(aspect_bound & 0xffff) >> 16));
836
837 aspect_vid = (rc_vid.r << 16) / rc_vid.b;
838
839 DEBUGF("aspect_vid: %u.%02u\n", (unsigned)(aspect_vid >> 16),
840 (unsigned)(100*(aspect_vid & 0xffff) >> 16));
841
842 if (aspect_vid >= aspect_bound)
843 {
844 /* Video proportionally wider than or same as bounding rectangle */
845 if (rc_vid.r > rc_bound.r - rc_bound.l)
846 {
847 rc_vid.r = rc_bound.r - rc_bound.l;
848 rc_vid.b = (rc_vid.r << 16) / aspect_vid;
849 }
850 /* else already fits */
851 }
852 else
853 {
854 /* Video proportionally narrower than bounding rectangle */
855 if (rc_vid.b > rc_bound.b - rc_bound.t)
856 {
857 rc_vid.b = rc_bound.b - rc_bound.t;
858 rc_vid.r = (aspect_vid * rc_vid.b) >> 16;
859 }
860 /* else already fits */
861 }
862
863 /* Even width and height >= 2 */
864 rc_vid.r = (rc_vid.r < 2) ? 2 : (rc_vid.r & ~1);
865 rc_vid.b = (rc_vid.b < 2) ? 2 : (rc_vid.b & ~1);
866
867 /* Center display in bounding rectangle */
868 rc_vid.l = ((rc_bound.l + rc_bound.r) - rc_vid.r) / 2;
869 rc_vid.r += rc_vid.l;
870
871 rc_vid.t = ((rc_bound.t + rc_bound.b) - rc_vid.b) / 2;
872 rc_vid.b += rc_vid.t;
873
874 DEBUGF("rc_vid: %d, %d, %d, %d\n", rc_vid.l, rc_vid.t,
875 rc_vid.r, rc_vid.b);
876
877#ifndef HAVE_LCD_COLOR
878 stream_gray_show(true);
879#endif
880
881 while (slider_state < STATE9)
882 {
883 button = mpeg_button_get(tmo);
884
885 switch (button)
886 {
887 case BUTTON_NONE:
888 break;
889
890 /* Coarse (1 minute) control */
891 case MPEG_START_TIME_DOWN:
892 case MPEG_START_TIME_DOWN | BUTTON_REPEAT:
893#ifdef MPEG_START_TIME_RC_DOWN
894 case MPEG_START_TIME_RC_DOWN:
895 case MPEG_START_TIME_RC_DOWN | BUTTON_REPEAT:
896#endif
897 resume_time = increment_time(resume_time, -60*TS_SECOND, duration);
898 slider_state = STATE0;
899 break;
900
901 case MPEG_START_TIME_UP:
902 case MPEG_START_TIME_UP | BUTTON_REPEAT:
903#ifdef MPEG_START_TIME_RC_UP
904 case MPEG_START_TIME_RC_UP:
905 case MPEG_START_TIME_RC_UP | BUTTON_REPEAT:
906#endif
907 resume_time = increment_time(resume_time, 60*TS_SECOND, duration);
908 slider_state = STATE0;
909 break;
910
911 /* Fine (1 second) control */
912 case MPEG_START_TIME_LEFT:
913 case MPEG_START_TIME_LEFT | BUTTON_REPEAT:
914#ifdef MPEG_START_TIME_RC_LEFT
915 case MPEG_START_TIME_RC_LEFT:
916 case MPEG_START_TIME_RC_LEFT | BUTTON_REPEAT:
917#endif
918#ifdef MPEG_START_TIME_LEFT2
919 case MPEG_START_TIME_LEFT2:
920 case MPEG_START_TIME_LEFT2 | BUTTON_REPEAT:
921#endif
922 resume_time = increment_time(resume_time, -TS_SECOND, duration);
923 slider_state = STATE0;
924 break;
925
926 case MPEG_START_TIME_RIGHT:
927 case MPEG_START_TIME_RIGHT | BUTTON_REPEAT:
928#ifdef MPEG_START_TIME_RC_RIGHT
929 case MPEG_START_TIME_RC_RIGHT:
930 case MPEG_START_TIME_RC_RIGHT | BUTTON_REPEAT:
931#endif
932#ifdef MPEG_START_TIME_RIGHT2
933 case MPEG_START_TIME_RIGHT2:
934 case MPEG_START_TIME_RIGHT2 | BUTTON_REPEAT:
935#endif
936 resume_time = increment_time(resume_time, TS_SECOND, duration);
937 slider_state = STATE0;
938 break;
939
940 case MPEG_START_TIME_SELECT:
941#ifdef MPEG_START_TIME_RC_SELECT
942 case MPEG_START_TIME_RC_SELECT:
943#endif
944 settings.resume_time = resume_time;
945 button = MPEG_START_SEEK;
946 slider_state = STATE9;
947 break;
948
949 case MPEG_START_TIME_EXIT:
950#ifdef MPEG_START_TIME_RC_EXIT
951 case MPEG_START_TIME_RC_EXIT:
952#endif
953 button = MPEG_START_EXIT;
954 slider_state = STATE9;
955 break;
956
957 case ACTION_STD_CANCEL:
958 button = MPEG_START_QUIT;
959 slider_state = STATE9;
960 break;
961
962#ifdef HAVE_LCD_ENABLE
963 case LCD_ENABLE_EVENT_0:
964 if (slider_state == STATE2)
965 display_thumb_image(&rc_vid);
966 continue;
967#endif
968
969 default:
970 rb->default_event_handler(button);
971 rb->yield();
972 continue;
973 }
974
975 switch (slider_state)
976 {
977 case STATE0:
978 if (!sliding)
979 {
980 if (rb->global_settings->talk_menu)
981 {
982 rb->talk_disable(true);
983#ifdef PLUGIN_USE_IRAM
984 mpegplayer_iram_restore();
985#endif
986 }
987 trigger_cpu_boost();
988 sliding = true;
989 }
990 stream_seek(resume_time, SEEK_SET);
991 show_loading(&rc_bound);
992 draw_slider(duration, resume_time, NULL);
993 slider_state = STATE1;
994 tmo = THUMB_DELAY;
995 break;
996 case STATE1:
997 display_thumb_image(&rc_vid);
998 slider_state = STATE2;
999 tmo = TIMEOUT_BLOCK;
1000 if (sliding)
1001 {
1002 cancel_cpu_boost();
1003 if (rb->global_settings->talk_menu)
1004 {
1005#ifdef PLUGIN_USE_IRAM
1006 mpegplayer_iram_preserve();
1007#endif
1008 rb->talk_disable(false);
1009 talk_val(resume_time / TS_SECOND, UNIT_TIME, false);
1010 talk_val(resume_time * 100 / duration, UNIT_PERCENT, true);
1011 }
1012 sliding = false;
1013 }
1014 default:
1015 break;
1016 }
1017
1018 rb->yield();
1019 }
1020
1021#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
1022 rb->remove_event(LCD_EVENT_ACTIVATION, get_start_time_lcd_enable_hook);
1023#endif
1024#ifndef HAVE_LCD_COLOR
1025 stream_gray_show(false);
1026 grey_clear_display();
1027 grey_update();
1028#endif
1029
1030 cancel_cpu_boost();
1031
1032 return button;
1033}
1034
1035static int show_start_menu(uint32_t duration)
1036{
1037 int selected = 0;
1038 int result = 0;
1039 bool menu_quit = false;
1040
1041 MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback,
1042 ID2P(LANG_RESTART_PLAYBACK),
1043 ID2P(LANG_RESUME_PLAYBACK),
1044 ID2P(LANG_SET_RESUME_TIME),
1045 ID2P(LANG_SETTINGS),
1046 ID2P(LANG_MENU_QUIT));
1047
1048 if (rb->global_settings->talk_menu)
1049 {
1050#ifdef PLUGIN_USE_IRAM
1051 mpegplayer_iram_preserve();
1052#endif
1053 rb->talk_disable(false);
1054 }
1055
1056 rb->button_clear_queue();
1057
1058 while (!menu_quit)
1059 {
1060 mpeg_sysevent_clear();
1061 result = rb->do_menu(&menu, &selected, NULL, false);
1062
1063 switch (result)
1064 {
1065 case MPEG_START_RESTART:
1066 settings.resume_time = 0;
1067 menu_quit = true;
1068 break;
1069
1070 case MPEG_START_RESUME:
1071 menu_quit = true;
1072 break;
1073
1074 case MPEG_START_SEEK:
1075 if (!stream_can_seek())
1076 {
1077 rb->splash(HZ, ID2P(LANG_UNAVAILABLE));
1078 break;
1079 }
1080
1081 result = get_start_time(duration);
1082
1083 if (result != MPEG_START_EXIT)
1084 menu_quit = true;
1085 break;
1086
1087 case MPEG_START_SETTINGS:
1088 mpeg_settings();
1089 break;
1090
1091 default:
1092 result = MPEG_START_QUIT;
1093 menu_quit = true;
1094 break;
1095 }
1096
1097 if (mpeg_sysevent() != 0)
1098 {
1099 result = MPEG_START_QUIT;
1100 menu_quit = true;
1101 }
1102 }
1103
1104 if (rb->global_settings->talk_menu)
1105 {
1106 rb->talk_disable(true);
1107#ifdef PLUGIN_USE_IRAM
1108 mpegplayer_iram_restore();
1109#endif
1110 }
1111
1112 return result;
1113}
1114
1115/* Return the desired resume action */
1116int mpeg_start_menu(uint32_t duration)
1117{
1118 mpeg_sysevent_clear();
1119
1120 switch (settings.resume_options)
1121 {
1122 case MPEG_RESUME_MENU_IF_INCOMPLETE:
1123 if (!stream_can_seek() || settings.resume_time == 0)
1124 {
1125 case MPEG_RESUME_RESTART:
1126 settings.resume_time = 0;
1127 return MPEG_START_RESTART;
1128 }
1129 default:
1130 case MPEG_RESUME_MENU_ALWAYS:
1131 return show_start_menu(duration);
1132 case MPEG_RESUME_ALWAYS:
1133 return MPEG_START_SEEK;
1134 }
1135}
1136
1137int mpeg_menu(void)
1138{
1139 int result;
1140
1141 MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback,
1142 ID2P(LANG_SETTINGS),
1143 ID2P(LANG_RESUME_PLAYBACK),
1144 ID2P(LANG_MENU_QUIT));
1145
1146 if (rb->global_settings->talk_menu)
1147 {
1148#ifdef PLUGIN_USE_IRAM
1149 mpegplayer_iram_preserve();
1150#endif
1151 rb->talk_disable(false);
1152 }
1153
1154 rb->button_clear_queue();
1155
1156 mpeg_sysevent_clear();
1157
1158 result = rb->do_menu(&menu, NULL, NULL, false);
1159
1160 switch (result)
1161 {
1162 case MPEG_MENU_SETTINGS:
1163 mpeg_settings();
1164 break;
1165
1166 case MPEG_MENU_RESUME:
1167 break;
1168
1169 case MPEG_MENU_QUIT:
1170 break;
1171
1172 default:
1173 break;
1174 }
1175
1176 if (mpeg_sysevent() != 0)
1177 result = MPEG_MENU_QUIT;
1178
1179 if (rb->global_settings->talk_menu)
1180 {
1181 rb->talk_disable(true);
1182#ifdef PLUGIN_USE_IRAM
1183 mpegplayer_iram_restore();
1184#endif
1185 }
1186
1187 return result;
1188}
1189
1190static void display_options(void)
1191{
1192 int selected = 0;
1193 int result;
1194 bool menu_quit = false;
1195
1196 MENUITEM_STRINGLIST(menu, "Display Options", mpeg_sysevent_callback,
1197#if MPEG_OPTION_DITHERING_ENABLED
1198 ID2P(LANG_DITHERING),
1199#endif
1200 ID2P(LANG_DISPLAY_FPS),
1201 ID2P(LANG_LIMIT_FPS),
1202 ID2P(LANG_SKIP_FRAMES),
1203#ifdef HAVE_BACKLIGHT_BRIGHTNESS
1204 ID2P(LANG_BACKLIGHT_BRIGHTNESS),
1205#endif
1206 );
1207
1208 rb->button_clear_queue();
1209
1210 while (!menu_quit)
1211 {
1212 mpeg_sysevent_clear();
1213 result = rb->do_menu(&menu, &selected, NULL, false);
1214
1215 switch (result)
1216 {
1217#if MPEG_OPTION_DITHERING_ENABLED
1218 case MPEG_OPTION_DITHERING:
1219 result = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0;
1220 mpeg_set_option(rb->str(LANG_DITHERING), &result, RB_INT, noyes, 2, NULL);
1221 settings.displayoptions =
1222 (settings.displayoptions & ~LCD_YUV_DITHER)
1223 | ((result != 0) ? LCD_YUV_DITHER : 0);
1224 rb->lcd_yuv_set_options(settings.displayoptions);
1225 break;
1226#endif /* MPEG_OPTION_DITHERING_ENABLED */
1227
1228 case MPEG_OPTION_DISPLAY_FPS:
1229 mpeg_set_option(rb->str(LANG_DISPLAY_FPS), &settings.showfps, RB_INT,
1230 noyes, 2, NULL);
1231 break;
1232
1233 case MPEG_OPTION_LIMIT_FPS:
1234 mpeg_set_option(rb->str(LANG_LIMIT_FPS), &settings.limitfps, RB_INT,
1235 noyes, 2, NULL);
1236 break;
1237
1238 case MPEG_OPTION_SKIP_FRAMES:
1239 mpeg_set_option(rb->str(LANG_SKIP_FRAMES), &settings.skipframes, RB_INT,
1240 noyes, 2, NULL);
1241 break;
1242
1243#ifdef HAVE_BACKLIGHT_BRIGHTNESS
1244 case MPEG_OPTION_BACKLIGHT_BRIGHTNESS:
1245 result = settings.backlight_brightness;
1246 mpeg_backlight_update_brightness(result);
1247 mpeg_set_int(rb->str(LANG_BACKLIGHT_BRIGHTNESS), NULL, UNIT_INT, &result,
1248 backlight_brightness_function, 1, -1,
1249 MAX_BRIGHTNESS_SETTING - MIN_BRIGHTNESS_SETTING,
1250 backlight_brightness_formatter,
1251 backlight_brightness_getlang);
1252 settings.backlight_brightness = result;
1253 mpeg_backlight_update_brightness(-1);
1254 break;
1255#endif /* HAVE_BACKLIGHT_BRIGHTNESS */
1256
1257 default:
1258 menu_quit = true;
1259 break;
1260 }
1261
1262 if (mpeg_sysevent() != 0)
1263 menu_quit = true;
1264 }
1265}
1266
1267static void audio_options(void)
1268{
1269 int selected = 0;
1270 int result;
1271 bool menu_quit = false;
1272
1273 MENUITEM_STRINGLIST(menu, "Audio Options", mpeg_sysevent_callback,
1274 ID2P(LANG_TONE_CONTROLS),
1275 ID2P(LANG_CHANNEL_CONFIGURATION),
1276 ID2P(LANG_CROSSFEED),
1277 ID2P(LANG_EQUALIZER),
1278 ID2P(LANG_DITHERING));
1279
1280 rb->button_clear_queue();
1281
1282 while (!menu_quit)
1283 {
1284 mpeg_sysevent_clear();
1285 result = rb->do_menu(&menu, &selected, NULL, false);
1286
1287 switch (result)
1288 {
1289 case MPEG_AUDIO_TONE_CONTROLS:
1290 mpeg_set_option(rb->str(LANG_TONE_CONTROLS), &settings.tone_controls, RB_INT,
1291 globaloff, 2, NULL);
1292 sync_audio_setting(result, false);
1293 break;
1294
1295 case MPEG_AUDIO_CHANNEL_MODES:
1296 mpeg_set_option(rb->str(LANG_CHANNEL_CONFIGURATION), &settings.channel_modes,
1297 RB_INT, globaloff, 2, NULL);
1298 sync_audio_setting(result, false);
1299 break;
1300
1301 case MPEG_AUDIO_CROSSFEED:
1302 mpeg_set_option(rb->str(LANG_CROSSFEED), &settings.crossfeed, RB_INT,
1303 globaloff, 2, NULL);
1304 sync_audio_setting(result, false);
1305 break;
1306
1307 case MPEG_AUDIO_EQUALIZER:
1308 mpeg_set_option(rb->str(LANG_EQUALIZER), &settings.equalizer, RB_INT,
1309 globaloff, 2, NULL);
1310 sync_audio_setting(result, false);
1311 break;
1312
1313 case MPEG_AUDIO_DITHERING:
1314 mpeg_set_option(rb->str(LANG_DITHERING), &settings.dithering, RB_INT,
1315 globaloff, 2, NULL);
1316 sync_audio_setting(result, false);
1317 break;
1318
1319 default:
1320 menu_quit = true;
1321 break;
1322 }
1323
1324 if (mpeg_sysevent() != 0)
1325 menu_quit = true;
1326 }
1327}
1328
1329static void resume_options(void)
1330{
1331 static const struct opt_items items[MPEG_RESUME_NUM_OPTIONS] = {
1332 [MPEG_RESUME_MENU_ALWAYS] =
1333 { STR(LANG_FORCE_START_MENU) },
1334 [MPEG_RESUME_MENU_IF_INCOMPLETE] =
1335 { STR(LANG_CONDITIONAL_START_MENU) },
1336 [MPEG_RESUME_ALWAYS] =
1337 { STR(LANG_AUTO_RESUME) },
1338 [MPEG_RESUME_RESTART] =
1339 { STR(LANG_RESTART_PLAYBACK) },
1340 };
1341
1342 mpeg_set_option(rb->str(LANG_MENU_RESUME_OPTIONS), &settings.resume_options,
1343 RB_INT, items, MPEG_RESUME_NUM_OPTIONS, NULL);
1344}
1345
1346static void clear_resume_count(void)
1347{
1348 settings.resume_count = 0;
1349 configfile_save(SETTINGS_FILENAME, config, ARRAYLEN(config),
1350 SETTINGS_VERSION);
1351}
1352
1353static void mpeg_settings(void)
1354{
1355 int selected = 0;
1356 int result;
1357 bool menu_quit = false;
1358
1359 MENUITEM_STRINGLIST(menu, "Settings", mpeg_sysevent_callback,
1360 ID2P(LANG_MENU_DISPLAY_OPTIONS),
1361 ID2P(LANG_MENU_AUDIO_OPTIONS),
1362 ID2P(LANG_MENU_RESUME_OPTIONS),
1363 ID2P(LANG_MENU_PLAY_MODE),
1364 ID2P(LANG_CLEAR_ALL_RESUMES));
1365
1366 rb->button_clear_queue();
1367
1368 while (!menu_quit)
1369 {
1370 mpeg_sysevent_clear();
1371
1372 result = rb->do_menu(&menu, &selected, NULL, false);
1373
1374 switch (result)
1375 {
1376 case MPEG_SETTING_DISPLAY_SETTINGS:
1377 display_options();
1378 break;
1379
1380 case MPEG_SETTING_AUDIO_SETTINGS:
1381 audio_options();
1382 break;
1383
1384 case MPEG_SETTING_ENABLE_START_MENU:
1385 resume_options();
1386 break;
1387
1388 case MPEG_SETTING_PLAY_MODE:
1389 mpeg_set_option(rb->str(LANG_MENU_PLAY_MODE), &settings.play_mode,
1390 RB_INT, singleall, 2, NULL);
1391 break;
1392
1393 case MPEG_SETTING_CLEAR_RESUMES:
1394 clear_resume_count();
1395 break;
1396
1397 default:
1398 menu_quit = true;
1399 break;
1400 }
1401
1402 if (mpeg_sysevent() != 0)
1403 menu_quit = true;
1404 }
1405}
1406
1407void init_settings(const char* filename)
1408{
1409 /* Set the default settings */
1410 settings.showfps = 0; /* Do not show FPS */
1411 settings.limitfps = 1; /* Limit FPS */
1412 settings.skipframes = 1; /* Skip frames */
1413 settings.play_mode = 0; /* Play single video */
1414 settings.resume_options = MPEG_RESUME_MENU_ALWAYS; /* Enable start menu */
1415 settings.resume_count = 0;
1416#ifdef HAVE_BACKLIGHT_BRIGHTNESS
1417 settings.backlight_brightness = -1; /* Use default setting */
1418#endif
1419#if MPEG_OPTION_DITHERING_ENABLED
1420 settings.displayoptions = 0; /* No visual effects */
1421#endif
1422 settings.tone_controls = false;
1423 settings.channel_modes = false;
1424 settings.crossfeed = false;
1425 settings.equalizer = false;
1426 settings.dithering = false;
1427
1428 if (configfile_load(SETTINGS_FILENAME, config, ARRAYLEN(config),
1429 SETTINGS_MIN_VERSION) < 0)
1430 {
1431 /* Generate a new config file with default values */
1432 configfile_save(SETTINGS_FILENAME, config, ARRAYLEN(config),
1433 SETTINGS_VERSION);
1434 }
1435
1436 rb->strlcpy(settings.resume_filename, filename, MAX_PATH);
1437
1438 /* get the resume time for the current mpeg if it exists */
1439 if ((settings.resume_time = configfile_get_value
1440 (SETTINGS_FILENAME, filename)) < 0)
1441 {
1442 settings.resume_time = 0;
1443 }
1444
1445#if MPEG_OPTION_DITHERING_ENABLED
1446 rb->lcd_yuv_set_options(settings.displayoptions);
1447#endif
1448
1449 /* Set our audio options */
1450 sync_audio_settings(false);
1451}
1452
1453void save_settings(void)
1454{
1455 unsigned i;
1456 for (i = 0; i < ARRAYLEN(config); i++)
1457 {
1458 configfile_update_entry(SETTINGS_FILENAME, config[i].name,
1459 *(config[i].int_p));
1460 }
1461
1462 /* If this was a new resume entry then update the total resume count */
1463 if (configfile_update_entry(SETTINGS_FILENAME, settings.resume_filename,
1464 settings.resume_time) == 0)
1465 {
1466 configfile_update_entry(SETTINGS_FILENAME, "Resume count",
1467 ++settings.resume_count);
1468 }
1469
1470 /* Restore audio options */
1471 sync_audio_settings(true);
1472}