summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-08-30 14:01:45 +0000
committerThomas Martitz <kugel@rockbox.org>2011-08-30 14:01:45 +0000
commitbaa070cca6d459a7c5aed81f29e4cc4f6c7410b3 (patch)
tree5123360aea420b96e4a97a8e88cf51b4277152d9 /apps/playback.c
parentd0b72e25903574acb1cf9184a6052cdd646dbc37 (diff)
downloadrockbox-baa070cca6d459a7c5aed81f29e4cc4f6c7410b3.tar.gz
rockbox-baa070cca6d459a7c5aed81f29e4cc4f6c7410b3.zip
GSoC/Buflib: Enable compaction in buflib.
This enables the ability to allocate (and free) memory dynamically without fragmentation, through compaction. This means allocations can move and fragmentation be reduced. Most changes are preparing Rockbox for this, which many times means adding a move callback which can temporarily disable movement when the corresponding code is in a critical section. For now, the audio buffer allocation has a central role, because it's the one having allocated most. This buffer is able to shrink itself, for which it needs to stop playback for a very short moment. For this, audio_buffer_available() returns the size of the audio buffer which can possibly be used by other allocations because the audio buffer can shrink. lastfm scrobbling and timestretch can now be toggled at runtime without requiring a reboot. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30381 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c76
1 files changed, 67 insertions, 9 deletions
diff --git a/apps/playback.c b/apps/playback.c
index e35d652ffb..af077e639a 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -732,8 +732,6 @@ static void scratch_mem_init(void *mem)
732 } 732 }
733} 733}
734 734
735/* Buffer must not move. And not shrink for now */
736static struct buflib_callbacks ops = { NULL, NULL };
737static int audiobuf_handle; 735static int audiobuf_handle;
738static size_t filebuflen; 736static size_t filebuflen;
739 737
@@ -744,8 +742,9 @@ size_t audio_buffer_available(void)
744 return core_available(); 742 return core_available();
745} 743}
746 744
747/* Set up the audio buffer for playback */ 745/* Set up the audio buffer for playback
748static void audio_reset_buffer(void) 746 * filebuflen must be pre-initialized with the maximum size */
747static void audio_reset_buffer_noalloc(void* filebuf)
749{ 748{
750 /* 749 /*
751 * Layout audio buffer as follows: 750 * Layout audio buffer as follows:
@@ -761,11 +760,6 @@ static void audio_reset_buffer(void)
761 760
762 /* Initially set up file buffer as all space available */ 761 /* Initially set up file buffer as all space available */
763 size_t allocsize; 762 size_t allocsize;
764 if (audiobuf_handle > 0)
765 audiobuf_handle = core_free(audiobuf_handle);
766
767 audiobuf_handle = core_alloc_maximum("audiobuf", &filebuflen, &ops);
768 unsigned char *filebuf = core_get_data(audiobuf_handle);
769 763
770 /* Subtract whatever voice needs */ 764 /* Subtract whatever voice needs */
771 allocsize = talkbuf_init(filebuf); 765 allocsize = talkbuf_init(filebuf);
@@ -830,6 +824,70 @@ bufpanic:
830 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen); 824 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen);
831} 825}
832 826
827
828/* Buffer must not move. */
829static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
830{
831 long offset = audio_current_track()->offset;
832 int status = audio_status();
833 /* TODO: Do it without stopping playback, if possible */
834 /* don't call audio_hard_stop() as it frees this handle */
835 if (thread_self() == audio_thread_id)
836 { /* inline case Q_AUDIO_STOP (audio_hard_stop() response
837 * if we're in the audio thread */
838 audio_stop_playback();
839 queue_clear(&audio_queue);
840 }
841 else
842 audio_queue_send(Q_AUDIO_STOP, 1);
843#ifdef PLAYBACK_VOICE
844 voice_stop();
845#endif
846 /* we should be free to change the buffer now */
847 size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK);
848 ssize_t size = (ssize_t)old_size - wanted_size;
849 /* set final buffer size before calling audio_reset_buffer_noalloc() */
850 filebuflen = size;
851 switch (hints & BUFLIB_SHRINK_POS_MASK)
852 {
853 case BUFLIB_SHRINK_POS_BACK:
854 core_shrink(handle, start, size);
855 audio_reset_buffer_noalloc(start);
856 break;
857 case BUFLIB_SHRINK_POS_FRONT:
858 core_shrink(handle, start + wanted_size, size);
859 audio_reset_buffer_noalloc(start + wanted_size);
860 break;
861 }
862 if ((status & AUDIO_STATUS_PLAY) == AUDIO_STATUS_PLAY)
863 {
864 if (thread_self() == audio_thread_id)
865 audio_start_playback(offset, 0); /* inline Q_AUDIO_PLAY */
866 else
867 audio_play(offset);
868 }
869
870 return BUFLIB_CB_OK;
871}
872
873static struct buflib_callbacks ops = {
874 .move_callback = NULL,
875 .shrink_callback = shrink_callback,
876};
877
878static void audio_reset_buffer(void)
879{
880 if (audiobuf_handle > 0)
881 {
882 core_free(audiobuf_handle);
883 audiobuf_handle = 0;
884 }
885 audiobuf_handle = core_alloc_maximum("audiobuf", &filebuflen, &ops);
886 unsigned char *filebuf = core_get_data(audiobuf_handle);
887
888 audio_reset_buffer_noalloc(filebuf);
889}
890
833/* Set the buffer margin to begin rebuffering when 'seconds' from empty */ 891/* Set the buffer margin to begin rebuffering when 'seconds' from empty */
834static void audio_update_filebuf_watermark(int seconds) 892static void audio_update_filebuf_watermark(int seconds)
835{ 893{