A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Clément Pit-Claudel
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
22#include "plugin.h"
23#include "lib/pluginlib_actions.h"
24
25
26
27const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
28
29static int current = 0;
30static bool tomorrow = false;
31static int alarms[2] = {0, 0}, maxval[2] = {24, 60}, prev_tick = 3600 * 24;
32static bool quit = false, usb = false, waiting = false, done = false;
33
34static inline int get_button(void)
35{
36 return pluginlib_getaction(HZ/2, plugin_contexts,
37 ARRAYLEN(plugin_contexts));
38}
39
40static int rem_seconds(void)
41{
42 int seconds = (((alarms[0] - rb->get_time()->tm_hour) * 3600)
43 +((alarms[1] - rb->get_time()->tm_min) * 60)
44 -(rb->get_time()->tm_sec));
45
46 /* The tomorrow flag means that the alarm should ring on the next day */
47 if (seconds > prev_tick) tomorrow = false;
48 prev_tick = seconds;
49
50 return seconds + (tomorrow ? 24 * 3600 : 0);
51}
52
53static void draw_centered_string(struct screen * display, char * string)
54{
55 int w, h;
56 display->getstringsize(string, &w, &h);
57
58 if (w > display->lcdwidth || h > display->lcdheight) {
59 rb->splash(0, string);
60 } else {
61 display->putsxy((display->lcdwidth - w) / 2,
62 (display->lcdheight - h) / 2,
63 string);
64 display->update();
65 }
66}
67
68static void draw(struct screen * display)
69{
70 char info[128];
71 display->clear_display();
72
73 int secs = rem_seconds();
74
75 if (waiting)
76 rb->snprintf(info, sizeof(info), "Next alarm in %02dh,"
77 " %02dmn, and %02ds.",
78 secs / 3600, (secs / 60) % 60, secs % 60);
79 else {
80 if (current == 0)
81 rb->snprintf(info, sizeof(info), "Set alarm at [%02d]:%02d.",
82 alarms[0],
83 alarms[1]);
84 else
85 rb->snprintf(info, sizeof(info), "Set alarm at %02d:[%02d].",
86 alarms[0],
87 alarms[1]);
88 }
89 draw_centered_string(display, info);
90}
91
92static bool can_play(void)
93{
94 int audio_status = rb->audio_status();
95 if ((!audio_status && rb->global_status->resume_index != -1)
96 && (rb->playlist_resume() != -1)) {
97 return true;
98 }
99 else if (audio_status & AUDIO_STATUS_PLAY)
100 return true;
101
102 return false;
103}
104
105static void resume_audio(void)
106{
107 int audio_status = rb->audio_status();
108 if (!audio_status && rb->global_status->resume_index != -1) {
109 if (rb->playlist_resume() != -1) {
110 rb->playlist_resume_track(rb->global_status->resume_index,
111 rb->global_status->resume_crc32,
112 rb->global_status->resume_elapsed,
113 rb->global_status->resume_offset);
114 }
115 }
116 else if (audio_status & AUDIO_STATUS_PLAY)
117 rb->audio_resume();
118}
119
120static void pause_audio(void)
121{
122 if (rb->audio_status() & AUDIO_STATUS_PLAY)
123 rb->audio_pause();
124}
125
126enum plugin_status plugin_start(const void* parameter)
127{
128 int button;
129 (void)parameter;
130
131 if (!can_play()) {
132 rb->splash(HZ*2, "No track to resume! "
133 "Play or pause one first.");
134 return PLUGIN_ERROR;
135 }
136 pause_audio();
137
138 while(!quit) {
139 FOR_NB_SCREENS(i) {
140 draw(rb->screens[i]);
141 }
142 button = get_button();
143
144#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
145 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
146 || (CONFIG_KEYPAD == IPOD_4G_PAD)
147 if (button == PLA_EXIT || button == PLA_CANCEL || button == PLA_UP)
148#else
149 if (button == PLA_EXIT || button == PLA_CANCEL)
150#endif
151 quit = true;
152
153 if (waiting) {
154 if (rem_seconds() <= 0) {
155 quit = done = true;
156 resume_audio();
157 }
158 }
159 else {
160 switch (button) {
161 case PLA_UP:
162 case PLA_UP_REPEAT:
163#ifdef HAVE_SCROLLWHEEL
164 case PLA_SCROLL_FWD:
165 case PLA_SCROLL_FWD_REPEAT:
166#endif
167 alarms[current] = (alarms[current] + 1) % maxval[current];
168 break;
169 case PLA_DOWN:
170 case PLA_DOWN_REPEAT:
171#ifdef HAVE_SCROLLWHEEL
172 case PLA_SCROLL_BACK:
173 case PLA_SCROLL_BACK_REPEAT:
174#endif
175 alarms[current] = (alarms[current] + maxval[current] - 1)
176 % maxval[current];
177 break;
178
179 case PLA_LEFT:
180 case PLA_LEFT_REPEAT:
181 case PLA_RIGHT:
182 case PLA_RIGHT_REPEAT:
183 current = (current + 1) % 2;
184 break;
185
186 case PLA_SELECT:
187 case PLA_SELECT_REPEAT: {
188 if (rem_seconds() < 0)
189 tomorrow = true;
190
191 waiting = true;
192 break;
193 }
194
195 default:
196 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
197 quit = usb = true;
198 break;
199 }
200 }
201 }
202
203 return (usb) ? PLUGIN_USB_CONNECTED
204 : (done ? PLUGIN_GOTO_WPS : PLUGIN_OK);
205}