summaryrefslogtreecommitdiff
path: root/apps/onplay.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/onplay.c')
-rw-r--r--apps/onplay.c320
1 files changed, 5 insertions, 315 deletions
diff --git a/apps/onplay.c b/apps/onplay.c
index 26a2614b56..5f8af77fca 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -200,322 +200,7 @@ static int bookmark_menu_callback(int action,
200 return action; 200 return action;
201} 201}
202 202
203enum ePT_SECS {
204 ePT_SECS_TTL = 0,
205 ePT_SECS_BEF,
206 ePT_SECS_AFT,
207 ePT_SECS_COUNT
208};
209
210enum ePT_KBS {
211 /* Note: Order matters (voicing order of LANG_PLAYTIME_STORAGE) */
212 ePT_KBS_TTL = 0,
213 ePT_KBS_BEF,
214 ePT_KBS_AFT,
215 ePT_KBS_COUNT
216};
217
218/* playing_time screen context */
219struct playing_time_info {
220 int curr_playing; /* index of currently playing track in playlist */
221 int nb_tracks; /* how many tracks in playlist */
222 /* seconds total, before, and after current position. Datatype
223 allows for values up to 68years. If I had kept it in ms
224 though, it would have overflowed at 24days, which takes
225 something like 8.5GB at 32kbps, and so we could conceivably
226 have playlists lasting longer than that. */
227 long secs[ePT_SECS_COUNT];
228 long trk_secs[ePT_SECS_COUNT];
229 /* kilobytes played total, before, and after current pos.
230 Kilobytes because bytes would overflow. Data type range is up
231 to 2TB. */
232 long kbs[ePT_KBS_COUNT];
233};
234
235/* list callback for playing_time screen */
236static const char * playing_time_get_or_speak_info(int selected_item, void * data,
237 char *buf, size_t buffer_len,
238 bool say_it)
239{
240 long elapsed_pct; /* percentage of duration elapsed */
241 struct playing_time_info *pti = (struct playing_time_info *)data;
242 switch(selected_item) {
243 case 0: { /* elapsed and total time */
244 char timestr1[25], timestr2[25];
245 format_time_auto(timestr1, sizeof(timestr1),
246 pti->secs[ePT_SECS_BEF], UNIT_SEC, false);
247
248 format_time_auto(timestr2, sizeof(timestr2),
249 pti->secs[ePT_SECS_TTL], UNIT_SEC, false);
250
251 if (pti->secs[ePT_SECS_TTL] == 0)
252 elapsed_pct = 0;
253 else if (pti->secs[ePT_SECS_TTL] <= 0xFFFFFF)
254 {
255 elapsed_pct = (pti->secs[ePT_SECS_BEF] * 100
256 / pti->secs[ePT_SECS_TTL]);
257 }
258 else /* sacrifice some precision to avoid overflow */
259 {
260 elapsed_pct = (pti->secs[ePT_SECS_BEF] >> 7) * 100
261 / (pti->secs[ePT_SECS_TTL] >> 7);
262 }
263 snprintf(buf, buffer_len, str(LANG_PLAYTIME_ELAPSED),
264 timestr1, timestr2, elapsed_pct);
265
266 if (say_it)
267 talk_ids(false, LANG_PLAYTIME_ELAPSED,
268 TALK_ID(pti->secs[ePT_SECS_BEF], UNIT_TIME),
269 VOICE_OF,
270 TALK_ID(pti->secs[ePT_SECS_TTL], UNIT_TIME),
271 VOICE_PAUSE,
272 TALK_ID(elapsed_pct, UNIT_PERCENT));
273 break;
274 }
275 case 1: { /* playlist remaining time */
276 char timestr[25];
277 format_time_auto(timestr, sizeof(timestr), pti->secs[ePT_SECS_AFT],
278 UNIT_SEC, false);
279 snprintf(buf, buffer_len, str(LANG_PLAYTIME_REMAINING), timestr);
280
281 if (say_it)
282 talk_ids(false, LANG_PLAYTIME_REMAINING,
283 TALK_ID(pti->secs[ePT_SECS_AFT], UNIT_TIME));
284 break;
285 }
286 case 2: { /* track elapsed and duration */
287 char timestr1[25], timestr2[25];
288
289 format_time_auto(timestr1, sizeof(timestr1), pti->trk_secs[ePT_SECS_BEF],
290 UNIT_SEC, false);
291 format_time_auto(timestr2, sizeof(timestr2), pti->trk_secs[ePT_SECS_TTL],
292 UNIT_SEC, false);
293
294 if (pti->trk_secs[ePT_SECS_TTL] == 0)
295 elapsed_pct = 0;
296 else if (pti->trk_secs[ePT_SECS_TTL] <= 0xFFFFFF)
297 {
298 elapsed_pct = (pti->trk_secs[ePT_SECS_BEF] * 100
299 / pti->trk_secs[ePT_SECS_TTL]);
300 }
301 else /* sacrifice some precision to avoid overflow */
302 {
303 elapsed_pct = (pti->trk_secs[ePT_SECS_BEF] >> 7) * 100
304 / (pti->trk_secs[ePT_SECS_TTL] >> 7);
305 }
306 snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRK_ELAPSED),
307 timestr1, timestr2, elapsed_pct);
308
309 if (say_it)
310 talk_ids(false, LANG_PLAYTIME_TRK_ELAPSED,
311 TALK_ID(pti->trk_secs[ePT_SECS_BEF], UNIT_TIME),
312 VOICE_OF,
313 TALK_ID(pti->trk_secs[ePT_SECS_TTL], UNIT_TIME),
314 VOICE_PAUSE,
315 TALK_ID(elapsed_pct, UNIT_PERCENT));
316 break;
317 }
318 case 3: { /* track remaining time */
319 char timestr[25];
320 format_time_auto(timestr, sizeof(timestr), pti->trk_secs[ePT_SECS_AFT],
321 UNIT_SEC, false);
322 snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRK_REMAINING), timestr);
323
324 if (say_it)
325 talk_ids(false, LANG_PLAYTIME_TRK_REMAINING,
326 TALK_ID(pti->trk_secs[ePT_SECS_AFT], UNIT_TIME));
327 break;
328 }
329 case 4: { /* track index */
330 int track_pct = (pti->curr_playing + 1) * 100 / pti->nb_tracks;
331 snprintf(buf, buffer_len, str(LANG_PLAYTIME_TRACK),
332 pti->curr_playing + 1, pti->nb_tracks, track_pct);
333
334 if (say_it)
335 talk_ids(false, LANG_PLAYTIME_TRACK,
336 TALK_ID(pti->curr_playing + 1, UNIT_INT),
337 VOICE_OF,
338 TALK_ID(pti->nb_tracks, UNIT_INT),
339 VOICE_PAUSE,
340 TALK_ID(track_pct, UNIT_PERCENT));
341 break;
342 }
343 case 5: { /* storage size */
344 int i;
345 char kbstr[ePT_KBS_COUNT][10];
346 203
347 for (i = 0; i < ePT_KBS_COUNT; i++) {
348 output_dyn_value(kbstr[i], sizeof(kbstr[i]),
349 pti->kbs[i], kibyte_units, 3, true);
350 }
351 snprintf(buf, buffer_len, str(LANG_PLAYTIME_STORAGE),
352 kbstr[ePT_KBS_TTL], kbstr[ePT_KBS_BEF],kbstr[ePT_KBS_AFT]);
353
354 if (say_it) {
355 int32_t voice_ids[ePT_KBS_COUNT];
356 voice_ids[ePT_KBS_TTL] = LANG_PLAYTIME_STORAGE;
357 voice_ids[ePT_KBS_BEF] = VOICE_PLAYTIME_DONE;
358 voice_ids[ePT_KBS_AFT] = LANG_PLAYTIME_REMAINING;
359
360 for (i = 0; i < ePT_KBS_COUNT; i++) {
361 talk_ids(i > 0, VOICE_PAUSE, voice_ids[i]);
362 output_dyn_value(NULL, 0, pti->kbs[i], kibyte_units, 3, true);
363 }
364 }
365 break;
366 }
367 case 6: { /* Average track file size */
368 char str[10];
369 long avg_track_size = pti->kbs[ePT_KBS_TTL] / pti->nb_tracks;
370 output_dyn_value(str, sizeof(str), avg_track_size, kibyte_units, 3, true);
371 snprintf(buf, buffer_len, str(LANG_PLAYTIME_AVG_TRACK_SIZE), str);
372
373 if (say_it) {
374 talk_id(LANG_PLAYTIME_AVG_TRACK_SIZE, false);
375 output_dyn_value(NULL, 0, avg_track_size, kibyte_units, 3, true);
376 }
377 break;
378 }
379 case 7: { /* Average bitrate */
380 /* Convert power of 2 kilobytes to power of 10 kilobits */
381 long avg_bitrate = (pti->kbs[ePT_KBS_TTL] / pti->secs[ePT_SECS_TTL]
382 * 1024 * 8 / 1000);
383 snprintf(buf, buffer_len, str(LANG_PLAYTIME_AVG_BITRATE), avg_bitrate);
384
385 if (say_it)
386 talk_ids(false, LANG_PLAYTIME_AVG_BITRATE,
387 TALK_ID(avg_bitrate, UNIT_KBIT));
388 break;
389 }
390 }
391 return buf;
392}
393
394static const char * playing_time_get_info(int selected_item, void * data,
395 char *buffer, size_t buffer_len)
396{
397 return playing_time_get_or_speak_info(selected_item, data,
398 buffer, buffer_len, false);
399}
400
401static int playing_time_speak_info(int selected_item, void * data)
402{
403 static char buffer[MAX_PATH];
404 playing_time_get_or_speak_info(selected_item, data,
405 buffer, MAX_PATH, true);
406 return 0;
407}
408
409/* playing time screen: shows total and elapsed playlist duration and
410 other stats */
411static bool playing_time(void)
412{
413 int error_count = 0;
414 unsigned long talked_tick = current_tick;
415 struct playing_time_info pti;
416 struct playlist_track_info pltrack;
417 struct mp3entry id3;
418 int i, fd;
419
420 pti.nb_tracks = playlist_amount();
421 playlist_get_resume_info(&pti.curr_playing);
422 struct mp3entry *curr_id3 = audio_current_track();
423 if (pti.curr_playing == -1 || !curr_id3)
424 return false;
425 pti.secs[ePT_SECS_BEF] = pti.trk_secs[ePT_SECS_BEF] = curr_id3->elapsed / 1000;
426 pti.secs[ePT_SECS_AFT] = pti.trk_secs[ePT_SECS_AFT]
427 = (curr_id3->length -curr_id3->elapsed) / 1000;
428 pti.kbs[ePT_KBS_BEF] = curr_id3->offset / 1024;
429 pti.kbs[ePT_KBS_AFT] = (curr_id3->filesize -curr_id3->offset) / 1024;
430
431 splash(0, ID2P(LANG_WAIT));
432 splash_progress_set_delay(5 * HZ);
433 /* Go through each file in the playlist and get its stats. For
434 huge playlists this can take a while... The reference position
435 is the position at the moment this function was invoked,
436 although playback continues forward. */
437 for (i = 0; i < pti.nb_tracks; i++) {
438 /* Show a splash while we are loading. */
439 splash_progress(i, pti.nb_tracks,
440 "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT));
441
442 /* Voice equivalent */
443 if (TIME_AFTER(current_tick, talked_tick + 5 * HZ)) {
444 talked_tick = current_tick;
445 talk_ids(false, LANG_LOADING_PERCENT,
446 TALK_ID(i * 100 / pti.nb_tracks, UNIT_PERCENT));
447 }
448 if (action_userabort(TIMEOUT_NOBLOCK))
449 goto exit;
450
451 if (i == pti.curr_playing)
452 continue;
453
454 if (playlist_get_track_info(NULL, i, &pltrack) >= 0)
455 {
456 bool ret = false;
457 if ((fd = open(pltrack.filename, O_RDONLY)) >= 0)
458 {
459 ret = get_metadata(&id3, fd, pltrack.filename);
460 close(fd);
461 if (ret)
462 {
463 if (i < pti.curr_playing) {
464 pti.secs[ePT_SECS_BEF] += id3.length / 1000;
465 pti.kbs[ePT_KBS_BEF] += id3.filesize / 1024;
466 } else {
467 pti.secs[ePT_SECS_AFT] += id3.length / 1000;
468 pti.kbs[ePT_KBS_AFT] += id3.filesize / 1024;
469 }
470 }
471 }
472
473 if (!ret)
474 {
475 error_count++;
476 continue;
477 }
478 }
479 else
480 {
481 error_count++;
482 break;
483 }
484 }
485
486 if (error_count > 0)
487 {
488 splash(HZ, ID2P(LANG_PLAYTIME_ERROR));
489 }
490
491 pti.nb_tracks -= error_count;
492 pti.secs[ePT_SECS_TTL] = pti.secs[ePT_SECS_BEF] + pti.secs[ePT_SECS_AFT];
493 pti.trk_secs[ePT_SECS_TTL] = pti.trk_secs[ePT_SECS_BEF] + pti.trk_secs[ePT_SECS_AFT];
494 pti.kbs[ePT_KBS_TTL] = pti.kbs[ePT_KBS_BEF] + pti.kbs[ePT_KBS_AFT];
495
496 struct gui_synclist pt_lists;
497 int key;
498
499 gui_synclist_init(&pt_lists, &playing_time_get_info, &pti, true, 1, NULL);
500 if (global_settings.talk_menu)
501 gui_synclist_set_voice_callback(&pt_lists, playing_time_speak_info);
502 gui_synclist_set_nb_items(&pt_lists, 8);
503 gui_synclist_set_title(&pt_lists, str(LANG_PLAYING_TIME), NOICON);
504 gui_synclist_draw(&pt_lists);
505 gui_synclist_speak_item(&pt_lists);
506 while (true) {
507 if (list_do_action(CONTEXT_LIST, HZ/2, &pt_lists, &key) == 0
508 && key!=ACTION_NONE && key!=ACTION_UNKNOWN)
509 {
510 talk_force_shutup();
511 return(default_event_handler(key) == SYS_USB_CONNECTED);
512 }
513
514 }
515
516 exit:
517 return false;
518}
519 204
520/* CONTEXT_WPS playlist options */ 205/* CONTEXT_WPS playlist options */
521static bool shuffle_playlist(void) 206static bool shuffle_playlist(void)
@@ -545,6 +230,11 @@ static int wps_view_cur_playlist(void)
545 return 0; 230 return 0;
546} 231}
547 232
233static void playing_time(void)
234{
235 plugin_load(PLUGIN_APPS_DIR"/playing_time.rock", NULL);
236}
237
548MENUITEM_FUNCTION(wps_view_cur_playlist_item, 0, ID2P(LANG_VIEW_DYNAMIC_PLAYLIST), 238MENUITEM_FUNCTION(wps_view_cur_playlist_item, 0, ID2P(LANG_VIEW_DYNAMIC_PLAYLIST),
549 wps_view_cur_playlist, NULL, Icon_NOICON); 239 wps_view_cur_playlist, NULL, Icon_NOICON);
550MENUITEM_FUNCTION(search_playlist_item, 0, ID2P(LANG_SEARCH_IN_PLAYLIST), 240MENUITEM_FUNCTION(search_playlist_item, 0, ID2P(LANG_SEARCH_IN_PLAYLIST),