forked from len0rd/rockbox
Fixed slow track switching and track pre-buffering. Fixed rockboy
crash while audio is playing. Some buffering adjustments made. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6930 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
cc377d5d18
commit
84d6f9e89b
3 changed files with 97 additions and 31 deletions
|
@ -61,6 +61,7 @@
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
|
static volatile bool codec_loaded;
|
||||||
static volatile bool playing;
|
static volatile bool playing;
|
||||||
static volatile bool paused;
|
static volatile bool paused;
|
||||||
|
|
||||||
|
@ -213,11 +214,20 @@ bool pcm_is_playing(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pcm_is_crossfade_active(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool pcm_is_lowdata(void)
|
bool pcm_is_lowdata(void)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pcm_flush_audio(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool pcm_crossfade_init(void)
|
bool pcm_crossfade_init(void)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -487,7 +497,8 @@ bool codec_seek_buffer_callback(off_t newpos)
|
||||||
if (difference >= 0) {
|
if (difference >= 0) {
|
||||||
logf("seek: +%d", difference);
|
logf("seek: +%d", difference);
|
||||||
codec_advance_buffer_callback(difference);
|
codec_advance_buffer_callback(difference);
|
||||||
pcm_play_stop();
|
if (!pcm_is_crossfade_active())
|
||||||
|
pcm_play_stop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,6 +519,7 @@ bool codec_seek_buffer_callback(off_t newpos)
|
||||||
if (buf_ridx < 0)
|
if (buf_ridx < 0)
|
||||||
buf_ridx = codecbuflen + buf_ridx;
|
buf_ridx = codecbuflen + buf_ridx;
|
||||||
ci.curpos -= difference;
|
ci.curpos -= difference;
|
||||||
|
if (!pcm_is_crossfade_active())
|
||||||
pcm_play_stop();
|
pcm_play_stop();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -554,7 +566,7 @@ void yield_codecs(void)
|
||||||
if (!pcm_is_playing())
|
if (!pcm_is_playing())
|
||||||
sleep(5);
|
sleep(5);
|
||||||
while (pcm_is_lowdata() && !ci.stop_codec &&
|
while (pcm_is_lowdata() && !ci.stop_codec &&
|
||||||
playing && queue_empty(&audio_queue))
|
playing && queue_empty(&audio_queue) && codecbufused > (128*1024))
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,8 +949,7 @@ void audio_check_buffer(void)
|
||||||
|
|
||||||
/* Limit buffering size at first run. */
|
/* Limit buffering size at first run. */
|
||||||
if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) {
|
if (conf_bufferlimit && (int)fill_bytesleft >= conf_bufferlimit) {
|
||||||
fill_bytesleft = conf_bufferlimit;
|
fill_bytesleft = conf_bufferlimit - codecbufused;
|
||||||
conf_bufferlimit = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to load remainings of the file. */
|
/* Try to load remainings of the file. */
|
||||||
|
@ -956,6 +967,7 @@ void audio_check_buffer(void)
|
||||||
last_peek_offset++;
|
last_peek_offset++;
|
||||||
} else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) {
|
} else if (tracks[track_widx].filerem == 0 || fill_bytesleft == 0) {
|
||||||
filling = false;
|
filling = false;
|
||||||
|
conf_bufferlimit = 0;
|
||||||
pcm_set_boost_mode(false);
|
pcm_set_boost_mode(false);
|
||||||
if (playing)
|
if (playing)
|
||||||
ata_sleep();
|
ata_sleep();
|
||||||
|
@ -1128,7 +1140,7 @@ void audio_thread(void)
|
||||||
ci.stop_codec = true;
|
ci.stop_codec = true;
|
||||||
ci.reload_codec = false;
|
ci.reload_codec = false;
|
||||||
ci.seek_time = 0;
|
ci.seek_time = 0;
|
||||||
//pcm_play_stop();
|
pcm_flush_audio();
|
||||||
audio_play_start((int)ev.data);
|
audio_play_start((int)ev.data);
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
|
@ -1195,6 +1207,7 @@ void codec_thread(void)
|
||||||
switch (ev.id) {
|
switch (ev.id) {
|
||||||
case CODEC_LOAD_DISK:
|
case CODEC_LOAD_DISK:
|
||||||
ci.stop_codec = false;
|
ci.stop_codec = false;
|
||||||
|
codec_loaded = true;
|
||||||
status = codec_load_file((char *)ev.data);
|
status = codec_load_file((char *)ev.data);
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
|
@ -1209,6 +1222,7 @@ void codec_thread(void)
|
||||||
|
|
||||||
ci.stop_codec = false;
|
ci.stop_codec = false;
|
||||||
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
||||||
|
codec_loaded = true;
|
||||||
status = codec_load_ram(cur_ti->codecbuf, codecsize,
|
status = codec_load_ram(cur_ti->codecbuf, codecsize,
|
||||||
&codecbuf[0], wrap);
|
&codecbuf[0], wrap);
|
||||||
break ;
|
break ;
|
||||||
|
@ -1221,6 +1235,8 @@ void codec_thread(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
codec_loaded = false;
|
||||||
|
|
||||||
switch (ev.id) {
|
switch (ev.id) {
|
||||||
case CODEC_LOAD_DISK:
|
case CODEC_LOAD_DISK:
|
||||||
case CODEC_LOAD:
|
case CODEC_LOAD:
|
||||||
|
@ -1297,6 +1313,8 @@ void audio_stop(void)
|
||||||
{
|
{
|
||||||
logf("audio_stop");
|
logf("audio_stop");
|
||||||
queue_post(&audio_queue, AUDIO_STOP, 0);
|
queue_post(&audio_queue, AUDIO_STOP, 0);
|
||||||
|
while (playing || codec_loaded)
|
||||||
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_pause(void)
|
void audio_pause(void)
|
||||||
|
@ -1524,6 +1542,7 @@ void audio_init(void)
|
||||||
filling = false;
|
filling = false;
|
||||||
codecbuf = &audiobuf[MALLOC_BUFSIZE];
|
codecbuf = &audiobuf[MALLOC_BUFSIZE];
|
||||||
playing = false;
|
playing = false;
|
||||||
|
codec_loaded = false;
|
||||||
paused = false;
|
paused = false;
|
||||||
track_changed = false;
|
track_changed = false;
|
||||||
current_fd = -1;
|
current_fd = -1;
|
||||||
|
|
|
@ -35,6 +35,7 @@ void pcm_play_data(const unsigned char* start, int size,
|
||||||
void pcm_play_stop(void);
|
void pcm_play_stop(void);
|
||||||
void pcm_play_pause(bool play);
|
void pcm_play_pause(bool play);
|
||||||
bool pcm_is_playing(void);
|
bool pcm_is_playing(void);
|
||||||
|
bool pcm_is_crossfade_active(void);
|
||||||
|
|
||||||
/* These functions are for playing chained buffers of PCM data */
|
/* These functions are for playing chained buffers of PCM data */
|
||||||
void pcm_play_init(void);
|
void pcm_play_init(void);
|
||||||
|
@ -45,6 +46,7 @@ void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left));
|
||||||
|
|
||||||
void pcm_set_boost_mode(bool state);
|
void pcm_set_boost_mode(bool state);
|
||||||
bool pcm_is_lowdata(void);
|
bool pcm_is_lowdata(void);
|
||||||
|
void pcm_flush_buffer(long length);
|
||||||
bool pcm_crossfade_init(void);
|
bool pcm_crossfade_init(void);
|
||||||
void audiobuffer_add_event(void (*event_handler)(void));
|
void audiobuffer_add_event(void (*event_handler)(void));
|
||||||
unsigned int audiobuffer_get_latency(void);
|
unsigned int audiobuffer_get_latency(void);
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
/* Must be a power of 2 */
|
/* Must be a power of 2 */
|
||||||
#define NUM_PCM_BUFFERS (PCMBUF_SIZE / CHUNK_SIZE)
|
#define NUM_PCM_BUFFERS (PCMBUF_SIZE / CHUNK_SIZE)
|
||||||
#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
|
#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
|
||||||
#define PCM_WATERMARK (CHUNK_SIZE * 4)
|
#define PCM_WATERMARK (CHUNK_SIZE * 6)
|
||||||
#define PCM_CF_WATERMARK (PCMBUF_SIZE - CHUNK_SIZE*8)
|
#define PCM_CF_WATERMARK (PCMBUF_SIZE - CHUNK_SIZE*8)
|
||||||
|
|
||||||
static bool pcm_playing;
|
static bool pcm_playing;
|
||||||
|
@ -60,6 +60,16 @@ long audiobuffer_free;
|
||||||
static long audiobuffer_fillpos;
|
static long audiobuffer_fillpos;
|
||||||
static bool boost_mode;
|
static bool boost_mode;
|
||||||
|
|
||||||
|
/* Crossfade modes. If CFM_CROSSFADE is selected, normal
|
||||||
|
* crossfader will activate. Selecting CFM_FLUSH is a special
|
||||||
|
* operation that only overwrites the pcm buffer without crossfading.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
CFM_CROSSFADE,
|
||||||
|
CFM_FLUSH
|
||||||
|
};
|
||||||
|
|
||||||
|
static int crossfade_mode;
|
||||||
static bool crossfade_enabled;
|
static bool crossfade_enabled;
|
||||||
static bool crossfade_active;
|
static bool crossfade_active;
|
||||||
static bool crossfade_init;
|
static bool crossfade_init;
|
||||||
|
@ -346,8 +356,6 @@ bool pcm_play_add_chunk(void *addr, int size, void (*callback)(void))
|
||||||
|
|
||||||
void pcm_watermark_callback(int bytes_left)
|
void pcm_watermark_callback(int bytes_left)
|
||||||
{
|
{
|
||||||
(void)bytes_left;
|
|
||||||
|
|
||||||
/* Fill audio buffer by boosting cpu */
|
/* Fill audio buffer by boosting cpu */
|
||||||
pcm_boost(true);
|
pcm_boost(true);
|
||||||
if (bytes_left <= CHUNK_SIZE * 2)
|
if (bytes_left <= CHUNK_SIZE * 2)
|
||||||
|
@ -395,12 +403,25 @@ bool pcm_crossfade_init(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logf("crossfading!");
|
logf("crossfading!");
|
||||||
|
crossfade_mode = CFM_CROSSFADE;
|
||||||
crossfade_init = true;
|
crossfade_init = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initialize a track switch so that audio playback will not stop but
|
||||||
|
* the switch to next track would happen as soon as possible.
|
||||||
|
*/
|
||||||
|
void pcm_flush_audio(void)
|
||||||
|
{
|
||||||
|
if (crossfade_init || crossfade_active)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
crossfade_mode = CFM_FLUSH;
|
||||||
|
crossfade_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
void pcm_flush_fillpos(void)
|
void pcm_flush_fillpos(void)
|
||||||
{
|
{
|
||||||
if (audiobuffer_fillpos) {
|
if (audiobuffer_fillpos) {
|
||||||
|
@ -419,19 +440,29 @@ void pcm_flush_fillpos(void)
|
||||||
|
|
||||||
static void crossfade_start(void)
|
static void crossfade_start(void)
|
||||||
{
|
{
|
||||||
if (!crossfade_init)
|
|
||||||
return ;
|
|
||||||
|
|
||||||
crossfade_init = 0;
|
crossfade_init = 0;
|
||||||
if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6)
|
if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 4) {
|
||||||
|
if (crossfade_mode == CFM_FLUSH)
|
||||||
|
pcm_play_stop();
|
||||||
return ;
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
pcm_flush_fillpos();
|
pcm_flush_fillpos();
|
||||||
pcm_boost(true);
|
pcm_boost(true);
|
||||||
crossfade_active = true;
|
crossfade_active = true;
|
||||||
crossfade_pos = audiobuffer_pos;
|
crossfade_pos = audiobuffer_pos;
|
||||||
crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
|
|
||||||
crossfade_rem = crossfade_amount;
|
switch (crossfade_mode) {
|
||||||
|
case CFM_CROSSFADE:
|
||||||
|
crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
|
||||||
|
crossfade_rem = crossfade_amount;
|
||||||
|
break ;
|
||||||
|
|
||||||
|
case CFM_FLUSH:
|
||||||
|
crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
|
||||||
|
crossfade_rem = crossfade_amount;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
|
||||||
crossfade_pos -= crossfade_amount*2;
|
crossfade_pos -= crossfade_amount*2;
|
||||||
if (crossfade_pos < 0)
|
if (crossfade_pos < 0)
|
||||||
|
@ -441,16 +472,29 @@ static void crossfade_start(void)
|
||||||
static __inline
|
static __inline
|
||||||
int crossfade(short *buf, const short *buf2, int length)
|
int crossfade(short *buf, const short *buf2, int length)
|
||||||
{
|
{
|
||||||
int i, size;
|
int size, i;
|
||||||
int val1 = (crossfade_rem<<10)/crossfade_amount;
|
int val1, val2;
|
||||||
int val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount;
|
|
||||||
|
|
||||||
// logf("cfi: %d/%d", length, crossfade_rem);
|
|
||||||
size = MIN(length, crossfade_rem);
|
size = MIN(length, crossfade_rem);
|
||||||
for (i = 0; i < size; i++) {
|
switch (crossfade_mode) {
|
||||||
buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10;
|
case CFM_CROSSFADE:
|
||||||
|
val1 = (crossfade_rem<<10)/crossfade_amount;
|
||||||
|
val2 = ((crossfade_amount-crossfade_rem)<<10)/crossfade_amount;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
buf[i] = ((buf[i] * val1) + (buf2[i] * val2)) >> 10;
|
||||||
|
}
|
||||||
|
break ;
|
||||||
|
|
||||||
|
case CFM_FLUSH:
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
buf[i] = buf2[i];
|
||||||
|
}
|
||||||
|
//memcpy((char *)buf, (char *)buf2, size*2);
|
||||||
|
break ;
|
||||||
}
|
}
|
||||||
crossfade_rem -= i;
|
|
||||||
|
crossfade_rem -= size;
|
||||||
if (crossfade_rem <= 0)
|
if (crossfade_rem <= 0)
|
||||||
crossfade_active = false;
|
crossfade_active = false;
|
||||||
|
|
||||||
|
@ -459,7 +503,9 @@ int crossfade(short *buf, const short *buf2, int length)
|
||||||
|
|
||||||
inline static bool prepare_insert(long length)
|
inline static bool prepare_insert(long length)
|
||||||
{
|
{
|
||||||
crossfade_start();
|
if (crossfade_init)
|
||||||
|
crossfade_start();
|
||||||
|
|
||||||
if (audiobuffer_free < length + audiobuffer_fillpos
|
if (audiobuffer_free < length + audiobuffer_fillpos
|
||||||
+ CHUNK_SIZE && !crossfade_active) {
|
+ CHUNK_SIZE && !crossfade_active) {
|
||||||
pcm_boost(false);
|
pcm_boost(false);
|
||||||
|
@ -487,15 +533,12 @@ void* pcm_request_buffer(long length, long *realsize)
|
||||||
|
|
||||||
if (crossfade_active) {
|
if (crossfade_active) {
|
||||||
*realsize = MIN(length, PCMBUF_GUARD);
|
*realsize = MIN(length, PCMBUF_GUARD);
|
||||||
//logf("cfb:%d/%d", *realsize, length);
|
|
||||||
ptr = &guardbuf[0];
|
ptr = &guardbuf[0];
|
||||||
} else {
|
} else {
|
||||||
*realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos
|
*realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos
|
||||||
- audiobuffer_fillpos);
|
- audiobuffer_fillpos);
|
||||||
if (*realsize < length) {
|
if (*realsize < length) {
|
||||||
//logf("gbr1:%d/%d", *realsize, length);
|
|
||||||
*realsize += MIN((long)(length - *realsize), PCMBUF_GUARD);
|
*realsize += MIN((long)(length - *realsize), PCMBUF_GUARD);
|
||||||
//logf("gbr2:%d/%d", *realsize, length);
|
|
||||||
}
|
}
|
||||||
ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
|
ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
|
||||||
}
|
}
|
||||||
|
@ -503,17 +546,20 @@ void* pcm_request_buffer(long length, long *realsize)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pcm_is_crossfade_active(void)
|
||||||
|
{
|
||||||
|
return crossfade_active;
|
||||||
|
}
|
||||||
|
|
||||||
void pcm_flush_buffer(long length)
|
void pcm_flush_buffer(long length)
|
||||||
{
|
{
|
||||||
int copy_n;
|
int copy_n;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
if (crossfade_active) {
|
if (crossfade_active) {
|
||||||
//logf("cfbf");
|
|
||||||
buf = &guardbuf[0];
|
buf = &guardbuf[0];
|
||||||
length = MIN(length, PCMBUF_GUARD);
|
length = MIN(length, PCMBUF_GUARD);
|
||||||
while (length > 0 && crossfade_active) {
|
while (length > 0 && crossfade_active) {
|
||||||
//logf("cfl:%d", length);
|
|
||||||
copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos);
|
copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos);
|
||||||
copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
|
copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
|
||||||
(const short *)buf, copy_n/2);
|
(const short *)buf, copy_n/2);
|
||||||
|
@ -525,7 +571,6 @@ void pcm_flush_buffer(long length)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
//logf("cfl2:%d", length);
|
|
||||||
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos);
|
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos);
|
||||||
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
|
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
|
||||||
audiobuffer_fillpos = copy_n;
|
audiobuffer_fillpos = copy_n;
|
||||||
|
@ -545,7 +590,6 @@ void pcm_flush_buffer(long length)
|
||||||
|
|
||||||
copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos);
|
copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos);
|
||||||
if (copy_n > 0) {
|
if (copy_n > 0) {
|
||||||
//logf("gbu:%d/%d/%d", copy_n, audiobuffer_fillpos, audiobuffer_pos);
|
|
||||||
audiobuffer_fillpos -= copy_n;
|
audiobuffer_fillpos -= copy_n;
|
||||||
pcm_flush_fillpos();
|
pcm_flush_fillpos();
|
||||||
copy_n = MIN(copy_n, PCMBUF_GUARD);
|
copy_n = MIN(copy_n, PCMBUF_GUARD);
|
||||||
|
@ -652,6 +696,7 @@ void pcm_play_start(void)
|
||||||
pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback);
|
pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback);
|
||||||
}
|
}
|
||||||
crossfade_active = false;
|
crossfade_active = false;
|
||||||
|
|
||||||
if(!pcm_is_playing())
|
if(!pcm_is_playing())
|
||||||
{
|
{
|
||||||
size = MIN(desc->size, 32768);
|
size = MIN(desc->size, 32768);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue