summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Giacomelli <giac2000@hotmail.com>2009-11-21 17:00:38 +0000
committerMichael Giacomelli <giac2000@hotmail.com>2009-11-21 17:00:38 +0000
commitecd9bcf3cb4d9ac1d0a6276ec66f20686d4c24ca (patch)
tree76331752aeff2e70566f39a5244513da0f331929
parent1717217cb852913cc21b044a779cad980564e989 (diff)
downloadrockbox-ecd9bcf3cb4d9ac1d0a6276ec66f20686d4c24ca.tar.gz
rockbox-ecd9bcf3cb4d9ac1d0a6276ec66f20686d4c24ca.zip
Commit FS#10605 - stable playback on low memory swcodec targets by Matthias Schneider. Should allow stable playback on targets with less then 4MB of RAM and sofware decoding such as the Sandisk Clip, c200v2, m200v4 and probably others. Fixes several problems in buffering that occured when the files to be buffered weren't much smaller then the ring buffer size. Fixes a bug where move_handle would corrupt the audio buffer when trying to copy a handle that both wrapped around the highest address in the ring buffer and overlapped part of the source and desination ranges. Moves the decision in playback.c about when to update the current track handle from audio_check_new_track to after the metadata has been buffered. Corrects several other minor pieces of code. I've logged about 100 hours without a crash on various players with this patch but its possible it breaks some combination of players and features I haven't thought to test.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23680 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/buffering.c89
-rw-r--r--apps/playback.c2
2 files changed, 47 insertions, 44 deletions
diff --git a/apps/buffering.c b/apps/buffering.c
index e80dc79b54..79144e78db 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -403,10 +403,17 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
403{ 403{
404 struct memory_handle *dest; 404 struct memory_handle *dest;
405 const struct memory_handle *src; 405 const struct memory_handle *src;
406 int32_t *here;
407 int32_t *there;
408 int32_t *end;
409 int32_t *begin;
410 size_t oldpos;
406 size_t newpos; 411 size_t newpos;
407 size_t size_to_move; 412 size_t size_to_move;
408 size_t final_delta = *delta; 413 size_t final_delta = *delta;
414 size_t n;
409 int overlap; 415 int overlap;
416 int overlap_old;
410 417
411 if (h == NULL || (src = *h) == NULL) 418 if (h == NULL || (src = *h) == NULL)
412 return false; 419 return false;
@@ -423,33 +430,34 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
423 mutex_lock(&llist_mutex); 430 mutex_lock(&llist_mutex);
424 mutex_lock(&llist_mod_mutex); 431 mutex_lock(&llist_mod_mutex);
425 432
426 newpos = RINGBUF_ADD((void *)src - (void *)buffer, final_delta); 433 oldpos = (void *)src - (void *)buffer;
434 newpos = RINGBUF_ADD(oldpos, final_delta);
427 overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1); 435 overlap = RINGBUF_ADD_CROSS(newpos, size_to_move, buffer_len - 1);
436 overlap_old = RINGBUF_ADD_CROSS(oldpos, size_to_move, buffer_len -1);
428 437
429 if (overlap > 0) { 438 if (overlap > 0) {
430 /* Some part of the struct + data would wrap, maybe ok */ 439 /* Some part of the struct + data would wrap, maybe ok */
431 size_t correction = 0; 440 size_t correction = 0;
432 /* If the overlap lands inside the memory_handle */ 441 /* If the overlap lands inside the memory_handle */
433 if ((unsigned)overlap > data_size) { 442 if (!can_wrap) {
434 /* Correct the position and real delta to prevent the struct from
435 * wrapping, this guarantees an aligned delta, I think */
436 correction = overlap - data_size;
437 } else if (!can_wrap) {
438 /* Otherwise the overlap falls in the data area and must all be 443 /* Otherwise the overlap falls in the data area and must all be
439 * backed out. This may become conditional if ever we move 444 * backed out. This may become conditional if ever we move
440 * data that is allowed to wrap (ie audio) */ 445 * data that is allowed to wrap (ie audio) */
441 correction = overlap; 446 correction = overlap;
442 /* Align correction to four bytes, up */ 447 } else if ((unsigned)overlap > data_size) {
443 correction = (correction+3) & ~3; 448 /* Correct the position and real delta to prevent the struct from
449 * wrapping, this guarantees an aligned delta, I think */
450 correction = overlap - data_size;
444 } 451 }
445 if (correction) { 452 if (correction) {
453 /* Align correction to four bytes up */
454 correction = (correction + 3) & ~3;
446 if (final_delta < correction + sizeof(struct memory_handle)) { 455 if (final_delta < correction + sizeof(struct memory_handle)) {
447 /* Delta cannot end up less than the size of the struct */ 456 /* Delta cannot end up less than the size of the struct */
448 mutex_unlock(&llist_mod_mutex); 457 mutex_unlock(&llist_mod_mutex);
449 mutex_unlock(&llist_mutex); 458 mutex_unlock(&llist_mutex);
450 return false; 459 return false;
451 } 460 }
452
453 newpos -= correction; 461 newpos -= correction;
454 overlap -= correction;/* Used below to know how to split the data */ 462 overlap -= correction;/* Used below to know how to split the data */
455 final_delta -= correction; 463 final_delta -= correction;
@@ -484,38 +492,33 @@ static bool move_handle(struct memory_handle **h, size_t *delta,
484 if (src == cur_handle) 492 if (src == cur_handle)
485 cur_handle = dest; 493 cur_handle = dest;
486 494
487 if (overlap > 0) { 495
488 /* FIXME : this code is broken and can leave the data corrupted when 496 /* Copying routine takes into account that the handles have a
489 * the amount of data to move is close to the whole buffer size. 497 * distance between each other which is a multiple of four. Faster 2 word
490 * 498 * copy may be ok but do this for safety and because wrapped copies should
491 * Example : ('S' is the source data, '-' is empty buffer) 499 * be fairly uncommon */
492 * Size of the buffer is 8 bytes, starts at 0. 500
493 * Size of the data to move is 7 bytes. 501 here = (int32_t *)((RINGBUF_ADD(oldpos, size_to_move - 1) & ~3)+ (intptr_t)buffer);
494 * 502 there =(int32_t *)((RINGBUF_ADD(newpos, size_to_move - 1) & ~3)+ (intptr_t)buffer);
495 * -SSSSSSS 503 end = (int32_t *)(( intptr_t)buffer + buffer_len - 4);
496 * ^-------- start of source data == 1 504 begin =(int32_t *)buffer;
497 * 505
498 * DD-DDDDD ('D' is desired destination data) 506 n = (size_to_move & ~3)/4;
499 * ^------ start of destination data == 3 507
500 * 508 if ( overlap_old > 0 || overlap > 0 ) {
501 * memmove(3, 1, 5); 509 /* Old or moved handle wraps */
502 * memmove(0, 7, 2); 510 while (n--) {
503 * 511 if (here < begin)
504 * First memmove() call will leave the buffer in this state: 512 here = end;
505 * 513 if (there < begin)
506 * -SSDDDDD 514 there = end;
507 * ^^ 515 *there-- = *here--;
508 * \--- data to be moved by the second memmove() call, but 516 }
509 * overwritten by the first call.
510 *
511 * See FS#10605 for more details
512 */
513 size_t first_part = size_to_move - overlap;
514 memmove(dest, src, first_part);
515 memmove(buffer, (const char *)src + first_part, overlap);
516 } else { 517 } else {
517 memmove(dest, src, size_to_move); 518 /* both handles do not wrap */
518 } 519 memmove(dest,src,size_to_move);
520 }
521
519 522
520 /* Update the caller with the new location of h and the distance moved */ 523 /* Update the caller with the new location of h and the distance moved */
521 *h = dest; 524 *h = dest;
@@ -641,10 +644,10 @@ static bool buffer_handle(int handle_id)
641 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0) 644 if (RINGBUF_ADD_CROSS(h->widx, copy_n, buf_ridx) >= 0)
642 return false; 645 return false;
643 646
644 /* This would read into the next handle, this is broken */ 647 /* This would read into the next handle, this is broken
645 if (h->next && RINGBUF_ADD_CROSS(h->widx, copy_n, 648 if (h->next && RINGBUF_ADD_CROSS(h->widx, copy_n,
646 (unsigned)((void *)h->next - (void *)buffer)) > 0) { 649 (unsigned)((void *)h->next - (void *)buffer)) > 0) {
647 /* Try to recover by truncating this file */ 650 Try to recover by truncating this file
648 copy_n = RINGBUF_ADD_CROSS(h->widx, copy_n, 651 copy_n = RINGBUF_ADD_CROSS(h->widx, copy_n,
649 (unsigned)((void *)h->next - (void *)buffer)); 652 (unsigned)((void *)h->next - (void *)buffer));
650 h->filerem -= copy_n; 653 h->filerem -= copy_n;
@@ -654,7 +657,7 @@ static bool buffer_handle(int handle_id)
654 continue; 657 continue;
655 else 658 else
656 break; 659 break;
657 } 660 } */
658 661
659 /* rc is the actual amount read */ 662 /* rc is the actual amount read */
660 int rc = read(h->fd, &buffer[h->widx], copy_n); 663 int rc = read(h->fd, &buffer[h->widx], copy_n);
diff --git a/apps/playback.c b/apps/playback.c
index f0794faf87..ff20172d83 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1549,7 +1549,6 @@ static int audio_check_new_track(void)
1549 /* Move to the new track */ 1549 /* Move to the new track */
1550 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK; 1550 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK;
1551 1551
1552 buf_set_base_handle(CUR_TI->audio_hid);
1553 1552
1554 if (automatic_skip) 1553 if (automatic_skip)
1555 { 1554 {
@@ -1904,6 +1903,7 @@ static void audio_thread(void)
1904 case Q_AUDIO_FINISH_LOAD: 1903 case Q_AUDIO_FINISH_LOAD:
1905 LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD"); 1904 LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD");
1906 audio_finish_load_track(); 1905 audio_finish_load_track();
1906 buf_set_base_handle(CUR_TI->audio_hid);
1907 break; 1907 break;
1908 1908
1909 case Q_AUDIO_PLAY: 1909 case Q_AUDIO_PLAY: