Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Playback: Move internal track list onto buffer

Does away the statically-allocated track list which frees quite
a fair amount of in-RAM size.

There's no compile-time hard track limit.

Recommended TODO (but not right away): Have data small enough use
the handle structure as its buffer data area. Almost the entire
handle structure is unused for simple allocations without any
associated filesystem path.

Change-Id: I74a4561e5a837e049811ac421722ec00dadc0d50

+483 -329
+6
apps/buffering.c
··· 43 43 /* #define LOGF_ENABLE */ 44 44 #include "logf.h" 45 45 46 + #define BUF_MAX_HANDLES 384 47 + 46 48 /* macros to enable logf for queues 47 49 logging on SYS_TIMEOUT can be disabled */ 48 50 #ifdef SIMULATOR ··· 1120 1122 return true; 1121 1123 } 1122 1124 #endif 1125 + if (handle_id <= 0) { 1126 + return true; 1127 + } 1128 + 1123 1129 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id); 1124 1130 return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id); 1125 1131 }
+1 -2
apps/buffering.h
··· 36 36 TYPE_ATOMIC_AUDIO, 37 37 TYPE_CUESHEET, 38 38 TYPE_BITMAP, 39 + TYPE_RAW_ATOMIC, 39 40 }; 40 41 41 42 /* Error return values */ ··· 73 74 * amount of data is ready (unless EOF is reached). 74 75 * NOTE: Tail operations are only legal when the end of the file is buffered. 75 76 ****************************************************************************/ 76 - 77 - #define BUF_MAX_HANDLES 256 78 77 79 78 int bufopen(const char *file, size_t offset, enum data_type type, 80 79 void *user_data);
+471 -327
apps/playback.c
··· 73 73 #define AUDIO_REBUFFER_GUESS_SIZE (1024*32) 74 74 75 75 /* Define LOGF_ENABLE to enable logf output in this file */ 76 - /* #define LOGF_ENABLE */ 76 + #if 0 77 + #define LOGF_ENABLE 78 + #endif 77 79 #include "logf.h" 78 80 79 81 /* Macros to enable logf for queues ··· 193 195 } filling = STATE_IDLE; 194 196 195 197 /* Track info - holds information about each track in the buffer */ 198 + #ifdef HAVE_ALBUMART 199 + #define TRACK_INFO_AA MAX_MULTIPLE_AA 200 + #else 201 + #define TRACK_INFO_AA 0 202 + #endif 203 + 204 + #ifdef HAVE_CODEC_BUFFERING 205 + #define TRACK_INFO_CODEC 1 206 + #else 207 + #define TRACK_INFO_CODEC 0 208 + #endif 209 + 210 + #define TRACK_INFO_HANDLES (3 + TRACK_INFO_AA + TRACK_INFO_CODEC) 211 + 196 212 struct track_info 197 213 { 214 + int self_hid; /* handle for the info on buffer */ 215 + 198 216 /* In per-track allocated order: */ 199 - int id3_hid; /* Metadata handle ID */ 200 - int cuesheet_hid; /* Parsed cuesheet handle ID */ 217 + union { 218 + int handle[TRACK_INFO_HANDLES]; /* array mirror for efficient wipe/close */ 219 + struct { 220 + int id3_hid; /* Metadata handle ID */ 221 + int cuesheet_hid; /* Parsed cuesheet handle ID */ 201 222 #ifdef HAVE_ALBUMART 202 - int aa_hid[MAX_MULTIPLE_AA];/* Album art handle IDs */ 223 + int aa_hid[MAX_MULTIPLE_AA]; /* Album art handle IDs */ 203 224 #endif 204 225 #ifdef HAVE_CODEC_BUFFERING 205 - int codec_hid; /* Buffered codec handle ID */ 226 + int codec_hid; /* Buffered codec handle ID */ 206 227 #endif 207 - int audio_hid; /* Main audio data handle ID */ 208 - size_t filesize; /* File total length on disk 209 - TODO: This should be stored 210 - in the handle or the 211 - id3 and would use less 212 - ram */ 228 + int audio_hid; /* Main audio data handle ID */ 229 + }; }; 230 + off_t filesize; /* File total length on disk 231 + TODO: This should be stored 232 + in the handle or the 233 + id3 and would use less 234 + ram */ 213 235 }; 214 236 215 - /* Track list - holds info about all buffered tracks */ 216 - #if MEMORYSIZE >= 32 217 - #define TRACK_LIST_LEN 128 /* Must be 2^int(+n) */ 218 - #elif MEMORYSIZE >= 16 219 - #define TRACK_LIST_LEN 64 220 - #elif MEMORYSIZE >= 8 221 - #define TRACK_LIST_LEN 32 222 - #else 223 - #define TRACK_LIST_LEN 16 224 - #endif 237 + /* On-buffer info format; includes links */ 238 + struct track_buf_info 239 + { 240 + int link[2]; /* prev/next handles */ 241 + struct track_info info; 242 + }; 225 243 226 - #define TRACK_LIST_MASK (TRACK_LIST_LEN-1) 244 + #define FOR_EACH_TRACK_INFO_HANDLE(i) \ 245 + for (int i = 0; i < TRACK_INFO_HANDLES; i++) 227 246 228 247 static struct 229 248 { 230 - /* read, write and current are maintained unwrapped, limited only by the 231 - unsigned int range and wrap-safe comparisons are used */ 232 - 233 - /* NOTE: there appears to be a bug in arm-elf-eabi-gcc 4.4.4 for ARMv4 where 234 - if 'end' follows 'start' in this structure, track_list_count performs 235 - 'start - end' rather than 'end - start', giving negative count values... 236 - so leave it this way for now! */ 237 - unsigned int end; /* Next open position */ 238 - unsigned int start; /* First track in list */ 239 - unsigned int current; /* Currently decoding track */ 240 - struct track_info tracks[TRACK_LIST_LEN]; /* Buffered track information */ 249 + /* TODO: perhaps cache -1/+1 delta handles if speed ever matters much 250 + because those lookups are common; also could cache a few recent 251 + acccesses */ 252 + int first_hid; /* handle of first track in list */ 253 + int current_hid; /* handle of track delta 0 */ 254 + int last_hid; /* handle of last track in list */ 255 + int in_progress_hid; /* track in process of loading */ 256 + unsigned int count; /* number of tracks in list */ 241 257 } track_list; /* (A, O-) */ 242 258 243 259 244 260 /* Playlist steps from playlist position to next track to be buffered */ 245 261 static int playlist_peek_offset = 0; 246 - 247 - /* Metadata handle of track load in progress (meaning all handles have not 248 - yet been opened for the track, id3 always exists or the track does not) 249 - 250 - Tracks are keyed by their metadata handles if track list pointers are 251 - insufficient to make comparisons */ 252 - static int in_progress_id3_hid = ERR_HANDLE_NOT_FOUND; 253 262 254 263 #ifdef HAVE_DISK_STORAGE 255 264 /* Buffer margin A.K.A. anti-skip buffer (in seconds) */ ··· 443 452 444 453 /** --- Track info --- **/ 445 454 446 - /* Close a handle and mark it invalid */ 447 - static void track_info_close_handle(int *hid_p) 455 + static void track_info_close_handle(int *hidp) 448 456 { 449 - int hid = *hid_p; 450 - 451 - /* bufclose returns true if the handle is not found, or if it is closed 452 - * successfully, so these checks are safe on non-existant handles */ 453 - if (hid >= 0) 454 - bufclose(hid); 455 - 456 - /* Always reset to "no handle" in case it was something else */ 457 - *hid_p = ERR_HANDLE_NOT_FOUND; 457 + bufclose(*hidp); 458 + *hidp = ERR_HANDLE_NOT_FOUND; 458 459 } 459 460 460 - /* Close all handles in a struct track_info and clear it */ 461 - static void track_info_close(struct track_info *info) 461 + /* Invalidate all members to initial values - does not close handles or sync */ 462 + static void track_info_wipe(struct track_info *infop) 462 463 { 463 - /* Close them in the order they are allocated on the buffer to speed up 464 - the handle searching */ 465 - track_info_close_handle(&info->id3_hid); 466 - track_info_close_handle(&info->cuesheet_hid); 467 - #ifdef HAVE_ALBUMART 468 - FOREACH_ALBUMART(i) 469 - track_info_close_handle(&info->aa_hid[i]); 470 - #endif 471 - #ifdef HAVE_CODEC_BUFFERING 472 - track_info_close_handle(&info->codec_hid); 473 - #endif 474 - track_info_close_handle(&info->audio_hid); 475 - info->filesize = 0; 476 - } 464 + /* don't touch ->self_hid */ 477 465 478 - /* Invalidate all members to initial values - does not close handles */ 479 - static void track_info_wipe(struct track_info * info) 480 - { 481 - info->id3_hid = ERR_HANDLE_NOT_FOUND; 482 - info->cuesheet_hid = ERR_HANDLE_NOT_FOUND; 483 - #ifdef HAVE_ALBUMART 484 - FOREACH_ALBUMART(i) 485 - info->aa_hid[i] = ERR_HANDLE_NOT_FOUND; 486 - #endif 487 - #ifdef HAVE_CODEC_BUFFERING 488 - info->codec_hid = ERR_HANDLE_NOT_FOUND; 489 - #endif 490 - info->audio_hid = ERR_HANDLE_NOT_FOUND; 491 - info->filesize = 0; 466 + FOR_EACH_TRACK_INFO_HANDLE(i) 467 + infop->handle[i] = ERR_HANDLE_NOT_FOUND; 468 + 469 + infop->filesize = 0; 492 470 } 493 - 494 471 495 472 /** --- Track list --- **/ 473 + 474 + /* Clear tracks in the list, optionally preserving the current track - 475 + returns 'false' if the operation was changed */ 476 + enum track_clear_action 477 + { 478 + TRACK_LIST_CLEAR_ALL = 0, /* Clear all tracks */ 479 + TRACK_LIST_KEEP_CURRENT, /* Keep current only; clear before + after */ 480 + TRACK_LIST_KEEP_NEW /* Keep current and those that follow */ 481 + }; 496 482 497 483 /* Initialize the track list */ 498 484 static void INIT_ATTR track_list_init(void) 499 485 { 500 - int i; 501 - for (i = 0; i < TRACK_LIST_LEN; i++) 502 - track_info_wipe(&track_list.tracks[i]); 503 - 504 - track_list.start = track_list.end = track_list.current; 486 + track_list.first_hid = 0; 487 + track_list.current_hid = 0; 488 + track_list.last_hid = 0; 489 + track_list.in_progress_hid = 0; 490 + track_list.count = 0; 505 491 } 506 492 507 493 /* Return number of items allocated in the list */ 508 - static unsigned int track_list_count(void) 494 + static inline unsigned int track_list_count(void) 509 495 { 510 - return track_list.end - track_list.start; 496 + return track_list.count; 511 497 } 512 498 513 499 /* Return true if the list is empty */ 514 500 static inline bool track_list_empty(void) 515 501 { 516 - return track_list.end == track_list.start; 502 + return track_list.count == 0; 517 503 } 518 504 519 - /* Returns true if the list is holding the maximum number of items */ 520 - static bool track_list_full(void) 505 + /* Returns a pointer to the track info data on the buffer */ 506 + static struct track_buf_info * track_buf_info_get(int hid) 521 507 { 522 - return track_list.end - track_list.start >= TRACK_LIST_LEN; 508 + void *p; 509 + ssize_t size = bufgetdata(hid, sizeof (struct track_buf_info), &p); 510 + return size == (ssize_t)sizeof (struct track_buf_info) ? p : NULL; 523 511 } 524 512 525 - /* Test if the index is within the allocated range */ 526 - static bool track_list_in_range(int pos) 513 + /* Synchronize the buffer object with the cached track info */ 514 + static bool track_info_sync(const struct track_info *infop) 527 515 { 528 - return (int)(pos - track_list.start) >= 0 && 529 - (int)(pos - track_list.end) < 0; 516 + struct track_buf_info *tbip = track_buf_info_get(infop->self_hid); 517 + if (!tbip) 518 + return false; 519 + 520 + tbip->info = *infop; 521 + return true; 530 522 } 531 523 532 - static struct track_info * track_list_entry(int pos) 524 + /* Return track info a given offset from the info referenced by hid and 525 + * place a copy into *infop, if provided */ 526 + static struct track_buf_info * 527 + track_list_get_info_from(int hid, int offset, struct track_info *infop) 533 528 { 534 - return &track_list.tracks[pos & TRACK_LIST_MASK]; 535 - } 529 + int sgn = SGN(offset); 530 + struct track_buf_info *tbip; 531 + 532 + while (1) 533 + { 534 + if (!(tbip = track_buf_info_get(hid))) 535 + break; 536 + 537 + if (!offset) 538 + break; 536 539 537 - /* Return the info of the last allocation plus an offset, NULL if result is 538 - out of bounds */ 539 - static struct track_info * track_list_last(int offset) 540 - { 541 - /* Last is before the end since the end isn't inclusive */ 542 - unsigned int pos = track_list.end + offset - 1; 540 + if ((hid = tbip->link[(unsigned)(sgn + 1) / 2]) <= 0) 541 + { 542 + tbip = NULL; 543 + break; 544 + } 543 545 544 - if (!track_list_in_range(pos)) 545 - return NULL; 546 + offset -= sgn; 547 + } 546 548 547 - return track_list_entry(pos); 549 + if (infop) 550 + { 551 + if (tbip) 552 + { 553 + *infop = tbip->info; 554 + } 555 + else 556 + { 557 + track_info_wipe(infop); 558 + infop->self_hid = ERR_HANDLE_NOT_FOUND; 559 + } 560 + } 561 + 562 + return tbip; 548 563 } 549 564 550 - /* Allocate space at the end for another track if not full */ 551 - static struct track_info * track_list_alloc_track(void) 565 + /* Commit the track info to the buffer updated with the provided source info */ 566 + static bool track_list_commit_buf_info(struct track_buf_info *tbip, 567 + const struct track_info *src_infop) 552 568 { 553 - if (track_list_full()) 554 - return NULL; 569 + /* Leaves the list unmodified if anything fails */ 570 + if (tbip->link[1] != ERR_HANDLE_NOT_FOUND) 571 + return false; 555 572 556 - return track_list_entry(track_list.end++); 557 - } 573 + int hid = tbip->info.self_hid; 574 + int last_hid = track_list.last_hid; 575 + struct track_buf_info *last_tbip = NULL; 558 576 559 - /* Remove the last track entry allocated in order to support backing out 560 - of a track load */ 561 - static void track_list_unalloc_track(void) 562 - { 563 - if (track_list_empty()) 564 - return; 577 + if (last_hid > 0 && !(last_tbip = track_buf_info_get(last_hid))) 578 + return false; 579 + 580 + tbip->info = *src_infop; 565 581 566 - track_list.end--; 582 + /* Insert last */ 583 + tbip->link[0] = last_hid; 584 + tbip->link[1] = 0; /* "In list" */ 567 585 568 - if (track_list.current == track_list.end && 569 - track_list.current != track_list.start) 586 + if (last_tbip) 570 587 { 571 - /* Current _must_ remain within bounds */ 572 - track_list.current--; 588 + last_tbip->link[1] = hid; 573 589 } 590 + else 591 + { 592 + track_list.first_hid = hid; 593 + track_list.current_hid = hid; 594 + } 595 + 596 + track_list.last_hid = hid; 597 + track_list.count++; 598 + return true; 574 599 } 575 600 576 - /* Return current track plus an offset, NULL if result is out of bounds */ 577 - static struct track_info * track_list_current(int offset) 601 + /* Free the track buffer entry and possibly remove it from the list if it 602 + was succesfully added at some point */ 603 + static void track_list_free_buf_info(struct track_buf_info *tbip) 578 604 { 579 - unsigned int pos = track_list.current + offset; 605 + int hid = tbip->info.self_hid; 606 + int next_hid = tbip->link[1]; 607 + 608 + if (next_hid != ERR_HANDLE_NOT_FOUND) 609 + { 610 + int prev_hid = tbip->link[0]; 611 + struct track_buf_info *prev_tbip = NULL; 612 + struct track_buf_info *next_tbip = NULL; 613 + 614 + if ((prev_hid > 0 && !(prev_tbip = track_buf_info_get(prev_hid))) || 615 + (next_hid > 0 && !(next_tbip = track_buf_info_get(next_hid)))) 616 + { 617 + return; 618 + } 619 + 620 + if (prev_tbip) 621 + { 622 + prev_tbip->link[1] = next_hid; 623 + } 624 + else 625 + { 626 + /* Was the first track; new first track is next one */ 627 + track_list.first_hid = next_hid; 628 + 629 + if (hid == track_list.current_hid) 630 + { 631 + /* Was the current track; new current track is next one */ 632 + track_list.current_hid = next_hid; 633 + } 634 + } 580 635 581 - if (!track_list_in_range(pos)) 582 - return NULL; 636 + if (next_tbip) 637 + { 638 + next_tbip->link[0] = prev_hid; 639 + } 640 + else 641 + { 642 + /* Was the last track; new last track is previous one */ 643 + track_list.last_hid = prev_hid; 583 644 584 - return track_list_entry(pos); 645 + if (hid == track_list.current_hid) 646 + { 647 + /* Was the current track; new current track is previous one */ 648 + track_list.current_hid = prev_hid; 649 + } 650 + } 651 + 652 + track_list.count--; 653 + } 654 + 655 + /* No movement allowed during bufclose calls */ 656 + buf_pin_handle(hid, true); 657 + 658 + FOR_EACH_TRACK_INFO_HANDLE(i) 659 + bufclose(tbip->info.handle[i]); 660 + 661 + /* Finally, the handle itself */ 662 + bufclose(hid); 663 + } 664 + 665 + /* Return current track plus an offset */ 666 + static bool track_list_current(int offset, struct track_info *infop) 667 + { 668 + return !!track_list_get_info_from(track_list.current_hid, offset, infop); 585 669 } 586 670 587 671 /* Return current based upon what's intended that the user sees - not 588 672 necessarily where decoding is taking place */ 589 - static struct track_info * track_list_user_current(int offset) 673 + static bool track_list_user_current(int offset, struct track_info *infop) 590 674 { 591 675 if (skip_pending == TRACK_SKIP_AUTO || 592 676 skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST) ··· 594 678 offset--; 595 679 } 596 680 597 - return track_list_current(offset); 681 + return !!track_list_get_info_from(track_list.current_hid, offset, infop); 598 682 } 599 683 600 684 /* Advance current track by an offset, return false if result is out of 601 685 bounds */ 602 - static struct track_info * track_list_advance_current(int offset) 686 + static bool track_list_advance_current(int offset, struct track_info *infop) 603 687 { 604 - unsigned int pos = track_list.current + offset; 688 + struct track_buf_info *new_bufinfop = 689 + track_list_get_info_from(track_list.current_hid, offset, infop); 605 690 606 - if (!track_list_in_range(pos)) 607 - return NULL; 691 + if (!new_bufinfop) 692 + return false; 608 693 609 - track_list.current = pos; 610 - return track_list_entry(pos); 694 + track_list.current_hid = new_bufinfop->info.self_hid; 695 + return true; 611 696 } 612 697 613 - /* Clear tracks in the list, optionally preserving the current track - 614 - returns 'false' if the operation was changed */ 615 - enum track_clear_action 698 + /* Return the info of the last allocation plus an offset, NULL if result is 699 + out of bounds */ 700 + static bool track_list_last(int offset, struct track_info *infop) 616 701 { 617 - TRACK_LIST_CLEAR_ALL = 0, /* Clear all tracks */ 618 - TRACK_LIST_KEEP_CURRENT, /* Keep current only; clear before + after */ 619 - TRACK_LIST_KEEP_NEW /* Keep current and those that follow */ 620 - }; 702 + return !!track_list_get_info_from(track_list.last_hid, offset, infop); 703 + } 621 704 622 - static void track_list_clear(enum track_clear_action action) 705 + /* Allocate a new struct track_info on the buffer; does not add to list */ 706 + static bool track_list_alloc_info(struct track_info *infop) 623 707 { 624 - logf("%s(%d)", __func__, (int)action); 708 + int hid = bufalloc(NULL, sizeof (struct track_buf_info), TYPE_RAW_ATOMIC); 709 + 710 + track_info_wipe(infop); 711 + 712 + struct track_buf_info *tbip = track_buf_info_get(hid); 713 + if (!tbip) 714 + { 715 + infop->self_hid = ERR_HANDLE_NOT_FOUND; 716 + bufclose(hid); 717 + return false; 718 + } 719 + 720 + infop->self_hid = hid; 721 + 722 + tbip->link[0] = 0; 723 + tbip->link[1] = ERR_HANDLE_NOT_FOUND; /* "Not in list" */ 724 + tbip->info.self_hid = hid; 725 + track_info_wipe(&tbip->info); 726 + 727 + return true; 728 + } 729 + 730 + /* Actually commit the track info to the track list */ 731 + static bool track_list_commit_info(const struct track_info *infop) 732 + { 733 + struct track_buf_info *tbip = track_buf_info_get(infop->self_hid); 734 + if (!tbip) 735 + return false; 736 + 737 + return track_list_commit_buf_info(tbip, infop); 738 + } 739 + 740 + /* Free the track entry and possibly remove it from the list if it was 741 + succesfully added at some point */ 742 + static void track_list_free_info(struct track_info *infop) 743 + { 744 + struct track_buf_info *tbip = track_buf_info_get(infop->self_hid); 745 + if (!tbip) 746 + return; 747 + 748 + track_list_free_buf_info(tbip); 749 + } 750 + 751 + /* Close all open handles in the range except the for the current track 752 + if preserving that */ 753 + static void track_list_clear(unsigned int action) 754 + { 755 + logf("%s:action=%u", __func__, action); 625 756 626 757 /* Don't care now since rebuffering is imminent */ 627 758 buf_set_watermark(0); 628 759 629 760 if (action != TRACK_LIST_CLEAR_ALL) 630 761 { 631 - struct track_info *cur = track_list_current(0); 632 - 633 - if (!cur || cur->id3_hid < 0) 762 + struct track_info info; 763 + if (!track_list_current(0, &info) || info.id3_hid < 0) 634 764 action = TRACK_LIST_CLEAR_ALL; /* Nothing worthwhile keeping */ 635 765 } 636 766 637 - /* Noone should see this progressing */ 638 - int start = track_list.start; 639 - int current = track_list.current; 640 - int end = track_list.end; 641 - 642 - track_list.start = current; 767 + int hid = track_list.first_hid; 768 + int current_hid = track_list.current_hid; 769 + int last_hid = action == TRACK_LIST_KEEP_NEW ? current_hid : 0; 643 770 644 - switch (action) 771 + while (hid != last_hid) 645 772 { 646 - case TRACK_LIST_CLEAR_ALL: 647 - /* Result: .start = .current, .end = .current */ 648 - track_list.end = current; 649 - break; 773 + struct track_buf_info *tbip = track_buf_info_get(hid); 774 + if (!tbip) 775 + break; 650 776 651 - case TRACK_LIST_KEEP_CURRENT: 652 - /* Result: .start = .current, .end = .current + 1 */ 653 - track_list.end = current + 1; 654 - break; 655 - 656 - case TRACK_LIST_KEEP_NEW: 657 - /* Result: .start = .current, .end = .end */ 658 - end = current; 659 - break; 660 - } 777 + int next_hid = tbip->link[1]; 661 778 662 - /* Close all open handles in the range except the for the current track 663 - if preserving that */ 664 - while (start != end) 665 - { 666 - if (action != TRACK_LIST_KEEP_CURRENT || start != current) 779 + if (action != TRACK_LIST_KEEP_CURRENT || hid != current_hid) 667 780 { 668 - struct track_info *info = 669 - &track_list.tracks[start & TRACK_LIST_MASK]; 670 - 671 781 /* If this is the in-progress load, abort it */ 672 - if (in_progress_id3_hid >= 0 && 673 - info->id3_hid == in_progress_id3_hid) 674 - { 675 - in_progress_id3_hid = ERR_HANDLE_NOT_FOUND; 676 - } 782 + if (hid == track_list.in_progress_hid) 783 + track_list.in_progress_hid = 0; 677 784 678 - track_info_close(info); 785 + track_list_free_buf_info(tbip); 679 786 } 680 787 681 - start++; 788 + hid = next_hid; 682 789 } 683 790 } 684 791 ··· 961 1068 #endif 962 1069 963 1070 /* Watermark is a function of the bitrate of the last track in the buffer */ 1071 + struct track_info info; 964 1072 struct mp3entry *id3 = NULL; 965 - struct track_info *info = track_list_last(0); 966 1073 967 - if (info) 968 - id3 = valid_mp3entry(bufgetid3(info->id3_hid)); 1074 + if (track_list_last(0, &info)) 1075 + id3 = valid_mp3entry(bufgetid3(info.id3_hid)); 969 1076 970 1077 if (id3) 971 1078 { ··· 980 1087 track that fits, in which case we should avoid constant buffer 981 1088 low events */ 982 1089 if (track_list_count() > 1) 983 - bytes = info->filesize + 1; 1090 + bytes = info.filesize + 1; 984 1091 } 985 1092 } 986 1093 else 987 1094 { 988 1095 /* Then set the minimum - this should not occur anyway */ 989 - logf("fwmark: No id3 for last track (s%u/c%u/e%u)", 990 - track_list.start, track_list.current, track_list.end); 1096 + logf("fwmark: No id3 for last track (f=%d:c=%d:l=%d)", 1097 + track_list.first_hid, track_list.current_hid, track_list.last_hid); 991 1098 } 992 1099 993 1100 /* Actually setting zero disables the notification and we use that 994 1101 to detect that it has been reset */ 995 1102 buf_set_watermark(MAX(bytes, 1)); 996 - logf("fwmark: %lu", (unsigned long)bytes); 1103 + logf("fwmark: %zu", bytes); 997 1104 } 998 1105 999 1106 ··· 1126 1233 1127 1234 /* Bring the user current mp3entry up to date and set a new offset for the 1128 1235 buffered metadata */ 1129 - static void playing_id3_sync(struct track_info *user_info, 1236 + static void playing_id3_sync(struct track_info *user_infop, 1130 1237 unsigned long elapsed, unsigned long offset) 1131 1238 { 1132 1239 id3_mutex_lock(); 1133 1240 1134 - struct mp3entry *id3 = bufgetid3(user_info->id3_hid); 1241 + struct mp3entry *id3 = bufgetid3(user_infop->id3_hid); 1135 1242 struct mp3entry *playing_id3 = id3_get(PLAYING_ID3); 1136 1243 1137 1244 pcm_play_lock(); ··· 1290 1397 if (id3->path[0] != '\0') 1291 1398 return true; /* Already filled */ 1292 1399 1293 - struct track_info *info = track_list_user_current(offset); 1400 + struct track_info info; 1294 1401 1295 - if (!info) 1402 + if (!track_list_user_current(offset, &info)) 1296 1403 { 1297 1404 struct mp3entry *ub_id3 = id3_get(UNBUFFERED_ID3); 1298 1405 1299 - if (offset > 0 && track_list_user_current(offset - 1)) 1406 + if (offset > 0 && track_list_user_current(offset - 1, NULL)) 1300 1407 { 1301 1408 /* Try the unbuffered id3 since we're moving forward */ 1302 1409 if (ub_id3->path[0] != '\0') ··· 1306 1413 } 1307 1414 } 1308 1415 } 1309 - else if (bufreadid3(info->id3_hid, id3)) 1416 + else if (bufreadid3(info.id3_hid, id3)) 1310 1417 { 1311 1418 id3->cuesheet = NULL; 1312 1419 return true; ··· 1348 1455 } 1349 1456 1350 1457 /* Get the codec into ram and initialize it - keep it if it's ready */ 1351 - static bool audio_init_codec(struct track_info *track_info, 1458 + static bool audio_init_codec(struct track_info *track_infop, 1352 1459 struct mp3entry *track_id3) 1353 1460 { 1354 1461 int codt_loaded = get_audio_base_codec_type(codec_loaded()); ··· 1366 1473 /* Close any buffered codec (we could have skipped directly to a 1367 1474 format transistion that is the same format as the current track 1368 1475 and the buffered one is no longer needed) */ 1369 - track_info_close_handle(&track_info->codec_hid); 1370 - #endif 1476 + track_info_close_handle(&track_infop->codec_hid); 1477 + track_info_sync(track_infop); 1478 + #endif /* HAVE_CODEC_BUFFERING */ 1371 1479 return true; 1372 1480 } 1373 1481 else ··· 1383 1491 #ifdef HAVE_CODEC_BUFFERING 1384 1492 /* Codec thread will close the handle even if it fails and will load from 1385 1493 storage if hid is not valid or the buffer load fails */ 1386 - hid = track_info->codec_hid; 1387 - track_info->codec_hid = ERR_HANDLE_NOT_FOUND; 1494 + hid = track_infop->codec_hid; 1495 + track_infop->codec_hid = ERR_HANDLE_NOT_FOUND; 1496 + track_info_sync(track_infop); 1388 1497 #endif 1389 1498 1390 1499 return codec_load(hid, track_id3->codectype); 1391 - (void)track_info; /* When codec buffering isn't supported */ 1500 + (void)track_infop; /* When codec buffering isn't supported */ 1392 1501 } 1393 1502 1394 1503 #ifdef HAVE_TAGCACHE ··· 1452 1561 /* Start the codec for the current track scheduled to be decoded */ 1453 1562 static bool audio_start_codec(bool auto_skip) 1454 1563 { 1455 - struct track_info *info = track_list_current(0); 1456 - struct mp3entry *cur_id3 = valid_mp3entry(bufgetid3(info->id3_hid)); 1564 + struct track_info info; 1565 + track_list_current(0, &info); 1566 + 1567 + struct mp3entry *cur_id3 = valid_mp3entry(bufgetid3(info.id3_hid)); 1457 1568 1458 1569 if (!cur_id3) 1459 1570 return false; 1460 1571 1461 - buf_pin_handle(info->id3_hid, true); 1572 + buf_pin_handle(info.id3_hid, true); 1462 1573 1463 - if (!audio_init_codec(info, cur_id3)) 1574 + if (!audio_init_codec(&info, cur_id3)) 1464 1575 { 1465 - buf_pin_handle(info->id3_hid, false); 1576 + buf_pin_handle(info.id3_hid, false); 1466 1577 return false; 1467 1578 } 1468 1579 ··· 1523 1634 /* Update the codec API with the metadata and track info */ 1524 1635 id3_write(CODEC_ID3, cur_id3); 1525 1636 1526 - ci.audio_hid = info->audio_hid; 1527 - ci.filesize = info->filesize; 1528 - buf_set_base_handle(info->audio_hid); 1637 + ci.audio_hid = info.audio_hid; 1638 + ci.filesize = info.filesize; 1639 + buf_set_base_handle(info.audio_hid); 1529 1640 1530 1641 /* All required data is now available for the codec */ 1531 1642 codec_go(); ··· 1538 1649 send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3); 1539 1650 } 1540 1651 1541 - buf_pin_handle(info->id3_hid, false); 1652 + buf_pin_handle(info.id3_hid, false); 1542 1653 return true; 1543 1654 1544 1655 (void)auto_skip; /* ifndef HAVE_TAGCACHE */ ··· 1549 1660 1550 1661 /* Load and parse a cuesheet for the file - returns false if the buffer 1551 1662 is full */ 1552 - static bool audio_load_cuesheet(struct track_info *info, 1663 + static bool audio_load_cuesheet(struct track_info *infop, 1553 1664 struct mp3entry *track_id3) 1554 1665 { 1555 1666 struct cuesheet *cue = get_current_cuesheet(); 1556 1667 track_id3->cuesheet = NULL; 1557 1668 1558 - if (cue && info->cuesheet_hid == ERR_HANDLE_NOT_FOUND) 1669 + if (cue && infop->cuesheet_hid == ERR_HANDLE_NOT_FOUND) 1559 1670 { 1560 1671 /* If error other than a full buffer, then mark it "unsupported" to 1561 1672 avoid reloading attempt */ ··· 1595 1706 if (hid < 0) 1596 1707 logf("Cuesheet loading failed"); 1597 1708 1598 - info->cuesheet_hid = hid; 1709 + infop->cuesheet_hid = hid; 1599 1710 } 1600 1711 } 1601 1712 ··· 1604 1715 1605 1716 #ifdef HAVE_ALBUMART 1606 1717 /* Load any album art for the file - returns false if the buffer is full */ 1607 - static bool audio_load_albumart(struct track_info *info, 1718 + static bool audio_load_albumart(struct track_info *infop, 1608 1719 struct mp3entry *track_id3) 1609 1720 { 1610 1721 FOREACH_ALBUMART(i) 1611 1722 { 1612 1723 struct bufopen_bitmap_data user_data; 1613 - int *aa_hid = &info->aa_hid[i]; 1724 + int *aa_hid = &infop->aa_hid[i]; 1614 1725 int hid = ERR_UNSUPPORTED_TYPE; 1615 1726 1616 1727 /* albumart_slots may change during a yield of bufopen, ··· 1656 1767 logf("Album art loading failed"); 1657 1768 hid = ERR_UNSUPPORTED_TYPE; 1658 1769 } 1770 + else 1771 + { 1772 + logf("Loaded album art:%dx%d", user_data.dim->width, 1773 + user_data.dim->height); 1774 + } 1659 1775 1660 1776 *aa_hid = hid; 1661 1777 } ··· 1668 1784 #ifdef HAVE_CODEC_BUFFERING 1669 1785 /* Load a codec for the file onto the buffer - assumes we're working from the 1670 1786 currently loading track - not called for the current track */ 1671 - static bool audio_buffer_codec(struct track_info *track_info, 1787 + static bool audio_buffer_codec(struct track_info *track_infop, 1672 1788 struct mp3entry *track_id3) 1673 1789 { 1674 1790 /* This will not be the current track -> it cannot be the first and the 1675 1791 current track cannot be ahead of buffering -> there is a previous 1676 1792 track entry which is either current or ahead of the current */ 1677 - struct track_info *prev_info = track_list_last(-1); 1678 - struct mp3entry *prev_id3 = bufgetid3(prev_info->id3_hid); 1793 + struct track_info prev_info; 1794 + track_list_last(-1, &prev_info); 1795 + 1796 + struct mp3entry *prev_id3 = bufgetid3(prev_info.id3_hid); 1679 1797 1680 1798 /* If the previous codec is the same as this one, there is no need to 1681 1799 put another copy of it on the file buffer (in other words, only ··· 1701 1819 char codec_path[MAX_PATH+1]; /* Full path to codec */ 1702 1820 codec_get_full_path(codec_path, codec_fn); 1703 1821 1704 - track_info->codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL); 1822 + track_infop->codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL); 1705 1823 1706 - if (track_info->codec_hid >= 0) 1824 + if (track_infop->codec_hid > 0) 1707 1825 { 1708 - logf("Buffered codec: %d", track_info->codec_hid); 1826 + logf("Buffered codec: %d", track_infop->codec_hid); 1709 1827 return true; 1710 1828 } 1711 1829 ··· 1726 1844 */ 1727 1845 static int audio_load_track(void) 1728 1846 { 1729 - if (in_progress_id3_hid >= 0) 1847 + struct track_info info; 1848 + 1849 + if (track_list.in_progress_hid > 0) 1730 1850 { 1731 1851 /* There must be an info pointer if the in-progress id3 is even there */ 1732 - struct track_info *info = track_list_last(0); 1733 - 1734 - if (info->id3_hid == in_progress_id3_hid) 1852 + if (track_list_last(0, &info) && info.self_hid == track_list.in_progress_hid) 1735 1853 { 1736 1854 if (filling == STATE_FILLING) 1737 1855 { 1738 1856 /* Haven't finished the metadata but the notification is 1739 1857 anticipated to come soon */ 1740 - logf("%s(): in progress ok: %d", __func__, info->id3_hid); 1858 + logf("%s:in progress:id=%d", __func__, info.self_hid); 1741 1859 return LOAD_TRACK_OK; 1742 1860 } 1743 1861 else if (filling == STATE_FULL) ··· 1745 1863 /* Buffer was full trying to complete the load after the 1746 1864 metadata finished, so attempt to continue - older handles 1747 1865 should have been cleared already */ 1748 - logf("%s(): finishing load: %d", __func__, info->id3_hid); 1866 + logf("%s:finished:id=%d", __func__, info.self_hid); 1749 1867 filling = STATE_FILLING; 1750 - buffer_event_finished_callback(BUFFER_EVENT_FINISHED, &info->id3_hid); 1868 + buffer_event_finished_callback(BUFFER_EVENT_FINISHED, &info.id3_hid); 1751 1869 return LOAD_TRACK_OK; 1752 1870 } 1753 1871 } 1754 1872 1755 1873 /* Some old, stray buffering message */ 1756 - logf("%s(): already in progress: %d", __func__, info->id3_hid); 1874 + logf("%s:busy:id=%d", __func__, info.self_hid); 1757 1875 return LOAD_TRACK_ERR_BUSY; 1758 1876 } 1759 1877 1760 1878 filling = STATE_FILLING; 1761 1879 1762 - struct track_info *info = track_list_alloc_track(); 1763 - if (info == NULL) 1880 + if (!track_list_alloc_info(&info)) 1764 1881 { 1765 1882 /* List is full so stop buffering tracks - however, attempt to obtain 1766 1883 metadata as the unbuffered id3 */ 1767 - logf("No free tracks"); 1884 + logf("buffer full:alloc"); 1768 1885 filling = STATE_FULL; 1769 1886 } 1770 1887 1771 1888 playlist_peek_offset++; 1772 1889 1773 - logf("Buffering track: s%u/c%u/e%u/p%d", 1774 - track_list.start, track_list.current, track_list.end, 1890 + logf("Buffering track:f=%d:c=%d:l=%d:pk=%d", 1891 + track_list.first_hid, track_list.current_hid, track_list.last_hid, 1775 1892 playlist_peek_offset); 1776 1893 1777 1894 /* Get track name from current playlist read position */ ··· 1781 1898 1782 1899 while (1) 1783 1900 { 1784 - 1785 1901 trackname = playlist_peek(playlist_peek_offset, name_buf, 1786 1902 sizeof (name_buf)); 1787 1903 ··· 1809 1925 id3_write_locked(UNBUFFERED_ID3, NULL); 1810 1926 1811 1927 if (filling != STATE_FULL) 1812 - track_list_unalloc_track(); /* Free this entry */ 1928 + track_list_free_info(&info); /* Free this entry */ 1813 1929 1814 - playlist_peek_offset--; /* Maintain at last index */ 1930 + playlist_peek_offset--; /* Maintain at last index */ 1815 1931 1816 1932 /* We can end up here after the real last track signals its completion 1817 1933 and miss the transition to STATE_FINISHED esp. if dropping the last 1818 1934 songs of a playlist late in their load (2nd stage) */ 1819 - info = track_list_last(0); 1820 - 1821 - if (info && buf_handle_remaining(info->audio_hid) == 0) 1935 + if (track_list_last(0, &info) && buf_handle_remaining(info.audio_hid) == 0) 1822 1936 filling_is_finished(); 1823 1937 else 1824 1938 filling = STATE_END_OF_PLAYLIST; ··· 1828 1942 1829 1943 /* Successfully opened the file - get track metadata */ 1830 1944 if (filling == STATE_FULL || 1831 - (info->id3_hid = bufopen(trackname, 0, TYPE_ID3, NULL)) < 0) 1945 + (info.id3_hid = bufopen(trackname, 0, TYPE_ID3, NULL)) < 0) 1832 1946 { 1833 1947 /* Buffer or track list is full */ 1834 1948 struct mp3entry *ub_id3; ··· 1843 1957 1844 1958 if (filling != STATE_FULL) 1845 1959 { 1846 - track_list_unalloc_track(); 1960 + track_list_free_info(&info); 1847 1961 filling = STATE_FULL; 1848 1962 } 1849 1963 ··· 1852 1966 } 1853 1967 else 1854 1968 { 1969 + info.filesize = filesize(fd); 1970 + 1971 + if (!track_list_commit_info(&info)) 1972 + { 1973 + track_list_free_info(&info); 1974 + track_list.in_progress_hid = 0; 1975 + return LOAD_TRACK_ERR_FAILED; 1976 + } 1977 + 1855 1978 /* Successful load initiation */ 1856 - info->filesize = filesize(fd); 1857 - in_progress_id3_hid = info->id3_hid; /* Remember what's in-progress */ 1979 + track_list.in_progress_hid = info.self_hid; 1858 1980 } 1859 1981 1860 1982 close(fd); ··· 1865 1987 can load the codec, the album art and finally the audio data. 1866 1988 This is called on the audio thread after the buffering thread calls the 1867 1989 buffering_handle_finished_callback callback. */ 1868 - static int audio_finish_load_track(struct track_info *info) 1990 + static int audio_finish_load_track(struct track_info *infop) 1869 1991 { 1870 1992 int trackstat = LOAD_TRACK_OK; 1871 1993 1872 - if (info->id3_hid != in_progress_id3_hid) 1994 + if (infop->self_hid != track_list.in_progress_hid) 1873 1995 { 1874 1996 /* We must not be here if not! */ 1875 - logf("%s: wrong track %d/%d", __func__, info->id3_hid, 1876 - in_progress_id3_hid); 1997 + logf("%s:wrong track:hids=%d!=%d", __func__, infop->self_hid, 1998 + track_list.in_progress_hid); 1877 1999 return LOAD_TRACK_ERR_BUSY; 1878 2000 } 1879 2001 1880 2002 /* The current track for decoding (there is always one if the list is 1881 2003 populated) */ 1882 - struct track_info *cur_info = track_list_current(0); 1883 - struct mp3entry *track_id3 = valid_mp3entry(bufgetid3(info->id3_hid)); 2004 + struct track_info cur_info; 2005 + track_list_current(0, &cur_info); 2006 + 2007 + struct mp3entry *track_id3 = valid_mp3entry(bufgetid3(infop->id3_hid)); 1884 2008 1885 2009 if (!track_id3) 1886 2010 { ··· 1892 2016 } 1893 2017 1894 2018 /* Try to load a cuesheet for the track */ 1895 - if (!audio_load_cuesheet(info, track_id3)) 2019 + if (!audio_load_cuesheet(infop, track_id3)) 1896 2020 { 1897 2021 /* No space for cuesheet on buffer, not an error */ 1898 2022 filling = STATE_FULL; ··· 1901 2025 1902 2026 #ifdef HAVE_ALBUMART 1903 2027 /* Try to load album art for the track */ 1904 - if (!audio_load_albumart(info, track_id3)) 2028 + if (!audio_load_albumart(infop, track_id3)) 1905 2029 { 1906 2030 /* No space for album art on buffer, not an error */ 1907 2031 filling = STATE_FULL; ··· 1912 2036 /* All handles available to external routines are ready - audio and codec 1913 2037 information is private */ 1914 2038 1915 - if (info == track_list_user_current(0)) 2039 + struct track_info user_cur; 2040 + track_list_user_current(0, &user_cur); 2041 + if (infop->self_hid == user_cur.self_hid) 1916 2042 { 1917 2043 /* Send only when the track handles could not all be opened ahead of 1918 2044 time for the user's current track - otherwise everything is ready ··· 1923 2049 1924 2050 #ifdef HAVE_CODEC_BUFFERING 1925 2051 /* Try to buffer a codec for the track */ 1926 - if (info != cur_info && !audio_buffer_codec(info, track_id3)) 2052 + if (infop->self_hid != cur_info.self_hid 2053 + && !audio_buffer_codec(infop, track_id3)) 1927 2054 { 1928 - if (info->codec_hid == ERR_BUFFER_FULL) 2055 + if (infop->codec_hid == ERR_BUFFER_FULL) 1929 2056 { 1930 2057 /* No space for codec on buffer, not an error */ 1931 2058 filling = STATE_FULL; 1932 - logf("buffer is full for now (%s)", __func__); 2059 + logf("%s:STATE_FULL", __func__); 1933 2060 } 1934 2061 else 1935 2062 { ··· 1950 2077 if (track_id3->elapsed > track_id3->length) 1951 2078 track_id3->elapsed = 0; 1952 2079 1953 - if (track_id3->offset >= info->filesize) 2080 + if ((off_t)track_id3->offset >= infop->filesize) 1954 2081 track_id3->offset = 0; 1955 2082 1956 2083 logf("%s: set offset for %s to %lu\n", __func__, ··· 1994 2121 1995 2122 if (hid >= 0) 1996 2123 { 1997 - info->audio_hid = hid; 1998 - 1999 - if (info == cur_info) 2124 + infop->audio_hid = hid; 2125 + if (infop->self_hid == cur_info.self_hid) 2000 2126 { 2001 2127 /* This is the current track to decode - should be started now */ 2002 2128 trackstat = LOAD_TRACK_READY; ··· 2020 2146 } 2021 2147 2022 2148 audio_finish_load_track_exit: 2149 + if (trackstat >= LOAD_TRACK_OK && !track_info_sync(infop)) 2150 + { 2151 + logf("Track info sync failed"); 2152 + trackstat = LOAD_TRACK_ERR_FINISH_FAILED; 2153 + } 2154 + 2023 2155 if (trackstat < LOAD_TRACK_OK) 2024 2156 { 2025 2157 playlist_skip_entry(NULL, playlist_peek_offset); 2026 - track_info_close(info); 2027 - track_list_unalloc_track(); 2158 + track_list_free_info(infop); 2028 2159 2029 2160 if (playlist_peek(playlist_peek_offset, NULL, 0)) 2030 2161 playlist_next(0); ··· 2035 2166 if (filling != STATE_FULL) 2036 2167 { 2037 2168 /* Load next track - error or not */ 2038 - in_progress_id3_hid = ERR_HANDLE_NOT_FOUND; 2169 + track_list.in_progress_hid = 0; 2039 2170 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER"); 2040 2171 audio_queue_post(Q_AUDIO_FILL_BUFFER, 0); 2041 2172 } ··· 2071 2202 2072 2203 if (trackstat >= LOAD_TRACK_OK) 2073 2204 { 2074 - if (track_list_current(0) == track_list_user_current(0)) 2205 + struct track_info info, user_cur; 2206 + track_list_current(0, &info); 2207 + track_list_user_current(0, &user_cur); 2208 + 2209 + if (info.self_hid == user_cur.self_hid) 2075 2210 playlist_next(0); 2076 2211 2077 - if (filling == STATE_FULL && !track_list_user_current(1)) 2212 + if (filling == STATE_FULL && !track_list_user_current(1, NULL)) 2078 2213 { 2079 2214 /* There are no user tracks on the buffer after this therefore 2080 2215 this is the next track */ ··· 2166 2301 (Q_AUDIO_FINISH_LOAD_TRACK) */ 2167 2302 static void audio_on_finish_load_track(int id3_hid) 2168 2303 { 2169 - struct track_info *info = track_list_last(0); 2304 + struct track_info info, user_cur; 2170 2305 2171 - if (!info || !buf_is_handle(id3_hid)) 2306 + if (!buf_is_handle(id3_hid) || !track_list_last(0, &info)) 2172 2307 return; 2173 2308 2174 - if (info == track_list_user_current(1)) 2309 + track_list_user_current(1, &user_cur); 2310 + if (info.self_hid == user_cur.self_hid) 2175 2311 { 2176 2312 /* Just loaded the metadata right after the current position */ 2177 - audio_update_and_announce_next_track(bufgetid3(info->id3_hid)); 2313 + audio_update_and_announce_next_track(bufgetid3(info.id3_hid)); 2178 2314 } 2179 2315 2180 - if (audio_finish_load_track(info) != LOAD_TRACK_READY) 2316 + if (audio_finish_load_track(&info) != LOAD_TRACK_READY) 2181 2317 return; /* Not current track */ 2182 2318 2183 - bool is_user_current = info == track_list_user_current(0); 2319 + track_list_user_current(0, &user_cur); 2320 + bool is_user_current = info.self_hid == user_cur.self_hid; 2184 2321 2185 2322 if (is_user_current) 2186 2323 { 2187 2324 /* Copy cuesheet */ 2188 - buf_read_cuesheet(info->cuesheet_hid); 2325 + buf_read_cuesheet(info.cuesheet_hid); 2189 2326 } 2190 2327 2191 2328 if (audio_start_codec(track_event_flags & TEF_AUTO_SKIP)) ··· 2197 2334 change otherwise */ 2198 2335 bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); 2199 2336 2200 - playing_id3_sync(info, -1, -1); 2337 + playing_id3_sync(&info, -1, -1); 2201 2338 2202 2339 if (!was_valid) 2203 2340 { ··· 2220 2357 /* Right now, only audio handles should end up calling this */ 2221 2358 if (filling == STATE_END_OF_PLAYLIST) 2222 2359 { 2223 - struct track_info *info = track_list_last(0); 2360 + struct track_info info; 2224 2361 2225 2362 /* Really we don't know which order the handles will actually complete 2226 2363 to zero bytes remaining since another thread is doing it - be sure 2227 2364 it's the right one */ 2228 - if (info && info->audio_hid == hid) 2365 + if (track_list_last(0, &info) && info.audio_hid == hid) 2229 2366 { 2230 2367 /* This was the last track in the playlist and we now have all the 2231 2368 data we need */ ··· 2276 2413 return; 2277 2414 } 2278 2415 2279 - struct track_info *info = track_list_current(0); 2416 + struct track_info info; 2417 + bool have_info = track_list_current(0, &info); 2280 2418 struct mp3entry *track_id3 = NULL; 2281 2419 2282 2420 id3_mutex_lock(); 2283 2421 2284 2422 /* Update the current cuesheet if any and enabled */ 2285 - if (info) 2423 + if (have_info) 2286 2424 { 2287 - buf_read_cuesheet(info->cuesheet_hid); 2288 - track_id3 = bufgetid3(info->id3_hid); 2425 + buf_read_cuesheet(info.cuesheet_hid); 2426 + track_id3 = bufgetid3(info.id3_hid); 2289 2427 } 2290 2428 2291 2429 id3_write(PLAYING_ID3, track_id3); ··· 2294 2432 skip_pending = TRACK_SKIP_NONE; 2295 2433 2296 2434 /* Sync the next track information */ 2297 - info = track_list_current(1); 2435 + have_info = track_list_current(1, &info); 2298 2436 2299 - id3_write(NEXTTRACK_ID3, info ? bufgetid3(info->id3_hid) : 2300 - id3_get(UNBUFFERED_ID3)); 2437 + id3_write(NEXTTRACK_ID3, have_info ? bufgetid3(info.id3_hid) : 2438 + id3_get(UNBUFFERED_ID3)); 2301 2439 2302 2440 id3_mutex_unlock(); 2303 2441 ··· 2326 2464 2327 2465 if (trackstat >= LOAD_TRACK_OK) 2328 2466 { 2329 - struct track_info *info = track_list_current(0); 2330 - 2331 - if (info->audio_hid < 0) 2332 - return; 2333 - 2334 - /* Everything needed for the codec is ready - start it */ 2335 - if (audio_start_codec(auto_skip)) 2467 + struct track_info info; 2468 + if (track_list_current(0, &info)) 2336 2469 { 2337 - if (!auto_skip) 2338 - playing_id3_sync(info, -1, -1); 2339 - return; 2470 + if (info.audio_hid < 0) 2471 + return; 2472 + 2473 + /* Everything needed for the codec is ready - start it */ 2474 + if (audio_start_codec(auto_skip)) 2475 + { 2476 + if (!auto_skip) 2477 + playing_id3_sync(&info, -1, -1); 2478 + return; 2479 + } 2340 2480 } 2341 2481 2342 2482 trackstat = LOAD_TRACK_ERR_START_CODEC; ··· 2398 2538 skip_pending = TRACK_SKIP_AUTO; 2399 2539 2400 2540 /* Does this track have an entry allocated? */ 2401 - struct track_info *info = track_list_advance_current(1); 2541 + struct track_info info; 2542 + bool have_track = track_list_advance_current(1, &info); 2402 2543 2403 - if (!info || info->audio_hid < 0) 2544 + if (!have_track || info.audio_hid < 0) 2404 2545 { 2405 2546 bool end_of_playlist = false; 2406 2547 2407 - if (info) 2548 + if (have_track) 2408 2549 { 2409 2550 /* Track load is not complete - it might have stopped on a 2410 2551 full buffer without reaching the audio handle or we just ··· 2418 2559 issue and a pointless full reload of all the track's 2419 2560 metadata may be avoided */ 2420 2561 2421 - struct mp3entry *track_id3 = bufgetid3(info->id3_hid); 2562 + struct mp3entry *track_id3 = bufgetid3(info.id3_hid); 2422 2563 2423 2564 if (track_id3 && !rbcodec_format_is_atomic(track_id3->codectype)) 2424 2565 { ··· 2595 2736 if (trackstat >= LOAD_TRACK_OK) 2596 2737 { 2597 2738 /* This is the currently playing track - get metadata, stat */ 2598 - playing_id3_sync(track_list_current(0), resume.elapsed, resume.offset); 2739 + struct track_info info; 2740 + track_list_current(0, &info); 2741 + playing_id3_sync(&info, resume.elapsed, resume.offset); 2599 2742 2600 2743 if (valid_mp3entry(id3_get(PLAYING_ID3))) 2601 2744 { ··· 2765 2908 /* Adjust things by how much the playlist was manually moved */ 2766 2909 playlist_peek_offset -= playlist_delta; 2767 2910 2768 - struct track_info *info = track_list_advance_current(track_list_delta); 2769 2911 int trackstat = LOAD_TRACK_OK; 2770 2912 2771 - if (!info || info->audio_hid < 0) 2913 + struct track_info info; 2914 + if (!track_list_advance_current(track_list_delta, &info) 2915 + || info.audio_hid < 0) 2772 2916 { 2773 2917 /* We don't know the next track thus we know we don't have it */ 2774 2918 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1); ··· 2883 3027 /* If in transition, key will have changed - sync to it */ 2884 3028 position_key = pcmbuf_get_position_key(); 2885 3029 2886 - if (pending == TRACK_SKIP_AUTO) 3030 + if (pending == TRACK_SKIP_AUTO && !track_list_advance_current(-1, NULL)) 2887 3031 { 2888 - if (!track_list_advance_current(-1)) 3032 + /* Not in list - must rebuffer at the current playlist index */ 3033 + if (audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1) 3034 + < LOAD_TRACK_OK) 2889 3035 { 2890 - /* Not in list - must rebuffer at the current playlist index */ 2891 - if (audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1) 2892 - < LOAD_TRACK_OK) 2893 - { 2894 - /* Codec is stopped */ 2895 - break; 2896 - } 3036 + /* Codec is stopped */ 3037 + break; 2897 3038 } 2898 3039 } 2899 3040 2900 3041 /* Set after audio_fill_file_buffer to disable playing id3 clobber if 2901 3042 rebuffer is needed */ 2902 3043 skip_pending = TRACK_SKIP_NONE; 2903 - struct track_info *cur_info = track_list_current(0); 3044 + 3045 + struct track_info cur_info; 3046 + track_list_current(0, &cur_info); 2904 3047 2905 3048 /* Track must complete the loading _now_ since a codec and audio 2906 3049 handle are needed in order to do the seek */ 2907 - bool finish_load = cur_info->audio_hid < 0; 3050 + bool finish_load = cur_info.audio_hid < 0; 2908 3051 2909 3052 if (finish_load && 2910 - audio_finish_load_track(cur_info) != LOAD_TRACK_READY) 3053 + audio_finish_load_track(&cur_info) != LOAD_TRACK_READY) 2911 3054 { 2912 3055 /* Call above should push any load sequence - no need for 2913 3056 halt_decoding_track here if no skip was pending here because ··· 2918 3061 2919 3062 if (pending == TRACK_SKIP_AUTO || finish_load) 2920 3063 { 2921 - if (!bufreadid3(cur_info->id3_hid, ci_id3) || 2922 - !audio_init_codec(cur_info, ci_id3)) 3064 + if (!bufreadid3(cur_info.id3_hid, ci_id3) || 3065 + !audio_init_codec(&cur_info, ci_id3)) 2923 3066 { 2924 3067 /* We should have still been able to get it - skip it and move 2925 3068 onto the next one - like it or not this track is broken */ ··· 2927 3070 } 2928 3071 2929 3072 /* Set the codec API to the correct metadata and track info */ 2930 - ci.audio_hid = cur_info->audio_hid; 2931 - ci.filesize = cur_info->filesize; 2932 - buf_set_base_handle(cur_info->audio_hid); 3073 + ci.audio_hid = cur_info.audio_hid; 3074 + ci.filesize = cur_info.filesize; 3075 + buf_set_base_handle(cur_info.audio_hid); 2933 3076 } 2934 3077 2935 3078 if (!haltres) ··· 3568 3711 { 3569 3712 if ((unsigned)slot < MAX_MULTIPLE_AA) 3570 3713 { 3571 - struct track_info *info = track_list_user_current(skip_offset); 3714 + struct track_info user_cur; 3715 + bool have_info = track_list_user_current(skip_offset, &user_cur); 3572 3716 3573 - if (!info && abs(skip_offset) <= 1) 3717 + if (!have_info && abs(skip_offset) <= 1) 3574 3718 { 3575 3719 /* Give the actual position a go */ 3576 - info = track_list_user_current(0); 3720 + have_info = track_list_user_current(0, &user_cur); 3577 3721 } 3578 3722 3579 - if (info) 3580 - return info->aa_hid[slot]; 3723 + if (have_info) 3724 + return user_cur.aa_hid[slot]; 3581 3725 } 3582 3726 3583 3727 return ERR_HANDLE_NOT_FOUND;
+5
firmware/export/system.h
··· 97 97 #define MAX(a, b) (((a)>(b))?(a):(b)) 98 98 #endif 99 99 100 + #ifndef SGN 101 + #define SGN(a) \ 102 + ({ typeof (a) ___a = (a); (___a > 0) - (___a < 0); }) 103 + #endif 104 + 100 105 /* return number of elements in array a */ 101 106 #define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0])) 102 107