forked from len0rd/rockbox
FS#5992 Reworked playback.c to fix voice bugs by Steve Bavin. Fixed to
work with the new scheduler and handled properly and fast the track skipping. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10966 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
4553069f9d
commit
815684aced
2 changed files with 173 additions and 109 deletions
|
|
@ -232,7 +232,7 @@ static inline void pcmbuf_add_chunk(void)
|
|||
pcmbuf_current->link = NULL;
|
||||
/* This is single use only */
|
||||
pcmbuf_event_handler = NULL;
|
||||
if (pcmbuf_read) {
|
||||
if (pcmbuf_read != NULL) {
|
||||
if (pcmbuf_flush)
|
||||
{
|
||||
pcmbuf_write_end->link = pcmbuf_read->link;
|
||||
|
|
@ -305,14 +305,14 @@ bool pcmbuf_is_lowdata(void)
|
|||
/* Amount of bytes left in the buffer. */
|
||||
inline size_t pcmbuf_free(void)
|
||||
{
|
||||
if (pcmbuf_read)
|
||||
if (pcmbuf_read != NULL)
|
||||
{
|
||||
size_t read = (size_t)pcmbuf_read->addr;
|
||||
size_t write =
|
||||
(size_t)&audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
|
||||
void *read = pcmbuf_read->addr;
|
||||
void *write = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
|
||||
if (read < write)
|
||||
read += pcmbuf_size;
|
||||
return read - write;
|
||||
return (size_t)(read - write) + pcmbuf_size;
|
||||
else
|
||||
return (size_t) (read - write);
|
||||
}
|
||||
return pcmbuf_size;
|
||||
}
|
||||
|
|
@ -335,7 +335,6 @@ bool pcmbuf_crossfade_init(bool manual_skip)
|
|||
return false;
|
||||
}
|
||||
|
||||
logf("pcmbuf_crossfade_init");
|
||||
pcmbuf_boost(true);
|
||||
|
||||
/* Don't enable mix mode when skipping tracks manually. */
|
||||
|
|
@ -444,10 +443,13 @@ void pcmbuf_play_start(void)
|
|||
* until dma has been initialized. */
|
||||
pcm_mute(true);
|
||||
|
||||
if (pcmbuf_read != NULL)
|
||||
{
|
||||
last_chunksize = pcmbuf_read->size;
|
||||
pcmbuf_unplayed_bytes -= last_chunksize;
|
||||
pcm_play_data(pcmbuf_callback,
|
||||
(unsigned char *)pcmbuf_read->addr, last_chunksize);
|
||||
}
|
||||
|
||||
/* Now unmute the audio. */
|
||||
pcm_mute(false);
|
||||
|
|
@ -462,7 +464,6 @@ static bool pcmbuf_flush_fillpos(void)
|
|||
if (audiobuffer_fillpos) {
|
||||
/* Never use the last buffer descriptor */
|
||||
while (pcmbuf_write == pcmbuf_write_end) {
|
||||
logf("pcmbuf_flush_fillpos no descriptors");
|
||||
/* Deboost to let the playback catchup */
|
||||
pcmbuf_boost(false);
|
||||
/* If this happens, something is being stupid */
|
||||
|
|
@ -511,7 +512,7 @@ static void crossfade_process_buffer(size_t fade_in_delay,
|
|||
fade_out_rem -= block_rem;
|
||||
|
||||
/* Fade this block */
|
||||
while (block_rem > 0)
|
||||
while (block_rem > 0 && fade_out_chunk != NULL)
|
||||
{
|
||||
/* Fade one sample */
|
||||
short *buf = (short *)(fade_out_chunk->addr);
|
||||
|
|
@ -777,7 +778,8 @@ static bool prepare_insert(size_t length)
|
|||
logf("pcm starting");
|
||||
pcmbuf_play_start();
|
||||
}
|
||||
} else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
|
||||
}
|
||||
else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
|
||||
pcmbuf_under_watermark();
|
||||
|
||||
return true;
|
||||
|
|
@ -823,7 +825,12 @@ void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix)
|
|||
{
|
||||
if (mix)
|
||||
{
|
||||
if (pcmbuf_mix_chunk || pcmbuf_read->link)
|
||||
if (pcmbuf_read == NULL)
|
||||
{
|
||||
*realsize = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (pcmbuf_mix_chunk || pcmbuf_read->link)
|
||||
{
|
||||
*realsize = MIN(length, PCMBUF_MIX_CHUNK);
|
||||
return voicebuf;
|
||||
|
|
@ -888,7 +895,7 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
|
|||
short *pcmbuf_end = (short *)fadebuf;
|
||||
size_t samples = NATIVE_FREQUENCY / 1000 * duration;
|
||||
|
||||
if (pcm_is_playing())
|
||||
if (pcm_is_playing() && pcmbuf_read != NULL)
|
||||
{
|
||||
if (pcmbuf_read->link)
|
||||
{
|
||||
|
|
@ -971,7 +978,7 @@ void pcmbuf_mix_voice(size_t length)
|
|||
short *obuf;
|
||||
size_t chunk_samples;
|
||||
|
||||
if (!pcmbuf_mix_chunk && pcmbuf_read)
|
||||
if (pcmbuf_mix_chunk == NULL && pcmbuf_read != NULL)
|
||||
{
|
||||
pcmbuf_mix_chunk = pcmbuf_read->link;
|
||||
/* Start 1/8s into the next chunk */
|
||||
|
|
|
|||
223
apps/playback.c
223
apps/playback.c
|
|
@ -22,6 +22,8 @@
|
|||
/* TODO: Also play, stop ^^ */
|
||||
/* TODO: Can use the track changed callback to detect end of track and seek
|
||||
* in the previous track until this happens */
|
||||
/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
|
||||
* play whilst audio is paused */
|
||||
/* Design: we have prev_ti already, have a conditional for what type of seek
|
||||
* to do on a seek request, if it is a previous track seek, skip previous,
|
||||
* and in the request_next_track callback set the offset up the same way that
|
||||
|
|
@ -39,7 +41,6 @@
|
|||
#include "file.h"
|
||||
#include "lcd.h"
|
||||
#include "font.h"
|
||||
#include "backlight.h"
|
||||
#include "button.h"
|
||||
#include "kernel.h"
|
||||
#include "tree.h"
|
||||
|
|
@ -81,10 +82,7 @@
|
|||
#include "recording.h"
|
||||
#endif
|
||||
|
||||
static volatile bool audio_codec_loaded;
|
||||
static volatile bool voice_codec_loaded;
|
||||
static volatile bool playing;
|
||||
static volatile bool paused;
|
||||
#define PLAYBACK_VOICE
|
||||
|
||||
|
||||
/* default point to start buffer refill */
|
||||
|
|
@ -99,10 +97,10 @@ static volatile bool paused;
|
|||
|
||||
/* macros to enable logf for queues */
|
||||
#ifdef SIMULATOR
|
||||
#define LOGF_QUEUES /* Define this for logf output of all queuing */
|
||||
#define PLAYBACK_LOGQUEUES /* Define this for logf output of all queuing */
|
||||
#endif
|
||||
|
||||
#ifdef LOGF_QUEUES
|
||||
#ifdef PLAYBACK_LOGQUEUES
|
||||
#define LOGFQUEUE(s) logf("%s", s)
|
||||
#else
|
||||
#define LOGFQUEUE(s)
|
||||
|
|
@ -159,6 +157,14 @@ enum {
|
|||
#endif
|
||||
#define CODEC_IRAM_SIZE 0xc000
|
||||
|
||||
#ifdef PLAYBACK_VOICE
|
||||
#ifdef SIMULATOR
|
||||
static unsigned char sim_iram[CODEC_IRAM_SIZE];
|
||||
#undef CODEC_IRAM_ORIGIN
|
||||
#define CODEC_IRAM_ORIGIN sim_iram
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SIMULATOR
|
||||
extern bool audio_is_initialized;
|
||||
#else
|
||||
|
|
@ -170,13 +176,9 @@ static bool audio_is_initialized = false;
|
|||
static struct mutex mutex_codecthread;
|
||||
static struct event_queue codec_callback_queue;
|
||||
|
||||
static struct mp3entry id3_voice;
|
||||
|
||||
static char *voicebuf;
|
||||
static size_t voice_remaining;
|
||||
static bool voice_is_playing;
|
||||
static void (*voice_getmore)(unsigned char** start, int* size);
|
||||
static struct thread_entry *voice_thread_p = NULL;
|
||||
static volatile bool audio_codec_loaded;
|
||||
static volatile bool playing;
|
||||
static volatile bool paused;
|
||||
|
||||
/* Is file buffer currently being refilled? */
|
||||
static volatile bool filling IDATA_ATTR;
|
||||
|
|
@ -197,9 +199,7 @@ size_t filebufused;
|
|||
static volatile size_t buf_ridx IDATA_ATTR;
|
||||
static volatile size_t buf_widx IDATA_ATTR;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
static unsigned char *iram_buf[2];
|
||||
#endif
|
||||
static unsigned char *dram_buf[2];
|
||||
|
||||
/* Step count to the next unbuffered track. */
|
||||
|
|
@ -209,7 +209,7 @@ static int last_peek_offset;
|
|||
track ring structure. */
|
||||
static int track_ridx;
|
||||
static int track_widx;
|
||||
static bool track_changed;
|
||||
static bool track_changed; /* Audio and codec threads */
|
||||
|
||||
/* Partially loaded song's file handle to continue buffering later. */
|
||||
static int current_fd;
|
||||
|
|
@ -218,23 +218,20 @@ static int current_fd;
|
|||
static size_t fill_bytesleft;
|
||||
|
||||
/* Track info structure about songs in the file buffer. */
|
||||
static struct track_info tracks[MAX_TRACK];
|
||||
static struct track_info tracks[MAX_TRACK]; /* Audio thread */
|
||||
|
||||
/* Pointer to track info structure about current song playing. */
|
||||
static struct track_info *cur_ti;
|
||||
static struct track_info *prev_ti;
|
||||
static struct track_info *cur_ti; /* Audio and codec threads */
|
||||
static struct track_info *prev_ti; /* Audio and codec threads */
|
||||
|
||||
/* Have we reached end of the current playlist. */
|
||||
static bool playlist_end = false;
|
||||
|
||||
/* Codec API including function callbacks. */
|
||||
extern struct codec_api ci;
|
||||
extern struct codec_api ci_voice;
|
||||
static bool playlist_end = false; /* Audio thread */
|
||||
|
||||
/* Was the skip being executed manual or automatic? */
|
||||
static bool automatic_skip;
|
||||
static bool dir_skip = false;
|
||||
static bool new_playlist = false;
|
||||
static bool automatic_skip = false; /* Audio and codec threads */
|
||||
static bool dir_skip = false; /* Audio thread */
|
||||
static bool new_playlist = false; /* Audio thread */
|
||||
static int wps_offset = 0;
|
||||
|
||||
/* Callback function to call when current track has really changed. */
|
||||
void (*track_changed_callback)(struct mp3entry *id3);
|
||||
|
|
@ -250,6 +247,7 @@ static bool v1first = false;
|
|||
|
||||
/* Multiple threads */
|
||||
static const char * get_codec_filename(int enc_spec);
|
||||
static void set_filebuf_watermark(int seconds);
|
||||
|
||||
/* Audio thread */
|
||||
static struct event_queue audio_queue;
|
||||
|
|
@ -257,12 +255,12 @@ static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
|
|||
static const char audio_thread_name[] = "audio";
|
||||
|
||||
static void audio_thread(void);
|
||||
static void set_filebuf_watermark(int seconds);
|
||||
static void audio_initiate_track_change(long direction);
|
||||
static bool audio_have_tracks(void);
|
||||
static void audio_reset_buffer(void);
|
||||
|
||||
/* Codec thread */
|
||||
extern struct codec_api ci;
|
||||
static struct event_queue codec_queue;
|
||||
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
|
||||
IBSS_ATTR;
|
||||
|
|
@ -271,6 +269,17 @@ static const char codec_thread_name[] = "codec";
|
|||
struct thread_entry *codec_thread_p;
|
||||
|
||||
/* Voice thread */
|
||||
#ifdef PLAYBACK_VOICE
|
||||
extern struct codec_api ci_voice;
|
||||
|
||||
static volatile bool voice_thread_start;
|
||||
static volatile bool voice_is_playing;
|
||||
static volatile bool voice_codec_loaded;
|
||||
static void (*voice_getmore)(unsigned char** start, int* size);
|
||||
static char *voicebuf;
|
||||
static size_t voice_remaining;
|
||||
static struct thread_entry *voice_thread_p = NULL;
|
||||
|
||||
static struct event_queue voice_queue;
|
||||
static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
|
||||
IBSS_ATTR;
|
||||
|
|
@ -286,30 +295,39 @@ static void voice_boost_cpu(bool state);
|
|||
#else
|
||||
#define voice_boost_cpu(state) do { } while(0)
|
||||
#endif
|
||||
|
||||
static void voice_thread(void);
|
||||
|
||||
#endif /* PLAYBACK_VOICE */
|
||||
|
||||
/* --- External interfaces --- */
|
||||
|
||||
void mp3_play_data(const unsigned char* start, int size,
|
||||
void (*get_more)(unsigned char** start, int* size))
|
||||
{
|
||||
#ifdef PLAYBACK_VOICE
|
||||
static struct voice_info voice_clip;
|
||||
voice_clip.callback = get_more;
|
||||
voice_clip.buf = (char *)start;
|
||||
voice_clip.size = size;
|
||||
logf("mp3 > voice Q_VOICE_STOP");
|
||||
LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
|
||||
queue_post(&voice_queue, Q_VOICE_STOP, 0);
|
||||
logf("mp3 > voice Q_VOICE_PLAY");
|
||||
LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
|
||||
queue_post(&voice_queue, Q_VOICE_PLAY, &voice_clip);
|
||||
voice_is_playing = true;
|
||||
voice_thread_start = true;
|
||||
voice_boost_cpu(true);
|
||||
#else
|
||||
(void) start;
|
||||
(void) size;
|
||||
(void) get_more;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp3_play_stop(void)
|
||||
{
|
||||
logf("mp3 > voice Q_VOICE_STOP");
|
||||
#ifdef PLAYBACK_VOICE
|
||||
LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
|
||||
queue_post(&voice_queue, Q_VOICE_STOP, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mp3_pause_done(void)
|
||||
|
|
@ -360,8 +378,9 @@ struct mp3entry* audio_current_track(void)
|
|||
const char *p;
|
||||
static struct mp3entry temp_id3;
|
||||
int cur_idx;
|
||||
int offset = ci.new_track + wps_offset;
|
||||
|
||||
cur_idx = track_ridx + ci.new_track;
|
||||
cur_idx = track_ridx + offset;
|
||||
cur_idx &= MAX_TRACK_MASK;
|
||||
|
||||
if (tracks[cur_idx].taginfo_ready)
|
||||
|
|
@ -369,7 +388,7 @@ struct mp3entry* audio_current_track(void)
|
|||
|
||||
memset(&temp_id3, 0, sizeof(struct mp3entry));
|
||||
|
||||
filename = playlist_peek(ci.new_track);
|
||||
filename = playlist_peek(offset);
|
||||
if (!filename)
|
||||
filename = "No file!";
|
||||
|
||||
|
|
@ -427,10 +446,7 @@ void audio_play(long offset)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (playing)
|
||||
audio_stop();
|
||||
|
||||
playing = true;
|
||||
LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
|
||||
queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
|
||||
}
|
||||
|
|
@ -440,8 +456,6 @@ void audio_stop(void)
|
|||
{
|
||||
LOGFQUEUE("audio > audio Q_AUDIO_STOP");
|
||||
queue_post(&audio_queue, Q_AUDIO_STOP, 0);
|
||||
while (playing || audio_codec_loaded)
|
||||
yield();
|
||||
}
|
||||
|
||||
void audio_pause(void)
|
||||
|
|
@ -461,10 +475,21 @@ void audio_next(void)
|
|||
if (global_settings.beep)
|
||||
pcmbuf_beep(5000, 100, 2500*global_settings.beep);
|
||||
|
||||
/* Should be safe to do outside of thread, that way we get
|
||||
* the instant wps response at least. */
|
||||
audio_initiate_track_change(1);
|
||||
// queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1);
|
||||
if (playlist_check(ci.new_track + wps_offset + 1))
|
||||
{
|
||||
LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
|
||||
queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1);
|
||||
/* Keep wps fast while our message travels inside deep playback queues. */
|
||||
wps_offset++;
|
||||
track_changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more tracks. */
|
||||
if (global_settings.beep)
|
||||
pcmbuf_beep(3000, 300, 2500*global_settings.beep);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void audio_prev(void)
|
||||
|
|
@ -472,8 +497,21 @@ void audio_prev(void)
|
|||
if (global_settings.beep)
|
||||
pcmbuf_beep(5000, 100, 2500*global_settings.beep);
|
||||
|
||||
audio_initiate_track_change(-1);
|
||||
// queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1);
|
||||
if (playlist_check(ci.new_track + wps_offset - 1))
|
||||
{
|
||||
LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
|
||||
queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1);
|
||||
/* Keep wps fast while our message travels inside deep playback queues. */
|
||||
wps_offset--;
|
||||
track_changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more tracks. */
|
||||
if (global_settings.beep)
|
||||
pcmbuf_beep(3000, 300, 2500*global_settings.beep);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void audio_next_dir(void)
|
||||
|
|
@ -598,7 +636,6 @@ void audio_set_crossfade(int enable)
|
|||
|
||||
/* Restart playback. */
|
||||
if (was_playing) {
|
||||
playing = true;
|
||||
LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
|
||||
queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
|
||||
|
||||
|
|
@ -619,7 +656,11 @@ void audio_preinit(void)
|
|||
playing = false;
|
||||
paused = false;
|
||||
audio_codec_loaded = false;
|
||||
#ifdef PLAYBACK_VOICE
|
||||
voice_is_playing = false;
|
||||
voice_thread_start = false;
|
||||
voice_codec_loaded = false;
|
||||
#endif
|
||||
track_changed = false;
|
||||
current_fd = -1;
|
||||
track_buffer_callback = NULL;
|
||||
|
|
@ -647,6 +688,7 @@ void audio_init(void)
|
|||
|
||||
void voice_init(void)
|
||||
{
|
||||
#ifdef PLAYBACK_VOICE
|
||||
if (!filebuf)
|
||||
return; /* Audio buffers not yet set up */
|
||||
|
||||
|
|
@ -672,10 +714,12 @@ void voice_init(void)
|
|||
|
||||
while (!voice_codec_loaded)
|
||||
yield();
|
||||
#endif
|
||||
} /* voice_init */
|
||||
|
||||
void voice_stop(void)
|
||||
{
|
||||
#ifdef PLAYBACK_VOICE
|
||||
/* Messages should not be posted to voice codec queue unless it is the
|
||||
current codec or deadlocks happen. This will be addressed globally soon.
|
||||
-- jhMikeS */
|
||||
|
|
@ -683,14 +727,14 @@ void voice_stop(void)
|
|||
return;
|
||||
|
||||
mp3_play_stop();
|
||||
while (voice_is_playing && !queue_empty(&voice_queue))
|
||||
yield();
|
||||
#endif
|
||||
} /* voice_stop */
|
||||
|
||||
|
||||
|
||||
/* --- Routines called from multiple threads --- */
|
||||
|
||||
#ifdef PLAYBACK_VOICE
|
||||
static void swap_codec(void)
|
||||
{
|
||||
int my_codec = current_codec;
|
||||
|
|
@ -698,31 +742,34 @@ static void swap_codec(void)
|
|||
logf("swapping out codec:%d", my_codec);
|
||||
|
||||
/* Save our current IRAM and DRAM */
|
||||
#ifndef SIMULATOR
|
||||
memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN,
|
||||
CODEC_IRAM_SIZE);
|
||||
#endif
|
||||
memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE);
|
||||
|
||||
/* Release my semaphore */
|
||||
mutex_unlock(&mutex_codecthread);
|
||||
|
||||
/* Loop until the other codec has locked and run */
|
||||
do {
|
||||
/* Release my semaphore and force a task switch. */
|
||||
mutex_unlock(&mutex_codecthread);
|
||||
yield();
|
||||
mutex_lock(&mutex_codecthread);
|
||||
/* Loop until the other codec has locked and run */
|
||||
} while (my_codec == current_codec);
|
||||
|
||||
/* Wait for other codec to unlock */
|
||||
mutex_lock(&mutex_codecthread);
|
||||
|
||||
/* Take control */
|
||||
current_codec = my_codec;
|
||||
|
||||
/* Reload our IRAM and DRAM */
|
||||
#ifndef SIMULATOR
|
||||
memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec],
|
||||
CODEC_IRAM_SIZE);
|
||||
#endif
|
||||
invalidate_icache();
|
||||
memcpy(codecbuf, dram_buf[my_codec], CODEC_SIZE);
|
||||
|
||||
logf("resuming codec:%d", my_codec);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void set_filebuf_watermark(int seconds)
|
||||
{
|
||||
|
|
@ -761,6 +808,8 @@ static const char * get_codec_filename(int enc_spec)
|
|||
|
||||
/* --- Voice thread --- */
|
||||
|
||||
#ifdef PLAYBACK_VOICE
|
||||
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
static void voice_boost_cpu(bool state)
|
||||
{
|
||||
|
|
@ -768,8 +817,8 @@ static void voice_boost_cpu(bool state)
|
|||
|
||||
if (state != voice_cpu_boosted)
|
||||
{
|
||||
cpu_boost(state);
|
||||
voice_cpu_boosted = state;
|
||||
cpu_boost(state);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -795,7 +844,7 @@ static bool voice_pcmbuf_insert_split_callback(
|
|||
while ((dest = pcmbuf_request_voice_buffer(est_output_size,
|
||||
&output_size, playing)) == NULL)
|
||||
{
|
||||
if (playing)
|
||||
if (playing && audio_codec_loaded)
|
||||
swap_codec();
|
||||
else
|
||||
yield();
|
||||
|
|
@ -823,7 +872,7 @@ static bool voice_pcmbuf_insert_split_callback(
|
|||
if (playing)
|
||||
{
|
||||
pcmbuf_mix_voice(output_size);
|
||||
if (pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30)
|
||||
if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) && audio_codec_loaded)
|
||||
swap_codec();
|
||||
}
|
||||
else
|
||||
|
|
@ -902,12 +951,18 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
|
|||
case Q_AUDIO_PLAY:
|
||||
LOGFQUEUE("voice < Q_AUDIO_PLAY");
|
||||
if (playing)
|
||||
{
|
||||
if (audio_codec_loaded)
|
||||
swap_codec();
|
||||
else
|
||||
yield();
|
||||
}
|
||||
break;
|
||||
|
||||
#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
|
||||
case Q_ENCODER_RECORD:
|
||||
LOGFQUEUE("voice < Q_ENCODER_RECORD");
|
||||
if (audio_codec_loaded)
|
||||
swap_codec();
|
||||
break;
|
||||
#endif
|
||||
|
|
@ -940,6 +995,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
|
|||
|
||||
case Q_VOICE_PLAY:
|
||||
LOGFQUEUE("voice < Q_VOICE_PLAY");
|
||||
if (!voice_is_playing)
|
||||
{
|
||||
struct voice_info *voice_data;
|
||||
voice_is_playing = true;
|
||||
|
|
@ -949,6 +1005,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
|
|||
voicebuf = voice_data->buf;
|
||||
voice_getmore = voice_data->callback;
|
||||
}
|
||||
goto voice_play_clip;
|
||||
|
||||
case SYS_TIMEOUT:
|
||||
LOGFQUEUE("voice < SYS_TIMEOUT");
|
||||
|
|
@ -967,7 +1024,7 @@ voice_play_clip:
|
|||
voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
|
||||
|
||||
/* If this clip is done */
|
||||
if (!voice_remaining)
|
||||
if (voice_remaining == 0)
|
||||
{
|
||||
LOGFQUEUE("voice > voice Q_VOICE_STOP");
|
||||
queue_post(&voice_queue, Q_VOICE_STOP, 0);
|
||||
|
|
@ -1044,6 +1101,7 @@ static void voice_thread(void)
|
|||
}
|
||||
} /* voice_thread */
|
||||
|
||||
#endif /* PLAYBACK_VOICE */
|
||||
|
||||
/* --- Codec thread --- */
|
||||
|
||||
|
|
@ -1097,11 +1155,15 @@ static bool codec_pcmbuf_insert_split_callback(
|
|||
|
||||
pcmbuf_write_complete(output_size);
|
||||
|
||||
if (voice_is_playing && pcm_is_playing() &&
|
||||
#ifdef PLAYBACK_VOICE
|
||||
if ((voice_is_playing || voice_thread_start)
|
||||
&& pcm_is_playing() && voice_codec_loaded &&
|
||||
pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
|
||||
{
|
||||
voice_thread_start = false;
|
||||
swap_codec();
|
||||
}
|
||||
#endif
|
||||
|
||||
length -= input_size;
|
||||
}
|
||||
|
|
@ -1684,11 +1746,13 @@ static void codec_thread(void)
|
|||
case Q_CODEC_LOAD_DISK:
|
||||
LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
|
||||
audio_codec_loaded = true;
|
||||
#ifdef PLAYBACK_VOICE
|
||||
if (voice_codec_loaded)
|
||||
{
|
||||
LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
|
||||
queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
|
||||
}
|
||||
#endif
|
||||
mutex_lock(&mutex_codecthread);
|
||||
current_codec = CODEC_IDX_AUDIO;
|
||||
ci.stop_codec = false;
|
||||
|
|
@ -1711,11 +1775,13 @@ static void codec_thread(void)
|
|||
}
|
||||
|
||||
audio_codec_loaded = true;
|
||||
#ifdef PLAYBACK_VOICE
|
||||
if (voice_codec_loaded)
|
||||
{
|
||||
LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
|
||||
queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
|
||||
}
|
||||
#endif
|
||||
mutex_lock(&mutex_codecthread);
|
||||
current_codec = CODEC_IDX_AUDIO;
|
||||
ci.stop_codec = false;
|
||||
|
|
@ -1729,11 +1795,13 @@ static void codec_thread(void)
|
|||
case Q_ENCODER_LOAD_DISK:
|
||||
LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
|
||||
audio_codec_loaded = false;
|
||||
#ifdef PLAYBACK_VOICE
|
||||
if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
|
||||
{
|
||||
LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
|
||||
queue_post(&voice_queue, Q_ENCODER_RECORD, NULL);
|
||||
}
|
||||
#endif
|
||||
mutex_lock(&mutex_codecthread);
|
||||
current_codec = CODEC_IDX_AUDIO;
|
||||
ci.stop_codec = false;
|
||||
|
|
@ -1747,8 +1815,10 @@ static void codec_thread(void)
|
|||
LOGFQUEUE("codec < SYS_USB_CONNECTED");
|
||||
queue_clear(&codec_queue);
|
||||
usb_acknowledge(SYS_USB_CONNECTED_ACK);
|
||||
if (voice_codec_loaded)
|
||||
#ifdef PLAYBACK_VOICE
|
||||
if(voice_codec_loaded)
|
||||
swap_codec();
|
||||
#endif
|
||||
usb_wait_for_disconnect(&codec_queue);
|
||||
break;
|
||||
#endif
|
||||
|
|
@ -2199,7 +2269,6 @@ static bool audio_loadcodec(bool start_play)
|
|||
ci.id3 = &cur_ti->id3;
|
||||
ci.taginfo_ready = &cur_ti->taginfo_ready;
|
||||
ci.curpos = 0;
|
||||
playing = true;
|
||||
LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
|
||||
queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_fn);
|
||||
return true;
|
||||
|
|
@ -2261,8 +2330,6 @@ static bool audio_loadcodec(bool start_play)
|
|||
buf_widx -= filebuflen;
|
||||
|
||||
tracks[track_widx].codecsize += rc;
|
||||
|
||||
audio_yield_codecs();
|
||||
}
|
||||
|
||||
tracks[track_widx].has_codec = true;
|
||||
|
|
@ -2941,9 +3008,6 @@ static void audio_stop_playback(void)
|
|||
(playlist_end && ci.stop_codec)?NULL:audio_current_track());
|
||||
}
|
||||
|
||||
while (voice_is_playing && !queue_empty(&voice_queue))
|
||||
yield();
|
||||
|
||||
filebufused = 0;
|
||||
playing = false;
|
||||
filling = false;
|
||||
|
|
@ -2968,7 +3032,6 @@ static void audio_play_start(size_t offset)
|
|||
#endif
|
||||
|
||||
/* Wait for any previously playing audio to flush - TODO: Not necessary? */
|
||||
while (audio_codec_loaded)
|
||||
audio_stop_codec_flush();
|
||||
|
||||
track_changed = true;
|
||||
|
|
@ -2977,6 +3040,7 @@ static void audio_play_start(size_t offset)
|
|||
playing = true;
|
||||
ci.new_track = 0;
|
||||
ci.seek_time = 0;
|
||||
wps_offset = 0;
|
||||
|
||||
if (current_fd >= 0)
|
||||
{
|
||||
|
|
@ -3057,15 +3121,9 @@ static void audio_new_playlist(void)
|
|||
|
||||
static void audio_initiate_track_change(long direction)
|
||||
{
|
||||
if (playlist_check(direction))
|
||||
{
|
||||
playlist_end = false;
|
||||
/* Flag track changed immediately so wps can update instantly.
|
||||
* No need to wait for disk to spin up or message to travel
|
||||
* through the deep queues as this info is only for the wps. */
|
||||
track_changed = true;
|
||||
ci.new_track += direction;
|
||||
}
|
||||
wps_offset -= direction;
|
||||
}
|
||||
|
||||
static void audio_initiate_dir_change(long direction)
|
||||
|
|
@ -3090,10 +3148,8 @@ static void audio_reset_buffer(void)
|
|||
/* Allow 2 codecs at end of file buffer */
|
||||
filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE);
|
||||
|
||||
#ifndef SIMULATOR
|
||||
iram_buf[0] = &filebuf[filebuflen];
|
||||
iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE];
|
||||
#endif
|
||||
dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2];
|
||||
dram_buf[1] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
|
||||
}
|
||||
|
|
@ -3102,10 +3158,8 @@ static void audio_reset_buffer(void)
|
|||
/* Allow for 1 codec at end of file buffer */
|
||||
filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
iram_buf[0] = &filebuf[filebuflen];
|
||||
iram_buf[1] = NULL;
|
||||
#endif
|
||||
dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE];
|
||||
dram_buf[1] = NULL;
|
||||
}
|
||||
|
|
@ -3129,7 +3183,10 @@ static void audio_test_track_changed_event(struct mp3entry *id3)
|
|||
|
||||
static void audio_playback_init(void)
|
||||
{
|
||||
#ifdef PLAYBACK_VOICE
|
||||
static bool voicetagtrue = true;
|
||||
static struct mp3entry id3_voice;
|
||||
#endif
|
||||
struct event ev;
|
||||
|
||||
logf("playback api init");
|
||||
|
|
@ -3162,6 +3219,7 @@ static void audio_playback_init(void)
|
|||
ci.discard_codec = codec_discard_codec_callback;
|
||||
|
||||
/* Initialize voice codec api. */
|
||||
#ifdef PLAYBACK_VOICE
|
||||
memcpy(&ci_voice, &ci, sizeof(struct codec_api));
|
||||
memset(&id3_voice, 0, sizeof(struct mp3entry));
|
||||
ci_voice.read_filebuf = voice_filebuf_callback;
|
||||
|
|
@ -3182,6 +3240,7 @@ static void audio_playback_init(void)
|
|||
ci_voice.id3 = &id3_voice;
|
||||
id3_voice.frequency = 11200;
|
||||
id3_voice.length = 1000000L;
|
||||
#endif
|
||||
|
||||
codec_thread_p = create_thread(codec_thread, codec_stack,
|
||||
sizeof(codec_stack),
|
||||
|
|
@ -3288,8 +3347,6 @@ static void audio_thread(void)
|
|||
case Q_AUDIO_DIR_SKIP:
|
||||
LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
|
||||
playlist_end = false;
|
||||
if (global_settings.beep)
|
||||
pcmbuf_beep(5000, 100, 2500*global_settings.beep);
|
||||
audio_initiate_dir_change((long)ev.data);
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue